Closed68

Box のクライアント資格情報許可によるサーバー認証を試してみる

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

このスクラップについて

Box の Business プランを契約したので管理コンソールが使えるようになった。

契約したといっても 2 週間は試用期間なのでこの間に検証が終われば費用は発生しない。

このスクラップでは Business プラン以上でしか試すことができないサーバー認証を試してみる。

サーバー認証には JWT と クライアント資格情報許可の 2 つの方法があり、JWT の方がより安全といわれるが手順が若干面倒なので最初はお手軽なクライアント資格情報許可から試してみようと思う。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

カスタムアプリケーションの作成

開発者コンソールにアクセスする。

アプリの新規作成ボタンを押す。

カスタムアプリを選ぶ。

こんなに複雑だったっけ?

アプリ名は My First App、目的は自動化とした。

次へボタンを押す。

認証方法はサーバー認証(クライアント資格情報許可)とした。

アプリの作成ボタンを押す。

無事にアプリが作成された。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

2 要素認証の有効化

カスタムアプリページの構成タブでクライアントシークレットを取得ボタンを押すとアラートが表示される。

Settings ボタンを押す。


アカウント ID ってマスクした方がいいのかな?

2 段階認証の設定ボタンを押す。

認証アプリを選んだ状態で次へボタンを押す。

QR コードが表示されるのでスマホの認証システムアプリなどで読み込む。

認証コードを入力して送信ボタンを押す。

電話番号を入力して送信ボタンを押す。

電話番号自体は保存されたようだがバックアップコードは表示されなかった。

気になるが閉じるボタンを押す。

2 段階認証の設定自体は終わったようだ。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ここまでは復習

ここまでは無料の Individual プランでも試せた。

これからが Business プラン以上で試しか試せないので本番になる。

気合いを入れていこう。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

Enterprise 設定の確認

まずは下記を確認することから始めてみよう。

  • デフォルトで公開アプリを無効にする
  • デフォルトで未公開アプリを無効にする
  • アプリトークンを使用する場合に管理者の承認を要求する

まずは管理コンソールにアクセスする。

2 段階認証を有効にしたので認証コードが求められるようになった。

ナビゲーションでアプリを選ぶ。

カスタムアプリマネージャタブを選ぶ。

アプリの設定ボタンを押す。

すべて無効になっていることが確認できた。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

自動と手動

承認の手続きには自動と手動の 2 つがある。

先ほどは気が付かなかったが開発者コンソールのカスタムアプリのページに承認タブがある。


承認タブは Individual プランではなかった

確認して送信ボタンがあり、多分このボタンを押すと管理者宛てにメールが送信される。

メールにリンクが記載されていてリンク先にアクセスすれば承認が完了するのかな?

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

まずは自動でやってみる

確認して送信ボタンを押す。

アプリの説明を入力してから送信ボタンを押す。

リストが表示されたのでメールが送信されたようだ。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

メールを確認

下記の件名のメールを受信した。

新しいカスタムアプリの承認リクエストがあります

本文に含まれるアプリの詳細を確認ボタンを押す。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

手動承認やスコープ変更について

クライアント ID を手動で登録することで実現できる。

これは別のアカウントでも大丈夫なのかな?

せっかく Individual プランの別アカウントも持っているので試してみよう。

承認後にスコープを変更した場合は再認証が必要になる。

これも後から試してみたい。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

カスタムアプリの件数

Business プランではアプリを 1 件までしか登録できないはず。

これも別アプリを作成して試してみたい。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

まずは準備が終わった

無事にサーバー認証を試してみる準備が終わった。

次からは実際にサーバー認証を試してみたい。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

その前に

下記の細々としたことを確かめていきたい。

  • 別アカウントのカスタムアプリを登録できる?
  • 承認後にスコープを変更した場合は再認証が必要になる?
  • Business プランでアプリを 2 つ以上登録できる?
  • 手動によるカスタムアプリの登録
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

Business プランでアプリを 2 つ登録

もう 1 つアプリを作って同じ要領で承認してみた。

結論から言うとできてしまった。

それでは契約時に価格表にあったエンタープライズアプリの統合とは何なのだろう?

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

新しく作成したアプリを削除してみる

開発者コンソールのカスタムアプリの一般設定タブに含まれるアプリを削除ボタンを押す。

