#InterSystems IRIS for Health

0 フォロワー · 887 投稿

InterSystems IRIS for Health™は、世界で最も重要なデータを管理する医療アプリケーションの迅速な開発を目的に特別に設計された世界初、かつ唯一のデータプラットフォームです。 トランザクションの処理と分析、拡張可能な医療データモデル、FHIRベースのソリューション開発、医療情報の相互運用性に関わる標準規格への対応など、すぐに使える強力な機能を搭載しています。 これらすべての機能により、開発者は価値を実現し、画期的なアプリケーションをすばやく構築することができます。 詳細はこちらをご覧ください

InterSystems公式 Seisuke Nakahashi · 5月 10, 2023

2023.2 の開発者プレビュープログラムの一環として、最初の開発者プレビューを公開いたします。今回リリースされたのは、InterSystems IRIS と InterSystems IRIS for Health です。

本リリースの注目点

2023.2では、多くの機能修正と改善に加えて、時間認識モデリング強化された外部テーブル読み込み専用の FEDERATED テーブルといった新機能が含まれる予定です。その一部は、今回の開発者プレビュー版にはまだ含まれていません。

2023.2の別の注目点は、プライベート・ウェブサーバ (PWS) がインストーラから削除されることです。このことは昨年に発表され、インターシステムズ製品のインストーラから削除予定ですが、今回のプレビュー版ではまだPWSは存在します。詳細はこちらのドキュメントをご覧ください。

--> PWSが含まれないインストーラにご興味のある方は、こちらのフォームからEAPに登録してください。その際、オプションで「No Private Web Server」をお選びください。このEAPに関する情報はこちらをご参照ください。

0
0 117
InterSystems公式 Seisuke Nakahashi · 5月 8, 2023

インターシステムズは現在、早期アクセスプログラム (EAP) に非常に注力しています。このプログラムは、私たちの製品がリリースされる前に、ユーザのみなさまにボランティアとして関わっていただくものです。次のグローバルサミットにおいても、あらためてプログラムを紹介させていただきます。

関わっていただくソフトウェアは、InterSystems IRIS 製品そのものの場合もありますが、たいていは、私たちがユーザ様の意見をいただきたい新機能に絞った単体ソフトウェアになります。 早期アクセスプログラムの参加利用規約は、評価いただくソフトウェアごとに変わります。 

プログラムに参加いただく方法はとても簡単です。こちらのリンク(英語)から、フォームに必要事項をご記入ください。

EAPに関する最新情報を入手されたいみなさまは、このページ をブックマークいただくか、このハッシュタグ を開発者コミュニティでフォローしてください。

より詳細な情報が必要な方は、このページでご質問いただくか、 EarlyAccess@InterSystems.com までメールをお送りください。

0
0 180
記事 Megumi Kakechi · 5月 8, 2023 4m read

これは InterSystems FAQ サイトの記事です。

InterSystems IRIS では、柔軟でユーザ拡張可能な監視ツールである「システムモニタ」をお使いいただくことが可能です。

システムモニタには、以下の3つのインスタンス監視ツールがあります。

  • システムモニタ:システムの状態およびリソースを監視・固定パラメータに基づいて通知 (アラートおよび警告) を生成
  • ヘルスモニタ:主要なシステムメトリックおよびユーザ定義メトリックをサンプリング&ユーザ変更可能パラメータおよび規定の通常値と比較し、該当しきい値を超えた場合に通知を生成
    ※ヘルスモニタは既定では無効となっています。
     起動するには、^%SYSMONMGR を使用してヘルスモニタを有効にする必要があります。
     ただし、システムモニタのサブスクライバクラスは、ヘルスモニタが有効でなくても動作します。
  • アプリケーションモニタ:重要なシステムメトリックをサンプリング&ユーザが作成したアラート定義を使用して評価

messages.logに、以下のようなログが記録される場合があります。

[SYSTEM MONITOR] DBLatency(c:\xxx\) Warning: DBLatency = 1510 ( Warnvalue is 1000).
※このメッセージの意味については こちらの記事 をご覧ください。

0
0 260
記事 Tomoko Furuzono · 5月 8, 2023 1m read

これは、InterSystems FAQサイトの記事です。
<ROLLFAIL>エラーは、ロールバック処理中に何らかのエラーが発生した場合に発生するエラーです。

トランザクション・ロールバックのロギング

よくあるケースはロールバック時点でシステム全体のジャーナリング機能が無効になっていた場合です。
ジャーナル機能が無効になるのは、ジャーナルを無効にする設定を行うかジャーナル格納ディレクトリのディスクが満杯のためにシステムがジャーナルを無効にした場合などです。

0
0 135
記事 Megumi Kakechi · 5月 1, 2023 6m read

IRISTEMPというデータベースをご存じでしょうか?

特定の処理に対してデータを無期限に保存する必要がなく、「同一プロセス内でのみ使用したい場合」や「IRISが起動中のみ使用したい場合」に、IRISTEMPデータベースに保存されるグローバルを使用できます。
IRISTEMPデータベースに保存されるグローバルに対する操作は ”一切ジャーナルされない” ため、効率性を最大限にしたい作業に使用できます。

IRISTEMPデータベースに保存されるグローバル(データ)には、以下の種類があります。

0
1 302
記事 Toshihiko Minamoto · 4月 28, 2023 2m read

本番環境でのopenhl pythonモジュールの使用に関する作業の説明の続きです。

Embedded Pythonを搭載しているirisは、まだ最終リリースがされていません(原文投稿当時)が、現時点で本番で使用する必要があります。 そこで、リクエストをxlsxファイルにエクスポートするサービスは別サーバーにバックアップし、クエリ結果は別データベースのグローバルに保存することにしました。

このデータベースは、ネットワーク化され、サービスサーバーはローカル、本番サーバーはリモートとしています。本番サーバー、サービスサーバ間のコミュニケーションは、REST サービスを使って実装しています。

つまり、クライアントアプリケーションのサーバー上では、ユーザーは大きなレポートを発行します。レポートはバックグラウンドで作成され、グローバルに保存されています。 リモートデータベース上では、グローバルへの完全な参照をパラメータとしてRESTサービスが呼び出されます。 このサービスはバックグラウンドで起動し、Excelファイルに内容をエクスポートし、その後、合図として生成されたファイルへのリンクでRESTサービスを呼び出します。 メッセージを受け取った本番サーバーのサービスは、Excelファイルをアーカイブして、クライアントにメールで送信します。 そして、ここで忘れてはならないのは、リモートとローカルのデータベースは単一のリソースで保護されなければならず、その特権はファイルを生成するユーザーに割り当てられなければならないことです。

これにより、プロダクトサーバーで%SYS.ZENReportExcelExporterを置き換えています。 将来的には、このソリューションの発展形として、メールによるファイル送信を、準備完了の通知によりユーザが独自にダウンロードできる生成ファイルのリンクパネルに置き換えることを計画しています。

0
0 387
InterSystems公式 Megumi Kakechi · 4月 28, 2023 2m read

インターシステムズは、IBM POWER8 以降の POWER プロセッサを搭載した AIX システムで、データベースおよびジャーナルファイルが破損する可能性がある問題を修正しました。
この問題は、データベースまたはジャーナルの暗号化が使用されている場合にのみ発生する可能性があります。


対象バージョン:
 InterSystems IRIS                      - 2022.1.3、2023.1 を除く全てのバージョン
 InterSystems IRIS for Health   - 2022.1.3、2023.1 を除く全てのバージョン
 HealthShare Health Connect   - 2022.1.3、2023.1 を除く全てのバージョン
 HealthShare ソリューション   - すべてのバージョン

 ※HealthShareソリューションはデータ要素の暗号化機能を使用していない為、
     本不具合が直接影響することはありません。ただし、HealthShare環境にて
     上記のようなデータ要素の暗号化機能を使用するカスタマイズがある場合は
     本アラートに記載されている回避方法に従う必要があります。

 InterSystems Cache および Ensemble - 2015.1 以降の全てのバージョン

0
0 136
記事 Megumi Kakechi · 4月 24, 2023 2m read

クラウド環境で Windows 英語版に日本語言語パックをインストールして日本語化している場合、設定に注意が必要です。

以下のようにランチャー(キューブ)メニューの一部が文字化けするのは、言語設定が足りていないのが原因と考えられます。


以下の設定をご確認ください。

Windows設定 > 時刻と言語 > 言語:管理用の言語設定
「Unicode 対応でないプログラムの現在の言語」が、日本語以外の言語 (例:英語(米国)) になっていないでしょうか?


この場合、システムロケールの変更 ボタンで現在のシステムロケールを「日本語(日本)」 に変更することで、文字化けが解消します。

※この変更を反映させるにはWindowsの再起動が必要です。
 

***

【注意】

システムロケールが「英語(米国)」のように日本語以外の言語になっている環境にIRISをインストールしている場合、IRISのデフォルトの ロケール定義 が日本語以外に設定されています。

この場合、例えばファイル入出力も日本語の言語対応がされないため、日本語を含むCSPなどのファイルインポートで文字化けが発生してしまいます。

その際には、OSのシステムロケールの変更に加えて、IRISのロケール定義も変更するようにしてください。


※以下の例は、日本語 Windows OS の場合

0
0 497
記事 Tomohiro Iwamoto · 4月 20, 2023 18m read

Azure ADをOPとして利用する

元のタイトルから外れますがAzure ADをOPとした場合に、Wepアプリケーション(CSP)とSPA+BFF形式のRPにどのような修正が必要かを調べました。
ある程度の差異は想定はしていましたが、思っていたより違うな、という印象を受けました。RP、リソースサーバ側でこれらの差異を吸収する必要がありました。

個人調べです。誤りがあるかもしれませんが、その際はご容赦ください。また、状況は刻々と変わる可能性があります。

相違点

  • frontchannel_logout_session_supportedをサポートしていない

    オプショナルな機能ではありますが、これが、一番残念でした。 sessionを使用したフロントチャネルログアウトをサポートしていないようです。実際、IDトークンに"sid"クレームが含まれていません。

    "http_logout_supported"はtrueなのでSLOは可能ですが、今回用意したクライアントでは実現していません。趣旨からそれますので、Azure使用時のSLOの実現は断念しました。ログアウト操作の対象は常に、ログアウトを実行したアプリケーション単独になります。

    AD FSはサポートしていると思われます。

  • "revocation_endpoint"をサポートしていない

    OpenId Connectディスカバリーに"revocation_endpoint"がありません(つまりサポートしていません)。

    そもそもSLOが無ければ、Revoke(アプリケーション単独でのログアウトに使用)を用意する意味はありませんので、これも断念しました。

  • Userinfoのエンドポイント

    IDトークンに同じ内容が含まれているので、それらを使うよう推奨されています。Azure AD使用時は、ユーザの情報(名前)をIDトークンから取得するよう変更しました。

    ID トークンの情報は、UserInfo エンドポイントで入手できる情報のスーパーセットです。 UserInfo エンドポイントを呼び出すトークンを取得すると、同時に ID トークンを取得できます。このため、UserInfo エンドポイントを呼び出す代わりに、トークンからユーザーの情報を取得することをお勧めします。

    UserInfoエンドポイントへのアクセスも実際に試してみましたが、エラーが発生しました。どうやらこのエンドポイントにアクセスするには、今回のような独自API(リソースサーバ)用ではなく、Graph API用のアクセストークンが要るようです。

    $ export access_token=...SCOPE['openid','profile','offline_access','api://xxxxx/scope1']で発行されたトークン...
    $ curl --insecure -H "Authorization: Bearer ${access_token}" -H 'Content-Type:application/json;charset=utf-8' https://graph.microsoft.com/oidc/userinfo 
    {"error":{"code":"InvalidAuthenticationToken","message":"Access token validation failure. Invalid audience.","innerError":{"date":"2023-04-20T01:33:53","request-id":"40c464e2-e83f-43e7-bbf5-ec50a9ea3b79","client-request-id":"40c464e2-e83f-43e7-bbf5-ec50a9ea3b79"}}}
    
    $ export access_token=...SCOPE['openid','profile','offline_access']で発行されたトークン...
    $ curl --insecure -H "Authorization: Bearer ${access_token}" -H 'Content-Type:application/json;charset=utf-8' https://graph.microsoft.com/oidc/userinfo 
    {"sub":"dwHvjtAK6XlYA1VJatjT2GY7dWBBXjhAv8ctUlcUcUE","name":"Alex Wilber","family_name":"Wilber","given_name":"Alex","picture":"https://graph.microsoft.com/v1.0/me/photo/$value","email":"AlexW@xxxxx.onmicrosoft.com"}
    
  • Introspectionをサポートしていない

    Introspectionは未サポートのようです。実行しないように修正しました。

  • アクセストークンのSCOPEパラメータ名が異なる

    SCOPEを示すパラメータ名がscpになっています。

      "scp": "scope1",
    
  • 暗黙のSCOPE

    独自(カスタム)API、今回の例ではscope1、が要求時のSCOPEクレームに含まれる場合、明示的に"openid profile offline_access"を含めても、トークンエンドポイントから取得したアクセストークンのSCOPEにはこれらを含まないようです。クライアントディスクリプション作成時に下記を指定することで対応可能です。

    Set c.AcceptNonStandardImplicitIdToken=1
    

    独自のAPIとMS Graph API用のSCOPEを混在させることは出来ないようです。MS Graph APIが優先されてしまいます。例えば

    SCOPE['openid','profile','offline_access','User.Read']の場合 
    => scp": "openid profile User.Read email","aud": "00000003-0000-0000-c000-000000000000"
    SCOPE['openid','profile','offline_access','api://xxxxx/scope1']の場合 
    => "scp": "scope1","aud": "api://xxxxx",
    SCOPE['openid','profile','offline_access','User.Read','api://xxxxx/scope1']の場合 
    => "scp": "openid profile User.Read email","aud": "00000003-0000-0000-c000-000000000000"
    

    Azure ADはAPI(リソースサーバ)ごとに、アクセストークンを使い分けるという設計思想のようです。アプリケーションが、MS Graph APIと独自APIの両方使いたかったらどうするのか、という話もありますが、今回は独自APIだけ(Userinfoのエンドポイント使用は除外したので)なので、良しとしました。

  • アクセストークン,IDトークンで同一クレーム名に異なる値が設定される

    "iss","aud"値がアクセストークン,IDトークンとで値が異なるため、クライアント側でのチェック対象を変える必要があります。

  アクセストークン
  {
    "aud": "api://xxx-xxx-xxx-xxx-xxx",
    "iss": "https://sts.windows.net/d8f44xxx-xxxx-xxxx-xxxx-xxxxxx2c5416/",
  }

  IDトークン
  {
    "aud": "xxx-xxx-xxx-xxx-xxx",
    "iss": "https://login.microsoftonline.com/d8f44xxx-xxxx-xxxx-xxxx-xxxxxx2c5416/v2.0",
  }
  • "aud"の値を複数指定できない

    リソースサーバ側で"aud"をチェックする処理で「リソースサーバのURL」の有無をチェックしている処理が通らなくなります。"aud"にはクライアントアプリケーションのCLIENT_IDがセットされています。ひとまずこの値をチェックするように修正をしました。

  • RefreshToken発行時のリクエストにSCOPE指定が必須

    Client_Secret指定時は、Optionalとなっているscopeですが、指定しないと下記のエラーが出ました。こちらの対応と同様にscopeを追加するために ##class(%ZSYS.OAuth2.Authorization).GetAccessTokenRefresh()を追加しました。

    AADSTS90009: Application 'xxx-xxx-xxx-xxx-xxx'(xxx-xxx-xxx-xxx-xxx) is requesting a token for itself. This scenario is supported only if resource is specified using the GUID based App Identifier. 
    
  • OIDCのクライアント動的登録機能をサポートしていない

    OIDCのクライアント動的登録機能は無いようです。

