GASのUSER_DEPLOYINGとUSER_ACCESSINGを分けた|管理画面に管理者が入れない

GASの管理画面とAPIで実行ユーザーを分けた記録 Google Workspace・GAS

GASで作った「共通ログイン」の管理画面に、管理者として登録したアカウントで入れない。許可リストには載っているのに、画面には「アクセス権がありません」と出る。

10月1日の更新で、この問題に対応するため、管理画面をAPI本体から別のGASプロジェクトへ分けました。DBを操作するAPIはデプロイ者の権限で動かし、画面はアクセスした利用者の権限で動かす構成です。

今回の焦点は、DBを操作する権限と、画面を使っている人の本人確認を、同じ実行ユーザー設定に任せていたことでした。

管理者一覧を見る前に、本人を特定できていなかった

共通ログインのAPIは、USER_DEPLOYING、つまりデプロイした人として実行する設定です。利用者全員に管理用DBを共有しなくても、API側で読み書きできるようにしていました。

管理画面も同じプロジェクトに置き、Session.getActiveUser().getEmail() で利用者を識別していました。しかし更新時の記録では、別ドメインや個人のGoogleアカウントで開くと、このメールアドレスが空になっていました。

空の値では、登録済みの管理者かどうかを照合できません。管理者の登録漏れと、本人を特定できない問題が、同じ拒否表示になっていました。

GASでは実行条件によって、アクティブユーザーのメールアドレスを取得できない場合があります。デプロイ者として動くWebアプリでの制限も、Sessionの公式リファレンスに説明されています。同じドメインで動いた結果だけを、別のアカウントにもそのまま当てはめられませんでした。

APIの設定を変えると、DBの権限も変わる

API本体を利用者として実行する設定に変えればよい、と一度は考えられます。ただし、それではDB操作も利用者の権限で実行されます。

わたしが残したかったのは、DBをバックエンドだけで扱う構成でした。そこで実行単位を2つに分けました。

役割 実行ユーザー 担当する処理
管理画面 USER_ACCESSING 利用者の承認を受け、操作をAPIへ中継する
API本体 USER_DEPLOYING 呼び出し元の本人確認、管理権限判定、DB操作

アクセスした人として実行するWebアプリでは、その人の権限で処理が動きます。この違いはGAS Webアプリの公式ガイドにも記載されています。

画面側にはDB操作を置きません。管理用スプレッドシートを利用者全員に共有する方式にも戻していません。

OAuthトークンで本人を確認してから、管理権限を判定する

管理画面の操作は、画面側のGASにある中継関数を通します。中継関数が利用者のOAuthアクセストークンを取得し、API本体へ送ります。

流れは次のようになりました。

1. 利用者が管理画面を開き、必要な権限を承認する。
2. 画面側のGASが、その利用者のアクセストークンを付けて操作を中継する。
3. API側がGoogleのtokeninfoでトークンを確認する。
4. 確認できたアカウントが管理者かを、API側で判定する。
5. 許可された管理操作を、API側の権限で実行する。

トークンの検証では、確認済みメールアドレスや有効期限を確認するコードがあります。呼び出し元アプリの制限は、追加設定がある場合に検査する実装です。設定の有無まで、ソースコードだけで確定したことにはしていません。

管理権限は、明示した管理者一覧、または管理者の役割を持つ登録Googleグループへの所属で判定します。その後10月3日の更新で、明示した管理者一覧はそのまま残し、それに加えて共通の登録グループのメンバーと、共通アカウントとして登録したGoogleアカウントも、全員を管理者として扱う形に変わりました。登録されていないアカウントは拒否します。Googleアカウントで本人と分かったことだけでは、管理者にはなりません。

画面に管理用ボタンを表示することと、APIが管理操作を許可することも別です。権限の判定はバックエンドに残しました。

途中でHTTP 401にも当たった

管理画面を分けた更新時の記録には、トークンを付けてAPIへ呼び出した際、Google側の入口でHTTP 401になったことも残っています。

この構成では、画面側のOAuthスコープにdrive.readonlyを含めて対応したと記録されています。現行マニフェストにも残っています。

ただし、これは今回のデプロイ設定と呼び出し経路で起きた401への対応です。「GASのAPIには常にDriveの読み取り権限が必要」と一般化する根拠にはしていません。画面側が管理DBを読み書きするために追加したスコープでもありません。

その後のAPI v27では、APIの入口そのものは匿名のリクエストも受け付ける設定にしました。代わりに、データを扱う操作はすべて、Googleで確認できたトークンと共通の登録がそろっていることを必須にしています。トークンなし・無効なトークンの呼び出しが拒否されることは、実際のHTTPリクエストで確認しました。管理画面側のマニフェストにはdrive.readonlyが今も残っています。

今回確認できた範囲

この記事を書く際に確認したのは、更新記録、現行コード、両プロジェクトのマニフェストです。次の点は、それらから確認できました。

  • 管理画面とAPIで、実行ユーザーの設定を分けている。
  • 管理画面が利用者のトークンを付けて操作を中継する。
  • API側に本人確認と管理者判定の処理がある。
  • DB操作はAPI本体に置かれている。
  • 旧管理画面の入口には、新しい画面への案内を返す実装がある。

一方、今回の執筆作業で、全アカウントの実機ログインや本番デプロイの反映確認まではしていません。別ドメイン、個人アカウント、未登録のアカウント、期限切れトークンなどの条件でどう動くかは、実行環境での検証と分けて扱います。

同じ症状を調べるなら、わたしは次の順番で確認します。

1. 誰として実行する設定かを、画面とAPIそれぞれで見る。
2. 管理者一覧の照合前に、本人を識別できているかを見る。
3. OAuthの本人確認と、アプリの管理権限判定を分けて見る。
4. 認証を直す変更が、DBの操作権限まで変えていないかを見る。
5. 登録済みのアカウントが使えることと、登録されていないアカウントが拒否されることを両方確かめる。

共通ログインの管理画面を直すために、DBを扱うAPIまで利用者の権限へ変える必要はありませんでした。今回の変更は、それぞれに必要な実行ユーザーを、別のプロジェクトで持たせる設計です。

認証方式と運用の構成を確認したいとき

コメント

タイトルとURLをコピーしました