2 段階認証の認証コードを入力する。

再び削除ボタンを押す。

確認モーダルに含まれる削除ボタンを押す。

アプリが削除される。

不思議なことに管理コンソールのカスタムアプリマネージャのページには残っている。

仕方がないので手動で削除しておく。

削除されなかった。

問い合わせが必要になってしまった。

裏側のことはよくわからないけど Box のデータでは承認はカスタムアプリを参照しているのではなくカスタムアプリのクライアント ID を格納しているのかな?

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

カスタムアプリの手動登録

前と同じ要領でカスタムアプリを作成する。

作成したらクライアント ID をコピーする。

管理コンソールのカスタムアプリマネージャのページにあるアプリの追加ボタンを押す。

クライアント ID を入力してから次へボタンを押す。

承認ボタンを押す。

無事に登録された。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

別アカウントのカスタムアプリ承認

Individual プランで契約しているアカウントのカスタムアプリを登録しようとしてみる。

結論だけ言うとできた。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

承認後のスコープ変更

カスタムアプリの構成タブのアプリケーションセクションで書き込みにチェックを入れてから変更を保存ボタンを押す。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

カスタムアプリ側では一見すると特に変化はない

ただし詳細ページでは書き込みがスコープに含まれていないことを確認できる。

再認証してみる。

アプリのスコープが増えたことが確認できた。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ほぼ期待通りだった

カスタムアプリを 2 つ以上承認できる点を除いては。

Business プランのエンタープライズアプリの統合 1 件とはどういうことなのだろう。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

今日はここまで

結局エンタープライズアプリ統合がわからなかった。

いずれわかる時が来るだろう。

一旦置いておいて次回は本題のサーバー認証を試してみよう。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ワークスペースの作成

少し時間が空いたので復習を兼ねて Kotlin で Box API Java SDK を使う準備をしてみる。

まずは IntelliJ IDEA を起動して下記の内容でプロジェクトを作成する。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

Box API Java SDK の追加

build.gradle.kts を開いて dependencies に Box API Java SDK を追加する。

build.gradle.kts(抜粋)
dependencies {
    testImplementation(kotlin("test"))
    implementation("com.box:box-java-sdk:4.0.1") // この行を追加しました。
}
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

アクセス情報の取得

アクセスするには 3 つの情報が必要となる。

  • クライアント ID
  • クライアントシークレット
  • エンタープライズ ID

クライアント ID とクライアントシークレットは開発者コンソールのカスタムアプリの構成タブから取得できる。

エンタープライズ ID はおそらく接続先の Box アカウント(多くの場合はカスタムアプリを作成した組織と同じ)のことで管理コンソールのアカウントと請求ページから取得できる

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

環境変数の設定

IntelliJ IDEA のメニュー > Run > Edit Configurations... を選んで環境変数を設定する。

  • BOX_CLIENT_ID
  • BOX_CLIENT_SECRET
  • BOX_ENTERPRISE_ID

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

環境変数の読み込みテスト

src/main/kotlin/Main.kt
fun main(args: Array<String>) {
    val clientId = System.getenv("BOX_CLIENT_ID")
    val clientSecret = System.getenv("BOX_CLIENT_SECRET")
    val enterpriseID = System.getenv("BOX_ENTERPRISE_ID")

    println("%s %s %s".format(clientId, clientSecret, enterpriseID))
}
実行結果
xxxx yyyy zzzz

Java に比べて Kotlin が快適過ぎる。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

動作確認用フォルダの作成

ルートフォルダ一覧の動作確認のために It works! と言う名前でフォルダを作成しておく。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

動作確認

It works! と表示されなかった。

実行結果
start
end

よくわからないけどサービスアカウントという概念について知る必要がありそう。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ユーザータイプ

https://ja.developer.box.com/guides/getting-started/user-types/

Box Enterprise では下記 4 つのユーザータイプがある。

  • 管理者(Admin)
  • 管理対象ユーザー(Managed user)
  • サービスアカウント(Service account)
  • App User(App user)

たくさんあってわかりにくいが下記の表がわかりやすかった。

管理者権限 管理者以外の権限
従来のユーザー 管理者 管理対象ユーザー
Platform のみ サービスアカウント App User
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

コラボレーションとは何か?

ドキュメントで出てきたので気になった。

