Google Apps API使用に必要なOAuth 2.0認証について学ぶ

  • このエントリーをはてなブックマークに追加
セキュリティ イメージ

クライアントアプリからGoogle Apps APIを使用し、Google CalendarやGoogle Driveなどを利用するには、OAuth 2.0で認証を行う必要があります。OAuth 2.0の仕組みやOAuth 2.0で認証を行うプログラミングの方法について解説します。

OAuth 2.0とは

OAuth 2.0 は、サードパーティーアプリによるHTTPサービスへの限定的なアクセスを可能にする認可フレームワークである。

[参考]The OAuth 2.0 Authorization Framework

OAuth 2.0の目的

従来のクライアントサーバー型の認証モデルでは、クライアントはリソースオーナーのクレデンシャル(IDやパスワード)を使ってサーバーに対して認証を行い、サーバー上の保護されたリソースにアクセスする。つまり、サードパーティーアプリに保護されたリソースへのアクセス権を与えるには、リソースオーナーは自身のクレデンシャル(ID/パスワード)をサードパーティーと共有する必要があるり、これはいくつかの問題と制限をもたらす。

  • サードパーティーアプリは、後の利用のためにリソースオーナーのクレデンシャル(ID/パスワード)を保存しておかなければならない。特にパスワードは平文 で保存されることになる。
  • パスワードを利用することでセキュリティが低下したとしても、サーバーはパスワードベースの認証方式をサポートしなければならない。
  • サードパーティーアプリは、リソースオーナーの保護されたリソースに対して過度に広範囲のアクセス権を得ることになる一方で、リソースオーナーは、アクセスをリソースのサブセットに限定したりアクセス可能期間を制限したりできない。
  • リソースオーナーは各サードパーティーごとにアクセス権を無効化することはできず、アクセス権を無効化する際にはすべてのサードパーティーが持つアクセス権を無効化しなければならない。つまりそれはパスワード変更を意味する。
  • サードパーティーアプリの情報漏えいはエンドユーザーのパスワードおよびパスワードによって保護されているすべての情報の漏洩につながる。

OAuthは、認可レイヤーをもうけてクライアントとリソースオーナーの役割を分けることで、これらの問題の解決に取り組む。OAuthでは、クライアントは、リソースオーナーのコントロール下にありリソースサーバーによってホストされているリソースへのアクセス権を要求する。そしてリソースオーナーのクレデンシャル(ID/パスワード)そのものとは別のクレデンシャル(アクセストークン)を取得する。

OAuth 2.0の登場人物

OAuthは以下の4つのロールを定義している。

  • リソースオーナー (resource owner)

保護されたリソースへのアクセスを許可するエンティティー、リソースオーナーが人間の場合はエンドユーザーと呼ばれる。

  • リソースサーバー (resource server)

保護されたリソースをホストし、アクセストークンを用いた保護されたリソースへのリクエストを受理してレスポンスを返すことのできるサーバーである。

  • クライアント (client)

リソースオーナーの認可を得て、リソースオーナーの代理として保護されたリソースに対するリクエストを行うアプリケーションである。  (OAuthクライアントは、サーバー上で動くアプリであることもあれば、デスクトップアプリやその他のデバイス上で動くアプリであることもある)

  • 認可サーバー (authorization server)

リソースオーナーの認証とリソースオーナーからの認可取得が成功した後、アクセストークンをクライアントに発行するサーバーである。

OAuth 2.0の仕組み

OAuth 2.0 認証のシーケンス図を以下に示します。

OAuth 2.0 の仕組み

Google Apps APIの認証情報を取得する

使用するAPIの認証情報を取得する手順を以下に示します。

使用するGoogle Apps APIを有効にする

Google Cloud Platform コンソールのAPI Managerで、プロジェクトで使用するAPIを有効にします。

Google Cloud Platform API Manager

  • 使用するAPI(ここでは、Google Drive API)をクリックします。

Google Drive APIは、アプリからユーザーデータへアクセスすることになるので、「OAuth 2.0によるユーザーデータへのアクセス」に該当します。

Google Cloud Platform API Manager

  • 「有効にする」をクリックします。

Google Drive APIでアクセスするための認証情報を作成していきます。

Google Cloud Platform API Manager

  • 「認証情報を作成」をクリックします。

プロジェクトへの認証情報を追加する

プロジェクトへの認証情報の追加を行っていきます。(以前の画面をショートカットし、この画面からも始められます)

必要な認証情報の種類を調べる

まずは、どんな認証情報が必要かを指定します。

Google Cloud Platform API Manager

  • 「使用するAPI」を選択します。(以前の画面で指定したGoogle Drive APIが選択されています)
  • 「APIを呼び出す場所」を指定します。ここでは、「その他のUI(Windows, CLIツールなど)」を選択します。
  • 「アクセスするデータの種類」を選択します。ここでは「ユーザーデータ」を選択します。
  • 「必要な認証情報」をクリックします。

OAuth 2.0 クライアントIDを作成する

Google Cloud Platform API Manager

  • アプリケーションIDの元になる「名前」を入力します。

OAuth 2.0 同意画面を設定する

Google Cloud Platform API Manager

  • プロバイダの「メールアドレス」を入力します。
  • 「ユーザに表示するサービス名」(何のサービスから認証を求められているかを識別できる名前)を入力します。
  • 「次へ」をクリックします。

認証情報をダウンロードする

Google Cloud Platform API Manager

  • 「ダウンロード」をクリックします。(後でダウンロードすることもできます)
  • 認証情報ファイル「client_id.json」がダウンロードされます。
  • 「完了」ボタンをクリックします。

