Google Appsでユーザーの外部アプリケーションの認可状況を監査する

Google AppsのAdmin Reports APIドメインのユーザーの外部アプリの認可状況がとれるようになったのでメモ

Reports API: Authorization Tokens Activity Report - Admin SDK — Google Developers

ソースコードは文末、今回はサービスアカウントで行っているが、認可時に特権管理者であればもちろんOK。

これになぜ興味をもったかというとGoogleのOAuth2のドキュメントに
Using OAuth 2.0 to Access Google APIs - Google Accounts Authentication and Authorization — Google Developersの項が増えて、accesstokenが25個までとなったため。

There is currently a 25-token limit per Google user account. If a user account has 25 valid tokens, the next authentication request succeeds, but quietly invalidates the oldest outstanding token without any user-visible warning.

(意訳)
Googleのアカウント毎にアクセストークンは25個までです。もしユーザーが有効なアクセストークンを25個もっていた場合、次の認可リクエストに成功するとユーザーへの警告などもなく、有効期限が古いものから順に無効化されていきます。

https://developers.google.com/accounts/docs/OAuth2#expiration

アカウント毎と書いてあるけど、これはプロジェクトかクライアントIDだろうな。本当にアカウントなのかな? とか、oldest outstanding tokenってrefreshTokenがあるから、有効期限が古いものからだろうなとかおもうことはあるが、ユーザーへの警告などもなく無効化されていきますが凶暴だなとおもうわけです。



担当している製品では1アカウントで複数の端末にアプリをインストールするのだけれど、この制限で最大25台毎(推奨は15 - 20)に1アカウント必要になったため、accesstokenの一覧がほしいんだけど、これまでそれに類するものが取得できなかったので、これでできそうということでやってみた。

package com.example;

import java.io.File;
import java.io.FileReader;
import java.util.Arrays;

import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.admin.reports.Reports;
import com.google.api.services.admin.reports.ReportsScopes;

public class ListDomainAccessTokenAudit {
  public static void main(String[]  args) throws Exception{
    JsonFactory jsonfactory = new GsonFactory();
    HttpTransport transport = new NetHttpTransport();

    // APIコンソールで取得出来る。中身はサービスアカウントのIDとclient_id,client_secret
    GoogleClientSecrets secret = GoogleClientSecrets.load(jsonfactory, new FileReader("client_secret.json"));

    String service_account = (String)secret.getWeb().get("client_email");
    String client_id = secret.getWeb().getClientId();
    
    // 事前準備としてGoogle Appsの管理コンソールでOAuthアクセスできるようにしておく
    GoogleCredential credential = new GoogleCredential.Builder()
      .setTransport(transport)
      .setJsonFactory(jsonfactory)
      .setClientSecrets(secret)
      .setServiceAccountId(service_account)
      // ドメイン管理者としてアクセス
      .setServiceAccountUser("admin@example.com")
      // サービスアカウントでアクセスするので、秘密鍵が必要。
      // APIコンソールから取得出来る証明書から設定
      .setServiceAccountPrivateKeyFromP12File(new File("service_account.p12"))
      // 監査用のスコープを設定する
      .setServiceAccountScopes(Arrays.asList(ReportsScopes.ADMIN_REPORTS_AUDIT_READONLY))
      .build();
    
    // accessTokenを取得
    if(!credential.refreshToken()){
      return ;
    }
    
    
    Reports reports = new Reports.Builder(transport, jsonfactory, credential)
      .setApplicationName(client_id)
      .build();
    // 全員分を取りたいときはuser@example.comの代わりにallを指定する
    System.out.println(reports.activities().list("user@example.com", "token").execute().toPrettyString());
  }
  
}