SaaSの共有リンクとアプリへの同意
是正した対象と残った経路を、変更後の保存状態で説明します。
説明
SaaSの公開範囲には共有リンク、利用者への直接権限、アプリへの同意など複数の経路があります。一つの経路を削除しても、ほかの経路が残る場合があります。
固定の共有権限台帳で対象リンクだけを削除し、残る権限を読み直します。アプリ同意と発行済みトークンも別の表として確認します。
是正した対象と残った経路を、変更後の保存状態で説明します。
1文書ごとの権限を読む
linkはリンク経由、directは主体へ直接付与した権限です。
from sp14 import *
from sp02 import show文書ごとの権限を読む
db=connect()
show(db,"SELECT * FROM permission ORDER BY id")doc7には匿名リンクとbobの直接権限、doc8には別の匿名リンクがあります。
2修正対象を文書IDと権限IDで固定する
p1だけを対象にします。
show修正対象を文書IDと権限IDで固定する(db,"SELECT id,object,principal,version FROM permission WHERE id='p1' AND object='doc7'")versionは1です。取得から更新までに変更された場合を検出するため、世代も条件へ含めます。
3古い世代での削除を試す
期待世代を0にした削除です。
cur=db.execute("DELETE FROM permission WHERE id='p1' AND object='doc7' AND version=0")
print(cur.rowcount古い世代での削除を試す)0行です。対象が消えていない状態を成功として報告しません。実APIでも条件付き更新の結果を確認します。
4一致する世代で削除して読み直す
世代1を指定し、doc7に残る権限を取得します。
print(db.execute("DELETE FROM permission WHERE id='p1' AND object='doc7' AND version=1").rowcount)
show一致する世代で削除して読み直す(db,"SELECT id,kind,principal FROM permission WHERE object='doc7'")1行削除され、bobの直接権限は残ります。匿名リンクの削除と、すべての利用者からのアクセス取消しは別です。
5別文書の権限を保持したことを確認する
doc8のp3を読み直します。
show別文書の権限を保持したことを確認する(db,"SELECT id,object,principal FROM permission WHERE object='doc8'")p3は残っています。目的がdoc7だけの是正なら、同じ種類のリンクを全件削除しないよう対象を絞ります。
6アプリの同意種別と範囲を読む
applicationとdelegatedを分けて表示します。
showアプリの同意種別と範囲を読む(db,"SELECT * FROM consent ORDER BY id")g1は利用者なしで使うapplication権限、g2は利用者に代わるdelegated権限の資料です。実効権限の判断には両者で異なる条件があります。
7同意取消しと既存トークンを別に確認する
g1を無効にした後、期限内のトークンを検索します。
db.execute("UPDATE consent SET active=0 WHERE id='g1'")
show同意取消しと既存トークンを別に確認する(db,"SELECT c.id,c.active,t.id AS token,t.expires FROM consent c LEFT JOIN token t ON t.grant_id=c.id ORDER BY c.id")g1は無効でもt1が残ります。既存トークンをいつ拒否するかはサービスの検証・失効方式を確認し、同意取消しだけで即時終了したと推測しません。
まとめ
共有の各経路を個別に棚卸しします。
対象と世代を条件にして変更し、読み直します。
同意取消しと発行済みトークンの扱いを確認します。
操作履歴と解説を振り返れます。
Python 3.15 / SQLite / 固定の主体・権限・操作記録
from sp14 import *
from sp02 import show
db=connect()
show(db,"SELECT * FROM permission ORDER BY id")id | object | kind | principal | role | version p1 | doc7 | link | anyone | read | 1 p2 | doc7 | direct | bob | read | 1 p3 | doc8 | link | anyone | read | 1
show(db,"SELECT id,object,principal,version FROM permission WHERE id='p1' AND object='doc7'")id | object | principal | version p1 | doc7 | anyone | 1
cur=db.execute("DELETE FROM permission WHERE id='p1' AND object='doc7' AND version=0")
print(cur.rowcount)0
print(db.execute("DELETE FROM permission WHERE id='p1' AND object='doc7' AND version=1").rowcount)
show(db,"SELECT id,kind,principal FROM permission WHERE object='doc7'")1 id | kind | principal p2 | direct | bob
show(db,"SELECT id,object,principal FROM permission WHERE object='doc8'")id | object | principal p3 | doc8 | anyone
show(db,"SELECT * FROM consent ORDER BY id")id | app | scope | kind | active g1 | app7 | Files.Read.All | application | 1 g2 | app7 | User.Read | delegated | 1
db.execute("UPDATE consent SET active=0 WHERE id='g1'")
show(db,"SELECT c.id,c.active,t.id AS token,t.expires FROM consent c LEFT JOIN token t ON t.grant_id=c.id ORDER BY c.id")id | active | token | expires g1 | 0 | t1 | 200 g2 | 1 | NULL | NULL
演習完了