既存のコンテンツでのコラボレーションにサービスアカウントを追加するには、他のユーザーの場合と同様、割り当てられたメールアドレスを使用してサービスアカウントを招待します。APIを使用してコラボレーションを追加する場合は、すでにコンテンツへのアクセス権があり、コラボレータを招待するための適切なコラボレーション権限を持っているユーザーのアクセストークンを使用する必要があります。また、サービスアカウントのユーザーIDも使用します。このユーザーIDは、サービスアカウントのアクセストークンを使用して現在のユーザーを取得エンドポイントを呼び出したときに返されます。

下記のドキュメントを読む限りだとファイル共有機能のような感じがする。

https://support.box.com/hc/ja/articles/360044195193

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

サービスアカウントをコラボレーターに追加してみる

共有を押す。

サービスアカウントのメールアドレスを入力する。

サービスアカウントのメールアドレスは開発者コンソールのカスタムアプリの一般設定に表示されているもので良いのかな?

入力したら送信ボタンを押す。

フォルダーの色が変わった。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

この状態で再実行してみる

IntelliJ IDEA で Ctrl + R で実行してみる。

実行結果
start
[204677117397] It works!
end

It works! ディレクトリが表示された!

まさか成功するとは思わなかった。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ユーザーの代理で操作

https://ja.developer.box.com/guides/authentication/select/#クライアント資格情報許可

クライアント資格情報許可を使用するサーバー側認証では、エンドユーザーによる操作が必要ありません。また、適切な権限が付与されていれば、この認証方法を使用して、企業内の任意のユーザーの代理で操作することができます。IDの確認には、アプリケーションのクライアントIDとクライアントシークレットを使用します。

Box API Java SDK の GitHub ページのドキュメントによると下記のようにすれば良いのかな?

https://github.com/box/box-java-sdk/blob/main/doc/authentication.md#as-user

api.asUser("USER-ID");
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ユーザー一覧の取得

ユーザーの代理で操作するにはユーザー ID が必要だがどうやって取得すれば良いかわからない。

API を使って取得しようとしてみる。

src/main/kotlin/Main.kt
import com.box.sdk.BoxCCGAPIConnection
import com.box.sdk.BoxUser

fun main(args: Array<String>) {
    val clientID = System.getenv("BOX_CLIENT_ID")
    val clientSecret = System.getenv("BOX_CLIENT_SECRET")
    val enterpriseID = System.getenv("BOX_ENTERPRISE_ID")

    val api = BoxCCGAPIConnection.applicationServiceAccountConnection(clientID, clientSecret, enterpriseID)
    val users = BoxUser.getAllEnterpriseUsers(api)

    println("start")

    for (user in users) {
        println("%s".format(user.name))
    }

    println("end")
}
実行結果
start
end

何も表示されなかった。

権限が不足しているのかな?

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

スコープの追加

開発者コンソールからカスタムアプリの構成タブでユーザーを管理するスコープを追加する。

忘れずに変更ボタンを押す。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

今日はここまで

無事にサーバー認証を行うことができた。

コラボレーション(ファイル共有)を使って動作確認もできた。

ユーザー ID の一覧は開発者トークンを利用すればできるようなので次回試してみたい。

それが終わったらユーザーの代理としてアクセスすることを検証してみよう。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

開発者トークンの取得

開発者コンソールのカスタムアプリの構成タブで開発者トークンを生成ボタンを押す。

開発者トークンは環境変数に BOX_DEVELOPER_TOKEN として設定しておく。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ユーザー一覧取得の再挑戦

ソースコードに変更を加える。

src/main/kotlin/Main.kt
import com.box.sdk.BoxAPIConnection
import com.box.sdk.BoxUser

fun main(args: Array<String>) {
    val developerToken = System.getenv("BOX_DEVELOPER_TOKEN")

    val api = BoxAPIConnection(developerToken)
    val users = BoxUser.getAllEnterpriseUsers(api)

    println("start")

    for (user in users) {
        println("%s: %s".format(user.name, user.id))
    }

    println("end")
}

Ctrl + R を押して実行する。

実行結果(例)
start
薄田 達哉: 12345678901
end

成功した、嬉しい。

一応アカウント設定ページのアカウント詳細セクションに表示されるアカウント ID を確認した所、同じ値だった。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

代理アクセスの設定