環境

Microsoft 365開発者サブスクリプション を有効化して使用しました。

開発者向けの無償のサブスクリプションです。余談ですが、Exchange Online上のメールの受信(pop3+oAuth2認証)テストにもこの環境を使用しました。

主な選択肢は下記のようにしました。

Set up a new Microsoft 365 developer sandboxを選択。
Instantを選択。
Country: AP
Admin: iwamoto
Password: xxxxxx

認証用にSMS用番号を求められるので入力。

これでiwamoto@xyz.onmicrosoft.comのようなアカウント名が付与されます。以後、このアカウントを使用して管理操作を行います。

ほおっておくと、ログインできなくなるような警告が出ました。
「組織のセキュリティを維持するために、セキュリティの既定値群がオンになっています。Microsoft Authenticator アプリをセットアップして、2 段階認証を使用してください。これが>必要になるまであと 14 日です。」
強制的に設定画面が出たので設定を行いました。スマホアプリのMicrosoft Authenticatorを使って表示されるQRコードを読み込むだけです。

Office365の一通りのアプリケーションの管理作業を行えるようになっています。また、ダミーのユーザが作成されていますので、後でログインユーザとして使用します。一番下に自分が登録されています。

付与されたアカウント(私の場合はiwamoto@xyz.onmicrosoft.com)でAzure Portalにログインします。

作業の流れ

先にお断りしておきますと、Azureでの作業は結構面倒です。

以下のような作業の流れになります。

  1. 最新のソースコードの取得

  2. Azure(OP)にアプリケーション(RP)を登録

  3. Azure(OP)にリソースサーバを登録

  4. IRIS(RP)にサーバデスクリプションを登録

  5. IRIS(RP)にサーバデスクリプション/クライアントを登録

  6. IRIS(リソースサーバ)にサーバデスクリプションを登録

  7. IRIS(リソースサーバ)にサーバデスクリプション/クライアントを登録

最新のソースコードの取得

サーバ環境

以前に、git clone実行されている方は、再度git pullをお願いします。始めて実行される方は、サーバ編をご覧ください。

cd iris-oauth2
git pull

クライアント環境

以前に、git clone実行されている方は、再度git pullをお願いします。始めて実行される方は、クライアント編をご覧ください。

cd angular-oauth2-client
git pull

Azure(OP)にアプリケーション(RP)を登録

こちらの内容に沿って作業を進めます。

アプリケーションの登録

アプリケーションの名前: myapp
サポートされているアカウントの種類: この組織ディレクトリのみに含まれるアカウント (MSFT のみ - シングル テナント)
リダイレクトURI: Web, https://webgw.localdomain/irisclient3/csp/sys/oauth2/OAuth2.Response.cls

リダイレクト URI, フロントチャネルのログアウト URL追加

