diff --git a/AGENTS.md b/AGENTS.md index 3206a8af8..414964f7d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ https://github.com/OpenTouryoProject/OpenTouryo/ と、ソレを使用したサンプル・アプリケーションの開発エージェント用。 -環境のセットアップとビルド手順は [root/Readme.ja.md](root/Readme.ja.md) を参照。 +環境のセットアップ・ビルド・検証の手順は [root/Readme.ja.md](root/Readme.ja.md) を参照。 本書は、その上で**エージェントが守るべきこと**と、**どの文書を見るか**を示す。 **プロジェクト共通の投稿規約は [Contributing.ja.md](Contributing.ja.md) に従う。** @@ -170,23 +170,17 @@ Copyright ブロックの扱い、`ArgumentException` 系の引数の順、`.bat ### ビルド・テスト・リリースの検証は、専用の文書に従う -変更を加えたあとの**検証**は、次の文書が一次情報である。 +**検証の手順そのものは、人もエージェントも同じである。** +入口は [root/Readme.ja.md](root/Readme.ja.md) の「ビルド後の検証」で、 +3 本のスクリプト(ビルド → 単体テスト → 疎通)と、その一次情報 +(`BUILDING.md` / `TESTING.md` / `SMOKETEST.md`、リリース時の作業全体は `RELEASE.md`)は、 +そこから辿れる。**本節は、その上で残るエージェント固有の判断だけを扱う。** -| 目的 | 読む文書 | -|---|---| -| **手順だけを引く(早見)** | [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) | -| リリース時の作業全体 | [`RELEASE.md`](root/programs/RELEASE.md) | -| 全ビルドの実行と判定 | [`BUILDING.md`](root/programs/BUILDING.md) | -| 単体テストの実行と判定 | [`TESTING.md`](root/programs/TESTING.md) | -| サンプルの疎通確認 | [`SMOKETEST.md`](root/programs/SMOKETEST.md) | - -検証は `1_BuildAll.ps1`(ビルド)→ `2_RunAllTests.ps1`(単体テスト)→ -`3_SmokeTest.ps1`(疎通)の 3 本で、いずれも終了コードで合否が分かる。 -**順序は固定**(1 のクリーンとアセンブリ配置が 2・3 の前提)。 - -**本書にコマンドは書かない。** 引数(`-IgnoreErrors` / `-Only` / `-List` / `-Lang`)と -合格の目安は [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) 1 節が一次情報である。 -**転記すると、両方を直さないかぎりズレる。** +**手順だけを引くなら [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) 1 節。** +引数(`-IgnoreErrors` / `-Only` / `-List` / `-Lang`)・合格の目安・ +実行順(**固定**。1 のクリーンとアセンブリ配置が 2・3 の前提)は、そこが一次情報である。 + +**本書にコマンドは書かない。転記すると、両方を直さないかぎりズレる。** `2_RunAllTests.ps1` はワーキング ツリーの `Result*.txt` を書き換える(従来のバッチ運用と同じ)。 **コミットの要否は人が判断する**ため、エージェントは差分を報告するに留める。 diff --git a/root/README.md b/root/README.md index 2b137494c..09d5babf3 100644 --- a/root/README.md +++ b/root/README.md @@ -133,6 +133,9 @@ cd C:\root\programs | `2_RunAllTests.ps1` | Runs the unit tests and compares the results with the previous ones | | `3_SmokeTest.ps1` | Starts the sample applications and checks that they work | +The three can also be run individually. **In that case the order is fixed**, +because the clean and the assembly deployment done by `1_` are prerequisites of `2_` and `3_`. + For the procedures and the criteria, refer to [`BUILDING.md`](programs/BUILDING.md) / [`TESTING.md`](programs/TESTING.md) / [`SMOKETEST.md`](programs/SMOKETEST.md) in the same folder. diff --git a/root/Readme.ja.md b/root/Readme.ja.md index 68c80d97e..210c809d0 100644 --- a/root/Readme.ja.md +++ b/root/Readme.ja.md @@ -131,6 +131,9 @@ cd C:\root\programs | `2_RunAllTests.ps1` | 単体テストを実行し、結果を前回のものと比較 | | `3_SmokeTest.ps1` | サンプルアプリケーションを起動して疎通を確認 | +3 本は個別に実行することもできます。**その場合の実行順は固定**です +(`1_` のクリーンとアセンブリ配置が `2_` `3_` の前提になっているため)。 + 手順と判定基準は、同じフォルダの [`BUILDING.md`](programs/BUILDING.md) / [`TESTING.md`](programs/TESTING.md) / [`SMOKETEST.md`](programs/SMOKETEST.md) を参照してください。 diff --git a/root/programs/CS/Frameworks/ANALYSIS.md b/root/programs/CS/Frameworks/ANALYSIS.md index 1b982b007..7ff041bda 100644 --- a/root/programs/CS/Frameworks/ANALYSIS.md +++ b/root/programs/CS/Frameworks/ANALYSIS.md @@ -193,6 +193,67 @@ private void UOC_SelectCount(TestParameterValue p) // private でよい --- +### 4.4 **非同期の実体(`~Async` は「別スレッドで同期実行」)**(#402) + +**D層に非同期の API は無い。** `BaseDam` は `ExecuteReader` / `ExecuteScalar` / +`ExecuteNonQuery` の同期版だけを持つ。 + +上位の `~Async` も、**別スレッドで同期版を走らせているだけ**である。 + +```csharp +// CallController.cs / BaseLogic.cs +return Task<...>.Factory.StartNew(() => { + return this.Invoke(...); // 同期版 +}); +``` + +**これはブロックの移動であって、除去ではない。** +呼び出し元のスレッドは解放されるが、**プールのスレッドが 1 本、DB 応答の間ずっと塞がる。** + +#### **非同期化しない、と判断している**(#402) + +業務系の DBMS アプリケーションでは、**非同期のサポートは重要ではない**と判断した。 + +**1 要求が 1 コネクションを保持する設計だからである。** + +``` +UOC_ConnectionOpen で Dam を作り、コネクションとトランザクションを開く + → B層の処理がすべて終わるまで保持 → Commit / Rollback +``` + +**同時実行数は、スレッド数ではなくコネクション プールの上限で決まる。** +スレッドを解放できても、プールが空かなければ次には進めない。 +非同期化で増えるのは「**待てる要求の数**」であって、 +「**同時に処理できる要求の数**」ではない。 + +| 論点 | 既存の機構 | +|---|---| +| 同時実行数の制御 | コネクション プール(上限) | +| 応答しない処理の打ち切り | `FxSqlCommandTimeout`(既定 30 秒) | + +**非同期化でしか得られないのは「実行中の中断」だけ**だが、 +業務システムでは利用者が処理を中断する場面が限られ、多くは `CommandTimeout` で足りる。 + +#### **プロバイダによって非同期の実体が違う** + +**足すとしても、一様には効かない。** +`DbCommand` の `~Async` は、プロバイダが上書きしなければ +**基底クラスの既定実装=呼び出し元スレッドで同期実行**になる。 +**`await` してもそこで止まる**ため、今より悪くなり得る。 + +| Dam | ライブラリ | 非同期の実体 | +|---|---|---| +| `DamSqlSvr` | `Microsoft.Data.SqlClient` | 真の非同期 | +| `DamPstGrS` | `Npgsql` | 真の非同期 | +| `DamMySQL` | `MySql.Data` | **要検証** | +| `DamManagedOdp` | `Oracle.ManagedDataAccess` | **要検証** | +| `DamODBC` / `DamOLEDB` | 標準 | **効果なし**(既定実装) | + +> **`~Async` という名前は「非同期である」と読まれる。** +> 効かないプロバイダに足すと、名前だけが非同期になり、実態を隠す。 + +--- + ## 5. 設定(XML 定義ファイル + appSettings) ### 5.1 XML 定義ファイル(`root/files/resource/Xml/`) diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/IdToken.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/IdToken.cs index be8e9092b..0989eb87e 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/IdToken.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/IdToken.cs @@ -29,6 +29,7 @@ //* ---------- ---------------- ------------------------------------------------- //* 2018/08/22 西野 大介 新規作成 //* 2018/11/28 西野 大介 証明書 & Jwk対応 + jkuチェック対応の追加 +//* 2026/09/10 玄人 幸道 CreateHashが左半分でなく左右のXORを返していたのを修正(#584) //********************************************************************************** using System; @@ -209,6 +210,19 @@ public static bool Verify(string id_token, /// /// string /// hash + /// + /// OIDC の定義(OpenID Connect Core 1.0 3.1.3.6 / 3.3.2.11)どおり、 + /// ハッシュの**左半分**(先頭 bytes.Length / 2 バイト)を base64url にする。 + /// + /// 2026/09/10 まで ArrayOperator.ShortenByteArray で半分にしていたため、 + /// 左半分ではなく**左半分と右半分の XOR** になっていた(#584)。 + /// ShortenByteArray は切り詰めではなく XOR による畳み込みで、 + /// 鍵長の調整(GetKeyedHash)がその挙動に依存するため、あちらは直さない。 + /// + /// VerifyHash も同じ CreateHash で作り直して比べるため、 + /// 本フレームワーク同士では誤っていても一致し、気付けなかった。 + /// **修正前の版で発行された値は、修正後の VerifyHash では検証に失敗する。** + /// public static string CreateHash(string input) { // ID Token の JOSE Header にある @@ -219,8 +233,9 @@ public static string CreateHash(string input) EnumHashAlgorithm.SHA256); // 左半分を base64url エンコードした値。 + // (ShortenByteArray は XOR で畳み込むため使わない。#584) return CustomEncode.ToBase64UrlString( - ArrayOperator.ShortenByteArray(bytes, (bytes.Length / 2))); + ArrayOperator.CopyArray(bytes, (bytes.Length / 2))); } /// diff --git a/root/programs/CS/Frameworks/Readme.txt b/root/programs/CS/Frameworks/Readme.txt deleted file mode 100644 index 6d09f1fdf..000000000 --- a/root/programs/CS/Frameworks/Readme.txt +++ /dev/null @@ -1,21 +0,0 @@ -<フォルダの説明> - -● Infrastructure - Frameworkの一式です。 - -● Tools - - - DPQuery_Tool - 動的パラメタライズド・クエリ分析ツール - - - DaoGen_Tool - D層自動生成ツール - - - DeployZipPackWithHTTP - Webデプロイ部品 - - - Encryption - 暗号化部品 - -● PortableClassLibrary - Silverlight, WinStore用部品 diff --git a/root/programs/CS/Frameworks/Tests/TestCode/Program.cs b/root/programs/CS/Frameworks/Tests/TestCode/Program.cs index f1fea76b9..b0335c30c 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/Program.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/Program.cs @@ -27,6 +27,7 @@ //* 2026/08/18 玄人 幸道 各テストを個別に try で囲むようにした(#564)。 //* 1 つが例外を投げると、以降が実行されなかった。 //* 2026/08/08 玄人 幸道 TestZipV2の呼び出しを追加(#524) +//* 2026/09/10 玄人 幸道 TestIdTokenの呼び出しを追加(#584) //********************************************************************************** using System; @@ -107,6 +108,10 @@ public static void Main(string[] args) // DB に接続するテストと前提が異なるため、プロジェクトを分けている。 #endregion + #region Framework + Program.Run("TestIdToken", TestIdToken.Root); + #endregion + #region Business // Touryo.Infrastructure.Business // GMTMaster diff --git a/root/programs/CS/Frameworks/Tests/TestCode/README.md b/root/programs/CS/Frameworks/Tests/TestCode/README.md index 2da272e99..85531e9d7 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/README.md +++ b/root/programs/CS/Frameworks/Tests/TestCode/README.md @@ -64,6 +64,12 @@ y_Build_TestCode_Public.bat … ビルド → 実行 → 結果ファイル | `TestLatebind` | `Public.Reflection` | 遅延バインドによる呼び出し(`NonPublic` を含む) | | `TestFastReflection` | `Public.FastReflection` | `AccessorCacher` / `InstanceCreator` 等の高速リフレクション(#522) | +### Framework + +| ファイル | 対象 | 見ていること | +|---|---|---| +| `TestIdToken` | `Framework.Authentication` | `at_hash` / `c_hash` / `s_hash` の計算(`IdToken.CreateHash` / `VerifyHash`)。**期待値は OIDC 仕様の例示値**(#584) | + `TestEmbedded.txt` は `TestResourceLoader` が読む埋め込みリソース。 **`LogicalName` を `TestCode.TestEmbedded.txt` に固定している** (既定のままだと `TestCodeFx` / `TestCodeCore` で名前が食い違うため)。 @@ -117,6 +123,17 @@ MyDebug.OutputDebugAndConsole( 桁の重みを `256 * j`(掛け算)で求めていたため 3 byte 目から誤っていたが、 8 byte の出力をそのまま期待値にしていたため、いったん見逃した。 +### 「作って、同じ実装で確かめる」は検算にならない + +**作る側と確かめる側が同じ実装を使うと、誤っていても一致する。** + +`IdToken.VerifyHash` は、`CreateHash` で作り直した値と比べるだけである。 +`CreateHash` は OIDC の定義(ハッシュの左半分)ではなく左右の XOR を返していたが、 +本フレームワーク同士では一致するため、**外部の RP に拒否されるまで気付かれなかった**(#584)。 + +**期待値には、実装と独立に求めた値を置く。** 仕様の例示値があればそれを使う +(`TestIdToken` は OpenID Connect Core 1.0 付録 A の値を使っている)。 + ### 境界は必ず跨ぐ 同じ `GetLongFromByte` は、**1〜2 byte だけを見ていると不具合に気付けない。** @@ -168,7 +185,7 @@ net48 側は `4_Build_CopyAssemblies.bat` が依存 DLL を `Build_net48` へ並 |---|---| | `PubCmnFunction.GetFileNameNoEx` | 第 2 引数は**パス区切り**。拡張子の区切りだと思って `'.'` を渡すと空文字が返る | | `ArrayOperator.CopyArray` | **配列を伸ばせない。** コピー長が「コピー先配列の長さ」で固定のため、コピー先を大きくするとコピー元が足りず落ちる。書込開始位置を 0 より後ろにしても落ちる | -| `ArrayOperator.ShortenByteArray` | 単純な切り詰めではなく、**XOR で畳み込む**(暗号鍵の生成用) | +| `ArrayOperator.ShortenByteArray` | 単純な切り詰めではなく、**XOR で畳み込む**(暗号鍵の生成用)。**切り詰めに使ってはならない**(`IdToken.CreateHash` がこれで誤った、#584)。切り詰めは `CopyArray` | | `ArrayOperator.GetLongFromByte` | ビッグ エンディアン。8 byte で最上位ビットが立つと **Int64 の範囲を超えて負になる**(2 の補数として解釈した値) | | `StringExtractor.GetParameterFromQueryString` | 「値が空」と「名前が無い」を**区別できない**(どちらも `""`) | | `ObjectInspector` | 再帰の深さは **5 まで**。入口で加算・出口で減算するカウンタで抑えている | diff --git a/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt b/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt index fb422eb14..f68215b51 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt +++ b/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt @@ -70,11 +70,11 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2026/08/20 10:54:24,630],[DEBUG],[1],LogIF.DebugLog("ACCESS"); -[2026/08/20 10:54:24,639],[INFO ],[1],LogIF.InfoLog("ACCESS"); -[2026/08/20 10:54:24,640],[WARN ],[1],LogIF.WarnLog("ACCESS"); -[2026/08/20 10:54:24,640],[ERROR],[1],LogIF.ErrorLog("ACCESS"); -[2026/08/20 10:54:24,640],[FATAL],[1],LogIF.FatalLog("ACCESS"); +[2026/09/10 22:27:52,562],[DEBUG],[1],LogIF.DebugLog("ACCESS"); +[2026/09/10 22:27:52,568],[INFO ],[1],LogIF.InfoLog("ACCESS"); +[2026/09/10 22:27:52,569],[WARN ],[1],LogIF.WarnLog("ACCESS"); +[2026/09/10 22:27:52,569],[ERROR],[1],LogIF.ErrorLog("ACCESS"); +[2026/09/10 22:27:52,569],[FATAL],[1],LogIF.FatalLog("ACCESS"); LogIF.Is*Enabled - ACCESS : Debug True / Info True / Warn True / Error True / Fatal True log4net: configuring repository [log4net-default-repository] using stream log4net: loading XML configuration @@ -2963,4 +2963,13 @@ CompiledExpressionCreater フィールド Field : フィールドの値 存在しないメンバ : 例外 System.ArgumentException ---------------------------------------------------------------------------------------------------- +IdToken.CreateHash +at_hash(OIDC Core 付録 A) : 77QmUPtjPfzWtF2AnpK9RQ(期待値と一致 : True) +c_hash(OIDC Core 付録 A) : LDktKdoQak3Pk0cnXxCltA(期待値と一致 : True) +s_hash(#584) : QCiR2bEHBPw1Pd2r2ZtS_Q(期待値と一致 : True) +---------------------------------------------------------------------------------------------------- +IdToken.VerifyHash +左半分(OIDC の定義) : True +左右の XOR(修正前の値) : False +---------------------------------------------------------------------------------------------------- log4net: Shutdown called on Hierarchy [log4net-default-repository] diff --git a/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt b/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt index 47010b38c..2e99c318f 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt +++ b/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt @@ -70,11 +70,11 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2026/08/20 10:54:29,651],[DEBUG],[2],LogIF.DebugLog("ACCESS"); -[2026/08/20 10:54:29,660],[INFO ],[2],LogIF.InfoLog("ACCESS"); -[2026/08/20 10:54:29,661],[WARN ],[2],LogIF.WarnLog("ACCESS"); -[2026/08/20 10:54:29,662],[ERROR],[2],LogIF.ErrorLog("ACCESS"); -[2026/08/20 10:54:29,662],[FATAL],[2],LogIF.FatalLog("ACCESS"); +[2026/09/10 22:27:55,097],[DEBUG],[2],LogIF.DebugLog("ACCESS"); +[2026/09/10 22:27:55,105],[INFO ],[2],LogIF.InfoLog("ACCESS"); +[2026/09/10 22:27:55,105],[WARN ],[2],LogIF.WarnLog("ACCESS"); +[2026/09/10 22:27:55,106],[ERROR],[2],LogIF.ErrorLog("ACCESS"); +[2026/09/10 22:27:55,106],[FATAL],[2],LogIF.FatalLog("ACCESS"); LogIF.Is*Enabled - ACCESS : Debug True / Info True / Warn True / Error True / Fatal True log4net: configuring repository [log4net-default-repository] using stream log4net: loading XML configuration @@ -2984,4 +2984,13 @@ CompiledExpressionCreater フィールド Field : フィールドの値 存在しないメンバ : 例外 System.ArgumentException ---------------------------------------------------------------------------------------------------- +IdToken.CreateHash +at_hash(OIDC Core 付録 A) : 77QmUPtjPfzWtF2AnpK9RQ(期待値と一致 : True) +c_hash(OIDC Core 付録 A) : LDktKdoQak3Pk0cnXxCltA(期待値と一致 : True) +s_hash(#584) : QCiR2bEHBPw1Pd2r2ZtS_Q(期待値と一致 : True) +---------------------------------------------------------------------------------------------------- +IdToken.VerifyHash +左半分(OIDC の定義) : True +左右の XOR(修正前の値) : False +---------------------------------------------------------------------------------------------------- log4net: Shutdown called on Hierarchy [log4net-default-repository] diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestIdToken.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestIdToken.cs new file mode 100644 index 000000000..b218d76b0 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestIdToken.cs @@ -0,0 +1,153 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestIdToken +//* クラス日本語名 :Framework.Authentication.IdTokenのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/09/10 玄人 幸道 新規作成(#584) +//********************************************************************************** + +using System; + +using Touryo.Infrastructure.Framework.Authentication; +using Touryo.Infrastructure.Public.Diagnostics; + +namespace TestCode +{ + /// Framework.Authentication.IdTokenのテスト + /// + /// at_hash / c_hash / s_hash の計算(CreateHash / VerifyHash)(#584)。 + /// + /// <期待値は、実装と独立に求めた値を使う> + /// VerifyHash は、同じ CreateHash で作り直した値と比べるだけである。 + /// **作る側が誤っていても、本フレームワーク同士では一致する。** + /// 2026/09/10 まで、CreateHash は左半分ではなく左右の XOR を返していたが、 + /// これでは気付けなかった。 + /// + /// そのため期待値には、OpenID Connect Core 1.0 付録 A の例示値と、 + /// #584 で実測に使った値(Python の hashlib で求めたもの)を置く。 + /// + public class TestIdToken + { + #region public + + /// Root + public static void Root() + { + TestIdToken.TestCreateHash(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestIdToken.TestVerifyHash(); + } + + #endregion + + #region private + + /// CreateHash + /// + /// SHA-256 の**左半分**(先頭 16 バイト)を base64url にした値になること。 + /// + private static void TestCreateHash() + { + MyDebug.OutputDebugAndConsole("IdToken.CreateHash"); + + // OpenID Connect Core 1.0 付録 A の例(access_token → at_hash) + TestIdToken.OutputCreateHash("at_hash(OIDC Core 付録 A)", + "jHkWEdUXMU1BwAsC4vtUsZwnNvTIxEl0z9K3vx5KF0Y", + "77QmUPtjPfzWtF2AnpK9RQ"); + + // OpenID Connect Core 1.0 付録 A の例(code → c_hash) + TestIdToken.OutputCreateHash("c_hash(OIDC Core 付録 A)", + "Qcb0Orv1zh30vL1MPRsbm-diHiMwcLyZvn1arpZv-Jxf_11jnpEX3Tgfvk", + "LDktKdoQak3Pk0cnXxCltA"); + + // #584 で実測に使った state → s_hash + TestIdToken.OutputCreateHash("s_hash(#584)", + "state-hybrid", + "QCiR2bEHBPw1Pd2r2ZtS_Q"); + } + + /// VerifyHash + /// + /// **修正前の版で発行された値(左右の XOR)は、検証に失敗する。** + /// 互換性が切れることを、ケースとして残しておく。 + /// + private static void TestVerifyHash() + { + MyDebug.OutputDebugAndConsole("IdToken.VerifyHash"); + + // 左半分(OIDC の定義) + TestIdToken.OutputVerifyHash("左半分(OIDC の定義)", + "state-hybrid", "QCiR2bEHBPw1Pd2r2ZtS_Q"); + + // 左右の XOR(2026/09/10 までの CreateHash が返していた値) + TestIdToken.OutputVerifyHash("左右の XOR(修正前の値)", + "state-hybrid", "iZPw3gFUI31HD9TANpAVbQ"); + } + + #endregion + + #region 出力のヘルパ + + /// CreateHash の結果を出力する + /// ケース名 + /// 入力(access_token / code / state) + /// 期待値(実装と独立に求めた値) + private static void OutputCreateHash(string caseName, string input, string expected) + { + try + { + string actual = IdToken.CreateHash(input); + + MyDebug.OutputDebugAndConsole( + caseName + " : " + actual + "(期待値と一致 : " + (actual == expected) + ")"); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole(caseName + " : 例外 " + ex.GetType().FullName); + } + } + + /// VerifyHash の結果を出力する + /// ケース名 + /// 入力(access_token / code / state) + /// 検証するハッシュ値 + private static void OutputVerifyHash(string caseName, string input, string hash) + { + try + { + MyDebug.OutputDebugAndConsole( + caseName + " : " + IdToken.VerifyHash(input, hash)); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole(caseName + " : 例外 " + ex.GetType().FullName); + } + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj b/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj index 9660f9bc0..19304f633 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj +++ b/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj @@ -20,6 +20,7 @@ + @@ -58,7 +59,9 @@ + OpenTouryo.Public / Public.Security が使うパッケージは、ここにも並べる必要がある。 + BouncyCastle.NetCore は GetHash が使う(IdToken.CreateHash 経由、#584)。--> + diff --git a/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj b/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj index 0c96a9d4e..093cc5539 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj +++ b/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj @@ -86,6 +86,9 @@ TestGetMessageAndProperty.cs + + TestIdToken.cs + TestJISCode.cs diff --git a/root/programs/CS/Samples4NetCore/Docker/ASPNETWebService/README.md b/root/programs/CS/Samples4NetCore/Docker/ASPNETWebService/README.md index c0a7d3161..09f306bd0 100644 --- a/root/programs/CS/Samples4NetCore/Docker/ASPNETWebService/README.md +++ b/root/programs/CS/Samples4NetCore/Docker/ASPNETWebService/README.md @@ -4,7 +4,8 @@ Linux コンテナで動かす(#582)。 **構成は [`../MVC_Sample/README.md`](../MVC_Sample/README.md) と同じである。** -方式(ホストビルド型)・設定の置き方・証明書の扱い・本番へ持って行くときの注意は、 +方式(ホストビルド型)・設定の置き方・証明書の扱い・本番へ持って行くときの注意、 +**起動のたびに publish とイメージ ビルドが走る理由**は、 **あちらが一次情報**なので、ここには書かない。 ここに書くのは**この Resource Server だけの事情**である。 diff --git a/root/programs/CS/Samples4NetCore/Docker/MVC_Sample/README.md b/root/programs/CS/Samples4NetCore/Docker/MVC_Sample/README.md index eefc6147a..3d4292861 100644 --- a/root/programs/CS/Samples4NetCore/Docker/MVC_Sample/README.md +++ b/root/programs/CS/Samples4NetCore/Docker/MVC_Sample/README.md @@ -36,6 +36,34 @@ powershell -NoProfile -ExecutionPolicy Bypass -File .\0_SetupCert.ps1 ログイン画面でユーザ名を入れると入れる(**ユーザ名が空でなければ認証する**実装)。 +### 毎回 publish とイメージ ビルドが走る + +**`1_PublishAndUp.bat` は、起動のたびに `publish` を作り直す。** + +``` +if exist ".\publish" rmdir /s /q ".\publish" +dotnet publish ... -o ".\publish" +docker compose up --build -d +``` + +意図的である。**ソースとコンテナの内容が必ず一致する**ことを保証している。 + +実測でも重くない。 + +``` +dotnet publish 7 秒ほど (obj\ は消さないので増分ビルドが効く) +docker compose up 6 秒ほど (ベース イメージと RUN 層はキャッシュが効く) +``` + +> **`rmdir` をやめてはいけない。** +> 出力先を消さずに publish すると、**ソースから消したファイルが残り続ける。** +> 古い DLL を抱えたまま動き、原因の分かりにくい不具合になる。 + +> **「起動だけ」の口を足すのも見送っている。** +> 古い `publish` のままコンテナが立ち上がると、 +> **直したはずのものが直っていない**という形で時間を失う。 +> 実際、`#578` では古いビルド成果物のまま測って原因を見誤った。 + ## ファイル構成 | | 役割 |