開発者コンソールからカスタムアプリで as-user ヘッダーを許可する必要がありそう。

許可したら今度は管理コンソールで再承認する必要がありそう。

まずは全く設定しないでやってみてどうなるかを確認してみようと思う。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

コーディング

src/main/kotlin/Main.kt
import com.box.sdk.BoxCCGAPIConnection
import com.box.sdk.BoxFolder

fun main(args: Array<String>) {
    val clientID = System.getenv("BOX_CLIENT_ID")
    val clientSecret = System.getenv("BOX_CLIENT_SECRET")
    val enterpriseID = System.getenv("BOX_ENTERPRISE_ID")
    val userID = System.getenv("BOX_USER_ID")

    val api = BoxCCGAPIConnection.applicationServiceAccountConnection(clientID, clientSecret, enterpriseID)
    api.asUser(userID)

    val rootFolder = BoxFolder.getRootFolder(api)

    println("start")

    for (itemInfo in rootFolder) {
        println("[%s] %s".format(itemInfo.id, itemInfo.name))
    }

    println("end")
}
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

動作確認

期待通り権限不足で実行が失敗した。

com.box.sdk.BoxAPIResponseException: The API returned an error code [403 | 3m617nhdbm0movmx.097f6bd405b5d7706dddc7374cf2d33c3] access_denied_insufficient_permissions - Access denied - insufficient permission

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

代理アクセスはクライアント資格情報許可ではできないかも

as-user ヘッダーの許可と再認証を行なってから再度実行してみたが結果は変わらなかった。

なんでだろうと思って調べたらサーバー認証にクライアント資格情報許可ではなくて JWT を使う必要がありそう。

https://ja.developer.box.com/guides/authentication/jwt/as-user/

as-userヘッダーを利用すると、JWTアプリケーションは別のユーザーの代理になることができます。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

まとめ

今回のスクラップ作成を通じて学んだことは下記の通り。

  • サーバ認証を試すには Box Business プラン以上が必要になる。
  • もしかしたら Box Business Starter でも大丈夫かも知れない。
  • カスタムアプリ承認には手動と自動の 2 つがある。
  • カスタムアプリの権限を変更したら再認証が必要となる。
  • 手動承認を使うと別アカウントのカスタムアプリも登録できる。
  • Business プランでもサーバー認証のカスタムアプリを 2 つ以上登録できる。
  • 承認したカスタムアプリは問い合わせないと削除できない。
  • SDK から接続するにはクライアント ID・クライアントシークレット・エンタープライズ ID の 3 点が必要となる。
  • エンタープライズ ID は管理コンソールのアカウントと請求ページから確認できる。
  • サービスアカウントには独自のルートフォルダーが与えられる。
  • サービスアカウントは API 経由でのみアクセスできる管理者のようなもの。
  • おそらく App ユーザーにも独自のルートフォルダーが与えられる。
  • Business Plus 以上だったら管理コンソールでサービスアカウントのルートフォルダーを一覧できそう。
  • ユーザーからサービスアカウントにフォルダを共有(コラボレーション)することでサービスアカウントはユーザーのファイルにアクセスできる。
  • サービスアカウントをコラボレーションに招待するとすぐに承認される。
  • ユーザー ID は API を使って一覧できるが自分のだけであればアカウント設定ページからも確認できる。

不明な点は下記の通り。

  • Box 価格体系ページにあるエンタープライズアプリの統合というのはいまだに何なのか謎である。
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

おわりに

サーバー認証を使ってファイルにアクセスできることを確認できて良かった。

サーバー認証を使った場合の初期設定はどうなるのだろう?

ユーザーさんの Box 管理者にカスタムアプリのクライアント ID を教える、カスタムアプリを承認してもらう、エンタープライズ ID を教えてもらうなどのステップが必要となりそう。

ユーザーのファイルにアクセスする必要があればユーザー ID の一覧も必要だが、これはカスタムアプリ側で取得できるのでユーザーさんの管理者にやってもらう必要は無さそう。

管理者は大変だけど OAuth 2.0 ユーザー認証のようにエンドユーザーさんに操作してもらう必要がないのでその点は楽なのかも知れない。

実際にサンプルアプリを作ってみるとイメージが湧くかも知れないので機会を作ってやってみようと思う。

このスクラップは2023/04/27にクローズされました