pythonコードでテスト実行をしたいので、2個目のリダイレクト先(https://login.microsoftonline.com/common/oauth2/nativeclient)を追加します
フロントチャネルのログアウト URLに(https://webgw.localdomain/irisclient3/csp/user/MyApp.Logout.cls)を指定します

証明書またはシークレットの追加

新しいクライアント シークレットを追加します。

以下のような情報を取得します。CLIENT_SECRET値はクライアントシークレット作成時にしか見れませんので、このタイミングで必ず書き留めます。

TENANT_ID = 'd8f44xxx-xxxx-xxxx-xxxx-xxxxxx2c5416' <=[アプリの登録]/[概要]ページの基本で見れる、ディレクトリ (テナント) ID
CLIENT_ID = "f7d8xxx-xxx-xxx-xxx-xxx" <= [アプリの登録]/[概要]ページの基本で見れる、アプリケーション (クライアント) ID
CLIENT_SECRET = "xxxxxxxxxxxxx"  <=クライアントシークレット作成時の「値」のほう。(シークレットIDではない)

これでIssuer エンドポイント(https://login.microsoftonline.com/d8f44xxx-xxxx-xxxx-xxxx-xxxxxx2c5416/v2.0)が確定します。後で、IRISへの登録時に使用します。

SCOPE追加

「APIの公開」画面で「Scopeの追加」を押してscope1を追加します。既定ではapi://xxxxxというプリフィックスが付きます。

Python + o365 でテスト

Azure AD側の設定が正しく行えているかの事前確認として、Pythonのo365パッケージを使用してトークン取得を行います。

こちらの記事を参考にさせていただきました。

get_token.pyの下記を取得した値に変更して実行します。

TENANT_ID = 'd8f44xxx-xxxx-xxxx-xxxx-xxxxxx2c5416'
CLIENT_ID = "f7d8xxx-xxx-xxx-xxx-xxx"
CLIENT_SECRET = "xxxxxxxxxxxxx" 

SCOPES = ['openid','profile','offline_access','api://f7d8xxx-xxx-xxx-xxx-xxx/scope1']

実行するとURLが表示されるので、ブラウザにペーストします。(初回実行時は)ログイン実行を促されますので、さきほど取得したアカウント(私の場合、iwamoto@xyz.onmicrosoft.com)でログインします。リダイレクトされて空白ページに移動しますので、そのURLをpythonのプロンプトにペーストして処理を終了します。

C:\git\iris-o365>python get_token.py
Visit the following url to give consent:
https://login.microsoftonline.com/d8f44xxx-xxxx-xxxx-xxxx-xxxxxx2c5416/oauth2/v2.0/authorize?response_type=code&client_id=f7d8xxx-xxx-xxx-xxx-xxx&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient&scope=profile+openid+api%3A%2F%2Ff7d8xxx-xxx-xxx-xxx-xxx%2Fscope1&state=K1p7qcbW0PWM29nWpdZRwoMyaWPojA&access_type=offline
Paste the authenticated url here:
https://login.microsoftonline.com/common/oauth2/nativeclient?code=0.AUoAek702LUSWUq0...  [ペースト]
[エンターキーを押下]
Authentication Flow Completed. Oauth Access Token Stored. You can now use the API.
Authenticated!
C:\git\iris-o365>

token.jsonというファイルが出来ますので、access_token, id_tokenをjwt.io等でデコードして内容を確認します。出来ていなければ、何かがおかしいので、設定を見直してください。これが成功しないと、以降の操作も成功しません。

jwt.ioによるとscp値は下記でした。

 "scp": "scope1",

IDTokenの"iss","aud"値がATのそれらと値が異なる事がわかります。これはRP内でATとIDトークンの両方をチェックしようとすると良からぬ影響が出ます。今回はRPではIDトークンのバリデーションだけを行うことで対応しています。

全てのアプリケーションを登録

同様にmyapp2,bff,bff2,という名前でアプリケーションを登録し、それぞれのCLIENT_ID, CLIENT_SECRET, SCOPEを記録しておきます。

面倒です。動的登録が出来ればな...と思いました。WebアプリケーションとSPA+BFF用に、各々2個のクライアント(実行されるIRISネームスペースが異なる)を登録するため、計4通り存在します。ひとまずmyapp(既に登録済み)とbffだけでも良いです。

取得したクライアントID,クライアントシークレット,SCOPE値をIRIS実行環境に反映する必要があります。 本例では、それらをJSONファイル化しておき、実行時にロードするという方法を採用しました。

テンプレートをコピーして使用します。先ほどのmyappの内容を含め、伏字の値を実際の値で置き換えてください。

cd config
cp azure.json.template azure.json
vi azure.json

Azure ADへの登録内容とazure.jsonへの反映箇所の関係

アプリケーションの名前: myapp (今までの作業で登録済みです)
リダイレクトURI: Web, https://webgw.localdomain/irisclient3/csp/sys/oauth2/OAuth2.Response.cls
フロントチャネルのログアウト URLに(https://webgw.localdomain/irisclient3/csp/user/MyApp.Logout.cls)
azure.jsonでの名称: USER_CLIENT_APP

アプリケーションの名前: myapp2
リダイレクトURI: Web, https://webgw.localdomain/irisclient3/csp/sys/oauth2/OAuth2.Response.cls
フロントチャネルのログアウト URLに(https://webgw.localdomain/irisclient3/csp/user2/MyApp.Logout.cls)
azure.jsonでの名称: USER2_CLIENT_APP

アプリケーションの名前: bff
リダイレクトURI: Web, https://webgw.localdomain/irisclient3/csp/sys/oauth2/OAuth2.Response.cls
フロントチャネルのログアウト URLに(https://webgw.localdomain/myapp/#/logout-bff)
azure.jsonでの名称: BFF_BFF_APP

アプリケーションの名前: bff2
リダイレクトURI: Web, https://webgw.localdomain/irisclient3/csp/sys/oauth2/OAuth2.Response.cls
フロントチャネルのログアウト URLに(https://webgw.localdomain/myapp2/#/logout-bff)
azure.jsonでの名称: BFF2_BFF_APP

Azure(OP)にリソースサーバを登録

同様にリソースサーバを登録します。リダイレクトは要りません。

アプリケーションの名前: myrsc
サポートされているアカウントの種類: この組織ディレクトリのみに含まれるアカウント (MSFT のみ - シングル テナント)

同様に新しいクライアント シークレットを追加します。

アプリケーションと同様に、ClientId, ClientSecretの値をazure.jsonの"RESSERVER_APP"下に反映しておきます。

azure.jsonの完成形

伏字だらけで少し分かりにくいですが、全てを埋めたazure.jsonは下記のようになります。

{
	"OP": "azure",
	"tenantID":"d8f44e7a-xxx-xxx-xxx-xxx",
	"issuerEndpoint":"https://login.microsoftonline.com/d8f44e7a-xxx-xxx-xxx-xxx/v2.0",
	"apps":{
		"USER_CLIENT_APP":{
			"ClientId":"e20dd7f3-xxx-xxx-xxx-xxx",
			"ClientSecret":"3bU8Q~9g8xLaAi81WshoTLZuh3rWwDO7NUaDKaa_",
			"SCOPES":"api://e20dd7f3-xxx-xxx-xxx-xxx/scope1",
			"fclouri":"https://webgw.localdomain/{{{HOSTNAME}}}/csp/user/MyApp.Logout.cls"
		},
		"USER2_CLIENT_APP":{
			"ClientId":"53bb346c-xxx-xxx-xxx-xxx",
			"ClientSecret":"oNe8Q~J-5iPyAj_zHd8r3axXxl9ffJRWrVZ0Sa~N",
			"SCOPES":"api://53bb346c-xxx-xxx-xxx-xxx/scope1",
			"fclouri":"https://webgw.localdomain/{{{HOSTNAME}}}/csp/user2/MyApp.Logout.cls"
		},
		"BFF_BFF_APP":{
			"ClientId":"a4ef08b0-xxx-xxx-xxx-xxx",
			"ClientSecret":"D2A8Q~CuxCGHYeXmUAqD7wjtY-gucdQU44Yj4b-U",
			"SCOPES":"api://a4ef08b0-xxx-xxx-xxx-xxx/scope1",
			"fclouri":"https://webgw.localdomain/myapp/#/logout-bff"
		},
		"BFF2_BFF_APP":{
			"ClientId":"dc04f6cd-xxx-xxx-xxx-xxx",
			"ClientSecret":"5Br8Q~h~CzkJW1z2NSWii0uAq0HuPvoW46cvhaKj",
			"SCOPES":"api://dc04f6cd-xxx-xxx-xxx-xxx/scope1",
			"fclouri":"https://webgw.localdomain/myapp2/#/logout-bff"
		}
	},
	"rsc":{
		"RESSERVER_APP": {
			"ClientId":"9842ba63-xxx-xxx-xxx-xxx",
			"ClientSecret":"7vJ8Q~PS7wFw_15SY.V3whxU2p3STBuvAUkTydjH"
		}
	}
}

このファイルを用意することが、下記の操作を行ったことになります。

  • IRIS(RP)にサーバデスクリプションを登録
  • IRIS(RP)にサーバデスクリプション/クライアントを登録
  • IRIS(リソースサーバ)にサーバデスクリプションを登録
  • IRIS(リソースサーバ)にサーバデスクリプション/クライアントを登録

ビルド

サーバ環境

cd iris-oauth2
cp webgateway* iris-webgateway-example/
./build.sh

クライアント

ビルドには、稼働中のサーバ環境が必要なので、この時点で行うことはありません。

実行

サーバ環境

config/azure.jsonを修正済みであることを確認した上で下記を実行してください。

./up-azure.sh
    ・
    ・
Useful links...
Web Gateway | http://webgw.localdomain/csp/bin/Systems/Module.cxw
RSC #1 SMP | http://webgw.localdomain/irisrsc/csp/sys/%25CSP.Portal.Home.zen
RSC #2 SMP | http://webgw.localdomain/irisrsc2/csp/sys/%25CSP.Portal.Home.zen
CSP based client server3 SMP | http://webgw.localdomain/irisclient3/csp/sys/%25CSP.Portal.Home.zen
CSP based client App3-1 | https://webgw.localdomain/irisclient3/csp/user/MyApp.Login.cls
CSP based client App3-2 | https://webgw.localdomain/irisclient3/csp/user2/MyApp.Login.cls
Angular based clien App | https://webgw.localdomain/myapp/ https://webgw.localdomain/myapp2/

クライアント

サーバ環境が起動した事を確認の上、実行します。

cd angular-oauth2-client
./build_and_deploy.sh
あるいは
./ng-start.sh (デバッグ実行)

操作方法

クライアント編と同じです。WebアプリケーションSPA+BFFを実行できます。

前回と異なり、ログインを実行すると、Azure ADのログイン画面が表示されますので、Microsoft 365開発者サブスクリプションで作成されたユーザでログイン(adelev@xxxxx.onmicrosoft.com等)します。

エラー

下記エラーが出た場合、IRISサーバ環境が古いままです。

$ ./build_and_deploy.sh
&#x2714; Browser application bundle generation complete.

Error: src/app/display-info-bff/display-info-bff.component.ts:44:26 - error TS2339: Property 'OP' does not exist on type '{ clientId: string; authUri: string; logoutUri: string; tokenUri: string; userinfoUri: string; redirectUri: string; scope: string; frontchannel_logout_uri: string; post_logout_redirect_uri: string; }'.

44     if (environment.auth.OP==='iris') {
                            ~~

(番外編)SAML認証

同じAD環境を使用して、コミュニティ記事(https://community.intersystems.com/post/work-saml-iris)のSAML認証をAzureで試してみました

ngrok は必要ありません。

IRISでのSAMLのサポートはoAuth2に対するそれほどは手厚くありません。下記コマンドでSAML応答(XML)の署名を確認して、その正当性を確認しています。

Set tSC = ##class(Ens.Util.XML.SecuritySignature).ValidateSAML(tSAML, tValSpec, X509File.Filename, tClockSkew)

実行方法

実行用のCSPアプリケーションを表示。

AD>エンタープライズ アプリケーション>すべてのアプリケーション>+新しいアプリケーション>独自のアプリケーションの作成を選択。

お使いのアプリの名前は何ですか?: myapp-saml ギャラリーに見つからないその他のアプリケーションを統合します (ギャラリー以外) 「作成」を押下。

シングルサインオンの設定「作業の開始」>シングル サインオン方式の選択で「SAML」を選択。

下記の必須項目に、アプリに表示されている内容をそのまま使用する。

基本的な SAML 構成
識別子: https://intersystems.com/saml/E106172E-DB35-11ED-B731-0242C0A82802
応答URL: https://webgw.localdomain/irisclient3/csp/user/SAML.MyApp.cls

[保存]を押下。

識別子はユニークであれば何でも良い。上記はアプリ内で生成した固定文字列"https://intersystems.com/saml/"+GUID。

「属性とクレーム」で「編集」を押し、詳細設定 => SAML クレームの詳細オプション 編集 属性名の形式を含める:有効 <=有効にする [保存]

この作業は不要(今回のケースでは無意味)かもしれない。

「SAML 証明書」から下記を全部ダウンロードする。
証明書 (Base64): myapp-saml.cer
証明書 (未加工): myapp-saml(1).cer
フェデレーション メタデータ XML: myapp-saml.xml

「ユーザとグループ」で「ユーザまたはグループの追加」を押し、ログインするユーザ(誰でも良いです。AlexW@xxxx.onmicrosoft.com)を追加。「割り当て」を押下して追加を完了する。

アプリで「ファイルを選択」を押し、先ほどダウンロードしたメタデータファイル(フェデレーション メタデータXML)を選択し「適用」を押す。 成功するとIdentity providerの情報やSAML要求の内容が表示される。画面最下の「Login」押下すると、Azureの「アカウントを選択する」画面が表示される。 先ほど追加したユーザ(AlexW@xxxx.onmicrosoft.com)で、ログイン。

ログインすると、画面にSAMLResponseの内容が表示される。

Validation: Success
NameID: AlexW@xxxx.onmicrosoft.com

と表示されていればログイン成功です。

オリジナル記事にもあるように、このアプリケーションは、ログインユーザの情報を取得(および署名のチェック)するだけで、アプリケーションのユーザとしての認証の仕組みは備えていません。必要に応じて、上記で得たNameIDを使用して、なんらかの方法でIRISのユーザとして認証してください。

オリジナル(GCP対応)からの修正点

オリジナル(GCP対応)を修正しています。 Azure発行のフェデレーション メタデータ XMLにnameIDFormat属性が含まれていなかったため、決め打ちで設定しています。

フォーマットについて、ドキュメント には、下記のように書いてあるが、emailAddressが返却されたのでemailAddressを採用。

現在 Azure AD では、次の SAML 2.0 のNameID フォーマット URI をサポートしています: urn:oasis:names:tc:SAML:2.0:nameid-format:persistent。

;Azure AD includes no NameIDFormat attribute. So nameIDFormat becomes null.
If $D(nameIDFormat)=0 {
  Set @..#SettingsGN@("nameIDFormat") = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
  #;Set @..#SettingsGN@("nameIDFormat") = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
  
}
Else {
  Set @..#SettingsGN@("nameIDFormat") = nameIDFormat
}
0
0 646
InterSystems公式 Toshihiko Minamoto · 4月 19, 2023

インターシステムズは、InterSystems IRIS Data Platform、InterSystems IRIS for Health、HealthShare Health Connect、InterSystems IRIS Studio 2023.1 リリースを一般提供開始(GA)したことを発表しました。

2023.1 は、拡張メンテナンス(EM)リリースです。2023.1では、多くのアップデートと機能拡張が追加されました。

また、Columnar Storageの本番対応、Bulk FHIRMacOS 13 Venturaへの対応など、まったく新しい機能が追加されています。さらに、 Foreign Table を使用する機能を提供する新機能は「実験的」としてリリースされ、早期アクセスプログラム(EAP)を通じてアクセスできるようになる予定です。

リリースハイライト

プラットフォームのアップデート

InterSystems IRIS Data Platform 2023.1では、本番用に以下の新しいオペレーティングシステムをサポートします。

  • MacOS 13 Ventura.

アナリティクスとAIのエンハンス

0
0 122
InterSystems公式 Toshihiko Minamoto · 4月 18, 2023

インターシステムズは、InterSystems IRIS、InterSystems IRIS for Health、HealthShare Health Connect 2022.1.3 のメンテナンスリリースを公開しましたのでお知らせします。このリリースでは、これまでの2022.1.xリリースに対して厳選された機能とバグフィックスが提供されます。

変更点についての追加情報は、これらのページでご覧いただけます

より良い製品にするため、開発者コミュニティにご意見をお寄せください。

ソフトウェアの入手方法

本ソフトウェアは、古典的なインストールパッケージとコンテナイメージの両方が利用可能です。  利用可能なインストーラとコンテナ・イメージの詳細なリストについては、「サポート対象プラットホーム」を参照してください。

0
0 96
InterSystems公式 Toshihiko Minamoto · 4月 18, 2023

インターシステムズは、まれに Enterprise Cache Protocol (ECP) クライアントが不安定になることがある不具合を修正しました。

この不具合は、以下の製品およびそれらをベースとしたインターシステムズの製品に存在します。

影響を受けるバージョン: 2022.1.x, 2022.2, 2022.3

InterSystems IRIS®

InterSystems IRIS for Health

HealthShare® Health Connect

影響を受けるバージョン: 2022.2 (ECPを導入しているお客様のみ)

InterSystems HealthShare®

この問題は、ECPクライアントシステムでのみ発生する可能性があります。この問題が発生すると、プロセスで <SYSTEM> または <DATABASE> エラーが発生することがあります。エラー後、ECPクライアントが不安定になり、場合によってはインスタンスがハングアップすることがあります。データへの影響はなく、ECP データサーバーも影響を受けません。

不安定な状態を解消するには、ECP クライアントインスタンスを再起動する必要があります

0
0 184
InterSystems公式 Toshihiko Minamoto · 4月 18, 2023

インターシステムズは、SQL クエリによって不正な結果が返される可能性がある不具合を修正しました。

この不具合は、以下の製品およびそれらをベースとしたインターシステムズの提供する製品に存在します。

影響を受けるバージョン:  2021.2, 2022.1.x, 2022.2, 2022.3

InterSystems IRIS®

InterSystems IRIS for Health

HealthShare® Health Connect

影響を受けるバージョン: 2022.2

 InterSystems HealthShare®

この問題は、SQL Runtime Plan Choice (RTPC) が有効(デフォルト設定)で、クエリに「真理値」である WHERE ? = ? が含まれている場合、発生することがあります。この問題が発生すると、一部の述語が正しく評価されない可能性があり、これが不正なクエリ結果につながります。

注意: SQL を確認することで、クエリの脆弱性を完全に評価することは不可能です。これは、InterSystems SQL のクエリ最適化により、クエリの内部表現に真理値が追加されるためです。

お使いの環境で InterSystems SQL が使用されている場合は、RTPC 機能を無効にすることで、この問題を直ちに修正することができます

0
0 160
記事 Mihoko Iijima · 4月 17, 2023 1m read

これは InterSystems FAQ サイトの記事です。

以下の状態の時、ReadOnlyでマウントされます。

0
0 282
記事 Megumi Kakechi · 4月 11, 2023 4m read

これは InterSystems FAQ サイトの記事です。
 

Question:

TIMESTAMP型の項目に対して、TO_CHAR() や TO_DATE() を用いた SELECT を実行すると以下のエラーになります。

実行SQL:

select 
  TO_CHAR(xxxDateTime,'YYYY-MM-DD')
from
  Test

エラー:
  [SQLCODE: <-400>:<深刻なエラーが発生しました>]
  [%msg: <Unexpected error occurred: <ZCHAR>IllegalValuePassedToTOCHAR^%qarfunc>]

エラーの原因を教えてください。


Answer:

こちらは、IRIS2022.1以降のバージョンで CREATE TABLE (DDL) の TIMESTAMP 型が IRIS側クラスで %Library.PosixTime にマッピングするように変更されているためです。
(アップグレードした環境の場合は、従来のままの %Library.TimeStamp にマッピングされています)

0
0 1527
記事 Tomoko Furuzono · 4月 11, 2023 2m read

これは、InterSystems FAQサイトの記事です。
管理ポータルの監査メニューを使用する場合、ユーザに監査データベースの閲覧のみを許可するということはできません。
管理ポータルから監査データベースを閲覧する場合は、そのユーザに、
・%Admin_Secure:U(監査以外にもセキュリティ関連の操作が可能となる)
・%DB_IRISAUDIT:RW(監査データベースへの読み込み/書き込み権限)
等のリソースへの権限が必要になりますが、これを与えることにより、監査データベースの閲覧以外の操作も可能となってしまいます。

監査データベースの閲覧のみを許可したい場合には、管理ポータルの監査メニューは使用せず、外部ツール等からSQLで監査テーブルを参照するようにします。
このとき、ユーザに必要な権限は以下の通りです。※他の権限は与えないようにします。
・IRISAUDITデータベースへのRW権限 ⇒ %DB_IRISAUDITロールの付与
・%SYS.AuditテーブルへのSelect権限
 

1.新規ロールの作成
必要な2つの権限のみを含むロールを作成します。

(1)新規作成
システム管理>セキュリティ>[新規ロール作成]>名前入力>[保存]


(2)作成したロールに%DB_IRISAUDITロールを割り当てる
ロールの定義編集>Assigned Toタブ>%DB_IRISAUDITを選択して[割り当てる]

0
0 124
記事 Tomoko Furuzono · 4月 11, 2023 2m read

これは、InterSystems FAQサイトの記事です。
%Library.GlobalクラスのExport()メソッドを使用してエクスポートする際に、エクスポート形式(第4引数:OutputFormat)を 7 の「ブロックフォーマット/Cachéブロックフォーマット(%GOF)」にした場合、マッピングされたグローバルはエクスポートできない仕様となっています(対象はネームスペースのデフォルトグローバルデータベースのグローバルのみ)。
マッピングされたグローバルを「ブロックフォーマット/Cachéブロックフォーマット(%GOF)」でエクスポートする為には、%Library.Global.Export()の第1パラメータにマッピング先のデータベースディレクトリを指定します。
実行例は以下の通りです。 

 set DB = "^^c:\InterSystems\Cache\Mgr\Test\"  ; "^^\<データベースフォルダーのパス>\"
 set sc = ##class(%Library.Global).Export(DB,"TESTGBL.gbl",FULLPATH,7,,"")
0
0 210
記事 Tomoko Furuzono · 4月 11, 2023 1m read

これは、InterSystems FAQサイトの記事です。
HL7の仕様では、日本語データを送受信する場合はJISを文字コードとして利用し、メッセージヘッダ(MSH)の18番目の2項目に iso-ir87 を指定します。
HL7用プロダクションでは、情報の入力はビジネスサービス、情報の出力はビジネスオペレーションを利用します。
日本語を含むHL7を送受信する場合は、入力/出力の対象となる全てのコンポーネントの設定で [追加の設定] の「キャラクターセット(Charset)」に iso-ir87 を指定することで正しく日本語データを取り扱うことができます。

0
0 394
記事 Tomoko Furuzono · 4月 11, 2023 3m read

これは、InterSystems FAQサイトの記事です。
データの登録/更新/削除を実行中でも、インデックスを再構築することは可能です。
ただし、再構築中は更新途中の状態で参照されますので、専用ユーティリティを使用することをお勧めします。
手順は以下の通りです。

  1. 追加予定のインデックス名をクエリオプティマイザから隠します。
  2. インデックス定義を追加し、再構築を実施します。
  3. 再構築が完了したら、追加したインデックスをオプティマイザに公開します。

実行例は以下の通りです。
Sample.Person の Home_State(連絡先住所の州情報)カラムに対して標準インデックス HomeStateIdx を定義する目的での例で記載します。 

1、追加予定のインデックス名を Caché のクエリオプティマイザから隠します。

>write $system.SQL.SetMapSelectability("Sample.Person","HomeStateIdx",0)
1

 2、インデックス定義を追加した後、再構築を実施します。
  定義例)Index HomeStateIdx On Home.State;

>do ##class(Sample.Person).%BuildIndices($LB("HomeStateIdx"))


 3、再構築が完了したら、追加したインデックスをオプティマイザに公開します

0
0 514
記事 Tomoko Furuzono · 4月 10, 2023 3m read

これは、InterSystems FAQサイトの記事です。
管理ポータル:システムエクスプローラの使用には、%DevelopmentリソースのUse特権が必要です。
システムエクスプローラでの参照のみ利用可能とする権限をユーザに付与したい場合は、%DevelopmentリソースのUse特権(※1)と、該当のデータベースリソース(※2)への参照特権(R)を付与したロールを作成し、これをユーザに与えます。
※1.「%Development:U」を付与している場合はターミナルやスタジオも参照のみで使用可能となります。
※2.参照したいデータベースに割り当てられているリソースが%DB_DEFAULTリソースになっており、このデータベースのみに参照権限を設定したい場合は、事前に、このデータベース用の独自リソース(%DB_<データベース名>)を作成し、該当データベースに割り当てるようにします。

<図:独自リソースの作成>
[管理ポータル]>[システム管理]>[構成]>[システム構成]>[ローカルデータベース]>(該当データベースを選択)

【例】:testAユーザに、TESTデータベースへの参照のみを許可する。
1.新規ロール作成

2.ロール編集(リソースへの権限の追加)

0
0 180
記事 Toshihiko Minamoto · 4月 5, 2023 3m read

テクノロジー分野で 19 年間働いてきた中、様々な分野でいくつかのプロジェクトに参加することができましたが、健康分野は私が一番惹かれている分野の 1 つです。

健康に焦点があてられたものを作成するチャンスを得るたびに、FHIR プロトコルを使用することにワクワクしています。

とは言え、テック系の 3 人の IT 男子で構成されるチームでは、本当に利用価値のあるものを作り出すのは困難であるため、女性の健康のように重要なトピックにおいては、この主題を非常によく理解している人をチームに招きました。

15 年以上の経験があるだけでなく、医師として 1,000 回以上の出産を担当した経験も持ち合わせた産婦人科医の Talita Yurie Nakata 医師です。 彼女のビジョンとガイダンスにより、私たちはこのアイデアの重要性と、それが医師と患者にどれだけ役立つかを理解しました。

このアプリケーションの背後には、患者(妊娠者)の情報を患者自身に提供し、そのデータを更新できるようにすれば、妊娠経過を管理している医師は常に状況を認識し、異常が発生した場合にアラートを受け取れるようになるという 構想があります。

患者の 2 つの指標(体重と血圧)データを使って、妊娠状況を監視し、望ましくない合併症を予防することができました。 (もちろん、より正確なビューを得るには、情報が多いほど良いのですが、この MVP ではこれらの 2 つのデータを使用します)

太りすぎには妊娠糖尿病のリスクが伴い、高血圧は子癇(しかん)を引き起こす可能性があります。

また、以下の記事で研究されているとおり、いずれの状態も、母体と胎児に多くの問題をもたらしてしまいます。

Maternal Obesity and Risk of Gestational Diabetes Mellitus(母体の肥満と妊娠糖尿病のリスク)
https://diabetesjournals.org/care/article/30/8/2070/28574/Maternal-Obesity-and-Risk-of-Gestational-Diabetes

Pre-Pregnancy Obesity, Excessive Gestational Weight Gain, and the Risk of Pregnancy-Induced Hypertension and Gestational Diabetes Mellitus(妊娠前の肥満、妊娠による過度の体重増加、および妊娠による高血圧と妊娠糖尿病のリスク)
https://www.mdpi.com/2077-0383/9/6/1980
 
Influence of maternal obesity on the association between common pregnancy complications and risk of childhood obesity: an individual participant data meta-analysis(一般的な妊娠合併症と小児肥満のリスクの関係に対する母体の肥満の影響: 各参加者データのメタ分析)
https://www.sciencedirect.com/science/article/abs/pii/S2352464218302736

FioCruz: Oswaldo Cruz Foundation
Gestational obesity: an alert situation(妊娠性肥満: 警戒すべき状況)
https://portal.fiocruz.br/noticia/obesidade-gestacional-uma-situacao-de-alerta

以下は、Febrasgo( ブラジル産婦人科連合会)からの引用です。

1 型糖尿病、2 型糖尿病、または妊娠糖尿病の女性は、子癇前症を発症するリスクが高くなります。 最初の 2 つの状況は慢性の軽度の炎症に関連しており(Nunemaker, 2016)、子癇前症の妊婦は妊娠前にインスリン抵抗性になりやすいという事実に加えて、これが糖尿病の女性が子癇前症を発症する可能性が高い理由の 1 つである可能性があります(Scioscia et al., 2009)。 妊娠糖尿病を患う妊婦には、内皮機能不全の証拠から、子癇前症の妊婦と同様の免疫プロファイルがあると言えます。

謝辞

繰り返しになりますが、作成する各アプリケーションへのすべてのコミュニティサポートに感謝の意を表したいと思います。

このアプリが興味深いと思われた方、インサイトに貢献していると感じた方は、ぜひこのアプリに投票してください。笑い

アプリを気に入っていただけた方、私たちのコミュニティへの貢献を楽しみとされている方は、Pregnancy Symptoms Tracker に投票し、この制作活動をご支援ください!

1
0 127
記事 Mihoko Iijima · 4月 10, 2023 4m read

これは InterSystems FAQ サイトの記事です。

バージョン2017.2以降から、CREATE TABLE文で作成したテーブル定義のデータを格納するグローバル変数の命名ルールが変わり ^EPgS.D8T6.1 のようなハッシュ化したグローバル変数名が設定されます。(この変更はパフォーマンス向上のために追加されました。)

※ バージョン2017.1以前については、永続クラス定義のルールと同一です。詳細は関連記事「永続クラス定義のデータが格納されるグローバル変数名について」をご参照ください。

以下のテーブル定義を作成すると、同名の永続クラス定義が作成されます。

CREATETABLE Test.Product(
    ProductID VARCHAR(10) PRIMARY KEY,
    ProductName VARCHAR(50),
    Price INTEGER
)

 永続クラス:Test.Productの定義は以下の通りです。(パラメータ:USEEXTENTSETに1が設定されます) 

0
0 309
記事 Tomohiro Iwamoto · 4月 7, 2023 21m read

クライアントアプリケーション編

IRISだけでoAuth2/OpenID ConnectのSSO/SLO環境を実現する/サーバ編」 のクライアントアプリケーション編です。サーバ編の構成が既に稼働していることを前提にしています。

既にサーバ編でgit clone実行された方(ありがとうございます)、若干の変更がありますのでgit pullと./build.shの実行をお願いします。

oAuth2クライアントアプリケーション(OICD用語ではRP。以下RPと称します)の形態として、5種類用意しています。


形態ライブラリ登録クライアントタイプSSOSLO
WebアプリケーションIRIS/CSPConfidential実装あり実装あり
SPAAngularPublic実装あり実装なし
SPA+BFFAngular,IRIS/RESTConfidential実装あり実装あり
PythonoauthlibConfidentialN/AN/A
curlN/AConfidentialN/AN/A

PythonやcurlがConfidential(client_secretの秘匿性を十分に保てる)か、というと微妙ですが、あくまで利用者は開発者のみ、という位置づけです。

Webアプリケーション(非SPA)

従来型のWebアプリケーション、Confidential Clientの例です。

                      login/logout
      +-----------------------------------------------------+
      |                                                     | 
ブラウザ ---Apache--> CSPベースのWebアプリケーション +--> 認可サーバ
(ユーザセッション,   (CSP SessionID,AT等)            |    (ユーザセッション)
CSP sessionID)                                       +--> リソースサーバ

IRISに限りませんが、SSOで得たユーザ情報(subクレーム)を、RPやリソースサーバで使用するユーザにどのようにマッピングするか設計・実装する必要があります。ここではRPの実装例として、下記の2種類を用意しています。

  • IRISのユーザ認証をしない

    IRISユーザとの認証(マッピング)は一切行わず、RPのアプリケーションコード内で取得したoAuth2/OIDC関連の情報のみでアクセス制御する形式です。
    サーバ編で使用したWebアプリケーション#1a,1bがこれに該当します。

    内容としては、この記事でGoogleをOPとした例を元に、IRISをOPに変更したものです。
    RPの一部として、認可コードフローの開始を行っています。

    この例ではRP上はIRISユーザ、UnknowUser(RoleはWebアプリケーションで付与)で動作します。

  • ログインフォームをカスタマイズして、IRISユーザとマッピングする

    IRISのログインページのカスタマイズ機能と代行ログインの仕組みを利用して、oAuth2/OIDC関連の情報取得とRPで使用するIRISユーザとの認証(マッピング)を行います。
    RP実行ユーザはSSOログインに使用したユーザ名に"OAuth"を付与した名称を持つ代行ユーザになります。

    例えば、testというユーザでSSOした場合、RP上のIRISユーザ名はAuth2test(RoleはZAUTHENTICATEで付与)になります

    Webアプリケーション#2がこれに該当します。

    RPは、認証が完了した状態からの開始になります。上記のLogin.clsが担っていた役割は、カスタムログインページZAUTHENITICATEに隠ぺいされます。

    現時点で、こちらの方法はあまり深堀りしていません。もう少し製品サイドの機能拡充を待ちたいと思います...。

SPA

Angularで動作する、Public Clientの例です。

                      login/logout
      +-----------------------------------------+
      |                                         | 
ブラウザ(SPA) -----Apache--+--> Webpack         |
(ユーザセッション)         +-------------> 認可サーバ
                           |               (ユーザセッション)           
                           +-------------> リソースサーバ

ng(AngularのCLI)でビルドを行い、ビルド成果物(webpack)をapacheに配布します。 SPAが直接アクセストークンを入手、使用しますので、セキュアな環境が必要な場合、その漏洩対策が必要とされています。

その対策が大変なので、BFFという仕組みが提案されています

現状、SLOは機能しません。正確には、認可サーバからのログアウトは実行されます(その結果、同じユーザセッションに属するトークンは破棄されます)が、SPAベースの各RPに対して、SLOされたというイベントを安全に伝える方法が無いため、各ブラウザタブのsessionStorageに保存されているアクセストークンの破棄などを行うRP側のlogout処理をトリガ出来ないためです。

トークンがExpire(デフォルトで3,600秒)すればRP自身で気づくきっかけになります

RPが定期的にuserinfo等を取得して、ユーザセッションが有効か確認するという方法はあり得ますが、認可サーバへのストレスが大きいです。

SLO実行後、認可サーバ上のユーザセッションは終了していますので、その後のRPでのトークンの更新やログアウト,リソースサーバでのGetIntrospectionは失敗します。

OpenID Connect Session Management 1.0のSession Status Change Notificationがこの仕組みに関する仕様です。
RPの画面にRP用、OP用のiframeをhiddenで用意しておいて、その両者(クロスドメインの可能性あり)でデータ交換することで、ログアウトされた(セッションのステータスが変更した)ことを知る...みたいな内容です。 IRISはOpenID Connect Session Management 1.0をサポートしていません。

IRISが対応しているのはfront channel logoutです。

もし深堀りされたいなら、こちらなどが参考になりそうです。

SPA+BFF

AngularにBFF(Backend For Frontend)を追加することで、Confidential Client化する例です。

                      login/logout
      +-----------------------------------------------------+
      |                                                     | 
ブラウザ(SPA) -----Apache--+--> Webpack                     |
(ユーザセッション,         +--> REST ------------+----> 認可サーバ
sessionID)                      (sessionID,AT等) |      (ユーザセッション)
                                                 +--> リソースサーバ

BFFについては、こちらの説明がわかりやすかったです。

ざっくりと言ってしまえば、SPA単独と比べてよりセキュアで、RPの種類が増えた際にアーキテクチャ上のメリットがある、ということです。

本BFF実装は、下記のIRISのRESTエンドポイント(そこで使用されるRP用のAPI)をAngularから呼び出す事で実現しています。

Angular側の大半の処理はbff.service.tsにあります。IRISのRESTエンドポイントはBFF.REST.clsで実装されています。


AngularIRIS実行されるAPI
接続、ログイン/getauthurl##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint()
userinfo取得/userinfo##class(%SYS.OAuth2.AccessToken).GetUserinfo()
リソースサーバアクセス/call通常のhttpリクエスト+アクセストークン
トークン更新/refresh##class(%ZSYS.OAuth2.Authorization).GetAccessTokenRefreshById() *1
ログアウト/getauthurl##class(%ZSYS.OAuth2.Authorization).GetLogoutEndpoint() *2
トークン破棄/revocation##class(%SYS.OAuth2.AccessToken).RevokeToken()

(*1)トークン更新は独自にメソッドを実装しています。
(*2)現在、独自メソッドを実装していますが、V2023.2以降で標準APIに反映される予定です。

ユーザエージェント-BFF間のセッション維持のために、##class(BFF.REST).GetAuthorizationCodeEndpoint()で、サーバ側で独自にsessionID(httponlyクッキー)発行しています。セッションIDの生成ロジックはセキュリティ強度に直結しますので、適宜見直してください。

Set sessionid=##class(%OAuth2.Utils).Base64UrlEncode($system.Encryption.GenCryptRand(12))  // 要変更
  ・
  ・
Do %response.SetCookie(..#SESSIONCOOKIE,sessionid,,..#COOKIEPATH,,..#SECURECOOKIE,1) ; secure,httponly 

Python

これはアプリケーションとは呼べないです。
認可コードフローを利用する、デバッグ、実験用途のpythonクライアントです。Confidential Clientとして登録しています。 ブラウザで実行すると、リダイレクトの連鎖の中で見落としてしまう内容を捕捉するために使用しました。

python +--> ブラウザ -----Apache--------> 認可サーバ
       |    (ユーザセッション)     (ユーザセッション)
       +---Apache---> リソースサーバ

curl

これはアプリケーションとは呼べないです。
これも、サーバの動作確認のためのデバッグ用途です。Confidential Clientとしています。 リソースオーナー・パスワード・クレデンシャルズのクライアントとして使用します。これもデバッグ、実験用途なので、受信したトークンの有効性チェック等は一切行っていません。

リソースオーナー・パスワード・クレデンシャルズの使用は禁止されるようです。

curl --Apache--+--> 認可サーバ
               +--> リソースサーバ

クライアント認証メソッドの設定

認可サーバへのRP登録時に、RPがトークンエンドポイントにアクセスする際のクライアント認証メソッドを指定します。

SPAだけは「エンコードされたボディから(client_secret_post)」を選択しています。残りは全て「ベーシック(client_secret_basic)」になっています。

下記は、MyApps.Installer.clsからの抜粋。

Set c.Metadata."token_endpoint_auth_method" = "client_secret_basic"

「エンコードされたボディから」はPOSTリクエストのBodyにパラメータとして渡す形式、「ベーシック」は、HTTPヘッダでAuthorization: Basic BASE64(client_id:client_secret)を指定する形式です。

IRISに用意されているRP用のAPI群

IRISベースのRP(CSPベースのWebアプリケーション、SPA+BFFのBFFサーバ)の場合、RP用に用意された以下のAPI群を使用できます。

詳細は、ドキュメントを参照ください。

ログイン時

##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint()は、認可サーバへのログインを実行するためのURLを返却します。ユーザがこのURLをクリックすることで、認可コードフローが開始します。

使用例はMyApp.Login.clsを参照ください。

set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
  $$$APP,
  scope,
  "https://webgw.localdomain/irisclient/csp/"_ns_"/MyApp.AppMain.cls",
  .properties,
  .isAuthorized,
  .sc)

$$$APPはRPを認可サーバに登録した際に使用した登録名(USER_CLIENT_APP等)です。scopeには認可を要求するスコープ("openid profile scope1"等)を指定します。

返却されるURLは次のような内容になります。いわゆる承認リクエストです。

https://webgw.localdomain/irisauth/authserver/oauth2/authorize
  ?response_type=code
  &client_id=01yJ2zW0K9XQqrroIB4b7PLci3NkJBegm0b_kBcFhgw
  &redirect_uri=https%3A//webgw.localdomain/irisclient/csp/sys/oauth2/OAuth2.Response.cls
  &scope=openid%20profile%20scope1
  &state=gWr5ipHAtskDhf0fFbNtxxJWnwY
  &nonce=paEDbHweG2xiJxWxotTfaJPbdB4
  &code_challenge=8X5l4fxCNOdLj-u87Mu3UwRH96dxYpjoGcv6Z-JZmEc
  &code_challenge_method=S256

RPのリダイレクト先を指定するredirectクエリパラメータ値がOAuth2.Response.clsになっていますが、これはIRISベースのRP専用のランディングページになっていて、RPがするべきこと(認可コードの取得、stateのチェック、アクセストークンリクエストの発行、などなど)を行ってくれます。

RPの登録内容(クライアントのリダイレクトURL)も、下記のようにホスト名、ポート番号、プレフィックスのみを指定すれば、このリダイレクト先が自動選択されます。

CSP(非REST)ベースのアプリケーションは、CSPセッションという独自のセッションID(%session.SessionId)と保存領域を作成します。oAuth2クライアントとして一度認証・認可を受けると、認証関連の情報(アクセストークン,有効期限など)を、このCSPセッションIDを主キーとしたテーブルに保存します(さきほどのOAuth2.Response.clsが実行)。

$ docker compose exec irisclient iris session iris -U%SYS "##class(%SYSTEM.SQL).Shell()"
[SQL]%SYS>>select ApplicationName,SessionId,Expires,ResponseType,Scope,CONVERT(VARCHAR(10),AccessToken) from OAuth2.AccessToken

ApplicationName SessionId       Expires ResponseType    Scope   Expression_6
CLIENT_APP      S1YXEXP9SP      1677551976      code    openid profile scope1 scope2 scope99    eyJ0eXAiOi

一方、ブラウザにはCSPセッションID(を拡張したデータ)のみがセッションクッキー(HttpOnly, デフォルト設定ではSameSite=Strict)で保存されます。

この辺りは従来のCSPのメカニズムそのものです。例えば CSPSESSIONID-SP-443-UP-irisclient-csp-user- というクッキー名になります。

認可コードフローの終了時には、GetAuthorizationCodeEndpoint()の第3引数で指定したURL、この場合はMyApp.AppMain.clsにリダイレクトされます。

認証済みか否かの確認

##class(%SYS.OAuth2.AccessToken).IsAuthorized()はRPが認証済みかどうかを確認するAPIです。

認可コードフローのリダイレクト先であるOAuth2.Response.clsはRPが認証済みかどうかを確認するための情報元をRPに格納します

2つの事を行ってくれます。

  • その情報の状態によってRPが既に認証済みかどうかの確認を行います

  • 認証済みである場合、アクセストークン、IDトークンなどを返却します

MyApp.Login.clsのOnPreHTTP()や、MyApp.AppMain.clsで使用されています。

RPが既に認証済みの場合は、MyApp.Login.clsのOnPreHTTP()が実行され、IsAuthorized()がTrueとなり、認可サーバを経由することなく、MyApp.AppMain.clsにリダイレクトされます。

ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
{
  #dim %response as %CSP.Response
  set scope="openid profile "_..#SCOPES
  if ##class(%SYS.OAuth2.AccessToken).IsAuthorized($$$APP,,scope,.accessToken,.idtoken,.responseProperties,.error) {
    set %response.Redirect="MyApp.AppMain.cls"
  }
  Return $$$OK
}

IDトークンの有効性の確認(Validation)

##class(%SYS.OAuth2.Validation).ValidateIDToken()はIDトークンの有効性を確認します。

どのような確認を行うかは、OIDC で定められています。

MyApp.AppMain.clsで使用されています。

set valid=##class(%SYS.OAuth2.Validation).ValidateIDToken(
    $$$APP,
    idtoken,
    accessToken,
    ..#SCOPES,
    ..#RSCURL1,  // RSCURL2の存在チェックはしていないので注意
    .jsonObject,
    .securityParameters,
    .sc)

トークンの受信後には署名の有無の確認を行います。

        Set isSigned=$Data(securityParameters("sigalg"))#2
        if 'isSigned="" { 
            write "署名されていません !<br>",!
        }

Introspection

##class(%SYS.OAuth2.AccessToken).GetIntrospection()は認可サーバにアクセストークンの有効性を問い合わせます。

認可サーバへのトラフィックが発生するため、opaqueのアクセストークンの場合は必須ですが、JWTの場合は任意とされています

MyApp.AppMain.clsで使用されています。

set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection($$$APP,accessToken,.jsonObject)

ログアウト時

##class(%SYS.OAuth2.Authorization).GetLogoutEndpoint()は、SLO(シングルログアウト)を実行するためのURLを返却します。ユーザがこのURLをクリックすることで、RP Initiatedのフロントチャネルログアウトが開始します。

Set ns=$ZCVT($NAMESPACE,"L") Set fclouri="https://webgw.localdomain/irisclient/csp/"_ns_"/MyApp.Login.cls"
Set url=##class(%SYS.OAuth2.Authorization).GetLogoutEndpoint($$$APP,fclouri)

返却されるURLは次のような内容になります。

https://webgw.localdomain/irisclient/csp/sys/oauth2/OAuth2.PostLogoutRedirect.cls
  ?register=irzgE0VENqa51QpmvGcmG-nDWn0

このURLをGETすると、さらに認可サーバのlogoutエンドポイントへのURLにリダイレクトされます。RP-Initiated Logoutのためのエンドポイントです。

 https://webgw.localdomain/irisauth/authserver/oauth2/logout
  ?id_token_hint=eyJ0eXAiO.....
  &post_logout_redirect_uri=https://webgw.localdomain/irisclient/csp/sys/oauth2/OAuth2.PostLogoutRedirect.cls
  &state=Pc73yDQFouYO1Y-a0PioOI3qRtw

RPのリダイレクト先を指定するpost_logout_redirect_uriクエリパラメータ値がOAuth2.PostLogoutRedirect.clsになっていますが、これはIRISベースのRP専用のランディングページになっていて、RPがするべきこと(RPに保存されているトークンの除去等)を行ってくれます。

ログアウト終了時には、GetLogoutEndpoint()の第2引数で指定したURL(この場合は、ログインページであるMyApp.Login.cls)にリダイレクトされます。

トークンの失効処理(Revocation)

##class(%SYS.OAuth2.AccessToken).RevokeToken()は指定したトークンを失効させます。

ユーザセッション使用時に、単独のアクセストークンのみを失効させることで、特定のアプリケーション単独のログアウトを実現します。ログイン時はSSOのメリットを受けつつ、ログアウトは個別に行いたい場合に使用できます。

CSPベースのWebアプリケーションの場合、ログアウト時にはCSPセッションを終了させますが、本メソッドの呼び出しは、CSPセッションの終了時に自動実行されるため、アプリケーションコードで明示的に呼び出す必要はありません。RESTを使用する場合、(USESESSIONパラメータを1にしない限り)CSPセッションは使用しませんので、明示的に呼び出す必要があります。

本例では、MyApp.AppMain.clsのOnPreHTTP()で下記を実行しています。

Do %session.Logout() 
Set %session.EndSession=1 ; will call OAuth2.SessionEvents.OnEndSession()
Set %response.Redirect="MyApp.Login.cls"

リソースサーバへのRESTアクセス

リソースサーバのRESTエンドポイント呼び出し時は、##class(%SYS.OAuth2.AccessToken).AddAccessToken()を使用してアクセストークンを追加します。追加方法は第2引数で指定します。省略時はHTTPヘッダーに"Authorization: Bearer"を追加します。

set httpRequest=##class(%Net.HttpRequest).%New()
// AddAccessToken adds the current access token to the request.
set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
    httpRequest,,
    ..#SSLCONFIG,
    $$$APP)
if $$$ISOK(sc) {
    Set url=..#RSCURL2_"/private" w "URL:"_url_"</BR>",!
    set sc=httpRequest.Get(url)
}

導入手順

複数のgitをcloneしますが、下記のフォルダ構造にしておけば、各種手順やシェルを修正することなく(最もストレスなく...)動作させる事が出来ます。

Linux
(任意)/iris-oauth             <= サーバ編で導入済みのはず
(任意)/angular-oauth2-client  <= git clone https://github.com/IRISMeister/angular-oauth2-client.git

Windows
C:\git\python-oauth2-client   <= git clone https://github.com/IRISMeister/python-oauth2-client.git
C:\git\angular-oauth2-client  <= ngビルドをWindowsで動かすのであれば

以下、(任意)は$HOME/gitとしています。

Webアプリケーション

導入手順

不要です。サーバに同梱されています。

起動方法

こちらはIRISサーバで完結するので、単独の起動方法はありません。サーバ用のコンテナ起動時に自動起動します。

アクセス方法



操作については、サーバ編を参照ください。

SPA(Angular)

F5(リロード)対策としてアクセストークンをsessionStorageに保存しています。XSS脆弱性に対してご注意ください。

導入手順

LinuxあるいはWindowsで実行します。
ビルド・実行にはnode, npm, ngが必要です。私の環境は以下の通りです。Windowsでも同じことが出来ます。

Windowsの場合、./build_and_deploy.ps1, ng-start.ps1内の$env:gitrootの値を環境にあわせて修正してください。

$ ng version

Angular CLI: 15.1.6
Node: 16.16.0
Package Manager: npm 9.3.0
OS: linux x64

Angular: 15.1.5
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1501.6
@angular-devkit/build-angular   15.1.6
@angular-devkit/core            15.1.6
@angular-devkit/schematics      15.1.6
@angular/cli                    15.1.6
@schematics/angular             15.1.6
rxjs                            7.8.0
typescript                      4.9.5

下記の手順でビルドしたangularアプリケーションのディストリビューション(./dist/*)を、iris-oauth2のhtdocs/下にコピーすることで使用可能になります。

  1. Git Clone

    カレントディレクトリが./iris-oauth2であることを確認してください。その1階層上のディレクトリに移動して、cloneします。

    $ pwd
    /home/irismeister/git/iris-oauth2
    $ cd ..
    $ git clone https://github.com/IRISMeister/angular-oauth2-client.git
    $ cd angular-oauth2-client
    
  2. $ npm install
    $ ./build_and_deploy.sh   (Windowsの場合は>powershell ./build_and_deploy.ps1)
    

    このシェルは下記を行います。

    • client_id, client_secretをサーバ配下のファイル(environment*.ts)から取得
    • NGビルド実行。 ターゲットは/myapp/
    • htdocs/myapp/以下にビルド成果物をコピー
    • NGビルド実行。 ターゲットは/myapp2/
    • htdocs/myapp2/以下にビルド成果物をコピー

    下記のように表示されれば成功です。

    $ ./build_and_deploy.sh
    &#x2714; Browser application bundle generation complete.
    &#x2714; Copying assets complete.
    &#x2714; Index html generation complete.
          ・
          ・
          ・
    Build at: 2023-04-05T07:23:58.705Z - Hash: 67aabdbbe8ad0bfa - Time: 6796ms
    deploying to iris-oauth2
    done
    Go to https://webgw.localdomain/myapp/ or https://webgw.localdomain/myapp2/
    $
    

以後、iris-oauth2をリビルドするなどで、client_id,client_secretが変更された場合は、build_and_deploy.shを再実行してください。

起動方法

こちらはApacheを使用しますので単独の起動方法はありません。サーバ用のコンテナ起動時に自動起動します。

アクセス方法


名称エンドポイント
SPAアプリケーション/myapp
SPAアプリケーション/myapp2

両者は、client_idが異なる(つまり別のRPとみなす)だけ内容は同じです。下記のような「最高にクール」な画面が表示されます。

「BFF接続テスト」を押すとBFFとの疎通確認を行い、成功の場合IRISバージョンを画面表示します。

「SPAでログイン」を押すと、SPAのみで認証を行います。下記のような画面が表示されれば成功です。適当にボタンを押して(処理内容はボタンが示す通りです)動作確認してください。

修正・デバッグ

修正・デバッグ目的で、Angular Live Development Serverで起動することができます。

./ng-start.sh (Windowsの場合は>powershell ./ng-start.ps1)

Compiled successfullyという起動メッセージが表示されたら、Angularアプリケーション(live)にアクセスします。

よくあるエラー

Unexpected request - client_idと表示される場合、(恐らく)client_idが正しく反映されていません。build_and_deploy.shで直ります。

今後の修正

今後のドキュメントへの加筆・修正等はこちらで行います。

SPA(Angular)+REST+BFF

Webアプリケーションではセッション管理にCSPセッションを使用していますが、SPA+BFFでは独自のセッションを作成しています。

sessionidというクッキー名です。

SLOが機能します。

導入手順

SPA(Angular)に同梱されています。

起動方法

SPA(Angular)と同時に起動されます。

アクセス方法

SPA(Angular)と同じです。

「SPA+BFFでログイン」を押すと、SPA+BFFで認証を行います。下記のような画面が表示されれば成功です。SPAとほぼ同じですが、こちらにはBFFサーバの情報表示とトークンの取り消し機能が追加されています。

Python

導入手順

ブラウザをポップアップさせる必要があるため、Windowsで稼働させます。
DOS窓から下記を実行します。

C:\git> git clone https://github.com/IRISMeister/python-oauth2-client.git
C:\git> cd python-oauth2-client

Linux上のssl/web/all.crt(Webサーバの証明書チェーン)をローカルのc:\tempにコピーしてください。

$ pwd
/home/irismeister/git/iris-oauth2
$ cp ssl/web/all.crt /mnt/c/temp

クライアント情報を起動時に出力された内容(client/credentials_python.json)で上書きコピー(無ければ新規作成)します。
コピー先は、cloneを実行したパスに合わせてください。

$ cp client/credentials_python.json /mnt/c/git/python-oauth2-client/credentials.json

アクセス方法

pythonコードを起動します。

C:\git\python-oauth2-client>run.bat

ブラウザ上に、認証画面が表示されますので、「引き受ける」を押します。Please close the window.と表示されたら、ブラウザは以後不要なので閉じます。 DOS窓上にサーバから得た情報が出力されているはずです。

C:\git\python-oauth2-client>python request.py

***** auth_url *****
https://webgw.localdomain/irisauth/authserver/oauth2/authorize?response_type=code&client_id=EKj6Bww0yiFgeuYUxtkyzfge84-keMy20uE5xTmlWPk&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&scope=openid+profile+scope1+scope2&state=aiq21soYtKWlzomgChYUlzVgjpby1v&code_challenge=AIu6-HIPnl1MKWIxImJ3Earg0ezfcUbNF75hLljXSmM&code_challenge_method=S256

***** headers *****
{'Content-Type': 'application/x-www-form-urlencoded'}

***** body *****

127.0.0.1 - - [05/Apr/2023 16:09:49] "GET /?code=N9Y2DT77QNd_d1mmnsSjwUiqbxOvDB3AfT9QM5mD6XFuYYByhtSD4AfIjjWGF6AFTwdhA8QyOjfX63RO1mYsvw&state=aiq21soYtKWlzomgChYUlzVgjpby1v HTTP/1.1" 200 -

***** decoded access token *****
{'alg': 'RS512', 'kid': '3', 'typ': 'JWT'}
{   'aud': [   'https://webgw.localdomain/irisrsc/csp/myrsc',
               'https://webgw.localdomain/irisrsc2/csp/myrsc',
               'EKj6Bww0yiFgeuYUxtkyzfge84-keMy20uE5xTmlWPk'],
               ・
               ・
               ・

ユーザセッション(CSPOAuth2Sessionクッキー)が有効になっているため、最後にログアウトを実行しています。新しいタブが開き、空白のページが表示されますので、閉じてください。

  # Logout 
  logout_url='https://webgw.localdomain/irisauth/authserver/oauth2/logout?id_token_hint='+id_token+'&post_logout_redirect_uri=http://localhost:8080/fclogout&state='+state
  open_new(logout_url)

ここをコメントアウトすれば、次回以降の認証時にはログイン画面がスキップされます。

よくあるエラー

urllib.error.URLError: <urlopen error [WinError 10061] 対象のコンピューターによって拒否されたため、接続できませんでした 。>

サーバ環境が起動していない、あるいは到達できない場合に発生します。

Unexpected request - client_id

ブラウザに上記の内容が表示される場合、credentials.jsonが正しくコピーされていません。
このエラーが発生すると、DOSがControl-Cを受け付けない状態で止まってしまいます。その場合、ブラウザで別タブを開いて http://localhost:8080/ を開いてください(何も表示されません)。これでpythonコードが完了するはずです。

  File "F:\ISJ\WorkAtHome\git\python-oauth2\httpserverhandler.py", line 32, in get_access_token_from_url
    context.load_verify_locations(os.environ['REQUESTS_CA_BUNDLE'])
FileNotFoundError: [Errno 2] No such file or directory

証明書のチェーン(all.crt)がc:\temp\にコピーされていません。

今後の修正

今後のドキュメントへの加筆・修正等はこちらで行います。

curl

導入手順

不要です。

本来Windowsで実行するべき内容ですが、サーバの修正時に使用することが大半なので、ここではLinuxで実行しています。そのため、Linuxの/etc/hostsにも下記を追加しています。

127.0.0.1       webgw.localdomain

認可サーバには以下の設定が行われています。

  1. 認可サーバの構成で「リソース所有者のパスワード認証情報」がチェックされている

  2. curlがクライアントとして登録されている

クライアントの種別:機密
リダイレクト URL:  http://localhost:8080/  (実際には使用されないので何でも良いです)
サポートする許可タイプ (少なくともひとつをチェック):「リソース所有者のパスワード認証情報」をチェック
サポートされている応答タイプ(少なくとも1つをチェックする): 「コード」をチェック

起動方法

下記は、curl.shの実行結果です。

$ pwd
/home/irismeister/git/iris-oauth2
$ ./curl.sh

{
  "sub": "_SYSTEM"
}

{
  "HostName": "irisrsc",
  "UserName": "UnknownUser",
  "sub": "_SYSTEM",
  "aud": [
    "https://webgw.localdomain/irisrsc/csp/myrsc",
    "https://webgw.localdomain/irisrsc2/csp/myrsc",
    ""
  ],
  "sigalg": "RS512",
  "Status": "OK",
  "TimeStamp": "04/04/2023 17:25:57",
  "exp": "1680600357(2023-04-04 18:25:57)",
  "debug": {
    "jti": "https://webgw.localdomain/irisauth/authserver/oauth2.A20EIIXeenDpM6oK_At6ZEtCcKY",
    "iss": "https://webgw.localdomain/irisauth/authserver/oauth2",
    "sub": "_SYSTEM",
    "exp": 1680600357,
    "aud": [
      "https://webgw.localdomain/irisrsc/csp/myrsc",
      "https://webgw.localdomain/irisrsc2/csp/myrsc",
      ""
    ],
    "scope": "openid profile scope1 scope2",
    "iat": 1680596757,
    "customer_id": "RSC-00001"
  }
}

その他の使い道

アクセストークンはBearerトークンなので、他の方法で取得したアクセストークンを使用してリソースサーバにアクセス出来ます。
どのRPを使っても構わないのですが、下記のように実行すれば、正当なアクセスとみなされます。

access_token="eyJ0eXAiO.....BlohDZw" # 表示されたアクセストークンをコピペして環境変数に設定
curl --insecure -H "Authorization: Bearer ${access_token}" -H 'Content-Type:application/json;charset=utf-8' \
https://webgw.localdomain/irisrsc/csp/myrsc/private -s | jq

このURLはサーバ編でアクセスを拒否('NoAccessToken'エラー)させるために使用したものと同じです。

アクセストークンの秘匿性を保つことがいかに重要であるかを示す例ですが、開発時にはリソースサーバの簡単なデバッグツールとして使用できます。

0
0 436
InterSystems公式 Maki Hashizawa · 4月 7, 2023

 

開発者の皆様、こんにちは。

医療ソリューション・サービスプロバイダー様向けにシリーズでお送りしているセミナーの第三弾のお知らせを致します。

是非ご参加くださいますようご案内致します。

【開催概要】

医療ソリューション・サービスプロバイダー様向け】
第4回 InterSystems 医療 x IT セミナー:ソリューション 開発編 III
~これからの医療ITソリューションに求められる姿を探る ―データ分析/データ活用 最前線~

日時:4月20日(木)13:00 ~14:30 

参加費:無料(事前登録制)

対象:医療情報システムベンダー、医療機器ベンダー、医療向けサービスベンダーの事業企画・開発の責任者の方


【お申込み・詳細はこちらから】

【プログラム】

13:00~13:05  開会挨拶
インターシステムズジャパン株式会社 カントリーマネージャー 林 雅音

13:05~13:45  ゲスト講演    
「Embedded Pythonがオブジェクトデータベース/InterOperability/MLの真価を引き出す」
 群馬大学医学部附属病院 システム統合センター 副センター長
 准教授 鳥飼 幸太 様
13:50~14:25    
「データプラットフォームとPythonの出会い:データ活用の新しいアプローチ」
 インターシステムズジャパン株式会社 堀田 稔

0
0 203
記事 Mihoko Iijima · 4月 6, 2023 1m read

開発者の皆さん、こんにちは!

この記事では、Developer Hub にあるチュートリアルの4番目のご紹介となる REST + Augular App チュートリアル についてご紹介します。

チュートリアルでは、IRISを利用してRESTサービスで使用するテーブル、データ、RESTサーバの機能をサンプルコードをコピーしながら作成していきます。

チュートリアルの中で作成するWebアプリはとてもシンプルな内容で、データベースにブックマークとして登録したいURLを保存し、参照するだけのページとしています。

データの登録も、IRISの管理ポータルのSQLメニューでINSERT文を実行する形式で進めていきます。

最終的には、以下の図にあるように「Add a new bookmark」以下のテキストボックスで新しいブックマークを登録できるように、Web画面とRESTサーバ用コードを追加していきます。

アカウント作成やログインも不要で  ボタンをクリックするだけで始められます👍

ぜひ、お試しください!​​​​​​

0
1 259
記事 Mihoko Iijima · 4月 4, 2023 7m read

開発者の皆さん、こんにちは。

Python Native APIを利用すると、IRISにあるグローバル変数の参照/更新をPythonから行えたり、メソッドやルーチンをPythonから実行することができます。

この記事では「AWS Lambda の IRIS Python Native API IRIS」の記事を参考に、NativeAPIを利用してPythonからIRISに接続するAWS Lambda関数を作成する流れで必要となる、レイヤー作成と関数用コードの作成例をご紹介します。

※ 事前にAWSのEC2インスタンス(Ubuntu 20.04を選択)にIRISをインストールした環境を用意した状態からの例でご紹介します。

0
0 388
記事 Tomohiro Iwamoto · 4月 3, 2023 31m read

本記事は、あくまで執筆者の見解であり、インターシステムズの公式なドキュメントではありません。

IRISのoAuth2機能関連の情報発信は既に多数ありますが、本稿では

  • 手順(ほぼ)ゼロでひとまず動作させてみる
  • 設定の見通しを良くするために、役割ごとにサーバを分ける
  • 目に見えない動作を確認する
  • クライアント実装(PythonやAngular,CSPアプリケーション等)と合わせて理解する
  • シングルサインオン/シングルログアウトを実現する

ということを主眼においています。

コミュニティ版で動作しますので、「とりあえず動かす」の手順に従って、どなたでもお試しいただけます。

現状、使用IRISバージョンはIRIS 2023.1のプレビュー版になっていますが、ソースコードは適宜変更します。

手順に沿ってコンテナを起動すると下記の環境が用意されます。この環境を使用して動作を確認します。

ユーザエージェント(ブラウザ)やPython/curlからのアクセスは、全てApache (https://webgw.localdomain/) 経由になります。青枠の中のirisclient等の文字はコンテナ名(ホスト名)です。

例えば、irisclientホストの/csp/user/MyApp.Login.clsにアクセスする場合、URLとして

 https://webgw.localdomain/irisclient/csp/user/MyApp.Login.cls

と指定します。

つまり、各エンドポイントは同一のorigin (https://webgw.localdomain) を持ちます。そのため、クロスサイト固有の課題は存在しません(カバーされません)が、仮に各サーバが別のドメインに存在しても基本的には動作するはずです。

oAuth2/OIDC(OpenID Connect)の利用シーンは多種多様です。

本例は、認証・認可サーバ,クライアントアプリケーション,リソースサーバの全てがIRISで実行されるクローズドな環境(社内や組織内での使用)を想定して、認可コードフロー(Authorization Code Flow)を実現します。分かりやすい解説が、ネットにたくさんありますので、コードフロー自身の説明は本稿では行いません。

認証・認可サーバの候補はIRIS, WindowsAD, Azure AD, AWS Cognito, Google Workspace, keycloak, OpenAMなどがあり得ます。個別に動作検証が必要です。

クライアントアプリケーション(RP)は、昨今はSPAが第一候補となると思いますが、利用環境によっては、SPA固有のセキュリティ課題に直面します。

IRISには、Confidential Clientである、従来型のWebアプリケーション(フォームをSubmitして、画面を都度再描画するタイプのWebアプリケーション)用のoAuth2関連のAPI群が用意されています。

そこで、Webアプリケーション(CSP)を選択することも考えられますが、クライアント編では、よりセキュアとされるSPA+BFF(Backend For Frontend)の構成を実現するにあたり、Webアプリケーション用APIをそのまま活用する方法をご紹介する予定です。

以下、サーバ編の動作確認には、CSPアプリケーションを使用しています。これは、新規開発にCSP(サーバページ)を使用しましょう、という事ではなく、BFF実現のために必要となる機能を理解するためです。BFFについては、クライアント編で触れます。BFFについては、こちらの説明がわかりやすかったです。

リソースサーバの役割はデータプラットフォームであるIRISは最適な選択肢です。医療系用のサーバ機能ですがFHIRリポジトリはその良い例です。本例では、至極簡単な情報を返すAPIを使用しています。

少しの努力でFHIRリポジトリを組み込むことも可能です。

サーバ編とクライアント編に分けて記載します。今回はサーバ編です。

とはいえ、クライアントとサーバが協調動作する仕組みですので、境界は少しあいまいです


使用環境

  • Windows10
    ブラウザ(Chrome使用)、curl及びpythonサンプルコードを実行する環境です。

  • Liunx (Ubuntu)
    IRIS, WebGateway(Apache)を実行する環境です。Windows10上のwsl2、仮想マシンあるいはクラウドで動作させる事を想定しています。

参考までに私の環境は以下の通りです。


用途O/Sホストタイプ
クライアントPCWindows10 Pro物理ホスト
Linux環境ubuntu 22.04.1 LTS上記Windows10上のwsl2

Linux環境はVMでも動作します。VMのubuntuは、ubuntu-22.04-live-server-amd64.iso等を使用して、最低限のサーバ機能のみをインストールしてあれば十分です。

Linux上に必要なソフトウェア

実行にはjq,openssl,dockerが必要です。 私の環境は以下の通りです。

$ jq --version
jq-1.6
$ openssl version
OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
$ docker version
Client: Docker Engine - Community
 Version:           23.0.1

とりあえず動かす

下記手順でとりあえず動かしてみることが出来ます。

  • 以下は、Linuxで実行します。

    git clone https://github.com/IRISMeister/iris-oauth2.git --recursive
    cd iris-oauth2
    ./first-run.sh
    

    この時点で下記をLinuxで実行し、OpenIDプロバイダーのメタデータを取得できる事を確認してください。こちらのような出力が得られるはずです。

    curl http://localhost/irisauth/authserver/oauth2/.well-known/openid-configuration
    
  • 以下はWindowsで実行します。

    クライアントPC(Windows)にホスト名(webgw.localdomain)を認識させるために、%SystemRoot%\system32\drivers\etc\hostsに下記を追加します。

    wsl2使用でかつlocalhostForwarding=Trueに設定してある場合は下記のように設定します。

    127.0.0.1 webgw.localdomain 
    

    VM使用時は、LinuxのIPを指定します。

    192.168.11.48 webgw.localdomain 
    

    次に、httpsの設定が正しく機能しているか確認します。作成された証明書チェーンをWindows側のc:\tempにコピーします。

    cp ssl/web/all.crt /mnt/c/temp
    

    VMの場合は、scp等を使用してssl/web/all.crtを c:\temp\all.crtにコピーしてください。以後、WSL2のコマンドのみを例示します。

    PCからcurlでリソースサーバの認証なしのRESTエンドポイントにアクセスします。ユーザ指定(-u指定)していないことに注目してください。

    curl --cacert c:\temp\all.crt --ssl-no-revoke -X POST https://webgw.localdomain/irisrsc/csp/myrsc/public
    {"HostName":"irisrsc","UserName":"UnknownUser","sub":"","aud":"","Status":"OK","TimeStamp":"03/28/2023 17:39:17","exp":"(1970-01-01 09:00:00)","debug":{}}
    

    認証なしのRESTサービスですので成功するはずです。次にアクセストークン/IDトークンによる認証・認可チェック処理を施したエンドポイントにアクセスします。

    curl --cacert c:\temp\all.crt --ssl-no-revoke -X POST https://webgw.localdomain/irisrsc/csp/myrsc/private
    {
      "errors":[ {
                "code":5035,
                "domain":"%ObjectErrors",
                "error":"エラー #5035: 一般例外 名前 'NoAccessToken' コード '5001' データ ''",
                "id":"GeneralException",
                "params":["NoAccessToken",5001,""
                ]
              }
      ],
      "summary":"エラー #5035: 一般例外 名前 'NoAccessToken' コード '5001' データ ''"
    }
    

    こちらは、期待通りエラーで終了します。

    次に、ブラウザでCSPベースのWEBクライアントアプリケーションを開きます。

    プライベート認証局発行のサーバ証明書を使用しているため、初回はブラウザで「この接続ではプライバシーが保護されません」といったセキュリティ警告が出ます。アクセスを許可してください。

    「oAuth2認証を行う」ボタンを押した際に、ユーザ名、パスワードを求められますので、ここではtest/testを使用してください。

    権限の要求画面で「許可」を押すと各種情報が表示されます。

    ページ先頭に「ログアウト(SSO)」というリンクがありますので、クリックしてください。最初のページに戻ります。

    IRISコミュニティエディションで、接続数上限に達してしまうと、それ以後は[Service Unavailable]になったり、認証後のページ遷移が失敗したりしますので、ご注意ください。その場合、下記のような警告メッセージがログされます。

    docker compose logs irisclient
    
    iris-oauth2-irisclient-1  | 03/24/23-17:14:34:429 (1201) 2 [Generic.Event] License limit exceeded 1 times since instance start.
    

    しばらく(10分ほど)待つか、終了・起動をしてください。

  • 以下は、Linuxで実行します。

    終了させるには下記を実行します。

    ./down.sh
    

主要エンドポイント一覧

下図は、コード認可フローを例にした、各要素の役割になります。用語としてはoAuth2を採用しています。

OIDCはoAuth2の仕組みに認証機能を載せたものなので、各要素は重複しますが異なる名称(Authorization serverはOIDC用語ではOP)で呼ばれています。

CLIENT SERVERという表現は「何どっち?」と思われる方もおられると思いますが、Client's backend serverの事で、サーバサイドに配置されるロジック処理機能を備えたWebサーバの事です。描画を担うJavaScriptなどで記述されたClient's frontendと合わせて単にClientと呼ぶこともあります。


要素サービス名OIDC用語oAuth2用語エンドポイント
ユーザエージェントN/AUser AgentUser AgentN/A
Web GatewaywebgwN/AN/A/csp/bin/Systems/Module.cxw
認可サーバの管理irisauthN/AN/A/irisauth/csp/sys/%25CSP.Portal.Home.zen
リソースサーバ#1の管理irisrscN/AN/Airisrsc/csp/sys/%25CSP.Portal.Home.zen
リソースサーバ#1irisrscN/AResource server/irisrsc/csp/myrsc/private
リソースサーバ#2の管理irisrsc2N/AN/A/irisrsc2/csp/sys/%25CSP.Portal.Home.zen
リソースサーバ#2irisrsc2N/AResource server/irisrsc2/csp/myrsc/private
WebApp 1a,1bの管理irisclientN/AN/A/irisclient/csp/sys/%25CSP.Portal.Home.zen
WebApp 1airisclientRPClient server/irisclient/csp/user/MyApp.Login.cls
WebApp 1birisclientRPClient server/irisclient2/csp/user/MyApp.AppMain.cls
WebApp 2の管理irisclient2N/AN/A/irisclient2/csp/sys/%25CSP.Portal.Home.zen
WebApp 2irisclient2RPClient server/irisclient2/csp/user/MyApp.AppMain.cls

エンドポイントのオリジン(https://webgw.localdomain)は省略しています


組み込みのIRISユーザ(SuperUser,_SYSTEM等)のパスワードは、merge1.cpfのPasswordHashで一括で"SYS"に設定しています。管理ポータルへのログイン時に使用します。

導入手順の解説

first-run.shは、2~5を行っています。

  1. ソースコード入手

    git clone https://github.com/IRISMeister/iris-oauth2.git --recursive
    
  2. SSL証明書を作成

    ./create_cert_keys.sh
    

    apache-sslに同梱のsetup.shを使って、鍵ペアを作成し、出来たsslフォルダの中身を丸ごと、ssl/web下等にコピーしています。コピー先と用途は以下の通りです。

    コピー先使用場所用途
    ssl/web/ApacheのSSL設定およびクライアントアプリ(python)Apacheとのhttps通信用
    irisauth/ssl/auth/認可サーバ認可サーバのクライアント証明書
    irisclient/ssl/client/CSPアプリケーション#1a,1bIRIS(CSP)がクライアントアプリになる際のクライアント証明書
    irisclient2/ssl/client/CSPアプリケーション#2IRIS(CSP)がクライアントアプリになる際のクライアント証明書
    irisrsc/ssl/resserver/リソースサーバリソースサーバのクライアント証明書
    irisrsc2/ssl/resserver/リソースサーバ#2リソースサーバのクライアント証明書
  3. PCにクライアント用の証明書チェーンをコピー

    all.crtには、サーバ証明書、中間認証局、ルート認証局の情報が含まれています。curlやpythonなどを使用する場合、これらを指定しないとSSL/TLSサーバ証明書の検証に失敗します。

    cp ssl/web/all.crt /mnt/c/temp
    

    備忘録

    下記のコマンドで内容を確認できます。

    openssl crl2pkcs7 -nocrl -certfile ssl/web/all.crt | openssl pkcs7 -print_certs -text -noout
    
  4. Web Gatewayの構成ファイルを上書きコピー

    cp webgateway* iris-webgateway-example/
    
  5. コンテナイメージをビルドする

    ./build.sh
    

各種セットアップは、各サービス用のDockerfile以下に全てスクリプト化されています。iris関連のサービスは、原則、##class(MyApps.Installer).setup()で設定を行い、必要に応じてアプリケーションコードをインポートするという動作を踏襲しています。例えば、認可サーバの設定はこちらのDockefileと、インストーラ用のクラスであるMyApps.Installer(内容は後述します)を使用しています。

  1. ブラウザ、つまりクライアントPC(Windows)にホスト名webgw.localdomainを認識させる

    上述の通りです。

起動方法

./up.sh

up時に表示される下記のようなjsonは、後々、pythonなどの非IRISベースのクライアントからのアクセス時に使用する事を想定しています。各々client/下に保存されます。

{
  "client_id": "trwAtbo5DKYBqpjwaBu9NnkQeP4PiNUgnbWU4YUVg_c",
  "client_secret": "PeDUMmFKq3WoCfNfi50J6DnKH9KlTM6kHizLj1uAPqDzh5iPItU342wPvUbXp2tOwhrTCKolpg2u1IarEVFImw",
  "issuer_uri": "https://webgw.localdomain/irisauth/authserver/oauth2"
}

コンテナ起動後、ブラウザで下記(CSPアプリケーション)を開く。
https://webgw.localdomain/irisclient/csp/user/MyApp.Login.cls

停止方法

./down.sh  

認可サーバの設定について

カスタマイズ内容

多様なユースケースに対応するために、認可サーバの動作をカスタマイズする機能を提供しています。

特に、%OAuth2.Server.Authenticateはプロダクションには適さない可能性が高いのでなんらかのカスタマイズを行うように注記されていますのでご注意ください。

本例では、認証関連で下記の独自クラスを採用しています。

  • 認証クラス

    %ZOAuth2.Server.MyAuthenticate.cls

    下記を実装しています。
    BeforeAuthenticate() — 必要に応じてこのメソッドを実装し、認証の前にカスタム処理を実行します。

    ドキュメントに下記の記載があります。本例ではscope2が要求された場合には、応答に必ずscope99も含める処理を行っています。

    通常、このメソッドを実装する必要はありません。ただし、このメソッドの使用事例の1つとして、FHIR® で使用される launch と launch/patient のスコープを実装するのに利用するというようなものがあります。この事例では、特定の患者を含めるようにスコープを調整する必要があります。

    AfterAuthenticate() — 必要に応じてこのメソッドを実装し、認証の後にカスタム処理を実行します。

    ドキュメントに下記の記載があります。本例ではトークンエンドポイントからの応答にaccountno=12345というプロパティを付与する処理を行っています。

    通常、このメソッドを実装する必要はありません。ただし、このメソッドの使用事例の1つとして、FHIR® で使用される launch と launch/patient のスコープを実装するのに利用するというようなものがあります。この事例では、特定の患者を含めるようにスコープを調整する必要があります。

    トークンエンドポイントからの応答はリダイレクトの関係でブラウザのDevToolでは確認できません。pythonクライアントで表示出来ます。

    {   'access_token': '...........',
        'accountno': '12345',
        'expires_at': 1680157346.845698,
        'expires_in': 3600,
        'id_token': '...........',
        'refresh_token': '..........',
        'scope': ['openid', 'profile', 'scope1', 'scope2', 'scope99'],
        'token_type': 'bearer'
    }
    
  • ユーザクラスを検証(ユーザの検証を行うクラス)

    %ZOAuth2.Server.MyValidate.cls

    下記を実装しています。
    ValidateUser() — (クライアント資格情報を除くすべての付与タイプで使用)

    ここでは、トークンに含まれる"aud"クレームのデフォルト値を変更したり、カスタムクレーム(customer_id)を含める処理を行っています。

    {
      "jti":"https://webgw.localdomain/irisauth/authserver/oauth2.UQK89uY7wBdysNvG-fFh44AxFu8",
      "iss":"https://webgw.localdomain/irisauth/authserver/oauth2",
      "sub":"test",
      "exp":1680156948,
      "aud":[
        "https://webgw.localdomain/irisrsc/csp/myrsc",
        "https://webgw.localdomain/irisrsc2/csp/myrsc",
        "pZXxYLRaP8vAOjmMetLe1jBIKl0wu4ehCIA8sN7Wr-Q"
      ],
      "scope":"openid profile scope1",
      "iat":1680153348,
      "customer_id":"RSC-00001",
      "email":"test@examples.com",
      "phone_number":"01234567"
    }
    

これらの独自クラスは、下記で設定しています。

リフレッシュトークン

「パブリッククライアント更新を許可」をオンにしています。

この設定をオンにすると、client_secretを含まない(つまりpublic clientの要件を満たすクライアント)からのリフレッシュトークンフローを受け付けます。そもそもPublic Clientにはリフレッシュトークンを発行しない、という選択もありますが、ここでは許可しています。

また、「リフレッシュ・トークンを返す」項目で「常にリフレッシュトークンを返す」を設定しています。

「scopeに"offline_access"が含まれている場合のみ」のように、より強めの制約を課すことも可能ですが、今回は無条件に返しています

ユーザセッションをサポート

認可サーバの"ユーザセッションをサポート"を有効に設定しています。この機能により、シングルサインオン(SSO)、シングルログアウト(SLO)が実現します。

ユーザセッションをユーザエージェントとRP間のセッション維持に使用する"セッション"と混同しないよう

この設定を有効にすると、認可時に使用したユーザエージェントは、以後、ユーザ名・パスワードの再入力を求めることなくユーザを認証します。以下のように動作を確認できます。

  1. CSPベースのアプリケーション#1aをブラウザで開きます。ユーザ名・パスワードを入力し、認証を行います。

  2. 同じブラウザの別タブで、異なるclient_idを持つCSPベースのアプリケーション#1bを開きます。本来であれば、ユーザ名・パスワード入力を求められますが、今回はその工程はスキップされます。

  3. 上記はほぼ同じ表示内容ですが$NAMESPACE(つまり実行されているアプリケーション)が異なります。

アプリケーションが最初に認可されたスコープと異なるスコープを要求した場合、以下のようなスコープ確認画面だけが表示されます。

この時点で認可サーバで下記を実行すると、現在1個のセッションに属する(同じGroupIdを持つ)トークンが2個存在することが確認できます。

$ docker compose exec irisauth iris session iris -U%SYS "##class(%SYSTEM.SQL).Shell()"
[SQL]%SYS>>SELECT * FROM OAuth2_Server.Session

ID                                              AuthTime        Cookie                                          Expires         Scope                   Username
6Xks9UD1fm8HU6u6FYf5eRtlyv8IU44LM4vGEkqbI60     1679909215      6Xks9UD1fm8HU6u6FYf5eRtlyv8IU44LM4vGEkqbI60     1679995615      openid profile scope1   test

[SQL]%SYS>>SELECT ClientId, GroupId,  Scope, Username FROM OAuth2_Server.AccessToken

ClientId                                        GroupId                                         Scope                   Username
qCIoFRl1jtO0KpLlCrfYb8TelYcy_G1sXW_vav_osYU     6Xks9UD1fm8HU6u6FYf5eRtlyv8IU44LM4vGEkqbI60     openid profile scope1   test
vBv3V0_tS3XEO5O15BLGOgORwk-xYlEGQA-48Do9JB8     6Xks9UD1fm8HU6u6FYf5eRtlyv8IU44LM4vGEkqbI60     openid profile scope1   test
  1. 両方のタブでF5を何度か押して、%session.Data("COUNTER")の値が増えて行くことを確認します。

セッションを持つアプリケーションの動作という見立てです。

  1. 1個目のタブ(CSPベースのアプリケーション#1a)でログアウト(SSO)をクリックします。ログアウトが実行され、最初のページに戻ります。

  2. 2個目のタブ(CSPベースのアプリケーション#1b)でF5を押します。「認証されていません! 認証を行う」と表示されます。

これで、1度のログアウト操作で、全てのアプリケーションからログアウトするSLOが動作したことがが確認できました。

同様に、サンプルのpythonコードも、一度認証を行うと、それ以降、何度実行してもユーザ名・パスワード入力を求めることはありません。これはpythonが利用するブラウザに"ユーザセッション"が記録されるためです。

          redirect
  <-----------------------------------
                                     |
python +--> ブラウザ           --> 認可サーバ
       |    (ユーザセッション)  
       +--> リソースサーバ

この設定が有効の場合、認可サーバはユーザエージェントに対してCSPOAuth2Sessionという名称のクッキーをhttpOnly, Secure設定で送信します。以後、同ユーザエージェントが認可リクエストを行う際には、このクッキーが使用され、(認可サーバでのチェックを経て)ユーザを認証済みとします。

CSPOAuth2Sessionの値は、発行されるIDトークンの"sid"クレームに含まれます。

{
  "iss":"https://webgw.localdomain/irisauth/authserver/oauth2",
  "sub":"test",
  "exp":1679629322,
  "auth_time":1679625721,
  "iat":1679625722,
  "nonce":"M79MJF6HqHHDKFpK4ZZJkaD3moE",
  "at_hash":"AFeWfbXALP78Y9KEhlKnp_5LJmEjthJQlJDGXh_eLPc",
  "aud":[
    "https://webgw.localdomain/irisrsc/csp/myrsc",
    "https://webgw.localdomain/irisrsc2/csp/myrsc",
    "SrGSiVPB8qWvQng-N7HV9lYUi5WWW_iscvCvGwXWGJM"
  ],
  "azp":"SrGSiVPB8qWvQng-N7HV9lYUi5WWW_iscvCvGwXWGJM",
  "sid":"yxGBivVOuMZGr2m3Z5AkScNueppl8Js_5cz2KvVt6dU"
}

詳細はこちら の「ユーザ・セッションのサポート」の項目を参照ください。

PKCE

認可コード横取り攻撃への対策である、PKCE(ピクシーと発音するそうです)関連の設定を行っています。そのため、PublicクライアントはPKCEを実装する必要があります。

  • 公開クライアントにコード交換用 Proof Key (PKCE) を適用する: 有効
  • 機密クライアントにコード交換用 Proof Key (PKCE) を適用する: 無効

ログアウト機能

OpenID Connectのログアウト機能について再確認しておきます。

実に、様々なログアウト方法が提案されています。メカニズムとして、postMessage-Based Logout,HTTP-Based Logoutがあり、ログアウト実行の起点によりRP-Initiated, OP-Initiatedがあり、さらにHTTP-Based LogoutはFront-Channel, Back-Channelがありと、利用環境に応じて様々な方法が存在します。

postMessageとはクロスドメインのiframe間でデータ交換する仕組みです

目的は同じでシングルログアウト(SLO)、つまり、シングルサインオンの逆で、OP,RP双方からログアウトする機能を実現することです。

本例での設定

HTTP-Basedを使用したほうがクライアント実装が簡単になる事、バックチャネルログアウトは現在IRISでは未対応であることから、本例では、フロントチャネルログアウトをRP-Initiatedで実行しています。

ユーザセッションが有効なクライアント(irisclient)のログアウト用のリンクをクリックすると下記のようなJavaScriptを含むページが描画されます。

<body onload="check(0)">
<iframe id=frame0 src=RP1のfrontchannel_logout_uri hidden></iframe>
<iframe id=frame1 src=RP2のfrontchannel_logout_uri hidden></iframe>
  ・
  ・
<scr1pt language=javascript type="text/javascript">
    function check(start) {
      個々のiframeの実行完了待ち
      if (完了) doRedirect()
    }
    function doRedirect() {
            post_logout_redirect_uriへのリダイレクト処理
    }
</scr1pt>

表示がおかしくなってしまうので、scriptをscr1ptに変更しています。インジェクション攻撃扱いされています...?

JavaScriptが行っていることは、iframe hiddenで指定された各RPログアウト用のエンドポイント(複数のRPにログインしている場合、iframeも複数出来ます)を全て呼び出して、成功したら、doRedirect()で、post_logout_redirect_urisで指定されたURLにリダイレクトする、という処理です。これにより、一度の操作で全RPからのログアウトとOPからのログアウト、ログアウト後の指定したページ(本例では最初のページ)への遷移が実現します。

内容を確認したい場合、ログアウトする前に、ログアウト用のリンクのURLをcurlで実行してみてください。

curl -L --insecure "https://webgw.localdomain/irisclient/csp/sys/oauth2/OAuth2.PostLogoutRedirect.cls?register=R3_wD-F5..."

一方、ユーザセッションが無効の場合は、ログアウトを実行したクライアントのみがfrontchannel_logout対象となります。

つまり、ユーザセッションを使用して、2回目以降にユーザ名・パスワードの入力なしで、認証されたアプリケーション群が、SLOでログアウトされる対象となります。

フロントチャネルログアウト実現のために、認可サーバの設定で、下記のログアウト関連の設定を行っています。

  • HTTPベースのフロントチャネルログアウトをサポート:有効
  • フロントチャネルログアウトURLとともに sid (セッションID) クレームの送信をサポート:有効

また、認可サーバ(irisauth)に以下のcookie関連の設定を行っています。

ドキュメントに従って、irisauthの/oauth2のUser Cookie Scopeをlaxとしています。

Note: For an InterSystems IRIS authorization server to support front channel logout, the User Cookie Scope for the /oauth2 web application must be set to Lax. For details on configuring application settings, see Create and Edit Applications.

本例は同じオリジンで完結している(Chromeであれば、ログアウト実行時に関わるhttpアクセスのRequest Headersに含まれるsec-fetch-site値がsame-originになっていることで確認できます)ので、この設定は不要ですが、備忘目的で設定しています。

また、クライアント(irisclient)に以下の設定を行っています。

  1. Session Cookie Scopeの設定

ドキュメントに従って、irisclientの/csp/userのSession Cookie Scopeをnoneとしています。

Note: For an InterSystems IRIS client to support front channel logout, the Session Cookie Scope of the client application to None. For details on configuring application settings, see Create and Edit Applications.

本例は同じオリジンで完結している(Chromeであれば、ログアウト実行時に関わるhttpアクセスのRequest Headersに含まれるsec-fetch-site値がsame-originになっていることで確認できます)ので、この設定は不要ですが、備忘目的で設定しています。

  1. "frontchannel_logout_session_required"をTrueに設定しています。

  2. "frontchannel_logout_uri"に"https://webgw.localdomain/irisclient/csp/user/MyApp.Logout.cls"を設定しています。

管理ポータル上には下記のように表示されています。このURLに遷移する際は、IRISLogout=endが自動付与されます。

If the front channel logout URL is empty, the client won't support front channel logout. 'IRISLogout=end' will always be appended to any provided URL.

IRISドキュメントに記述はありませんが、Cache'の同等機能の記述はこちらです。IRISLogout=endは、CSPセッション情報の破棄を確実なものとするためと理解しておけば良いでしょう。

一般論として、ログアウト時のRP側での処理は認可サーバ側では制御不可能です。本当にセッションやトークンを破棄しているか知るすべがありません。IRISLogout=endはRPがCSPベースである場合に限り、それら(cspセッションとそれに紐づくセッションデータ)の破棄を強制するものです。非CSPベースのRPにとっては意味を持ちませんので、無視してください。

各サーバの設定について

各サーバの設定内容とサーバ環境を自動作成する際に使用した各種インストールスクリプトに関する内容です。

認可サーバ

認可サーバ上の、oAUth2/OIDC関連の設定は、MyApps.Installerにスクリプト化してあります。

下記の箇所で、「OAuth 2.0 認可サーバ構成」を行っています。

Set cnf=##class(OAuth2.Server.Configuration).%New()
  ・
  ・
Set tSC=cnf.%Save()

これらの設定は、認可サーバで確認できます。

認可サーバ上のクライアントデスクリプション

下記のような箇所が3か所あります。これらは「 OAuth 2.0 サーバ クライアントデスクリプション」で定義されている、python, curl, angularのエントリに相当します。

Set c=##class(OAuth2.Server.Client).%New()
Set c.Name = "python"
  ・
  ・
Set tSC=c.%Save()

これらに続くファイル操作は、利便性のためにclient_idなどをファイル出力しているだけで、本来は不要な処理です。

これらはコンテナイメージのビルド時に実行されます。

これらの設定は、認可サーバで確認できます。

CSPベースのWebアプリケーション

実行内容の説明は、クライアント編で行います。

CSPベースのWebアプリケーションの設定は、MyApps.Installerにスクリプト化してあります。

oAUth2/OIDC関連の設定(クライアントの動的登録)は、irisclient用のRegisterAll.mac、およびirisclient2用のRegisterAll.macにスクリプト化してあります。

これらはregister_oauth2_client.shにより、コンテナ起動後に実行されます。

これらの設定は、クライアント用サーバで確認できます。

動的登録を行った時点で、これらの内容が認可サーバに渡されて、認可サーバ上に保管されます。その内容は、認可サーバで確認できます。

ビルド時に生成されるclient_idがURLに含まれるため、リンクを用意できません。画像イメージのみです。

リソースサーバ

リソースサーバの設定は、MyApps.Installerにスクリプト化してあります。

リソースサーバのRESTサービスは、IRISユーザUnknownUserで動作しています。

リソースサーバは、受信したトークンのバリデーションをするために、REST APIの実装で、下記のAPIを使用しています。

アクセストークンをhttp requestから取得します。

set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.tSC)

アクセストークンのバリデーションを実行します。この際、..#AUDがアクセストークンのaudクレームに含まれていることをチェックしています。

if '(##class(%SYS.OAuth2.Validation).ValidateJWT($$$APP,accessToken,,..#AUD,.jsonObjectJWT,.securityParameters,.tSC)) {

署名の有無の確認をしています。

Set sigalg=$G(securityParameters("sigalg"))
if sigalg="" { 
  set reason=..#HTTP401UNAUTHORIZED
  $$$ThrowOnError(tSC)				
}

(べた書きしていますが)受信したアクセストークンのSCOPEクレーム値がscope1を含まない場合、http 404エラーを返しています。

if '(jsonObjectJWT.scope_" "["scope1 ") { set reason=..#HTTP404NOTFOUND throw }

oAUth2/OIDC関連の設定(クライアントの動的登録)は、Register.macにスクリプト化してあります。

これらはregister_oauth2_client.shにより、コンテナ起動後に実行されます。

これらの設定は、リソースサーバで確認できます。

動的登録を行った時点で、これらの内容が認可サーバに渡されて、認可サーバ上に保管されます。その内容は、認可サーバで確認できます。

ビルド時に生成されるclient_idがURLに含まれるため、リンクを用意できません。画像イメージのみです。

署名(JWK)

認可サーバをセットアップすると、一連の暗号鍵ペアが作成されます。これらはJWTで表現されたアクセストークンやIDトークンを署名する(JWS)ために使用されます。

鍵情報は認可サーバのデータべースに保存されています。参照するにはirisauthで下記SQLを実行します。

$ docker compose exec irisauth iris session iris -U%SYS "##class(%SYSTEM.SQL).Shell()"

SELECT PrivateJWKS,PublicJWKS FROM OAuth2_Server.Configuration

PrivateJWKSの内容だけを見やすいように整形するとこちらのようになります。

実際にアクセストークンを https://jwt.io/ で確認してみます。ヘッダにはkidというクレームが含まれます。これはトークンの署名に使用されたキーのIDです。

{
  "typ": "JWT",
  "alg": "RS512",
  "kid": "3"
}

これで、このトークンはkid:3で署名されていることがわかります。 この時点で、Signature Verifiedと表示されていますが、これはkid:3の公開鍵を使用して署名の確認がとれたことを示しています。

公開鍵は公開エンドポイントから取得されています

次に、エンコード処理(データへのJWSの付与)を確認するために、ペーストしたトークンの水色の部分(直前のピリオドも)をカットします。Invalid Signatureに変わります。

さきほどSQLで表示したPrivateJWKSの内容のkid:3の部分だけ(下記のような内容)を抜き出して下のBOXにペーストします。

{
  "kty": "RSA",
  "n": "....",
  "e": "....",
  "d": "....",
    ・
    ・
    ・
  "alg": "RS512",
  "kid": "3"
}

水色部分が復元され、再度、Signature Verifiedと表示されるはずです。また、水色部分は元々ペーストしたアクセストークンのものと一致しているはずです。

本当に大切な秘密鍵はこういう外部サイトには張り付けないほうが無難かも、です

ログ取得方法

各所でのログの取得方法です。

認可サーバ(IRIS)

認可サーバ上の実行ログを取得、参照出来ます。クライアントの要求が失敗した際、多くの場合、クライアントが知りえるのはhttpのステータスコードのみで、その理由は明示されません。認可サーバ(RPがIRISベースの場合は、クライアントサーバでも)でログを取得すれば、予期せぬ動作が発生した際に、原因のヒントを得ることができます。

  • ログ取得開始

    ./log_start.sh
    

    これ以降、発生した操作に対するログが保存されます。ログは^ISCLOGグローバルに保存されます。

  • ログを出力

    ログは非常に多くなるので、いったんファイルに出力してIDE等で参照するのが良いです。

    ./log_display.sh
    

    Webアプリケーション1aをユーザエージェント(ブラウザ)からアクセスした際のログファイルの出力例はこちらです。

  • ログを削除
    ログを削除します。ログ取得は継続します。

    ./log_clear.sh
    
  • ログ取得停止 ログ取得を停止します。ログ(^ISCLOGグローバル)は削除されません。

    ./log_end.sh
    

IRISサーバのログ確認

IRISサーバが稼働しているサービス名(認可サーバならirisauth)を指定します。

IRISコミュニティエディション使用時に、接続数オーバ等を発見できます。

docker compose logs -f irisauth

WebGWのログ確認

WebGWコンテナ内で稼働するapacheのログを確認できます。

全体の流れを追ったり、エラー箇所を発見するのに役立ちます。

docker compose logs -f webgw
0
1 570
記事 Mihoko Iijima · 3月 28, 2023 3m read

開発者の皆さん、こんにちは。

前の記事では「機械学習を試せるチュートリアル:IntegratedML」で試せる内容をご紹介しましたが、この記事では Interoperability(相互運用性)チュートリアル の内容を少しご紹介します。

Interoperability(相互運用性)チュートリアルでは、Redditに新しく投稿された記事=(https://www.reddit.com/new/)を一定間隔で取得し、全投稿の中から「猫(cat)」🐈について記載されている情報のみを抽出し、対象記事をファイル出力する流れをご体験いただけます。

0
0 340
記事 Megumi Kakechi · 3月 28, 2023 3m read

これは InterSystems FAQ サイトの記事です。
 

テーブル名/カラム名/インデックス名を変更したい場合、以下のケース別に変更方法をご案内します。

A. テーブル名・カラム名の変更
B. インデックス名の変更
 

-------------------------------------------------------------------------
A. テーブル名・カラム名の変更する方法
-------------------------------------------------------------------------

テーブル(クラス)名とカラム(プロパティ)名は基本的には変えないようにしてください。

もし「SQLアクセス時の名前だけ変更したい」場合は、以下のように新しい名前を SqlTableName(テーブル名)、SqlFieldName(カラム名) として指定することができます。

Class User.test Extends%Persistent [ SqlTableName = test2 ] {
    Property p1 As%Integer [ SqlFieldName = xx ];
    ....
0
1 233