現象
UserStoreType を mem 以外(sql / ora / npg)にすると、CIBA と Device Authorization Grant が動かない。
#207 で入れたストア切り替えで初めて回せるようになり、7 件の不具合 が出た。
sql(SQL Server)での E2E 通しは 224 件中 103 件が失敗 で始まった。
System.InvalidOperationException: Sequence contains no elements
at Dapper.SqlMapper.ThrowZeroRows(Row row)
at ...CibaProvider.ReceiveTokenReq(...)
ORA-01400: ("SCOTT"."DeviceAuthZData"."Id") に NULL は挿入できません
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
Cannot implicitly convert type 'decimal' to 'long'. An explicit conversion exists (are you missing a cast?)
at ...DeviceAuthZProvider.ReceiveTokenReq(...)
内訳は次の 3 系統。
A. provider の SQL 分岐(3 方言すべて)
内容
箇所
A-1
Dapper の QueryFirst は、行が無いと例外を投げる (null を返さない)。そのため直後の if (dyn == null)(「レコードなし」の分岐)が到達不能 で、存在しない device_code / auth_req_id を渡すと HTTP 500 になる
9(DeviceAuthZProvider 6 / CibaProvider 3)
A-2
Result 列は未応答のとき NULL だが、SQL 分岐は非 null 前提でキャストしていた。GetState は空文字を「未応答」として authorization_pending を返す作りなので、NULL は空文字として渡すのが正しい
6
A-3
RequestObjectProvider.Get が、行が無いとき SQL 分岐だけ null を返していた(Memory 分岐は "")。その null が JsonConvert.DeserializeObject(null) に渡り ArgumentNullException になる
1
A-1 / A-2 は mem では通る(Memory 分岐は別実装)ため、これまで露出していなかった。
B. Oracle の DDL(#206 で追加した分の作り込み)
内容
B-1
CREATE SEQUENCE …; / ALTER TABLE …; の行末にコメントを書くと、sqlplus が次の文を飲み込む (ORA-03405)。結果、後続の表が作られない
B-2
ORA-01400(20 件)。sqlserver は IDENTITY(1,1)、pstgrs は serial で自動採番されるが、Oracle を「シーケンス + NOT NULL」にしたため、Id を渡さない provider の INSERT が落ちる (UserClaims だけは provider 側が NEXTVAL を明示しているので通っていた)
C. Oracle の方言(既存)
内容
C-1
Oracle に boolean が無い。 Result は NUMBER(3) で 0 / 1 / NULL。((bool)…) では変換できず、bool.TryParse("1") が失敗して GetState が irregularity_data を返す。例外は出ない ため、authorization_pending / access_denied が出ないまま 14 件が静かに失敗する
C-2
Oracle の NUMBER は decimal で返る。 dynamic 経由の暗黙変換は通らず RuntimeBinderException(4 件)。CibaProvider は ((long)dyn.AuthReqExp) と明示していて、これが「CIBA は通るのに Device AuthZ が落ちる」差そのものだった
環境
バージョン
1st_agent_ph1(d9645c0 時点)
構成要素
CommonLibrary、files/resource/MultiPurposeAuthSite/Sql/oracle/Create_UserStore.sql
ターゲット
net48 / net10.0(npg は Npgsql が #if NETCORE のみのため net10.0 だけ)
UserStoreType
sql / ora / npg(mem では再現しない)
再現手順
対象の DBMS を起動し、Create_UserStore.sql でストアを作る
E2E テストで UserStoreType を切り替えられるようにする(SQL 系のストアが未検証) #207 のオプションでストアを指定して E2E を通す
.\2_RunAllTests.ps1 -Launch -UserStoreType sql -ConnectionString '...;Encrypt=false;'
.\2_RunAllTests.ps1 -Launch -UserStoreType ora -ConnectionString '...'
.\2_RunAllTests.ps1 -Launch -UserStoreType npg -ConnectionString '...'
期待する動作
4 ストアで E2E の結果が同じになる。 ストアの違いは実装の内側の話で、プロトコルの応答は変わらないはず。
調べたこと
修正前後を実測した。
UserStoreType
修正前
修正後
mem
222 成功 / 0 失敗 / 2 Skip
222 / 0 / 2(変化なし)
sql
103 失敗 → 12 失敗
222 / 0 / 2
ora
18 失敗 → 14 → 8
222 / 0 / 2
npg
111 / 0 / 113
111 / 0 / 113(Skip 113 は net48 が Npgsql 非対応のため)
ビルドは エラー 0 / 警告 45(net48)・39(net10.0)で、警告は増えていない。
A-1 / A-2 は 6f6eda1 の親にも同じ形で存在し(QueryFirst( が DeviceAuthZProvider 6 箇所・CibaProvider 3 箇所、bool result = dyn. が 3 箇所)、今回の変更で持ち込んだものではない。
B-1 / B-2 は 6cdf3b8(#206 )で Oracle 側に表を足したときの作り込み。
静的な確認では出ない種類の不具合である。 いずれも「SQL 系ストアに実際に回した」ことで初めて分かった。#207 のストア切り替えが無ければ、mem が緑である限り気付けない。
利用者への影響
あり。 mem 以外のストアでは、CIBA と Device Authorization Grant が使えない
(存在しないコードを渡すと HTTP 500、Oracle では応答が irregularity_data になる)。
mem のみで運用している場合は影響しない。
なお、修正は既に作ってあり、この Issue の番号で同一コミットとして入る。
上の「調べたこと」の実測表は、その修正の前後を測った値である。
現象
UserStoreTypeをmem以外(sql/ora/npg)にすると、CIBA と Device Authorization Grant が動かない。#207 で入れたストア切り替えで初めて回せるようになり、7 件の不具合が出た。
sql(SQL Server)での E2E 通しは 224 件中 103 件が失敗で始まった。内訳は次の 3 系統。
A. provider の SQL 分岐(3 方言すべて)
QueryFirstは、行が無いと例外を投げる(nullを返さない)。そのため直後のif (dyn == null)(「レコードなし」の分岐)が到達不能で、存在しないdevice_code/auth_req_idを渡すと HTTP 500 になるDeviceAuthZProvider6 /CibaProvider3)Result列は未応答のとき NULL だが、SQL 分岐は非 null 前提でキャストしていた。GetStateは空文字を「未応答」としてauthorization_pendingを返す作りなので、NULL は空文字として渡すのが正しいRequestObjectProvider.Getが、行が無いとき SQL 分岐だけnullを返していた(Memory 分岐は"")。そのnullがJsonConvert.DeserializeObject(null)に渡りArgumentNullExceptionになるA-1 / A-2 は
memでは通る(Memory 分岐は別実装)ため、これまで露出していなかった。B. Oracle の DDL(#206 で追加した分の作り込み)
CREATE SEQUENCE …;/ALTER TABLE …;の行末にコメントを書くと、sqlplusが次の文を飲み込む(ORA-03405)。結果、後続の表が作られないORA-01400(20 件)。sqlserverはIDENTITY(1,1)、pstgrsはserialで自動採番されるが、Oracle を「シーケンス +NOT NULL」にしたため、Idを渡さない provider のINSERTが落ちる(UserClaimsだけは provider 側がNEXTVALを明示しているので通っていた)C. Oracle の方言(既存)
ResultはNUMBER(3)で 0 / 1 / NULL。((bool)…)では変換できず、bool.TryParse("1")が失敗してGetStateがirregularity_dataを返す。例外は出ないため、authorization_pending/access_deniedが出ないまま 14 件が静かに失敗するNUMBERはdecimalで返る。dynamic経由の暗黙変換は通らずRuntimeBinderException(4 件)。CibaProviderは((long)dyn.AuthReqExp)と明示していて、これが「CIBA は通るのに Device AuthZ が落ちる」差そのものだった環境
1st_agent_ph1(d9645c0時点)files/resource/MultiPurposeAuthSite/Sql/oracle/Create_UserStore.sqlnpgは Npgsql が#if NETCOREのみのため net10.0 だけ)sql/ora/npg(memでは再現しない)再現手順
Create_UserStore.sqlでストアを作る期待する動作
4 ストアで E2E の結果が同じになる。 ストアの違いは実装の内側の話で、プロトコルの応答は変わらないはず。
調べたこと
修正前後を実測した。
memsqloranpgビルドは エラー 0 / 警告 45(net48)・39(net10.0)で、警告は増えていない。
A-1 / A-2 は
6f6eda1の親にも同じ形で存在し(QueryFirst(がDeviceAuthZProvider6 箇所・CibaProvider3 箇所、bool result = dyn.が 3 箇所)、今回の変更で持ち込んだものではない。B-1 / B-2 は
6cdf3b8(#206)で Oracle 側に表を足したときの作り込み。静的な確認では出ない種類の不具合である。 いずれも「SQL 系ストアに実際に回した」ことで初めて分かった。#207 のストア切り替えが無ければ、
memが緑である限り気付けない。利用者への影響
あり。
mem以外のストアでは、CIBA と Device Authorization Grant が使えない(存在しないコードを渡すと HTTP 500、Oracle では応答が
irregularity_dataになる)。memのみで運用している場合は影響しない。なお、修正は既に作ってあり、この Issue の番号で同一コミットとして入る。
上の「調べたこと」の実測表は、その修正の前後を測った値である。