Google Apps APIを使用したPythonクライアントアプリを作成する

Google Apps APIを使用した、アプリのプログラミングの方法について示します。

環境:Python 3.6.1

Google Client Library をインストールする

Google Apps APIを使用するには、Google Client library をインストールします。

$ pip install –upgrade google-api-python-client

Pythonソースコードの実行時に「ImportError: cannot import name ‘discovery’」のエラーが出力される場合は、以下のコマンドでGoogle Client Libraryを再インストールしてみてください。

pip install –force-reinstall google-api-python-client

OAuth 2.0 プログラミング

以下に、OAuth 2.0 のクレデンシャル(アクセストークン)を取得するPythonソースコードを示します。

from __future__ import print_function
import httplib2
import os

from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage

try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None

# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/google-drive-credential.json
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Google Drive List Files'

def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)credentials
    credential_path = os.path.join(credential_dir,
                                   'google-drive-credential.json')

    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials

リソースにアクセスするクライアントアプリ

リソース(Google Drive)のクレデンシャル(アクセストークン)を取得し、リソース(Google Drive)のファイルリストを表示するPythonソースコードを示します。

def main():
    """Shows basic usage of the Google Drive API.

    Creates a Google Drive API service object and outputs the names and IDs
    for up to 10 files.
    """
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('drive', 'v3', http=http)

    results = service.files().list(
        pageSize=10,fields="nextPageToken, files(id, name)").execute()
    items = results.get('files', [])
    if not items:
        print('No files found.')
    else:
        print('Files:')
        for item in items:
            print('{0} ({1})'.format(item['name'], item['id']))

if __name__ == '__main__':
    main()

Google Drive APIのOAuth 2.0 SCOPE情報

上記アプリでは、SCOPESに「https://www.googleapis.com/auth/drive.readonly」を設定していますが、Google Drive APIのOAuth 2.0 SCOPE情報には以下が指定できます。アプリの機能に対する適切なSCOPE情報を設定してください。

SCOPE 意味
https://www.googleapis.com/auth/drive Application Dataフォルダを除く、ユーザーの全てのファイルへ完全なアクセスを許可します。このスコープは、厳密に必要な場合にのみリクエストしてください。
https://www.googleapis.com/auth/drive.readonly ファイルメタデータとファイルコンテンツへの読み取り専用アクセスを許可します。
https://www.googleapis.com/auth/drive.appfolder Application Dataフォルダへのアクセスを許可します。
 https://www.googleapis.com/auth/drive.file  アプリで作成または開いたファイルへのファイル単位のアクセスを許可します。
 https://www.googleapis.com/auth/drive.install  ユーザーがアプリのインストールを承認できるようにするための特別なスコープです。
 https://www.googleapis.com/auth/drive.metadata  ファイルメタデータ(downloadUrlおよびcontentHints.thumbnailを除く)への読み書きアクセスを許可しますが、ファイルコンテンツの読み取り、ダウンロード、書き込み、アップロードへのアクセスは許可されません。ファイルの作成、削除、または削除をサポートしません。 また、アクセスのエスカレーションを防ぐためにフォルダや共有を変更することもできません。
 https://www.googleapis.com/auth/drive.metadata.readonly  ファイルメタデータ(downloadUrlとcontentHints.thumbnailを除く)への読み取り専用アクセスを許可しますが、ファイルコンテンツの読み取りやダウンロードは許可しません。
 https://www.googleapis.com/auth/drive.photos.readonly  すべての写真に読み取り専用アクセスを許可します。 spacesパラメータはphotosに設定する必要があります。
 https://www.googleapis.com/auth/drive.scripts  Apps Scriptファイルへのアクセスを許可します。

クライアントアプリ実行時の認証プロセス

クライアントアプリの実行

クライアントアプリを実行する前に、以下の準備をしておきます。

  • 認証情報ファイルを所定の場所(アプリのコードに合わせ、「client_secret.json」にリネームし、ここではアプリのソースコードと同じ場所)へ配備します。
  • クレデンシャルファイル(アクセストークン)の格納ディレクトリ(ここでは「~/.credentials」)を作成しておきます。

上記で作成した、Google Driveのファイル一覧を表示するアプリを実行します。

$ python listfiles.py
  • Pythonコマンドでアプリ「listfiles.py」を実行します。

[注意]リモートでアプリを実行する場合は、リモートデスクトップ接続などでアプリを起動してください。Tera TermなどSSHでアプリを起動してもブラウザと連携した認証プロセスが実行できません。

リソースオーナへの認証リクエスト

ブラウザでGoogleへログインしている場合はアカウントの選択画面が表示されます。ログインしていない場合は、Googleアカウント(メールアドレス)とパスワード入力画面が表示されます。

OAuth 2.0 認証プロセス

  • 「<プロジェクト名>に移動」をクリックすると、プロバイダの情報(メールアドレス、サービス名)が確認できます。
  • 認証を与えるGoogle Driveのアカウントを選択します。

OAuth 2.0 認証プロセス

  • クライアントアプリからのリクエストに応じる場合は「許可」をクリックします。

認証に成功すると以下の画面が表示されます。

OAuth 2.0 認証プロセス

アクセストークンによるリソースへのアクセス

認証が成功するとリソース(Google Drive)へアクセスするためのアクセストークン(ここでは「google-drive-credentials.json」ファイル)が生成されます。以降のアプリ実行ではこのファイルを使用しリソース(Google Drive)へアクセスするので、毎回認証を求められることはありません。

Google Drive API OAuth 2.0 by Python

[参考]Google Drive APIs > REST > Python Quickstart

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。

コメントを残す

*