#セキュリティ

0 フォロワー · 64 投稿

ITのセキュリティとは、ハードウェア、ソフトウェアまたは情報の盗難および損傷からコンピューターシステムを保護すること、およびこれらが与えるサービスの混乱または誤った指示から保護することです。 

セキュリティに関するInterSystemsのドキュメントを参照してください。

記事 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月 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 · 1月 31, 2023 10m read

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

この記事では、IRIS Security Package 用 REST API をセットアップする方法を学習します。 簡単な HTTP リクエストによって、ユーザー、役割、アプリケーションの追加などを作成し、ObjectScript でクライアントアプリケーションを生成できるようになります。

必要条件

必要なのは:

  1. IRISインスタンス(インストールキットまたはDocker)
  2. ObjectScript package manager (ZPM)
  3. ObjectScriptクライアントを生成するための2つ目のIRISインスタンス(オプション)

OpenExchangeで既存のアプリケーションとライブラリのセットを使用する予定です。 package manager (ZPM)を使用すると、それらのインストールが非常に簡単になります。 インスタンスに ZPM がない場合は、IRIS ターミナルにこのラインをコピーすることで簡単にインストールすることができます。

set $namespace="%SYS" do ##class(Security.SSLConfigs).Create("ssl") set r=##class(%Net.HttpRequest).%New(),r.Server="pm.community.intersystems.com",r.SSLConfiguration="ssl" do r.Get("/packages/zpm/latest/installer"),$system.OBJ.LoadStream(r.HttpResponse.Data,"c")

Webアプリケーションの作成

パッケージ関連の REST サービスは、Config-API アプリケーションのバージョン 1.4.0 以降で利用できます。 このアプリケーションをZPMコマンドで簡単にインストールすることにします。

zpm "install config-api"

デフォルトでは、Config-API をインストールしても REST サービスは公開されないので、Web アプリケーション「/config-api」を作成する必要があります。 管理ポータルでの手動操作を避けるために、即時使用可能なスクリプトが用意されています。

Do ##class(Api.Config.Developers.Install).installMainRESTApp()

セキュリティパッケージのRESTサービスが、「/config-api/security/」というパスで利用できるようになりました。

APIセキュリティ

これで、「/config-api」Webアプリケーションが作成されると、管理ポータルで詳細を確認できるようになります。

webapp

デフォルトでは、ユーザが%Admin_Secureリソースを持っている場合、アプリケーションはログインとパスワード(基本認証)によってのみアクセスできます。

もちろん、これだけでは十分ではありません。 リクエストにはHTTPSプロトコルを使用し、WebGatewayとIRISインスタンス間の通信を暗号化する必要があります。API Manager(IAM)を利用するのも有効かもしれません。そうすることで、例えば特定のIPアドレスからのHTTPリクエストのみを受け付けるなど、よりスムーズなアクセス制御が可能になります。 設定方法については、この記事の範囲外なので、詳しくは説明しません。しかし、このテーマについては、コミュニティや公式ドキュメントでより多くの記事を見つけることができます。しかし、もしあなたが私にコメントを残して、私はあなたにWebGateway HTTPSとSSLTLSを持つDockerベースのリポジトリを提供することを望みます。

OnPreDispatchのカスタマイズ (オプション)

RESTディスパッチクラス "Api.Config.REST.Main" は、 "OnPreDispatch" メソッドを実装しています。このメソッドは、リクエスト処理の前に呼び出されます。各リクエストに対して実行したい共通のコードをここに置くだけです。pContinueに0を設定すると、リクエストは処理されないことを覚えておいてください。

Class Api.Config.REST.Main Extends %CSP.REST
{

....

ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean) As %Status
{
    Set sc = $$$OK, class = ##class(Api.Config.REST.OnPreDispatchAbstract).GetSubClass()

    Set pContinue = $$$YES

    Return:class="" sc

    Return $CLASSMETHOD(class, "OnPreDispatch", pUrl, pMethod, .pContinue)
}
}

デフォルトの実装では、"Api.Config.REST.OnPreDispatchAbstract "のサブクラスが存在するかどうかをチェックします。 もし存在すれば、それが実行されます。カスタムコードを実行するフックがあるので、API Managerがない場合、追加のアクセスチェックやロギングを行う代替手段にもなります。

以下は、受信したリクエストのみをログに記録する実装例です。

Class dc.sample.RestSecurity Extends Api.Config.REST.OnPreDispatchAbstract
{

ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean) As %Status
{
    Set sc = $$$OK

    /// カスタムアクセス認証はここで実装してください。

    Set key = $Increment(^RestSecurity.log)
    Set ^RestSecurity.log(key) = $ZDateTime($Horolog,3,1) _ " " _ pMethod _ " " _pUrl _ "( IP : " _ $Get(%request.CgiEnvs("REMOTE_ADDR")) _ ")"

    merge ^RestSecurity.log(key, "CgiEnvs") = %request.CgiEnvs
    merge ^RestSecurity.log(key, "Data") = %request.Data

    // 実行を停止する例:
    // Set %response.Status = "401 Unauthorized"
    // Set pContinue = $$$NO

    Quit sc
}
}

REST APIのテスト

このAPIは http://localhost:52773/config-api/security/ で公開されている 仕様(swagger 2.0)で提供されています(必要に応じてポート番号を修正してください)。そのため、例えばOpenExchangeで公開されているswagger-uiというアプリケーションを使用すれば、簡単にクライアントアプリケーションを生成することができます。

swagger-uiをインストールします。

zpm "install swagger-ui"

次に、URLhttp://localhost:52773/csp/swagger-ui/index.htmlでブラウザを開きます。

ページを開くと、ほとんどの場合、エラーが表示されます。

swerr

このエラーは、デフォルトでswagger-uiが存在しないURLから仕様を取得しようとするために発生します。このエラーを回避するには、RESTサービスのURLを調査することで、swagger-uiを強制的に開かせることができます:

Do ##class(Api.Config.Developers.Install).SetSwaggerUIDefaultPath("/config-api/security/")

ここでブラウザを更新してください。 %Admin_secure リソースを持つユーザーでログインしてください。

swspec

この段階では、ユーザー、役割、リソース、SSL構成、およびWebアプリケーションに対して、**C**reate **R**ead **U**pdate **D**elete の操作が可能であることが、このインターフェイスで確認することができます。

サービスやシステム設定の場合は少し違っていて、読み込み(GET)と変更(PUT)しかできません。

このインターフェースは、かなり詳細なswagger仕様のおかげで自己文書化されています。

swuser

POST /user をクリックすれば、詳細な説明、リクエストのサンプルボディ、モデルの完全なドキュメントを得ることができるので、ここで各リクエストをテストする方法を説明することは有益ではありません。 この記事では、SQL 特権という特殊なケースについてのみ説明します。

SQL特権の追加

POST/sqlprivileges

SQL 特権を設定します。

以下は、"select " 特権を追加するためのボディの例です。

{
  "Grantable": "1",
  "Grantee": "MyRoleName",
  "Grantor": "_system",
  "Namespace": "USER",
  "Privilege": "s",
  "SQLObject": "1,schema_name.table_name"
}

特権は次の値を取ることができます:s (select)、 i (insert)、 u (update)、 d (delete)、 r (reference)、 および e (execute).

SQLObjectは、テーブルを表す "1"、ビューを表す "3"、ストアドプロシージャを表す "9 "から始まります。

多数のテーブルに特権を割り当てる必要がある場合、あまり便利ではありません......。 この場合は「(PUT)/sqlhelper」を使用するのがよいでしょう。

特権を削除する

DELETE/sqlprivileges​/{id}

削除は、名前空間、SQLObject、特権、付与者、付与者から構成されるIDによって行われます。前回の特権の作成に対応するIDは「USER||1,schema_name.table_name||s||MyRoleName|_system」であります。特殊文字のエスケープに注意してください。

スキーマ内のすべてのテーブルに特権を追加する

PUT/sqlhelper

このサービスでは、1つまたは複数のスキーマの全テーブルに一連の権限を割り当てることができます。以下はボディの例です。

{
  "Grantable": "1",
  "Grantee": "MyNewRole",
  "Grantor": "_system",
  "Namespace": "USER",
  "Table": {
    "Schemas": [
      "schema_name",
      "schema_name_2"
    ],
    "Privileges": [
      "S",
      "I",
      "U",
      "D"
    ]
  }
}

HTTP ObjectScript クライアントを生成する

Swagger editorでは、swaggerの仕様から様々な言語でクライアントを生成することができますが、残念ながらObjectScriptはそのリストに含まれていません。 ただし、OpenExchangeにあるアプリケーション「OpenApi-client-gen」を使えば生成することが可能です。現在のところ、swagger 2.0仕様にのみ対応しています。

Install openapi-client-gen:

zpm "install openapi-client-gen"

クライアントアプリケーションを生成します:

Set features("simpleHttpClientOnly") = 1
Set sc = ##class(dc.openapi.client.Spec).generateApp("IrisSecurity", "https://raw.githubusercontent.com/lscalese/iris-config-api/master/swagger-security.json", .features)
Write !,"Status : ",$SYSTEM.Status.GetOneErrorText(sc)

以下に、HTTPリクエストでWebアプリケーションの一覧を取得し、その結果をターミナルに表示するコードの例を示します。

Class iris.dc.sample.ObjectScriptRestClient
{

ClassMethod GetRequestObj() As %Net.HttpRequest
{
    Set httpRequest = ##class(%Net.HttpRequest).%New()
    Set httpRequest.Username = "_system"
    Set httpRequest.Password = "SYS"
    Set httpRequest.Server = "iris-security-rest-server"
    Set httpRequest.Port = 52773
    Set httpRequest.Https = 0
    Quit httpRequest
}

ClassMethod ExampleGetWebAppList() As %Status
{
    Set sc = $$$OK
    Set httpClient = ##class(IrisSecurity.HttpClient).%New()
    Set httpRequest = ..GetRequestObj()
    Do httpRequest.SetHeader("accept", "application/json")
    Set msg = ##class(IrisSecurity.msg.GetListOfWebAppsRequest).%New()
    Set sc = httpClient.GETGetListOfWebApps(msg,.response,.httpRequest,.httpresponse)
    Write !,"Status           : ",$SYSTEM.Status.GetOneErrorText(sc)
    Quit:$$$ISERR(sc) sc
    Write !,"Http Status Code : ",response.httpStatusCode
    Write !
    zw response

    If response.httpStatusCode = 200 {
        Set formatter=##class(%JSON.Formatter).%New()
        Do formatter.Format({}.%FromJSON(response.body))
    }

    Quit sc
}

}

GitHub

もしあなたがDockerユーザーなら、この記事で見てきたことはすべて次のGitHubリポジトリで公開されています:https://github.com/lscalese/iris-sample-security-rest-api.

このように実行します。

git clone https://github.com/lscalese/iris-sample-security-rest-api.git
cd iris-sample-security-rest-api
docker-compose up -d

これで、URL http://localhost:32773/swagger-ui/index.html でブラウザを開き、REST API を直接テストすることができます。

また、iris-cliサービスにおいてターミナルを開き、生成されたObjectScriptクライアントアプリケーションをテストすることもできます。

docker exec -it iris-security-rest-client iris session iris
Do ##class(iris.dc.sample.ObjectScriptRestClient).ExampleGetWebAppList()

JSON形式で表示されたWebアプリケーションのリストが表示されるはずです。

0
0 315
記事 Megumi Kakechi · 1月 30, 2023 8m read

以下の2つの方法でセキュリティ設定をエクスポートおよびインポートできます。

- コマンドラインで行う場合は、^SECURITYユーティリティを使用します。
- プログラムで行う場合は、SecurityパッケージのExportおよびImportメソッドを使用します。
 

設定をエクスポートする方法:

◆コマンドラインで設定をエクスポートする方法(^SECURITY)

セキュリティの全ての設定、または個々のセクションをエクスポートできます。


^SECURITYを使用して、すべてをエクスポートする場合:

^SECURITYを使用すると、インスタンスのすべてのセキュリティ設定を簡単にエクスポートまたはインポートできます。
ターミナルで %SYS ネームスペースに移動し、^SECURITYを開始します。

USER>zn"%SYS"%SYS>do^SECURITY

^SECURITY を実行後、オプション12 の System parameter setup を選択します。
次のメニューで、オプション5 の Export All Security settings を選択します。
以下のようなプロンプトが表示されますので、Yes を入力します。

Export ALL security records? Yes => [yes または y を入力 -- 大文字小文字は関係ありません]
0
0 218
記事 Toshihiko Minamoto · 8月 17, 2022 11m read


InterSystems IRIS には、暗号化、復号化、およびハッシュ操作の優れたサポートが備わっています。 クラス %SYSTEM.Encryption(https://docs.intersystems.com/iris20212/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&PRIVATE=1&CLASSNAME=%25SYSTEM.Encryption)の中には、市場に出回っている主なアルゴリズムのクラスメソッドがあります。

IRIS アルゴリズムと暗号化/復号化の方式

ご覧のとおり、操作は鍵に基づいており、3 つのオプションが含まれます。

  • 対称鍵: 暗号化と復号化の操作を実行する部分で同じ秘密鍵が使用されます。
  • 非対称鍵: 暗号化と復号化の操作を実行する部分で、暗号化に同じ秘密鍵が使用されますが、 復号化においては、各パートナーが秘密鍵を所有します。 この鍵は身元を証明するものであるため、他人と共有することはできません。
  • ハッシュ: 暗号化だけが必要で、復号化が不要である場合に使用されます。強力なユーザーパスワードを保存する際に一般的なアプローチです。

対称暗号化と非対称暗号化の違い

  • 対称暗号化では、メッセージを受信する必要のある人の間で単一の鍵を共有して使用しますが、非対称暗号化では、通信時に公開鍵と秘密鍵のペアを使用してメッセージの暗号化と復号化を行います。
  • 対称暗号化は古いテクニックであるのに対し、非対称暗号化は比較的最近のテクニックです。
  • 非対称暗号化は、対称暗号化モデルで鍵を共有する必要性に関わる固有の問題を補完するために導入されました。公開鍵と秘密鍵のペアを使用することで、鍵を共有する必要がなくなっています。
  • 非対称暗号化には、対称暗号化よりも比較的時間がかかります。
  <th>
    対称暗号化
  </th>
  
  <th>
    非対称暗号化
  </th>
</tr>

<tr>
  <td>
    暗号文のサイズ
  </td>
  
  <td>
    元のプレーンテキストファイルより小さい暗号文。
  </td>
  
  <td>
    元のプレーンテキストファイルより大きい暗号文。
  </td>
</tr>

<tr>
  <td>
    データサイズ
  </td>
  
  <td>
    ビッグデータの送信に使用される。
  </td>
  
  <td>
    スモールデータの送信に使用される。
  </td>
</tr>

<tr>
  <td>
    リソース使用率
  </td>
  
  <td>
    対称鍵暗号化は、リソース使用率が低い場合に機能します。
  </td>
  
  <td>
    非対称暗号化では、大量のリソースを消費する必要があります。
  </td>
</tr>

<tr>
  <td>
    鍵の長さ
  </td>
  
  <td>
    128 または 256 ビットの鍵サイズ。
  </td>
  
  <td>
    RSA 2048 ビット以上の鍵サイズ。
  </td>
</tr>

<tr>
  <td>
    セキュリティ
  </td>
  
  <td>
    暗号化に単一の鍵を使用するため、セキュリティが低下。
  </td>
  
  <td>
    暗号化と復号化を 2 つの異なる鍵で行うため、はるかに安全。
  </td>
</tr>

<tr>
  <td>
    鍵の数
  </td>
  
  <td>
    対称暗号化では、暗号化と復号化に単一の鍵を使用する。
  </td>
  
  <td>
    非対称暗号化では、暗号化と復号化に 2 つの異なる鍵を使用する。
  </td>
</tr>

<tr>
  <td>
    テクニック
  </td>
  
  <td>
    古いテクニック。
  </td>
  
  <td>
    最新のテクニック。
  </td>
</tr>

<tr>
  <td>
    機密性
  </td>
  
  <td>
    暗号化と復号化に使用される単一の鍵には、その鍵が改ざんされる可能性がある。
  </td>
  
  <td>
    暗号化と復号化で個別に 2 つの鍵が作成されるため、鍵を共有する必要がない。
  </td>
</tr>

<tr>
  <td>
    速度
  </td>
  
  <td>
    対称暗号化は高速な手法。
  </td>
  
  <td>
    非対称暗号化は速度が低下する。
  </td>
</tr>

<tr>
  <td>
    アルゴリズム
  </td>
  
  <td>
    RC4、AES、DES、3DES、および QUAD。
  </td>
  
  <td>
    RSA、Diffie-Hellman、ECC アルゴリズム。
  </td>
</tr>
主な違い

出典: https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences 

%SYSTEM.Encryption クラスを使用して暗号化、復号化、ハッシュを実行

IRIS の暗号化、復号化、およびハッシュ操作のサポートを使用するには、https://github.com/yurimarx/cryptography-samples にアクセスし、以下の手順に従ってください。

  1. リポジトリを任意のローカルディレクトリに Clone/git pull します。
$ git clone https://github.com/yurimarx/cryptography-samples.git
  1. このディレクトリで Docker ターミナルを開き、以下を実行します。
$ docker-compose build
  1. IRIS コンテナを実行します。
$ docker-compose up -d
  1. IRIS ターミナルを開きます。
$ docker-compose exec iris iris session iris -U IRISAPP

IRISAPP>
  1. 非対称暗号化の RSA Encrypt を実行するには、以下を実行します。
IRISAPP>Set ciphertext = ##class(dc.cryptosamples.Samples).DoRSAEncrypt("InterSystems")
IRISAPP>Write ciphertext
Ms/eR7pPmE39KBJu75EOYIxpFEd7qqoji61EfahJE1r9mGZX1NYuw5i2cPS5YwE3Aw6vPAeiEKXF
rYW++WtzMeRIRdCMbLG9PrCHD3iQHfZobBnuzx/JMXVc6a4TssbY9gk7qJ5BmlqRTU8zNJiiVmd8
pCFpJgwKzKkNrIgaQn48EgnwblmVkxSFnF2jwXpBt/naNudBguFUBthef2wfULl4uY00aZzHHNxA
bi15mzTdlSJu1vRtCQaEahng9ug7BZ6dyWCHOv74O/L5NEHI+jU+kHQeF2DJneE2yWNESzqhSECa
ZbRjjxNxiRn/HVAKyZdAjkGQVKUkyG8vjnc3Jw==
  1. 非対称復号化の RSA Decrypt を実行するには、以下を実行します。
IRISAPP>Set plaintext = ##class(dc.cryptosamples.Samples).DoRSADecrypt(ciphertext)
IRISAPP>Write plaintext
InterSystems
  1. 非対称暗号化の AES CBC Encrypt を実行するには、以下を実行します。
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoAESCBCEncrypt("InterSystems")
8sGVUikDZaJF+Z9UljFVAA==
  1. 対称暗号化の AES CBC Decrypt を行うには、以下を実行します。
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoAESCBCDecrypt("8sGVUikDZaJF+Z9UljFVAA==")
InterSystems
  1. 古いハッシュアプローチの MD5 hash を実行するには、以下を実行します。
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoHash("InterSystems")
rOs6HXfrnbEY5+JBdUJ8hw==
  1. 推奨されるハッシュアプローチの SHA hash を実行するには、以下を実行します。
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoSHAHash("InterSystems")
+X0hDlyoViPlWOm/825KvN3rRKB5cTU5EQTDLvPWM+E=
  1. ターミナルを終了するには、以下を実行します。
HALT または H を入力(大文字と小文字は区別されません)

 

ソースコードについて

1. 対称鍵について

# 対称暗号化/復号化で使用する
ENVSECRETKEY=InterSystemsIRIS

Dockerfile に、対称操作で秘密鍵として使用される環境鍵が作成されました。

2. 非対称鍵について

# 非対称暗号化/復号化で使用する RUN openssl req -new -x509 -sha256 -config example-com.conf -newkey rsa:2048 -nodes -keyout example-com.key.pem -days 365 -out example-com.cert.pem

Dockerfile に、非対称操作で使用される秘密鍵と公開鍵が生成されました。

3. 対称暗号化

//暗号化するための対称鍵の例
 
ClassMethodDoAESCBCEncrypt(plaintextAs%String)As%Status
{
    // utf-8 に変換
    Settext=$ZCONVERT(plaintext,"O","UTF8")
   
    // 秘密鍵を設定
    Setsecretkey=$system.Util.GetEnviron("SECRETKEY")
    SetIV=$system.Util.GetEnviron("SECRETKEY")
   
    // テキストを暗号化
    Settext=$SYSTEM.Encryption.AESCBCEncrypt(text,secretkey,IV)
    Setciphertext=$SYSTEM.Encryption.Base64Encode(text)
   
    Writeciphertext
}

テキストの暗号化に AES CBC Encrypt 操作が使用されました。
Base64 Encode は、プリティ/読み取り可能なテキストとしてユーザーに結果を返します。

4. 対称復号化

//復号化するための対称鍵の例
 
ClassMethodDoAESCBCDecrypt(ciphertextAs%String)As%Status
{
    // 秘密鍵を設定
    Setsecretkey=$system.Util.GetEnviron("SECRETKEY")
    SetIV=$system.Util.GetEnviron("SECRETKEY")
   
    // テキストを復号化
    Settext=$SYSTEM.Encryption.Base64Decode(ciphertext)
    Settext=$SYSTEM.Encryption.AESCBCDecrypt(text,secretkey,IV)
   
    Setplaintext=$ZCONVERT(text,"I","UTF8")
    Writeplaintext
}

テキストの復号化に AES CBC Decrypt 操作が使用されました。
Base64 Decode は、復号化に使用できるように、暗号化されたテキストをバイナリテキストに返します。

5. 非対称暗号化

//暗号化するための非対称鍵の例
 
ClassMethodDoRSAEncrypt(plaintextAs%String)As%Status
{
    // 公開鍵証明書を取得
    SetpubKeyFileName="/opt/irisbuild/example-com.cert.pem"
    SetobjCharFile=##class(%Stream.FileCharacter).%New()
    SetobjCharFile.Filename=pubKeyFileName
    SetpubKey=objCharFile.Read()
 
    // RSA を使って暗号化
    Setbinarytext=$System.Encryption.RSAEncrypt(plaintext,pubKey)
    Setciphertext=$SYSTEM.Encryption.Base64Encode(binarytext)
   
    Returnciphertext
}

RSA で暗号化するには、公開鍵ファイルの内容を取得する必要があります。
テキストの暗号化に、RSA Encrypt 操作が使用されました。

6. 非対称復号化

//復号化するための非対称鍵の例
 
ClassMethodDoRSADecrypt(ciphertextAs%String)As%Status
{
    // 秘密鍵を取得
    SetprivKeyFileName="/opt/irisbuild/example-com.key.pem"
    SetprivobjCharFile=##class(%Stream.FileCharacter).%New()
    SetprivobjCharFile.Filename=privKeyFileName
    SetprivKey=privobjCharFile.Read()
 
    // 暗号文をバイナリ形式で取得
    Settext=$SYSTEM.Encryption.Base64Decode(ciphertext)
 
    // RSA を使って復号化
    Setplaintext=$System.Encryption.RSADecrypt(text,privKey)
 
    Returnplaintext
}

RSA で復号化するには、秘密鍵ファイルの内容を取得する必要があります。
テキストの復号化に、RSA Decrypt 操作が使用されました。

7. MD5 を使ったテキストのハッシュ化(古いアプローチ)

//ハッシュの例
 
ClassMethodDoHash(plaintextAs%String)As%Status
{
    // utf-8 に変換
    Settext=$ZCONVERT(plaintext,"O","UTF8")
   
    // テキストをハッシュ化
    Sethashtext=$SYSTEM.Encryption.MD5Hash(text)
   
    Setbase64text=$SYSTEM.Encryption.Base64Encode(hashtext)
 
    // 16 進テキストを以下のベストプラクティスに変換
    Sethextext=..GetHexText(base64text)
 
    // 小文字を使って返す
    Write$ZCONVERT(hextext,"L")
}

MD5 Hash 操作でテキストを暗号化すると、それを復号化することはできません。
MD5 を使ったハッシュ化は、安全でないと見なされているため、新しいプロジェクトには推奨されません。 そのため、この方式は SHA に置き換えられています。 InterSystems IRIS は SHA をサポートしています(次の例で紹介します)。

8. SHA を使ったテキストのハッシュ化(推奨されるアプローチ)

この例では、SHA-3 Hash 方式を使用します。 InterSystems のドキュメントによると、この方式は、US Secure Hash Algorithm - 3 を使ってハッシュを生成します。 (詳細は、連邦情報処理規格 202 をご覧ください。)

//SHA を使ったハッシュ
 
ClassMethodDoSHAHash(plaintextAs%String)As%Status
{
    // utf-8 に変換
    Settext=$ZCONVERT(plaintext,"O","UTF8")
   
    // テキストをハッシュ化
    Sethashtext=$SYSTEM.Encryption.SHA3Hash(256,text)
   
    Setbase64text=$SYSTEM.Encryption.Base64Encode(hashtext)
 
    // 16 進テキストを以下のベストプラクティスに変換
    Sethextext=..GetHexText(base64text)
 
    // 小文字を使って返す
    Write$ZCONVERT(hextext,"L")
}

SHA 方式では、ハッシュ操作で使用するビット長を設定できます。 ビット数が多いほど、ハッシュを解読するのがより困難になりますが、 ハッシュ化の処理速度が低下してしまいます。 この例では、256 ビットが使用されました。 ビット長については以下のオプションを選択できます。

  • 224(SHA-224)
  • 256(SHA-256)
  • 384(SHA-384)
  • 512(SHA-512)
0
0 537
記事 Hiroshi Sato · 3月 23, 2022 1m read

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

以下のコードは、https://www.intersystems.com/assets/intersystems-logo.png をダウンロードし、c:\temp\test.pngとしてファイルを保存する例になります。

以下のコードを動作させるためには、SSLTESTという名前のSSL定義を作成しておく必要があります。

0
0 197
記事 Hiroshi Sato · 12月 21, 2021 1m read

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

監査ログをプログラミングで出力するために、監査ログの一覧を取得する%SYS.Audit クラスのListクエリを利用することができます。


サンプルコードは以下のようになります。

 Set statement=##class(%SQL.Statement).%New()  
 Set status=statement.%PrepareClassQuery("%SYS.Audit","List")
 Set rs=statement.%Execute()  
 Set tab = $char(9)
 While rs.%Next() {    
   Write rs.%Get("TimeStamp")_tab_rs.%Get("Event")_tab_rs.%Get("Username"),!      
}
0
0 240
記事 Megumi Kakechi · 12月 9, 2021 3m read

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

【 管理ポータルへのパスワード認証設定方法 】

管理ポータルの、
 [ホーム] > [システム管理] > [セキュリティ] > [アプリケーション] > [ウェブ・アプリケーション]
で /csp/sys、および、/csp/sys/ 以下の各アプリケーション(/csp/sys/expなど) の編集画面を開き、“許可された認証方法” の、"認証なし" のチェックを外し、“パスワード” のみチェックをして保存します。

また、これと同様のことを、ターミナルから、^SECURITYルーチンを使用して実行することも可能です。
以下は/csp/sys/アプリケーションに対する実行例です。*実行は%SYSネームスペースで行って下さい。*

0
0 621
InterSystems公式 Yoichi Miyashita · 12月 1, 2021

InterSystems 製品のキットには Apache Web サーバが含まれています。
これにより、お客様が外部Webサーバをインストールせずに Caché/IRIS 管理ポータルを動作させる為の便利な方法を提供しています。
ただし、このWebサーバを実稼働インスタンスに使用しないでください。お客様は、システムに応じたニーズとセキュリティ/リスク要件に適合するWebサーバを別途インストールする必要があります。

最近のテストでは、現在含まれている Apache Web サーバにいくつかのセキュリティ問題があることがわかっていますが InterSystems が管理していないテクノロジである為、
InterSystems は、Apache または別のサードパーティから直接取得した Web サーババージョンをインストールし、付属の Apache Webサーバ を無効にすることをお勧めします。
InterSystems は、今後のリリースに Apache Web サーバの新しいバージョンを含める予定です。
現在のバージョンと同様に、そのバージョンも本番インスタンスには使用できません。
当社の製品の将来のリリースでは、InterSystems はWeb サーバを同梱またはインストールしません。
計画の詳細については、今後、更新情報を提供する予定です。 

0
0 179
記事 Megumi Kakechi · 11月 15, 2021 1m read

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

SELinuxの機能が有効になっているとファイルアクセス時にセキュリティコンテキストのチェックで permission エラーになります。

CSP のページについても同様に permission エラーになっているため、Apache にて 403 Forbidden エラーになります。  

以下の設定でSELinuxの機能を無効にすることで回避できます。

設定ファイル /etc/selinux/config の SELINUX=disableに設定し、OS の再起動を行います。

例:

0
0 392
お知らせ Mihoko Iijima · 11月 2, 2021

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

次の InterSystems オンラインプログラミングコンテストが決定しました! 

お題は・・・・   🏆 InterSystems Security Contest 🏆

応募期間は 2021年11月15日~11月28日 です!

💰 賞金総額: $9,450 💰


<--break->

0
0 138
記事 Toshihiko Minamoto · 10月 26, 2021 10m read

InterSystems IRISを初めて使用し始める際には、最低限のセキュリティレベルでのみシステムをインストールするのが通例です。 パスワードを入力する回数が少なくて済むため、初めて作業を始めるときに、開発サービスやWebアプリケーションの操作がより簡単になるからです。 また、開発済みのプロジェクトまたはソリューションをデプロイする際には、最小限のセキュリティを適用している方が便利な場合があります。 それでも、プロジェクトを開発環境から非常に敵対的な可能性のあるインターネット環境に移行する時が来れば、本番環境にデプロイされる前に、最大限のセキュリティ設定(つまり、完全なロックダウン状態)でテストしなければなりません。 これがこの記事の論点です。 InterSystems Caché、Ensemble、およびIRISにおけるDBMSセキュリティ問題をさらに包括的に説明した記事については、私の別の記事、「Recommendations on installing the InterSystems Caché DBMS for a production environment」(本番環境向けにInterSystems Caché DBMS をインストールするための推奨事項)をご覧ください。 InterSystems IRISのセキュリティシステムは、さまざまなカテゴリ(ユーザー、サービス、リソース、特権、およびアプリケーション)に異なるセキュリティ設定を適用する概念に基づいています。 ユーザーにはロールを割り当てることができます。 ユーザーとロールには、データベース、サービス、およびアプリケーションといったリソースに対し、さまざまな読み取り、書き込み、および使用の権限を付与することができます。 ユーザーとロールには、データベースのSQLテーブルに対するSQL特権も与えられます。

セキュリティレベルの違い

InterSystems IRISをインストールするときに、最小、通常、またはロックダウンというセキュリティレベルを選択できます。 レベルは、ユーザーエンゲージメントの程度、使用可能なロールとサービス、およびサービスとアプリケーションの認証方法の構成に違いがあります。 詳細については、『InterSystems IRISのインストール準備』ガイドの「InterSystemsセキュリティの準備」セクションをご覧ください。
ドキュメントには、レベルごとのセキュリティ設定を説明する、以下の表が含まれています。 この設定の変更は、システム管理ポータルのインターフェースで行えます。

ユーザーセキュリティの初期設定

セキュリティ設定最小限通常ロックダウン
パスワードのパターン3.32ANP3.32ANP8.32ANP
非アクティブになる期間090日90日
_SYSTEMユーザーの有効化不可
UnknownUserに割り当てられるロール%Allなしなし

サービスの初期プロパティ

サービスプロパティ最小限通常ロックダウン
パブリック許可を使用はいはいいいえ
認証が必要いいえはいはい
有効化されたサービスほとんどいくつか最小限

初期設定で有効にされているサービスの設定

サービス最小限通常ロックダウン
%Service_Bindings有効有効無効
*%Service_CSP有効有効有効
%Service_CacheDirect有効無効無効
%Service_CallIn有効無効無効
%Service_ComPort無効無効無効
%Service_Console有効有効有効
%Service_ECP無効無効無効
%Service_MSMActivate無効無効無効
%Service_Monitor無効無効無効
%Service_Shadow無効無効無効
%Service_Telnet無効無効無効
%Service_Terminal有効有効有効
%Service_WebLink無効無効無効

*InterSystems IRISの場合、%Service_CSPは%Service_WebGatewayを適用します。 使用されるサービスは、オペレーティングシステムごとにわずかに異なります。

セキュリティを向上させるには

有効なサービスごとに、適切な認証方法(非認証、パスワード、Kerberos、または委任)を選択する必要があります。 また、システムで使用されていないWebアプリケーションを無効にする必要もあります。 有効になっているWebアプリケーションについては、正しい認証方法(認証済み、パスワード、Kerberos、委任、ログイン、またはcookie)を選択する必要があります。 もちろん、プロジェクトは顧客の要件に従って機能できるように、管理者がプロジェクトやソリューションごとにセキュリティ設定を選択するため、 ユーザーが作業を実際に行えるようにシステムの利便性を十分に維持しながら、侵入者を寄せ付けないように十分なセキュリティを保つバランスを常に取らなければなりません。 ご承知のとおり、最も安全なシステムは無効化されたシステムです。

システムのセキュリティレベルを何度も手動で引き上げる必要があるのであれば、それは、そういった問題を解決するソフトウェアモジュールを記述する必要があるという兆候に違いありません。 実際、InterSystems Open Exchangeには、セキュリティの向上に役立つロックダウンプログラムがあります。 プログラムのソースコードは、InterSystems isc-apptools-lockdownページのリポジトリにあります。 LockDownプログラムは以下のことを行います。

まず、プレインストールされた以下のユーザーのパスワードを変更します。

  • Admin
  • CSPSystem
  • IAM
  • SuperUser
  • UnknownUser
  • _Ensemble
  • _SYSTEM

次に、以下を除くすべてのサービスを無効にします。

  • %%service_webゲートウェイ
  • %service_console
  • %service_login
  • %service_terminal

さらに、以下を含むすべてのWebアプリケーションにパスワード保護を設定します。

  • /csp/ensdemo
  • /csp/samples
  • /csp/user
  • /isc/studio/usertemplates
  • /csp/docbook
  • /csp/documatic
  • /isc/studio/rules
  • /isc/studio/templates

最後に、以下のようなシステムワイドのセキュリティパラメーターを設定します。

  • パスワードの複雑さ「8.32 ANP」
  • 90日間の非利用アカウント制限
  • 監査およびすべてのセキュリティ関連イベント LockDownプログラムは、GitHubからLockDown.clsをダウンロードして、システムにインストールできます。 そして、ターミナルモードで、以下を入力します。
USER>zn “%SYS”
%SYS>do $system.OBJ.Load("/home/irisusr/LockDown.cls","ck")

または、以下のコマンドを使用して、パブリックレジスタからZPMバッチマネージャを使ってインストールすることも可能です。

USER>zn “%SYS”
%SYS> zpm “install isc-apptools-lockdown”

ロックダウンの実行

ロックダウンを実行する前に、バックアップを作成しておくことを強くお勧めします。 LockDownプログラムは、%SYS領域から実行する必要があります。 プレインストールされたすべてのユーザーのパスワードを変更しない場合は、最初のパラメーターを空のままにします。 IRIS Studio、Atelier、またはVSCodeを使ってプログラムとクラスを編集する機能を維持する場合は、%Service_Bindingsサービスを無効にしないでください。 これを確実に機能させるには、バインディング引数を1に設定する必要があります。 次に例を示します。 do ##class(App.Security.LockDown).Apply("New Password 123",.msg,1) このモジュールには、システムパスワードが改ざんされた場合やロックダウンを実行せずにプレインストールされたすべてのアカウントを入れ替える必要がある場合に役立つ関数も含まれています。 次のようにして実行することができます。 do ##class(App.Security.LockDown).Change Password("New Password 123", "Admin,CSPSystem,IAM,SuperUser,Unknown User, _Ensemble,_SYSTEM") ほとんどの場合、ロックダウンを実行した後は、アプリケーションあまたはプロジェクトが動作しなくなります。 これを修正するには、いくつかのセキュリティ設定を元の状態に復元する必要があります。 これは、管理ポータルインターフェース(セキュリティセクション)またはプログラムで実行できます。

ロックダウン後のセキュリティ設定の変更

ロックダウン後、Webアプリケーションがパスワード以外の認証方法を使用している場合、それらを有効にする必要があります。 zpm-registry-test-deploymentというソフトウェアモジュールを実行することをお勧めします。これには、ZPM-registryプロジェクト向けのLockDownの使用例が含まれています。 次のコードは、インストールの最後に適用されています。 プロジェクトは、最小限のセキュリティレベルでIRISにインストールされました。 以下は、コードが実行する必要のあった項目です。

  • プレインストールされたすべてのユーザーのパスワードを変更する。
  • このプロジェクトで使用されていないすべてのサービスを無効にする。
  • Webアプリケーション/レジストリ(許可されていないユーザーはレジストリのパッケージのリストを取得できます)を除く、システム上の全アプリケーションのパスワード保護を有効にする。
  • レジストリに新しいパッケージを公開する権限を持つ新しいユーザーを作成する。 このユーザーには、IRISAPPデータベースのプロジェクトテーブルに対する書き込み権限が必要です。

新しいユーザーを作成します。

set tSC= ##class(App.Security.LockDown).CreateUser(pUsername, "%DB_"_Namespace, pPassword, "ZMP registry user",Namespace)
If $$$ISERR(tSC) quit tSC
write !,"Create user "_pUsername

新しいユーザーと許可されていないユーザーの特権を追加します。

set tSC=##class(App.Security.LockDown).addSQLPrivilege(Namespace, "1,ZPM.Package", "s", "UnknownUser")
set tSC=##class(App.Security.LockDown).addSQLPrivilege(Namespace, "1,ZPM.Package", "s", pUsername)
set tSC=##class(App.Security.LockDown).addSQLPrivilege(Namespace, "1,ZPM.Package_dependencies", "s", pUsername)
set tSC=##class(App.Security.LockDown).addSQLPrivilege(Namespace, "1,ZPM_Analytics.Event", "s", pUsername)
set tSC=##class(App.Security.LockDown).addSQLPrivilege(Namespace, "9,ZPM.Package_Extent", "e", pUsername)
set tSC=##class(App.Security.LockDown).addSQLPrivilege(Namespace, "9,ZPM_Analytics.Event_Extent", "e", pUsername)
If $$$ISERR(tSC) quit tSC
write  !,"Add privileges "

LockDownプログラムを実行します。

set tSC= ##class(App.Security.LockDown).Apply(NewPassSys)
If $$$ISERR(tSC) quit tSC

Change the settings for the web app so that an unknown user can log in:
set prop("AutheEnabled")=96
set tSC=##class(Security.Applications).Modify("/registry",.prop)
If $$$ISERR(tSC) quit tSC
write !,"Modify /registry "

Change the settings for the %service_terminal service, changing the authorization method to Operating System, Password:
set name="%service_terminal"
set prop("Enabled")=1
set prop("AutheEnabled")=48 ; Operating System,Password
set tSC=##class(Security.Services).Modify(name,.prop)
If $$$ISERR(tSC) quit tSC
write !,"Modify service terminal"

まとめ

この記事では、システムのセキュリティレベルを引き上げる理由とこれをプログラムで実行する方法を説明し、InterSystems LockDownプログラムを使った例を紹介しました。 最初にシステム内のすべてを終了する方法を使用しました(つまり、最大セキュリティレベルを設定しました)。 次に、プロジェクトが機能するのに必要なサービスとアプリケーションのみを開いて、セキュリティを緩和しました。 他の方法やベストプラクティスが必ず存在すると思っています。コミュニティによるこの記事のディスカッションの一環として、それらについてぜひ聞かせてください。

0
0 394
記事 Mihoko Iijima · 10月 12, 2021 6m read

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

いつも使用しているユーザでアプリケーションや InterSystems 製品(IRIS/Caché/Ensemble/HealthShare) にアクセスしたとき、セキュリティ設定変更などの影響で急にアクセスできなくなった!という場合に、調査に便利な監査ログの参照方法をご紹介します。

ここでは、%Allロールを持つシステム管理ユーザ( _system や SuperUser )で管理ポータルにアクセスできる状態での確認方法をご紹介します。

監査ログですが、まずはシステムで監査が取られる設定になっているかご確認ください(通常無効化されている場合は、調査の時だけ有効に変更してください)。

管理ポータル > システム管理 > セキュリティ > 監査 > 監査を有効に

次に、アクセスできなくなった原因を探るため、以下のシステムイベントの監査を取得できるように変更します。

管理ポータル > システム管理 > セキュリティ > 監査 > システムイベントを構成
以下のイベントの「状態変更」をクリックし、 Enabled に はい と表示されるようにします。

  • %System/%Login/LoginFailure
  • %System/%Security/Protect
0
0 1030
記事 Hiroshi Sato · 9月 9, 2021 2m read

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

2025.1以降CORS関連の設定方法は大きく変わっています。

詳細は、以下の記事を参照してください。

jQueryを使用してIRISからJSONデータを取得する方法

%CSP.REST クラスを継承する REST 用ディスパッチクラスで REST を実装している場合は、クロスドメイン制約回避用に用意されたパラメータ HandleCorsRequest を利用します。

設定方法は以下の通りです。

REST 用ディスパッチクラスをスタジオで修正する場合は、
[クラス] > [リファクタ] > [オーバーライド] を開き、[パラメータ]タブを選択 > [HandleCorsRequest] を選択後OKボタンを押下します。

 

以下の定義が追加されるので、1を設定します。

Parameter HandleCorsRequest=1;

REST ディスパッチクラスを Atelier で修正する場合は、オーバーライドメニューの用意がないため、パラメータの定義を追加するか、%CSP.REST クラスを開き、HandleCorsRequest の定義をコピーし修正します。

0
0 692
記事 Toshihiko Minamoto · 8月 11, 2021 17m read

不在時に、セキュリティとプライバシーを維持しながら、コンピューターを相互に信頼させるにはどうすればよいでしょうか?

「ドライマルティーニを」と彼は言った。 「1 杯。 深いシャンパングラスで。」
「承知いたしました。」
「気が変わった。 ゴードンを 3、ヴォッカを 1、キナリレを半量。 キンキンに冷えるまでよくシェイクしてから、大きめの薄いレモンピールを 1 つ加えてくれ。 わかったかい?」
「お承りいたしました。」 バーテンダーはその考えが気に入ったようだった。
イアン・フレミング著『カジノ・ロワイヤル』(1953 年)より

OAuth は、ユーザーログイン情報を伴うサービスを「運用中」のデータベースから、物理的にも地理的にも分離する上で役立ちます。 このように分離すると、ID データの保護が強化され、必要であれば、諸国のデータ保護法の要件に準拠しやすくしてくれます。

OAuth を使用すると、ユーザーは、最小限の個人データをさまざまなサービスやアプリケーションに「公開」しながら、一度に複数のデバイスから安全に作業することができるようになります。 また、サービスのユーザーに関する「過剰な」データを操作しなくてよくなります(データはパーソナル化されていない形態で処理することができます)。

InterSystems IRIS を使用する場合、OAuth と OIDC サービスを自律的かつサードパーティのソフトウェア製品と連携してテストし、デプロイするための既成の完全なツールセットを利用できます。

OAuth 2.0 と Open ID Connect

OAuth と Open ID Connect(OIDC または OpenID)は、アクセスと識別をデリゲートするためにオープンプロトコルを汎用的に組み合わせたもので、21 世紀現在、人気を得ているようです。 大規模な使用において、これより優れたオプションはまだ誰も思いついていません。 HTTP(S) プロトコル上にとどまり、JWT(JSON Web Token)コンテナを使用するため、特にフロントエンドのエンジニアに人気があります。

OpenID は OAuth を使用して機能しています。実際、OpenID は OAuth のラッパーです。 OpenID を電子識別システムの認証と作成に使用するオープンスタンダードとして使用することは、開発者にとって目新しい事ではありません。 2019 年には、公開から 14 周年を迎えました(バージョン 3)。 Webとモバイル開発、そしてエンタープライズシステムで人気があります。

そのパートナーである OAuth オープンスタンダードはアクセスをデリゲートする役割を担っており、12 年目を迎えています。関連する RFC 5849 標準が登場してからは 9 年です。 この記事の目的により、プロトコルの最新バージョンである OAuth 2.0 と最新の RFC 6749 を使用することにしましょう。 (OAuth 2.0 は、その前身の OAuth 1.0 とは互換していません。)

厳密に言えば、OAuth はプロトコルではなく、ソフトウェアシステムにアクセス権制限アーキテクチャを実装する際に、ユーザー識別操作を分離して別のトラステッドサーバーに転送するための一連のルール(スキーム)です。

OAuth は特定のユーザーについて何も言及できないことに注意してください! ユーザーが誰であるか、ユーザーがどこにいるのか、またユーザーが現在コンピューターを使用しているかどうかさえも、知ることはできません。 ただし、OAuth を使用すれば、事前に発行されたアクセストークンを使用して、ユーザーが参加することなくシステムと対話することが可能であり、 これは重要なポイントです(詳細は、OAuth サイトにある「User Authentication with OAuth 2.0」をご覧ください)。

User-Managed Access(UMA)プロトコルも OAuth に基づくプロトコルです。 OAuth、OIDC、および UMA を合わせて使用することで、次のような分野で保護された ID とアクセス管理(IdM、IAM)システムを実装することができます。

API エコノミーの新しいアクセス制御ベン図
API エコノミーの新しいアクセス制御ベン図

何よりも、個人データをシステムのほかの部分と同じ場所に保存してはいけません。 認証と認可は物理的に分離する必要があります。 そして、ID と認証を各個人に与えることが理想と言えます。 自分で保管せずに、 所有者のデバイスを信頼するのです。

信頼と認証

ユーザーの個人データを自分のアプリや作業データベースと組み合わさったストレージ場所に保存するのはベストプラクティスではありません。 言い換えれば、このサービスを提供できる信頼のある人を選ぶようにする必要があります。

このサービスは、次の項目で構成されます。

  • ユーザー
  • クライアントアプリ
  • 識別サービス
  • リソースサーバー

アクションは、ユーザーのコンピューターの Web ブラウザで実行されます。 ユーザーには識別サービスが備わったアカウントがあり、 クライアントアプリは、識別サービスと相互インターフェースとの契約に署名済みです。 リソースサーバーは、識別サービスを信頼して、識別できた人にアクセスキーを発行します。

ユーザーはクライアント Web アプリを実行して、リソースを要求します。 クライアントアプリは、アクセス権が必要なそのリソースへのキーを提示する必要があります。
ユーザーにキーがない場合、クライアントアプリはリソースサーバーへのキーを発行するために契約している識別サービスに接続します(ユーザーを識別サービスに転送します)。

識別サービスは、どのようなキーが必要かを問い合わせます。

ユーザーは、リソースにアクセスするためのパスワードを入力します。 この時点でユーザー認証が行われ、ユーザーの身元が確認されると、リソースへのキーが提供され(ユーザーをクライアントアプリに戻します)、ユーザーがリソースを利用できるようになります。

認可サービスの実装

InterSystems IRIS プラットフォームでは、必要に応じてさまざまなプラットフォームからのサービスをアセンブルできます。 次はその例です。

  1. デモクライアントが登録された OAuth サーバーを構成して起動します。
  2. デモ OAuth クライアントを OAuth サーバーと Web リソースに関連付けて構成します。
  3. OAuth を使用できるクライアントアプリを開発します。 Java、Python、C#、または Node JS を使用できます。 以下の方に、ObjectScript でのアプリケーションコードの例を示しています。

OAuth にはさまざまな設定があるため、チェックリストが役立ちます。 例を見ていきましょう。 IRIS 管理ポータルに移動し、[システム管理]>[セキュリティ]>[OAuth 2.0]>[サーバー]の順に選択します。

各項目には設定行の名前とコロン、そして必要であればその後に例または説明が含まれます。 別の方法として、Daniel Kutac の 3 部構成になっている「InterSystems IRIS Open Authorization Framework (OAuth 2.0)の実装 - パート1」、パート2、そしてパート3 に記載されているスクリーンショットのヒントを参考にしてください。

次のスクリーンショットはすべて、例として提示されています。 独自のアプリケーションを作成する際は、別のオプションを選択する必要があるでしょう。

[一般設定]タブで、次のように設定してください。

  • 説明: 構成の説明を入力します。「認証サーバー」など。
  • ジェネレーターのエンドポイント(以降「EPG」)のホスト名: サーバーの DNS 名。
  • サポートされている許可の種類(少なくとも 1 つを選択):
    • 認可コード
    • 暗黙
    • アカウントの詳細: リソース、所有者、パスワード
    • クライアントアカウントの詳細
  • SSL/TLS 構成: oauthserver

[スコープ]タブで、次を設定します。

  • サポートされているスコープを追加: この例では「scope1」です。

[間隔]タブで、次を設定します。

  • アクセスキー間隔: 3600
  • 認可コードの間隔: 60
  • キー更新の間隔: 86400
  • セッション中断間隔: 86400
  • クライアントキー(クライアントシークレット)の有効期間: 0

[JWT 設定]タブで、次を設定します。

  • 入力アルゴリズム: RS512
  • キー管理アルゴリズム: RSA-OAEP
  • コンテンツ暗号化アルゴリズム: A256CBC-HS512

[カスタマイズ]タブで、次を設定します。

  • 識別クラス: %OAuth2.Server.Authenticate
  • ユーザークラスの確認: %OAuth2.Server.Validate
  • セッションサービスクラス: OAuth2.Server.Session
  • キーの生成クラス: %OAuth2.Server.JWT
  • カスタムネームスペース: %SYS
  • カスタマイズロール(少なくとも 1 つ選択): %DB_IRISSYS および %Manager

では、変更内容を保存します。

次のステップでは、OAuth サーバーにクライアントを登録します。 [顧客の説明]ボタンをクリックして、[顧客の説明を作成]をクリックします。

[一般設定]タブで、次の情報を入力します。

  • 名前: OAuthClient
  • 説明: 簡単な説明を入力します。
  • クライアントタイプ: 機密
  • リダイレクト URL: oauthclient から識別した後に、アプリに戻るポイントのアドレス。
  • サポートされている付与の種類:
    • 認可コード: はい
    • 暗黙
    • アカウントの詳細: リソース、所有者、パスワード
    • クライアントアカウントの詳細
    • JWT 認可
  • サポートされているレスポンスタイプ: 次のすべてを選択してください。
    • コード
    • id_token
    • id_token キー
    • トークン
  • 認可タイプ: シンプル

[クライアントアカウントの詳細]タブは自動的に入力されますが、クライアントの正しい情報であるかを確認してください。
[クライアント情報] タブには次の項目があります。

  • 認可画面:
    • クライアント名
    • ロゴの URL
    • クライアントのホームページ URL
    • ポリシーの URL
    • 利用規約の URL

では、[システム管理]>[セキュリティ]>[OAuth 2.0]>[クライアント]の順に移動して、OAuth サーバークライアントにバインディングを構成します。

サーバーの説明の作成:

  • ジェネレーターのエンドポイント: 一般的なサーバーのパラメーターから取得されます(上記を参照)。
  • SSL/TLS 構成: 事前構成済みのリストから選択します。
  • 認可サーバー:
    • 認可エンドポイント: EPG + /authorize
    • キーエンドポイント: EPG + /token
    • ユーザーエンドポイント: EPG + /userinfo
    • キーのセルフテストエンドポイント: EPG + /revocation
    • キーの終了エンドポイント: EPG + /introspection
  • JSON Web Token(JWT)設定:
    • 動的登録以外のほかのソース: URL から JWKS を選択します。
    • URL: EPG + /jwks

このリストから、たとえばサーバーが OAuth-client にユーザーに関するさまざまな情報を提供できることがわかります(scopes_supported および claims_supported)。 また、アプリケーションを実装するときは、共有する準備ができているデータが何であるかをユーザーに尋ねても何の価値もありません。 以下の例では、scope1 の許可のみを要求します。

では、構成を保存しましょう。

SSL 構成に関するエラーがある場合は、[設定]>[システム管理]>[セキュリティ]>[SSL/TSL 構成]に移動して、構成を削除してください。

これで OAuth クライアントをセットアップする準備が整いました。
[システム管理]>[セキュリティ]>[OAuth 2.0]>[クライアント]>[クライアント構成]>[クライアント構成を作成]に移動します。 [一般]タブで、次を設定します。

  • アプリケーション名: OAuthClient
  • クライアント名: OAuthClient
  • 説明: 説明を入力します。
  • 有効: はい
  • クライアントタイプ: 機密
  • SSL/TCL 構成: oauthclient を選択します。
  • クライアントリダイレクト URL: サーバーの DNS 名
  • 必要な許可の種類:
    • 認可コード: はい
    • 暗黙
    • アカウントの詳細: リソース、所有者、パスワード
    • クライアントアカウントの詳細
    • JWT 認可
  • 認可タイプ: シンプル

[クライアント情報]タブで、次を設定します。

  • 認可画面:
    • ロゴの URL
    • クライアントのホームページ URL
    • ポリシーの URL
    • 利用規約の URL
  • デフォルトのボリューム: サーバーに以前に指定したものが取得されます(scope1 など)。
  • 連絡先メールアドレス: カンマ区切りでアドレスを入力します。
  • デフォルトの最大経過時間(分): 最大認可経過時間または省略できます。

[JWT 設定]タブで、次を設定します。

  • JSON Web Token(JWT)設定
  • X509 アカウントの詳細から JWT 設定を作成する
  • IDToken アルゴリズム:
    • 署名: RS256
    • 暗号化: A256CBC
    • キー: RSA-OAEP
  • Userinfo アルゴリズム
  • アクセストークンアルゴリズム
  • クエリアルゴリズム

[クライアントログイン情報]タブで、次を設定します。

  • クライアント ID: クライアントがサーバーに登録された際に発行された ID(上記を参照)。
  • 発効されたクライアント ID: 入力されません
  • クライアントシークレット: クライアントがサーバーに登録された際に発行されたシークレット(上記を参照)。
  • クライアントシークレットの有効期限: 入力されません
  • クライアント登録 URI: 入力されません

構成を保存しましょう。

OAuth 認可を使用した Web アプリ

OAuth は、インタラクション参加体(サーバー、クライアント、Web アプリケーション、ユーザーのブラウザ、リソースサーバー)間の通信チャネルが何らかの形で保護されていることに依存しています。 この役割は SSL/TLS プロトコルが果たしているのがほとんどですが、 OAuth は、保護されていないチャネルでも機能します。 そのため、たとえばサーバー Keycloak はデフォルトで HTTP プロトコルを使用して、保護なしで実行します。 調整と調整時のデバッグが単純化されます。 サービスを実際に使用する際、OAuth のチャネル保護は、厳重な要件に含まれるべきであり、Keycloak ドキュメントに記述されている必要があります。 InterSystems IRIS の開発者は、OAuth に関するより厳密なアプローチに従っており、SSL/TSL の使用を要件としています。 単純化できる唯一の方法は、自己署名証明書を使用するか、組み込みの IRIS サービス PKI([システム管理]>>[セキュリティ]>>[公開鍵システム]を利用することです。

ユーザーの認可の検証は、UAuth サーバーに登録されているアプリケーションの名前と OAuth クライアントスコープの 2 つのパラメータを明示的に示すことで行えます。

Parameter OAUTH2APPNAME = "OAuthClient";
set isAuthorized = ##class(%SYS.OAuth2.AccessToken).IsAuthorized(
..#OAUTH2APPNAME,
.sessionId,
"scope1",
.accessToken,
.idtoken,
.responseProperties,
.error)

認可がない場合に備え、ユーザー ID をリクエストして、アプリケーションを操作する許可を取得するためのリンクを準備しておきます。 ここでは、OAuth サーバーに登録されているアプリケーションの名前を指定して、OAuth クライアントと要求されるボリューム(スコープ)を入力するだけでなく、ユーザーを返す Web アプリケーションのポイントへのバックリンクも指定する必要があります。

Parameter OAUTH2CLIENTREDIRECTURI = "https://52773b-76230063.labs.learning.intersystems.com/oauthclient/"
set url = ##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
..#OAUTH2APPNAME,
"scope1",
..#OAUTH2CLIENTREDIRECTURI,
.properties,
.isAuthorized,
.sc)

 

IRIS を使用して、ユーザーを IRIS OAuth サーバーに登録しましょう。 たとえば、ユーザーに名前とパスワードを設定するだけで十分です。
受信した参照の下でユーザーを転送すると、サーバーはユーザーを識別する手続きを実行し、Web アプリケーションのアカウントデータによって、操作許可が照会されます。また、%SYS フィールドのグローバル OAuth2.Server.Session で自身に結果を保持します。

  1. 認可されたユーザーのデータを示します。 手続きが正常に完了したら、アクセストークンなどがあります。 それを取得しましょう。

    set valid = ##class(%SYS.OAuth2.Validation).ValidateJWT( .#OAUTH2APPNAME, accessToken, "scope1", .aud, .JWTJsonObject, .securityParameters, .sc )

以下に、完全に動作する OAuth の例のコードを示します。

Class OAuthClient.REST Extends %CSP.REST
{
Parameter OAUTH2APPNAME = "OAuthClient";
Parameter OAUTH2CLIENTREDIRECTURI = "https://52773b-76230063.labs.learning.intersystems.com/oauthclient/";
// to keep sessionId
Parameter UseSession As Integer = 1;
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
    &lt;Routes>
        &lt;Route Method="GET" Url = "/" Call = "Do" />
    &lt;/Routes>
}
ClassMethod Do() As %Status
{
    // Check for accessToken
    set isAuthorized = ##class(%SYS.OAuth2.AccessToken).IsAuthorized(
        ..#OAUTH2APPNAME,
        .sessionId,
        "scope1",
        .accessToken,
        .idtoken,
        .responseProperties,
        .error)
    // to show accessToken
    if isAuthorized {
     set valid = ##class(%SYS.OAuth2.Validation).ValidateJWT(
         ..#OAUTH2APPNAME,
         accessToken,
         "scope1",
         .aud,
         .JWTJsonObject,
         .securityParameters,
         .sc
     )
     &html&lt; Hello!&lt;br> >
         w "You access token = ", JWTJsonObject.%ToJSON()
     &html&lt; &lt;/html> >
     quit $$$OK
    }
    // perform the process of user and client identification and get accessToken
    set url = ##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
        ..#OAUTH2APPNAME,
        "scope1",
        ..#OAUTH2CLIENTREDIRECTURI,
        .properties,
        .isAuthorized,
        .sc)
    if $$$ISERR(sc) {
         w "error handling here"
         quit $$$OK
    }
    // url magic correction: change slashes in the query parameter to its code
    set urlBase = $PIECE(url, "?")
    set urlQuery = $PIECE(url, "?", 2)
    set urlQuery = $REPLACE(urlQuery, "/", "%2F")
    set url = urlBase _ "?" _ urlQuery
    &html&lt;
     &lt;html>
         &lt;h1>Authorization in IRIS via OAuth2&lt;/h1>
         &lt;a href = "#(url)#">Authorization in &lt;b>IRIS&lt;/b>&lt;/a>
     &lt;/html>
    >
    quit $$$OK
}
}

コードの作業コピーは、InterSystems GitHub リポジトリ(https://github.com/intersystems-community/iris-oauth-example)にもあります。

必要に応じて、OAuth サーバーと OAuth クライアントに高度なデバッグメッセージモードを有効にしてください。これらは、%SYS エリアの ISCLOG グローバルに記述されます。

set ^%ISCLOG = 5
set ^%ISCLOG("Category", "OAuth2") = 5
set ^%ISCLOG("Category", "OAuth2Server") = 5

詳細については、「IRIS、OAuth 2.0 と OpenID Connect の使用」ドキュメントをご覧ください。

まとめ

これまで見てきたように、すべての OAuth 機能には簡単にアクセスでき、完全に使用できる状態になっています。 必要に応じて、ハンドラークラスとユーザーインターフェースを独自のものに置き換えることができます。 OAuth サーバーとクライアントの設定は、管理ポータルを使う代わりに、構成ファイルで構成することも可能です。

0
0 417
記事 Toshihiko Minamoto · 8月 9, 2021 4m read

1 年ほど前、私のチーム(多数の社内アプリケーションの構築と管理、および他の部署のアプリケーションで使用するツールやベストプラクティスの提供を担う InterSystems のアプリケーションサービス部門)は、Angular/REST ベースのユーザーインターフェースを元々 CSP や Zen を使って構築された既存のアプリケーションに作りこむ作業を開始しました。 この道のりには、皆さんも経験したことがあるかもしれない興味深いチャレンジがありました。既存のデータモデルとビジネスロジックに新しい REST API を構築するというチャレンジです。

このプロセスの一環として、REST API 用に新しいフレームワークを構築しました。あまりにも便利であるため、自分たちだけに取っておくわけにはいきません。 そこで、Open Exchange の https://openexchange.intersystems.com/package/apps-rest で公開することにしました。 今後数週間または数か月の間に、これに関する記事がいくつか掲載される予定です。それまでは、GitHub のプロジェクトドキュメント)https://github.com/intersystems/apps-rest)に用意されたチュートリアルをご利用ください。

はじめに、設計の目標と意図についていくつか以下に示します。 すべての目標が実現したわけではありませんが、順調に進んでいます!

高速開発とデプロイ

REST アプローチは、Zen と同じアプリケーション開発のクイックスタートを提供し、一般的な問題を解決しながら、アプリケーション固有の特殊なユースケースに柔軟性を提供する必要があります。

  • REST アクセスへの新しいリソースの公開は、Zen DataModel と同じくらい簡単である必要があります。
  • REST リソースの追加/変更には、アクセスされているレベルでの変更が必要です。
  • REST による永続クラスの公開は、継承と最小限のオーバーライドで行えるべきですが、ハンドコーディング相当の機能もサポートする必要があります。 (これは、%ZEN.DataModel.Adaptor と %ZEN.DataModel.ObjectDataModel に似ています。)
  • エラー処理/レポート、シリアル化/逆シリアル化、検証などに関する一般的なパターンは、各アプリケーションの各リソースに対して再実装する必要があってはいけません。
  • SQL クエリ、フィルタリング、順序付け、および高度な検索機能とページネーションのサポートは、各アプリケーションに再実装するのではなく、組み込みである必要があります。
  • REST API はオブジェクトレベル(CRUD)でだけでなく、既存の API/ライブラリのクラスメソッドとクラスクエリに対しても簡単に構築できます。

セキュリティ

セキュリティは、付け足しで行うものではなく、設計/実装時に断定的に決定するものです。

  • REST 機能がクラス継承によって取得される場合、開発者が能動的にアクセスが必要な人とアクセス条件を指定するまでリソースにアクセスできない動作をデフォルトとします。
  • SQL 関連機能の実装を標準化することで、SQL インジェクション攻撃の標的を最小にします。
  • 設計には OWASP API トップ 10(参照: https://owasp.org/www-project-api-security)を考慮する必要があります。

持続可能性

アプリケーション設計の統一性はエンタープライズアプリケーションエコシステムにおいて強力なツールです。

  • 多様なハンドコーディングされた REST API と実装を蓄積するのではなく、一連のポートフォリオを通じて外観が似通った REST API を作成しなければなりません。 この統一性により、次が達成されなければなりません。
    • 共通のデバッグ手法
    • 共通のテスト手法
    • REST API に接続するための共通の UI 手法
    • 複数の API にアクセスする複合アプリケーションの開発の簡便性
  • REST を介して提供または受け入れられるオブジェクト表現のエンドポイントと形式は、エンドポイントに基づいて API ドキュメント(Swagger/OpenAPI)を自動的に生成できるほど十分に定義されている必要があります。
  • 業界標準の API ドキュメントに基づき、サードパーティまたは業界標準のツールを使用して、クライアントコードの一部(REST 表現に対応する typescript クラスなど)を生成できるようにします。
0
0 240
記事 Toshihiko Minamoto · 7月 28, 2021 7m read

この 3 部構成の記事では、IAM を使って、以前に IRIS にデプロイされた認証されていないサービスに OAuth 2.0 標準に従ったセキュリティを追加する方法を説明します。

パート 1 では、サービスを保護するプロセス全体を理解しやすくするために、IRIS と IAM の基本的な定義と構成を示しながら OAuth 2.0 の背景を説明しました。

パート 2 では、着信リクエストに存在するアクセストークンを検証し、検証が成功した場合にはそのリクエストをバックエンドに転送するように IAM を構成する手順について詳しく説明しました。

連載の最後となるこのパートでは、IAM がアクセストークンを生成(承認サーバーとして機能します)してそれを検証するために必要な構成と、重要な最終考慮事項を説明します。

IAM をお試しになりたい方は、InterSystems 営業担当者にお問い合わせください。

シナリオ 2: 承認サーバーとアクセストークンのバリデーターとしての IAM

このシナリオでは、最初のシナリオとは異なり、「OAuth 2.0 Authentication」というプラグインを使用します。

このリソース所有者パスワード資格情報フローで IAM を承認サーバーとして使用するには、クライアントアプリケーションがユーザー名とパスワードを認証する必要があります。 IAM からアクセストークンを取得するリクエストは、認証が成功した場合にのみ行う必要があります。

プラグインを「SampleIRISService」に追加しましょう。 以下のスクリーンショットからわかるように、このプラグインを構成するために入力が必要なフィールドがいくつかあります。

まず、「SampleIRISService」の ID を[service_id]フィールドに貼り付けて、このプラグインをサービスに適用します。

[config.auth_header_name]フィールドには、承認トークンを運搬するヘッダー名を指定します。 ここでは、デフォルト値の「authorization」のままにします。

「OAuth 2.0 Authentication」プラグインは、認可コードグラント、クライアント資格情報、インプリシットグラント、またはリソース所有者パスワード資格情報グラントの OAuth 2.0 フローをサポートしています。 この記事ではリソース所有者パスワードを使用しているため、[config.enable_password_grant]チェックボックスをオンにします。

[config.provision_key]フィールドには、プロビジョンキーとして使用される任意の文字列を入力します。 この値は、IAM にアクセストークンをリクエストするために使用されます。

ここでは、ほかのすべてのフィールドはデフォルト値のままにしました。 各フィールドの完全なリファレンスは、こちらからアクセスできるプラグインのドキュメントをご覧ください。

最終的に、プラグイン構成は次のようになります。

プラグインが作成されたら、「ClientApp」コンシューマーへの資格情報を作成する必要があります。

作成するには、左メニューの[コンシューマー]に移動して[ClientApp]をクリックします。 次に[資格情報]タブをクリックして[新しい OAuth 2.0 アプリケーション]ボタンをクリックします。

次のページでは、[名前]フィールドにアプリケーションを識別するための任意の名前を入力し、[client_id]フィールドと[client_secret]にクライアント ID とクライアントシークレットを定義し、[redirect_uri]フィールドに承認後にユーザーが送信されるアプリケーションの URL を入力します。 そして、[作成]をクリックします。

これで、リクエストを送信する準備が整いました。

最初に行うのは、IAM からアクセストークンを取得するためのリクエストです。 「OAuth 2.0 Authentication」プラグインは自動的に、作成済みのルートに「/oauth2/token」パスを追加して、エンドポイントを作成します。

注意: HTTPS プロトコルと、TLS/SSL リクエストをリスンする IAM のプロキシポート(デフォルトポートは 8443)を使用していることを確認してください。 これは OAuth 2.0 の要件です。

したがって、この場合、次の URL に POST リクエストを行う必要があります。

https://iamhost:8443/event/oauth2/token

リクエスト本文に、次の JSON を含める必要があります。

{
   "client_id": "clientid",
   "client_secret": "clientsecret",
   "grant_type": "password",
   "provision_key": "provisionkey",
   "authenticated_userid": "1"
}

ご覧のとおり、この JSON には「OAuth 2.0 Authentication」プラグイン作成中に定義した値(「grant_type」や「provision_key」など)とコンシューマーの資格情報の作成中に定義した値(「client_id」や「client_secret」など)が含まれています。

提供されたユーザー名とパスワードが正しく認証された場合には、クライアントアプリケーションによって「authenticated_userid」パラメーターも追加される必要があります。 この値は、認証されたユーザーを一意に識別するために使用されます。

リクエストとそれに対応するレスポンスは次のようになります。

これで、上記のレスポンスの「access_token」値を次の URL への GET リクエストの「ベアラートークン」として含めて、イベントデータを取得するリクエストを行えるようになりました。

https://iamhost:8443/event/1

アクセストークンが期限切れになった場合は、アクセストークンを取得するために使用したのと同じエンドポイントに、わずかに異なる本文を使って POST リクエストを送信し、期限切れのアクセストークンととも受け取ったリフレッシュトークンを使用して、新しいアクセストークンを生成することができます。

{
   "client_id": "clientid",
   "client_secret": "clientsecret",
   "grant_type": "refresh_token",
   "refresh_token": "E50m6Yd9xWy6lybgo3DOvu5ktZTjzkwF"
}

リクエストとそれに対応するレスポンスは次のようになります。

「OAuth 2.0 Authentication」プラグインには、アクセストークンを表示して無効にするという興味深い機能があります。

トークンを一覧表示するには、次に示す IAM の管理 API のエンドポイントに GET リクエストを送信します。

https://iamhost:8444/{workspace_name}/oauth2_tokens

上記の {workspace_name} は使用される IAM ワークスペースの名前です。 RBAC を有効している場合に備え、IAM の管理 API を呼び出すために必要な資格情報を入力してください。

「credential_id」は ClientApp コンシューマー内に作成した OAuth アプリケーションの ID(この場合は SampleApp)で、「service_id」はこのプラグインが適用される「SampleIRISService」の ID であることに注意してください。

トークンを無効にするには、次のエンドポイントに DELETE リクエストを送信します。

https://iamhost:8444/Sample/oauth2_tokens/{token_id}

上記の {token_id} は無効にされるトークンの ID です。

無効化されたトークンを使おうとした場合、この無効なトークンをベアラートークンとして含む GET リクエストを 次の URL に送信すると、トークンが無効であるか期限切れであるというメッセージが表示されます。

https://iamhost:8443/event/1

最終的な考慮事項

この記事では、IRIS にデプロイされている認証されていないサービスに対し、IAM で OAuth 2.0 認証を追加する方法を示しました。 サービスそのものは、IRIS で認証されないままとなることに注意してください。 したがって、IRIS サービスのエンドポイントを IAM レイヤーを介さずに直接呼び出すと、情報は認証なしで表示されます。 そのため、ネットワークレベルでセキュリティルールを設定し、不要なリクエストが IAM レイヤーをバイパスしないようにすることが重要です。

IAM の詳細についてはこちらをご覧ください。

IAM をお試しになりたい方は、InterSystems 営業担当者にお問い合わせください。

0
0 226
記事 Toshihiko Minamoto · 7月 26, 2021 5m read

この 3 部構成の記事では、IAM を使って、以前に IRIS にデプロイされた認証されていないサービスに OAuth 2.0 標準に従ったセキュリティを追加する方法を説明します。

パート 1 では、サービスを保護するプロセス全体を理解しやすくするために、IRIS と IAM の基本的な定義と構成を示しながら OAuth 2.0 の背景を説明しました。

このパートでは、着信リクエストに存在するアクセストークンを検証し、検証が成功した場合にはそのリクエストをバックエンドに転送するように IAM を構成する手順について詳しく説明します。

この連載の最後のパートでは、IAM でアクセストークンを生成し(承認サーバーとして機能します)、それを検証するようにするための構成を説明し、重要な最終考慮事項を示します。

IAM をお試しになりたい方は、InterSystems 営業担当者にお問い合わせください。

シナリオ 1: アクセストークンのバリデーターとして機能する IAM

このシナリオでは、JWT(JSON Web トークン)形式でアクセストークンを生成する外部承認サーバーを使用します。 この JWT はアルゴリズム RS256 と秘密鍵を使用して署名されています。 JWT 署名を検証するには、ほかのグループ(この場合 IAM)に承認サーバーが提供する秘密鍵が必要です。

外部承認サーバーが生成するこの JWT には、本体に、このトークンの有効期限を示すタイムスタンプを含む「exp」と呼ばれるクレームと、承認サーバーのアドレスを含む「iss」と呼ばれる別のクレームも含まれます。

したがって、IAM はリクエストを IRIS に転送する前に、承認サーバーの秘密鍵と JWT 内の「exp」クレームに含まれる有効期限のタイムスタンプを使用して、この JWT 署名を検証する必要があります。

これを IAM で構成するために、まず、IAM の「SampleIRISService」に「JWT」というプラグインを追加しましょう。 追加するには、IAM のサービスページに移動して「SampleIRISService」の ID をコピーします。これは後で使用します。

コピーしたら、プラグインに移動して[新規プラグイン]ボタンをクリックし、「JWT」プラグインを見つけて[有効化]をクリックします。

次のページで、[service_id]フィールドに「SampleIRISService」の ID を貼り付け、[config.claims_to_verify]パラメーターの「exp」ボックスを選択します。


[config.key_claim_name]パラメーターの値が「iss」であることに注意してください。 これは後で使用します。

次に、[作成]ボタンをクリックします。

クリックしたら、左メニューの「コンシューマー」セクションに移動し、前に作成した「ClientApp」をクリックします。 [資格情報]タブに移動し、[新しい JWT 資格情報]ボタンをクリックします。

次のページで、JWT の署名に使用されるアルゴリズム(この場合 RS256)を選択肢、[rsa_public_key]フィールドに公開鍵(PEM 形式で承認サーバーから提供された公開鍵)を貼り付けます。

[鍵]フィールドには、JWT プラグインを追加したときに[config.key_claim_name]フィールドに入力した JWT クレームのコンテンツを挿入する必要があります。 したがって、この場合は、JWT の iss クレームのコンテンツを挿入する必要があります。私の場合、このコンテンツは承認サーバーのアドレスです。

挿入したら、[作成]ボタンをクリックします。

ヒント: デバッグ用に、JWT をデコードするオンラインツールがあります。それに公開鍵を貼り付けると、クレームとその値を確認して、署名を検証することができます。 このオンラインツールは https://jwt.io/#debugger にあります。

JWT プラグインが追加されたため、認証無しでリクエストを送信することはできなくなりました。 以下に示すように、単純な GET リクエストを認証なしで次の URL に送信する場合、

http://iamhost:8000/event/1

「401 Unauthorized」ステータスコードで不正なメッセージが返されます。

IRIS から結果を取得するには、リクエストに JWT を追加する必要があります。

したがって、最初に承認サーバーに JWT をリクエストする必要があります。 ここで使用しているカスタム承認サーバーは、POST リクエストが、ユーザーやクライアント情報を含むキー値ペアとともに次の URL に送信された場合に JWT を返します。

https://authorizationserver:5001/auth

このリクエストとそのレスポンスは次のようになります。

次に、レスポンスから取得した JWT を承認ヘッダーの下にベアラートークンとして追加し、以前に使用したのと同じ URL に GET リクエストを送信することができます。

http://iamhost:8000/event/1

または、クエリ文字列パラメーターとして追加することも可能です。クエリ文字列のキーは、JWT プラグインを追加したときに[config.uri_param_names]フィールドに指定された値(この場合は「jwt」)です。

最後に、[config.cookie_name]フィールドに名前が入力されている場合は、JWT を cookie としてリクエストに含めるオプションもあります。

IAM でアクセストークンを生成して検証するために必要な構成と重要な最終考慮事項を理解するには、この連載のパート 3 であり最後となる記事をご覧ください。

0
0 196
記事 Toshihiko Minamoto · 7月 19, 2021 5m read

はじめに

近年、オープン認証フレームワーク(OAuth)を使って、あらゆる種類のサービスから信頼性のある方法で安全かつ効率的にリソースにアクセスするアプリケーションが増えています。 InterSystems IRIS はすでに OAuth 2.0 フレームワークに対応しており、事実コミュニティには、OAuth 2.0 と InterSystems IRIS に関する素晴らしい記事が掲載されています。

しかし、API 管理ツールの出現により、一部の組織はそのツールを単一の認証ポイントとして使用し、不正なリクエストが下流のサービスに到達するのを防ぎ、サービスそのものから承認/認証の複雑さを取り除いています。

ご存知かもしれませんが、InterSystems は、IRIS Enterprise ライセンス(IRIS Community Edition ではありません)で利用できる InterSystems API Management(IAM)という API 管理ツールを公開しています。 こちらには、InterSystems API Management を紹介する素晴らしい別のコミュニティ記事が掲載されています。

 これは、IAM を使って、以前に IRIS にデプロイされた認証されていないサービスに OAuth 2.0 標準に従ったセキュリティを追加する方法を説明した 3 部構成記事の最初の記事です。

サービスを保護するプロセス全体を理解しやすくするために、最初の記事では、IRIS と IAM の基本的な定義と構成を示しながら OAuth 2.0 の背景を説明します。

この連載記事のパート 2 以降では、IAM によってサービスを保護する上で考えられる 2 つのシナリオを説明します。 最初のシナリオでは、IAM は着信リクエストに存在するアクセストークンを検証し、検証が成功した場合にのみリクエストを 転送します。 2 番目のシナリオでは、IAM がアクセストークンを生成し(承認サーバーとして機能します)、それを検証します。

従って、パート 2 では、シナリオ 1 を構成するために必要な手順を詳しく説明し、パート 3 ではシナリオ 2 の構成を説明した上で、最終的な考慮事項を示します。

IAM をお試しになりたい方は、InterSystems 営業担当者にお問い合わせください。

OAuth 2.0 の背景

すべての OAuth 2.0 承認フローには基本的に以下の 4 つのグループが関わっています。

  1. ユーザー
  2. クライアント
  3. 承認サーバー
  4. リソース所有者

分かりやすくするために、この記事では「リソース所有者パスワード資格情報」OAuth フローを使用しますが、IAM ではあらゆる OAuth フローを使用できます。 また、この記事では範囲を指定しません。

注意: クライアントアプリはユーザー資格情報を直接処理するため、クライアントアプリの信頼性が非常に高い場合にのみリソース所有者パスワード資格情報フローを使用することをお勧めします。 ほとんどの場合、クライアントはファーストパーティアプリである必要があります。

以下は、一般的なリソース所有者パスワード資格情報フローの手順です。

  1. ユーザーはクライアントアプリに資格情報(ユーザー名とパスワードなど)を入力します。
  2. クライアントアプリは承認サーバーにユーザー資格情報と独自の ID(クライアント ID とクライアントシークレットなど)を送信します。 承認サーバーはユーザー資格情報とクライアント ID を検証し、アクセストークンを返します。
  3. クライアントはトークンを使用して、リソースサーバーにあるリソースにアクセスします。
  4. リソースサーバーは受け取ったアクセストークンを検証してから、クライアントに情報を返します。

これを踏まえ、IAM を使用して OAuth 2.0 を処理できるシナリオが 2 つあります。

  1. IAM はバリデーターをして機能し、クライアントアプリが提供するアクセストークンを検証し、アクセストークンが有効である場合にのみリソースサーバーにリクエストを転送します。この場合、アクセストークンはサードパーティの承認サーバーによって生成されます。
  2. IAM は承認サーバーとしてクライアントにアクセストークンを提供し、アクセストークンのバリデーターとしてアクセストークンを検証してから、リソースサーバーにリクエストをリダイレクトします。

IRIS と IAM の定義

この記事では、「/SampleService」という IRIS Web アプリケーションを使用します。 以下のスクリーンショットからわかるように、これは IRIS にデプロイされた認証されていない REST サービスです。

さらに、以下のスクリーンショットのとおり、IAM 側では 1 つのルートを含む「SampleIRISService」というサービスが構成されています。

また、IAM では、IAM で API を呼び出しているユーザーを識別するために、最初に資格情報の無い「CliantApp」というコンシューマーが構成されています。

上記の構成により、IAM は次の URL に送信されるすべての GET リクエストを IRIS にプロキシしています。

http://iamhost:8000/event

この時点では、認証は使用されていません。 したがって、認証無しで単純な GET リクエストを次の URL に送信する場合、

http://iamhost:8000/event/1

必要なレスポンスを得られます。

この記事では、「PostMan」というアプリを使用してリクエストを送信し、レスポンスを確認します。 以下の PostMan のスクリーンショットでは、単純な GET リクエストとそのレスポンスを確認できます。

着信リクエストに存在するアクセストークンを検証するように IAM を構成する方法を理解するには、この連載のパート 2 をお読みください。

0
0 197
記事 Shintaro Kaminaka · 4月 15, 2021 9m read

開発者の皆さん、こんにちは。 以前の記事でIRIS for Health上でFHIRリポジトリを構築し、OAuth2認証を構成する方法をご紹介しました。

この代行認証編では、IRIS for HealthのFHIRリポジトリに組み込まれた認証機能ではなく、IRISの代行認証機能+ZAUTHENTICATEルーチンを使用して認証を行う方法をご紹介します。

前回記事でご紹介したように、標準のFHIRリポジトリの認証機構では、アクセストークンの発行先を追加するためのAudienceの指定(aud=https://~) や、アクセストークンだけではなくベーシック認証の情報を送付するなどの対応が必要でした。

スクラッチでFHIRクライアントを開発するのではなく、既成の製品やアプリケーションからアクセスする場合、上記のような処理の実装ができないことがあるかもしれません。 そのような場合には、この代行認証+ZAUTHENTICATEルーチンを使用して、カスタマイズした認証の仕組みを構築することができます。

この記事に含まれる情報のドキュメントについて

この記事で記載されている情報はIRIS for Healthのドキュメントにも含まれている内容をわかりやすく再構成したものです。

RESTサービスの保護:RESTアプリケーションおよびOAuth2.0

OAuth 2.0 クライアントとしての InterSystems IRIS Web アプリケーションの使用法


代行認証を有効にする

まず使用しているIRIS環境で「代行認証」機能を有効にし、アクセスするFHIRリポジトリの「Webアプリケーション設定」で「代行認証」機能を使える用に構成します。


認証/ウェブセッションオプション画面

まずシステムとして「代行認証」が使用できるように構成します。

管理ポータルの システム管理→セキュリティ→システム・セキュリティ→認証/ウェブセッションオプション と進み、「代行認証を許可」をチェックします。 「代行認証によるOS認証を許可」ではありませんのでご注意ください。

image


%Service_WebGatewayサービス 画面

次に、CSPゲートウェイを経由したWebのアクセスに対して、「代行認証」が有効になるよう構成します。

管理ポータルの システム管理→セキュリティ→サービス と進み、「%Service_WebGateway」をクリックして、許可された認証方法の「代行」にチェックがついていることを確認します。もしチェックされていなければ、チェックして保存を実行してください。

image


FHIRリポジトリの ウェブアプリケーションの編集 画面

最後に、アクセスするFHIRリポジトリの ウェブ・アプリケーションの編集画面で「代行認証」を有効にします。

管理ポータルの システム管理→セキュリティ→アプリケーション→ウェブ・アプリケーション と進み、該当のFHIRリポジトリアプリケーションを選択します。 特に変更をしていなければ、/csp/healthshare/<namespace>/fhir/r4 となっています。

この画面で、セキュリティの設定:許可された認証方法の「代行」をチェックして保存します。

image

これで、「代行認証」を利用する準備はOKです。次は、実際に代行認証のためのロジックが記載されたZAUTHENTICATEルーチンを用意します。


ZAUTHETICATEルーチンの入手とインポート

ZAUTHENTICATEルーチンのサンプルはInterSystemsのGitHubで公開されています。

GitHub:Samples-Security

この記事ではここで紹介されているREST.ZAUTHENTICATE.macルーチンを利用します。 GitHubのREADMEに記載されているこのルーチンの説明をここにも転載します。

  • REST.ZAUTHENTICATE.mac is another sample routine that demonstrates how to authenticate a REST application using OAuth 2.0. To use this sample:
    1. Configure the resource server containing the REST application as an OAuth 2.0 resource server.
    2. Copy this routine to the %SYS namespace as ZAUTHENTICATE.mac.
    3. Modify value of applicationName in ZAUTHENTICATE.mac.
    4. Allow delegated authentication for %Service.CSP.
    5. Make sure that the web application for the REST application is using delegated authentication.

この記事では、先に手順の4.,5.を済ませているので、ルーチンのインポートを実施しましょう。 (上記READMEでは、%Service.CSPと記載されていますが、現在は%Service_WebGatewayになっています。)

GitHubからルーチンをダウンロードしてインポートするか、あるいは、このリンクから直接ルーチンを表示し、中身をStudioやVS Codeのエディタを使ってコピーしてZAUTHENTICATEルーチンをつくることもできます。%SYSネームスペースに作成します。

(注意:2021/4/16時点ではこのルーチンをスタジオからインポートするとエラーが発生してしまいます。お手数ですが、ファイルの中身をコピーしてZAUTHENTICATEルーチンを作成する方法で回避してください。)

ZAUTHENTICATEルーチンを作成したら、applicationNameを変更します。これは前回の記事で記載したOAuth2クライアントアプリケーションの クライアント構成 画面で作成した「アプリケーション名」を指定します。

image

ここでは前回の記事にならい「FHIRResource」としています。コードの一部を紹介します。

// Usually you will need to modify at least the roles to be assigned.
set roles="%DB_DEFAULT,%Operator"

$$$SysLog(3,"OAuth2","[ZAUTHENTICATE]","ServiceName="_ServiceName_", Username="_Username_", roles="_roles)

// MUST BE MODIFIED FOR EACH INSTANCE WHICH USES OAuth 2.0 for REST.
// The application name used to define the authorization server to this resource server.
set applicationName="FHIRResource"

set loginSuccessful=0
set errorText=""

コードを変更したらコンパイルを実行します。

このZAUTHENTICATEルーチンで重要なのは以下のコード部分です。 GetAccessTokenFromRequestメソッドを使用してHTTPリクエストからアクセストークンを取り出し、ValidateJWTメソッドを使用してValidationを実施し正しいアクセストークンであることを確認しています。

// This ZAUTHENTICATE routine will support OAuth 2.0 based
// delegated authentication for subclasses of %CSP.REST.
set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc)

// Check if authorized.
// if the access token is not a JWT, we would need to validate the access token
// using another means such as the introspection or userinfo endpoint.
if $$$ISOK(sc) {
	set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(applicationName,accessToken,,,.jsonObject,,.sc)
}

POSTMANからのテスト

それでは前回同様、RESTクライアントツールのPOSTMANからテストしてみましょう。 前回同様、まずはアクセストークンを取得します。

前回とは異なり、Auth URLにaudパラメータを追加する必要はありません。トークンを取得できたら、「Use Token」ボタンをクリックし、そのトークンを使用できるようにします。

次は、FHIRリポジトリへのアクセスです。今回は前回と異なり、ベーシック認証と組み合わせる必要はありませんので、そのままFHIRリポジトリにアクセスするRESTのURLのみを入力し、実行します。

FHIRリソースが取得できたら成功です。

2020.4以降の対応

IRIS for Health 2020.4ではこちらの記事に掲載したように、FHIRリポジトリ上でアクセストークンのスコープ情報がチェックされるようになりました。 このため、セキュリティ用件にも依存しますが、ZAUTHENTICATEルーチンで必ずしもアクセストークンのValidationチェックを行う必要はありません。 これまでこのシリーズで紹介してきましたように、IRIS for HealthがOAuth2認可サーバの役割も兼ねている場合、2020.4上で動かす最も単純な方法は、ZAUTHENTICATEルーチンのGetCredentialsラベルで、アクセストークンを取得する際にも指定したIRISパスワードユーザを返すようにすることです。

例:アクセストークンを取得した際のユーザと image

同じユーザを返すようにする。(このdaikoユーザには%All権限を与えています)

GetCredentials(ServiceName,Namespace,Username,Password,Credentials) Public {
	if ServiceName="%Service_WebGateway" {
		// Supply user name and password for authentication via a subclass of %CSP.REST
		set Username="daiko"
		set Password="xxxxx"
	}
	quit $$$OK
}

こちらの代行認証に関するドキュメントに記載があるように、GetCredentialsラベルで実在するIRISパスワードユーザが返された場合はそのユーザに認証が行われるため、ZAUTHENTICATEルーチンで実行されていたアクセストークンのValidationチェックのロジックは実施されなくなります。 ただし、アクセストークンの検証はその後FHIRリポジトリ上で実施されるため不正なアクセストークンでアクセスしたりすることはできません。 なお、2020.4では、スコープのチェックやAudience情報のチェックも行われるため、このバージョンの代行認証では aud=https://~ の情報の追加や適切なスコープ指定も必要になります。

テストとしてはこの方法で動作を確認することができると思いますが、もちろん実際のアプリケーションで実装する場合は、より複雑な状況を考慮に入れる必要があるでしょう。例えば、アクセスするユーザごとに異なるIRISパスワードユーザをもつケースもあれば、そもそもアクセストークンの発行元であOAuth2認可サーバが、IRISではなく他のサービスである可能性もあります。後者のようなケースでは、このZAUTHENTICATEルーチン上で代行ユーザを作成する必要があり、さらにそのユーザ名はアクセストークン内のユーザ情報(sub)と一致する必要があります。

残念ながらこの記事でそれらの状況をすべてカバーすることはできませんが、この記事に記載されている情報がIRIS for HealthのFHIRリポジトリを活用したセキュアなアプリケーション構築の一助となれば幸いです。

0
0 474
記事 Shintaro Kaminaka · 4月 15, 2021 7m read

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

以前の記事でIRIS for Health上でFHIRリポジトリを構築し、OAuth2認証を構成する方法をご紹介しました。 IRIS for Health 2020.4がリリースされ、FHIRリポジトリのアクセストークンをチェックする機能が追加になりました。

ドキュメントはAccess Token Scopesです。

この記事ではドキュメントの記載も抜粋しながらこの機能を紹介していきます。

Basic Processing

The access token that accompanies a request must include at least one patient clinical scope or user clinical scope, or else the request is rejected with an HTTP 403 error. If an access token contains both a patient clinical scope and a user clinical scope, the FHIR server enforces the patient clinical scope while ignoring the user clinical scope.

(訳)リクエストに添付されるアクセストークンには、患者のクリニカル・スコープまたはユーザーのクリニカル・スコープが少なくとも1つ含まれていなければならず、そうでなければリクエストはHTTP 403エラーで拒否されます。アクセストークンに患者のクリニカル・スコープとユーザーのクリニカル・スコープの両方が含まれている場合、FHIRサーバーは患者のクリニカル・スコープを強制し、ユーザーのクリニカル・スコープを無視します。

この機能が追加になったことで、以前の記事でご紹介していたような、"scope1"のようなスコープ指定では403エラーとなり、FHIRリポジトリから応答を受け取ることはできなくなりました。(前回の構成が残っている方はぜひ2020.4にアップグレードして403エラーになることを試してみてください。)

この記事では、正しいスコープを指定して、FHIRリポジトリにアクセスする方法をご紹介します。 ベースとなるOAuth2サーバ構成やクライアント構成に関しては以前と変わりませんので、以前の記事を参考にしてください。


SMART on FHIR : Scopes and Launch Context

今回のIRISの実装は、SMART on FHIRプロジェクトのスコープ定義をベースにしています。

SMART App Launch: Scopes and Launch Context

このサイトのQuick Startに記載されている以下のスコープをベースにこの記事の検証を進めてみたいと思います。 詳細についてはSMART on FHIRの上記解説サイトをご覧ください。

ScopeGrant
patient/*.read現在の患者のあらゆるリソースを読むことができる許可
user/*.*現在のユーザーがアクセスできるすべてのリソースの読み取りと書き込みの許可


OAuth 2.0 認可サーバ構成の変更

まず、OAuth2認可サーバ構成で、サポートしていないスコープが許可されるように構成します。 OAuth2認可サーバの「スコープ」タブで、「サポートしていないスコープを許可」にチェックを入れます。

image


スコープを指定してPatientリソースを登録する

それでまず、Patientリソースを登録してみましょう。 Create Interactionを行う場合には、user clinical scope が必要になります。以下はIRIS for Healthのドキュメントからの抜粋です。

Create Interaction

Requests to create a new Patient resource must include a user clinical scope that gives write permissions (user/Patient.write or user/Patient.*). You cannot perform a create interaction for a Patient resource with a patient clinical scope; patient clinical scopes must include a patient context value, and the create interaction cannot include a resource id.

(訳)新規にPatientリソースを作成する要求には、書き込み権限(user/Patient.writeまたはuser/Patient.*)を与えるユーザークリニカルスコープを含める必要があります。患者臨床スコープには患者コンテキスト値を含める必要があり、作成インタラクションにリソースIDを含めることはできません

先ほど、でてきたスコープ「user/*.*」を追加して、アクセストークンを取得し、Patientリソースを登録してみましょう。

以下の図はRESTツールPOSTMAN上で、スコープを指定している画面です。

image

任意のスコープを許可する設定が正しく動作していれば以下のような確認画面が表示されます。

image

「許可」をクリックして、アクセストークンを取得します。このアクセストークンを使ってPatientリソースを登録してみましょう。 まず登録するPatientリソースを用意してください。FHIR公式ページから取得しても良いですし、過去のコミュニティ記事から取得しても良いです。

POSTMANを使う場合、Bodyタブに登録したいリソースを貼り付けます。

image

前回記事同様、アクセストークン+ベーシック認証を行う必要があるので、取得したアクセストークンを access_toke=eyXXX としてパラメータに追加し、Authorizationタブではベーシック認証を選択してください。

image

メソッドがPOSTであること、リクエストURLが正しくPatientを指定していることなども確認出来たら、登録を実行してみてください。Status 201 Created が返ってきたら登録は成功です。

登録が成功したら、続いてGETも試してみてください。 このスコープは読み取りの権限もありますから取得できるはずです。

リソースが取得できたら、今登録したPatientリソースのリソースIDも確認してください。以下の例では 1 になります。

image


スコープを指定してPatientリソースを取得する

では、Patientリソースが登録できたので、今度は異なるスコープを指定して先ほどのPatientリソースを取得してみましょう。

患者に紐づく情報を取得する場合、patient clinical scope が必要になります。

Patient Clinical Scope / Patient Context Value

If an access token includes a patient clinical scope, it must also include a patient context value (also known as “launch context”) that is the id of a Patient resource. This patient context value provides access to the specified Patient and its related resources.

(訳)アクセストークンに患者の臨床範囲が含まれる場合、Patient リソースの ID である患者コンテキスト値(「起動コンテキスト」とも呼ばれる)も含まれなければならない。この患者コンテキスト値は、指定された患者及びその関連リソースへのアクセスを提供する。

今回はスコープに「patient/*.read」を追加します。もう一点どの患者情報にアクセスできるのか判断するために、PatientリソースのリソースID情報を含むPatient Context Valueをスコープとして渡します。具体的には、「launch/patient/1」(リソースID=1の場合)もスコープとして指定します。

POSTMANでは以下のように指定します。スコープの間は半角スペースで区切ります。

image

アクセストークンを取得できたら、先ほどと同じ手順でリクエストを投げてみましょう。 ただし、今回取得したアクセストークンで取得できるFHIRリソースはリソースID=1のPatientリソースに紐づく情報だけであることにご注意ください。ということは、取得するためにRESTのパスは Patient/1 となります。

例:https://<server>/csp/healthshare/fhirserver/fhir/r4/Patient/1?access_token=eyXXX

無事に先ほどのPatientリソースが取得できたらアクセス成功です! 次は、このトークンが本当にリソースID=1だけに制限されているかも確認してみましょう。他のリソースIDを指定するか、Patientリソース全体を取得するようなリクエストを投げてみてください(ただし存在しないPatientのリソースIDを指定するとそのリソースは存在しませんという別のエラーになります。)

例:https://<server>/csp/healthshare/fhirserver/fhir/r4/Patient/2?access_token=eyXXX 例:https://<server>/csp/healthshare/fhirserver/fhir/r4/Patient?access_token=eyXXX

Status 403エラーになりましたか?エラーが返れば確認は成功です。


まとめ

どのようなFHIRリソースをFHIRリポジトリに格納しているのか?また、どのようなアプリケーションを構築して、どのようにユーザにアクセス制限を設定したいのか?等により、利用すべきスコープの使い方は異なってきます。

安全なFHIRアプリケーションを構築するために、この新しいアクセストークンスコープ機能(とあとこの記事が)活用されると幸いです。

0
0 510
記事 Mihoko Iijima · 12月 28, 2020 3m read

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

データベース暗号化は、ディスクヘの書き込みまたはディスクからの読み取りで暗号化と復号が実行されるため、アプリケーションのロジックに手を加える必要はありません。

この機能のドキュメントについては、以下ご参照ください。

マネージド・キー暗号化【IRIS】

マネージド・キー暗号化


暗号化データベース作成までの流れは、以下の通りです。

(1) 暗号化キーの作成

  • (a) 管理者 ユーザ名/パスワード
  • (b) 暗号化キーファイル

(2) 暗号化キーの有効化

(3) 暗号化されたデータベースの作成

暗号化データベース作成後の運用のための設定は以下の通りです。

〇 データベース暗号化の起動設定(暗号化キーの有効化をどのように行うか)

暗号化されたデータベースは、"暗号化キーの有効" が行われてアクセスできるようになります。
既定の設定では、"暗号化キーの有効"を行いませんので、以下3種類の方法から選択します。

① キーを有効化しない起動の構成

既定の設定のまま、インスタンス起動時に "暗号化キーの有効" が行われません。
暗号化されたデータベースをマウントする前に管理ポータルなどから "暗号化キーの有効" を行う必要があります。

以下の場合、この運用は適応できません。

0
0 349
記事 Toshihiko Minamoto · 12月 16, 2020 1m read

Windows と Mac で InterSystems IRIS 2019.1 (および 2018.1.2) の SSL/TLS 設定に認証局 (CA) の証明書を簡単に追加する新しい方法ができました。  IRIS にオペレーティングシステムの証明書ストアを使用することを要求するために、

%OSCertificateStore

を "信頼された証明書機関 X.509 証明書を含むファイル" のフィールドに入力します。   以下はポータルでそれを実行する方法を示した画像です。

また、これについて説明したドキュメントへのリンクはこちらです。  "信頼された証明書機関の証明書を含むファイル" のオプションの中を探してください。

必要な操作はこれだけです!  これで、OS 証明書ストアに載っているすべての CA の証明書をこの設定に使用することができます。

0
0 277
記事 Mihoko Iijima · 12月 15, 2020 1m read

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

デフォルトでは、セキュリティ脆弱性対応の観点でウェブサービス用テストページの実行を許可していません。

テスト目的等で利用する場合は、テストページへのアクセスを有効にする必要があり、以下グローバル変数のセットを %SYS ネームスペースで実行する必要があります。

set ^SYS("Security","CSP","AllowClass",0,"%SOAP.WebServiceInvoke")=1
set ^SYS("Security","CSP","AllowClass",0,"%SOAP.WebServiceInfo")=1

 

詳細については、以下のドキュメントもご参照下さい。

カタログおよびテスト・ページについて【IRIS】

カタログおよびテスト・ページについて 

0
0 163
記事 Toshihiko Minamoto · 12月 7, 2020 10m read

    以前の記事では Arduino を使い始め、最終的には気象観測所のデータを表示できるようになりました。 この記事ではさらに掘り下げ、InterSystems Caché アプリケーションに対して RFID カードと Arduino を介した認証をセットアップします。

 

認証の委任

Caché には認証コードの書き込みを許可することで、認証を委任するための仕組みがあります。 この仕組みを有効にするには、次の手順を実行する必要があります。

  • ZAUTHENTICATE ルーチンにユーザー認証コードを記述します。 このルーチンにはユーザー名/パスワードの取得、それらの検証と権限の割り当て、パスワード変更、トークン生成の 4 つのエントリポイントがあります。 詳細については、以下をお読みください。
    1. Caché で委任認証を有効にします([SMP] → [System Administration] → [Security] → [System Security] → [Authentication/CSP Session Options] を開き、[Allow Delegated authentication] ボックスにチェックを入れて設定を保存します)。
    2. 関連するサービスかアプリケーションの委任認証を有効にします(前者の場合は [SMP] → [Menu] → [Manage Services] → [Service] → [Allowed Authentication Methods] → [Delegated] を選択 → [Save]、後者の場合は [SMP] → [Menu] → [Manage Web Applications] → [Application] → [Allowed Authentication Methods] → [Delegated] を選択 → [Save])。

    仕組み

    委任認証は、委任認証が有効になっているサービスや Web アプリケーションに対してユーザーが認証される際に発生します。

    1. ZAUTHENTICATE ルーチンが呼び出されます。 このルーチンのコードはユーザーによって書かれたものであり、OS への呼び出しを含む任意の Caché ObjectScript コードである可能性があります。
    2. 次のステップは、ZAUTHENTICATE の呼び出しが成功したかどうかによって決まります。
    • ZAUTHENTICATE の呼び出しが成功し、ユーザーが ZAUTHENTICATE で認証されたのが初めてだった場合は「委任されたユーザー」が作成されます。 ZAUTHENTICATE がロールやその他の権限をユーザーに割り当てた場合は、それらがユーザープロパティになります。
    • ZAUTHENTICATE の呼び出しが成功し、ユーザーが ZAUTHENTICATE で認証されたのが初めてではなかった場合はそのユーザーのレコードが更新されます。
    • ZAUTHENTICATE の呼び出しが成功しなかった場合、ユーザーはアクセスエラーを受け取ります。
    1. インスタンスとサービスで 2 要素認証が有効になっている場合は、ユーザーの電話番号と事業者の検索が開始されます。 これらの情報が入力されている場合は、2 要素認証が実行されます。 入力されていない場合は、ユーザーは認証されません。

    ユーザー情報の出処は?

    次のように、アプリケーション/サービスで有効になっている認証方法に応じた 2 つの認証方法があります。

    • 委任: ユーザー名/パスワードは ZAUTHENTICATE ルーチン(GetCredentials エントリポイント)から取得され、ZAUTHENTICATE を使用して検証されます(ユーザータイプ: 委任)。
  • 委任およびパスワード: ユーザー名/パスワードは GetCredentials から取得されますが、標準の Caché ツールを使用してチェックされます(ユーザータイプ: Caché)。
  • 次に、ZAUTHENTICATE ルーチンとそのエントリポイントを見てみましょう。

    ZAUTHENTICATE

    これはメインルーチンであり、次の 4 つのエントリポイントで構成されています。

    GetCredentials

    このエントリポイントはサービスで委任認証が有効になっている場合に呼び出され、ユーザーにユーザー名/パスワードの入力を求める代わりに呼び出されます。 このルーチンのコードは、ユーザー名とパスワードを(何らかの方法で)取得します。 その後、(このエントリポイントの外部で)受信したユーザー名とパスワードはユーザーから通常の方法で入力されたかのように認証されます。 ユーザー名とパスワードは、キーボードからの入力、API、外部デバイスを使用したスキャンなど、任意の方法で取得できます。 この記事では、RFID カードを使用した認証を実装します。

    このエントリポイントはステータスを返します。ステータスがエラーの場合は監査ログに記録され、認証試行は拒否されます。 ただし、エラーステータス $SYSTEM.Status.Error($$$GetCredentialsFailed) が返された場合は、例外的に通常のユーザー名/パスワードの入力が続きます。 シグネチャは次のとおりです。

    GetCredentials(ServiceName, Namespace, Username, Password, Credentials) Public { }

    説明:

    • ServiceName – 接続が確立されるサービスの名前
    • Namespace – ネームスペース(接続時に指定されている場合)
    • Username – ユーザー名
    • Password – パスワード
  • Credentials – 現在使用されていません
  • このエントリポイントの重要な機能について説明します。 委任認証とパスワード認証の両方がサービスやアプリケーションで有効になっている場合、ユーザー名とパスワードは GetCredentials エントリポイントを介して受信されますが、それらの情報は標準のパスワード認証に使用されます(ユーザーが手動で入力した場合と同じ)。また、認証が成功した場合のユーザーは委任ユーザーではなく通常の Cache ユーザーになります。

    ZAUTHENTICATE

    初回認証が成功すると、ZAUTHENTICATE はロールやその他のユーザープロパティを定義します。 初回認証以外の場合はプロパティが更新されます(例えば、Roles はログインのたびに指定する必要があります)。 そのために、Properties 配列のプロパティを定型化したコードで設定する必要があります。 シグネチャは以下のとおりです。

    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) Public { }

    Properties 配列の説明:

    • Properties("Comment") — コメント
    • Properties("FullName") — 氏名
    • Properties("NameSpace") — 初期ネームスペース
    • Properties("Roles") — カンマ区切りのロールのリスト
    • Properties("Routine") — 初期ルーチン
    • Properties("Password") — パスワード
    • Properties("Username") — ユーザー名
    • Properties("PhoneNumber") — ユーザーの電話番号
    • Properties("PhoneProvider") — 電話会社
  • Properties("AutheEnabled") — 標準の 2 要素認証を有効化します(この目的のために、$$$AutheTwoFactorSMS に等しい値を設定する必要があります)
  • ChangePassword

    ユーザーパスワードを変更するためのエントリポイントです。シグネチャは次のとおりです。

    ChangePassword(Username, NewPassword, OldPassword, Status) Public { }

    説明:

    • NewPassword — 新しいパスワード
    • OldPassword — 古いパスワード
  • Status — パスワード変更の結果
  • SendTwoFactorToken

    標準の 2 要素認証で使用されるものです。 リクエストの形式と認証トークンを指定します。 シグネチャは以下のとおりです。

    SendTwoFactorToken(Username, ServiceName,Namespace,Application,Credentials,SecurityToken,TwoFactorTimeout,UserPhoneNumber) Public { }
    

    説明:

    • Application — ユーザーが接続している CSP アプリケーションまたはルーチン
    • SecurityToken — ユーザーに送信されるトークン
    • TwoFactorTimeout — トークンの有効期限が切れる時間
  • UserPhoneNumber — ユーザーの電話番号
  • まずは簡単な例から始めましょう。Windows での Caché ターミナルを担う %Service_Console サービスは、ユーザー名とパスワードの入力をユーザーに要求します。 このサービスに対して委任認証を有効にしましょう。 以下は、ユーザーにユーザー名とパスワードの入力を要求する ZAUTHENTICATE ルーチン(%SYS ネームスペース内)です。

    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC {
        #Include %occStatus
        Quit $$$OK
    }
    GetCredentials(ServiceName, Namespace, Username, Password, Credentials) Public {
        #Include %occErrors
        #Include %occStatus
        Do ##class(%Prompt).GetString("USER:",.Username)
        Do ##class(%Prompt).GetString("PASS:",.Password)
        Quit $$$OK
    }

    ターミナルの場合、これは通常のユーザー名認証と同じように見えます。

    >USER: _SYSTEM
    >PASS: SYS

    RFID

    それでは、RFID による認証を見てみましょう。 考え方は単純で、Caché が暗号化されたユーザー名とパスワードをカードに書き込み、認証中に Caché がカードをスキャンして復号化し、受け取ったユーザー名とパスワードを認証に使用するというものです。

    まず、Arduino Uno と RFID-RC522 モジュールの回路図をご覧ください。

    MF522 ライブラリを使用した C のコードはここにあります。 このコードでは、COM ポート経由で次の 2 つのコマンドを受信できます。

    • Get – RFID カードのブロック 2 / 4 / 5 / 6 の内容が COM ポートに渡されます
  • Set@bloc2@bloc4@bloc5@bloc6 — ブロック 2 / 4 / 5 / 6 の値が受信したデータに置き換えられます
  • Caché 側には Arduino.Delegate クラスがあり、その中に次の 2 つの対応するエントリポイントがあります。

    • SetCredentials — ユーザー名とパスワードの入力を取得し、それをシステムに格納されているキーを使用して AES 暗号化で暗号化し、RFID カードに書き込みます。
  • GetCredentials — カードから暗号化テキストを受信して復号化し、ユーザー名、パスワード、および操作のステータスを返します。
  • また、GetCredentials を使用して Arduino.Delegated クラスを呼び出す ZAUTHENTICATE ルーチンは以下のとおりです。

    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC {
        #Include %occStatus
        Quit $$$OK
    }
    GetCredentials(ServiceName, Namespace, Username, Password, Credentials) Public {
        #Include %occErrors
        #Include %occStatus
        Quit ##class(Arduino.Delegated).GetCredentials(.Username, .Password)
    }
    

    これで準備完了です! 組み立て後のデバイスは次のようになります。

    次のようにターミナルでシステム暗号化キーを設定します(%SYS ネームスペースと Arduino.Delegated クラスを使用できる必要があります)。

    Do ##class(Arduino.Delegated).InitEncryption(Key, IV)
    

    ここで、Key は暗号化キー、IV は初期化ベクトルです。 これらは、ユーザー名とパスワードを暗号化するために使用されます。 コマンドを使用して認証するには、Arduino を Caché に接続し、カードに情報を書き込みます。

    Do ##class(Arduino.Delegated).SetCredentials("_SYSTEM", "SYS")
    

    適切なサービスまたは Web アプリケーション(端末やシステム管理ポータルなど)で委任認証とパスワード認証を有効にすると、カードを RFID カードリーダーにかざすことで認証できるようになります。

    考えられる機能強化

    • マネージド暗号化キーを使用してユーザー名とパスワードを暗号化すると、セキュリティを強化できます。
    • 2 要素認証を使用すると、セキュリティを強化できます。具体的には、先にユーザー名とパスワードのペアを取得してから、ユーザーに固有のキーが格納されているカードを読み取ります。 次に、受信したキーをシステムに格納されている特定ユーザーのキーで確認する必要があります。 任意のユーザーデータを格納する方法は、InterSystems のコミュニティで議論されています
  • それぞれ 15 文字を超えるユーザー名とパスワードを格納する機能を追加します。
  • まとめ

    柔軟性の高い Caché の認証システムを使えば、任意のユーザー認証ロジックを実装できます。

    リンク

    0
    0 1034
    記事 Toshihiko Minamoto · 12月 4, 2020 5m read

    みなさん、こんにちは。

    数日前、SOAP(Web)サービスを使用して、REST に基づく新しいアプリケーション API と同じ認証を使用できるように、既存のレガシーアプリケーションを拡張したい、とお客様から伺いました。 新しいアプリケーションは OAuth2 を使用しているため、課題は明らかでした。SOAP リクエストを含むアクセストークンをどのようにしてサーバーに渡すか、ということです。

    Google でしばらく調べてみたところ、SOAP エンベロープにヘッダー要素を追加してから、アクセストークンを検証するために必要なことを Web サービス実装が実行できるようにするのが 1 つの実現方法であることがわかりました。

    幸い、私たちは、SOAP リクエストにカスタムヘッダーを提供するための仕組みを提供しています。 そこで、ドキュメントを確認したところ(詳細はこちら)、次のクラスが出てきました。

    カスタムヘッダークラス

    Class API.SOAP.OAuth2Header Extends %SOAP.Header
    {
    
    Property accessToken As %String(MAXLEN = "");
    
    }
    

    確かに、非常に単純です。 必要なのはアクセストークンを渡すことだけですが、ほかの情報も渡すように拡張することもできます。

    Webサービス実装クラス

    /// API.SOAP.MyService
    Class API.SOAP.MyService Extends %SOAP.WebService [ ProcedureBlock ]
    {
    
    /// Webサービスの名前。
    Parameter SERVICENAME = "MyService";
    
    /// TODO: これを実際の SOAP ネームスペースに変更してください。
    /// Webサービスの SOAP ネームスペース
    Parameter NAMESPACE = "http://tempuri.org";
    
    /// 参照先クラスのネームスペースが WSDL に使用されます。
    Parameter USECLASSNAMESPACES = 1;
    
    /// TODO: 引数と実装を追加してください。
    /// GetVersion
    Method GetAccountBalance(pAccNo As %String) As API.SOAP.DT.Account [ WebMethod ]
    
    {
      #define APP       "ANG RESOURCES"
      try {
        #dim tAccessTokenHeader as API.SOAP.OAuth2Header=..HeadersIn.GetAt("OAuth2Header")
    
        $$$THROWONERROR(tSC,##class(%SYS.OAuth2.AccessToken).GetIntrospection($$$APP,tAccessTokenHeader.accessToken,.jsonObjectAT))
    
        /* service specific check */
        // check whether the request is asking for proper scope for this service
        if '(jsonObjectAT.scope["account") set reason="scope not supported" throw 
            
        if '(##class(%SYS.OAuth2.Validation).ValidateJWT($$$APP,tAccessTokenHeader.accessToken,,,.jsonObjectJWT,.securityParameters,.tSC)) {
          set reason="unauthorized access attempt"
          throw
        }           
        set tAccountObject=##class(API.SOAP.DT.Account).%New()
        set tAccountObject.accno=pAccNo
        set tAccountObject.owner=jsonObjectJWT."acc-owner"
        set tAccountObject.balance=$random(200000)
      } catch (e) {
        set fault=..MakeFault($$$FAULTServer,"SECURITY",reason)
        Do ..ReturnFault(fault)
      }
      Quit tAccountObject
    }
    
    XData AdditionalHeaders
    
    {
    <parameters xmlns="http://www.intersystems.com/configuration">
    <request>
    <header name="OAuth2Header" class="API.SOAP.OAuth2Header"/> 
    </request>
    </parameters>
    }
    }
    

    アクセストークンの確認について、少し説明しましょう。 ご覧のとおり、最初に行うタスクは、カスタムヘッダーからアクセストークンを取得して、オブジェクト表現に逆シリアル化することです。

    その後は、スコープをチェックするかどうか、JWT トークンの検証などさらなる検証を実行するのかを決めることができます(OAuth2 認証サーバーの設定方法や、私が非常にお勧めしているOpenID を使用するかどうかに依存しています)。

    では、クライアント側を確認してみましょう。

    クライアントが OAuth2 認証サーバーのアクセストークンをどのように受け取るのかについては他の記事で説明しているので、ここでは深く言及せずにおきますが、代わりに、アクセストークンを Web サービスクライアントに提供する方法を確認することにしましょう。 (Web サービスクライアントクラスは、Atelier または Studio IDE から標準の SOAP ウィザード/クライアントオプションを実行して生成します。)

    次は私のクライアントのコードスニペットです。

      set tWSClient=##class(Web.WSC.MyServiceSoap).%New()
      set tWSHeader=##class(Web.WSC.s0.OAuth2Header).%New()
    
      set tWSHeader.accessToken=accessToken
      do tWSClient.HeadersOut.SetAt(tWSHeader,"access-token")
      #dim tAccountObject as Web.WSC.s0.Account=tWSClient.GetAccountBalance(tAccNo)
    

    リソースサーバーにおけるセキュリティ設定に関する考慮事項

    リソースサーバー(Web サーバー)で CSP アプリケーションをセットアップするには、認証されていないユーザーを許可するのが最も簡単なやり方ですが、これにはリスクが伴います。サービスやメソッドごとにアクセストークンをチェックし検証するのはあなた次第です。 アクセストークンが存在しないか有効でない場合は、SOAP フォルトを返さなければなりません。

    より優れた代替手段としては、委任認証を使用し、ZAUTHENTICATE ルーチンでアクセストークンを取得して、何らかの意図的なユーザー名(アクセストークンリクエストのスコープ付きで OpenID プロファイルが提供されている場合は JWT から取得可能)を、Web サーバーメソッドを実行するために最低限必要なロールで割り当てる方法があります。

    0
    0 809
    記事 Hiroshi Sato · 10月 29, 2020 1m read

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

    起動時に、 CTELNETD startup error: bind(sock) failed Telnet23ポートは別ソフトでは使用していません。というエラーが発生する場合の対処法です。

    現在、InterSystems製品と以下のソフトの組み合わせで、この現象が発生することがわかっています。

    1. NOD32 (セキュリティソフト)※1
    2. McAfee (セキュリティソフト・V5以前)※2
    3. AntiVirus2004 (セキュリティソフト)
    4. AirH トルネード (パケット圧縮ツール)
    5. Norton インターネットセキュリティ ※3
    6. Norton パーソナルファイアウォール ※3
    7. Sygate Personal Firewall
    8. WinGate
    9. Outpost
    10. ZoneAlarm
    11. McAfee Security Suite のプライバシーサービス  

    これらがインストールされていると、InterSystems製品の起動も、各GUIツールも正しく動作しません。


    上記ソフトウェアについては、アンインストールをお願いいたします。

    ※1 IMONで、InterSystems製品の全実行ファイルを監視をしないように指定することで、正常に動作します。

    0
    0 525
    記事 Mihoko Iijima · 9月 16, 2020 2m read

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

    InterSystemsでは、パフォーマンスの影響や動作不調を避けるために、データベースファイルを含む主要なコンポーネントをウイルススキャンの対象から除外していただくことを推奨しております。

    具体的には、アンチウイルスソフトのスキャン対象から、以下のファイルを除外してください。

    • データベースファイル(IRIS.DAT/CACHE.DAT)
    • <インストールディレクトリ>/bin 内の実行可能ファイル(EXE) 
    • ライトイメージジャーナル(WIJ)
    • ジャーナルディレクトリ内のジャーナルファイル

    上記ファイルが、アンチウイルスソフトで除外設定されていない場合、「SERIOUS DISK WRITE ERROR...」のようなエラーが発生する場合があります。

    このエラーは、実際にハード的なディスク障害が原因であることもありますが、それ以外にアンチウィルスソフトのウィルスチェックなどによって、ディスクへの書き込みが阻止された場合にも起こります。

    詳細は、下記ドキュメントページをご参照ください。

    インターシステムズ製品と連係して動作するようにサードパーティ・ソフトウェアを構成する方法【IRIS】
    インターシステムズ製品と連係して動作するようにサードパーティ・ソフトウェアを構成する方法

    0
    0 417
    記事 Shintaro Kaminaka · 8月 26, 2020 23m read

    作成者:Daniel Kutac(InterSystems セールスエンジニア)

    パート 3. 付録

    InterSystems IRIS OAUTH クラスの説明

    この連載の前のパートでは、InterSystems IRIS を OAUTH クライアントおよび認可/認証サーバー(OpenID Connect を使用)として機能するように構成する方法について学びました。 この連載の最後のパートでは、InterSystems IRIS OAuth 2.0 フレームワークを実装するクラスについて説明します。 また、一部の API クラスのメソッドの使用例についても説明します。

    OAuth 2.0 を実装する API クラスは、目的に応じて 3 種類のグループに分けることができます。 すべてのクラスは %SYS ネームスペースで実装されています。 これらの一部は(% package 経由で)公開されていますが、一部は非公開になっており、開発者が直接呼び出すことはできません。

    内部クラス

    これらのクラスは OAuth2 パッケージに属しています。

    次の表に、対象となるクラスの一部を掲載しています(クラスの完全なリストについては、CachéあるいはIRIS インスタンスのオンラインクラスリファレンスを参照してください)。 以下の表に掲載されているものを除き、これらのクラスをアプリケーション開発者が直接使用することはできません。

      <td>
        説明
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.AccessToken
      </td>
      
      <td>
        Persistent(永続クラス)
    

    OAuth2.AccessToken は、OAuth 2.0 アクセストークンとその関連情報を格納します。 これは、アクセストークンの OAUTH クライアントコピーです。OAuth2.AccessToken は、SessionId と ApplicationName の組み合わせによってインデックス化されます。 したがって、SessionId/ApplicationName ごとに 1 つのスコープのみをリクエストできます。 2 回目のリクエストが別のスコープで行われ、アクセストークンがまだ付与されている場合は、新しいリクエストのスコープが予期されるスコープになります。

    <tr style="height:0px">
      <td>
        OAuth2.Client
      </td>
      
      <td>
        Persistent(永続クラス)
    

    OAuth2.Application クラスは OAuth2 クライアントを記述し、RFC 6749 に基づいてアプリケーションを認可するために使用する認可サーバーを参照します。 クライアントシステムは、さまざまなアプリケーションで複数の認可サーバーと共に使用できます。

    <tr style="height:0px">
      <td>
        OAuth2.Response
      </td>
      
      <td>
        CSPページ
    

    これは、InterSystems IRIS OAuth 2.0 クライアントコードから使用される OAuth 2.0 認可サーバーからの応答用のランディングページです。 応答はここで処理され、最終的なターゲットにリダイレクトされます。

    <tr style="height:0px">
      <td>
        OAuth2.ServerDefinition
      </td>
      
      <td>
        Persistent(永続クラス)
    

    OAUTH クライアント(この InterSystems IRIS インスタンス)が使用する認可サーバーの情報が格納されています。 認可サーバーの定義ごとに複数のクライアント構成を定義できます。

    <tr style="height:0px">
      <td>
        OAuth2.Server.AccessToken
      </td>
      
      <td>
        Persistent(永続クラス)
    

    アクセストークンは OAUTH サーバーの OAuth2.Server.AccessToken によって管理されます。 このクラスには、アクセストークンと関連プロパティが格納されます。 このクラスは、認可サーバーのさまざまな要素間の通信手段でもあります。

    <tr style="height:0px">
      <td>
        OAuth2.Server.Auth
      </td>
      
      <td>
        CSP ページ
    

    認可サーバーは、RFC 6749 で指定されている認可コードおよびインプリシットグラントタイプの認可制御フローをサポートします。 OAuth2.Server.Auth クラスは認可エンドポイントとして機能し、RFC 6749 に従ってフローを制御する %CSP.Page のサブクラスです。

    <tr style="height:0px">
      <td>
        OAuth2.Server.Client
      </td>
      
      <td>
        Persistent(永続クラス)
    

    OAuth2.Server.Configuration は、この認可サーバーに登録したクライアントを記述する永続クラスです。

    <tr style="height:0px">
      <td>
        OAuth2.Server.Configuration
      </td>
      
      <td>
        Persistent(永続クラス)
    

    認可サーバーの構成が格納されます。 すべての構成クラスには、ユーザーが構成の詳細を入力するためのシステム管理ポータルページがそれぞれ存在します。

    クラス名

    OAuth2.Client、OAuth2.ServerDefinition、OAuth2.Server.Client、OAuth2.Configuration の各オブジェクトは UI を使用せずに開き、変更し、作成または変更した構成を保存できます。 これらのクラスを使用し、構成をプログラムで操作できます。

    サーバーカスタマイズ用クラス

    これらのクラスは %OAuth2 パッケージに属しています。 このパッケージには、一連の内部クラス(ユーティリティ)が含まれています。ここでは、開発者が使用できるクラスについてのみ説明します。 これらのクラスは、OAuth 2.0 Server Configuration(サーバー構成)ページで参照されます。

      <td>
        CSPページ
    

    %OAuth2.Server.Authenticate はデフォルトの Authenticate クラスだけでなく、ユーザーが作成したすべての Authenticate クラスのサブクラスとして機能します。 Authenticate クラスは、ユーザーを認証するために OAuth2.Server.Auth の認可エンドポイントによって使用されます。 このクラスを使用すると、認証プロセスをカスタマイズできます。次のメソッドを OAuth2.Server のデフォルトをオーバーライドするために実装できます。 DirectLogin– ログインページを表示しない場合にのみ使用します。 DisplayLogin – 認可サーバーのログインフォームを実装します。 DisplayPermissions – リクエストされたスコープのリストを使用してフォームを実装します。CSS を変更することで、外観や操作性をさらにカスタマイズできます。 CSS スタイルは DrawStyle メソッドで定義されます。loginForm は DisplayLogin フォーム用です。permissionForm は DisplayPermissions フォーム用です。

    <tr style="height:0px">
      <td>
        %OAuth2.Server.Validate
      </td>
      
      <td>
        CSP ページ
    

    これは、サーバーに含まれているデフォルトの Validate User Class(ユーザー検証クラス)です。 デフォルトのクラスは、認証サーバーが配置されている Cache またはIRISインスタンスのユーザーデータベースを使用してユーザーを検証します。 サポートされるプロパティは、issuer(Issuer)、role、sub(Username)です。Validate User Class は Authorization Server Configuration(認可サーバーの構成)で指定されます。 ユーザー名とパスワードの組み合わせを検証し、ユーザーに関連付けられたプロパティ一式を返す ValidateUser メソッドを含める必要があります。

    <tr style="height:0px">
      <td>
        %OAuth2.Server.Generate
      </td>
      
      <td>
        Registered Object(登録オブジェクト)
    

    %OAuth2.Server.Generate は、サーバーに含まれているデフォルトのGenerate Token Class(トークン生成クラス)です。 デフォルトのクラスは、ランダムな文字列を opaque アクセストークンとして生成します。Generate Token Class は、Authorization Server Configuration で指定されます。 ValidateUser メソッドによって返されるプロパティの配列に基づいてアクセストークンを生成するために使用される GenerateAccessToken メソッドを含める必要があります。

    <tr style="height:0px">
      <td>
        %OAuth2.Server.JWT
      </td>
      
      <td>
        Registered Object(登録オブジェクト)
    

    %OAuth2.Server.JWT は、サーバーに含まれている JSON Web トークンを作成する Generate Token Class です。 Generate Token Class は、Authorization Server Configuration で指定されます。 ValidateUser メソッドによって返されるプロパティの配列に基づいてアクセストークンを生成するために使用される GenerateAccessToken メソッドを含める必要があります。

    <tr style="height:0px">
      <td>
        %OAuth2.Utils
      </td>
      
      <td>
        Registered Object(登録オブジェクト)
    

    このクラスは、さまざまなエンティティのログの記録を実装します。 カスタマイズの章のサンプルコードに、可能な使用法を示しています。

    %OAuth2.Server.Authenticate

    次の画像に、OAuth 2.0 認可サーバー構成の対応するセクションを示します。

    OpenID Connect を JWT 形式の識別情報トークン(id_token)と共に使用する場合は、構成内のデフォルトの Generate Token Class である %OAuth2.Server.Generate%OAuth2.Server.JWT に置換してください。それ以外の場合は、デフォルトの Generate クラスのままにしてください。

    カスタマイズオプションについては、後で別の章で詳しく説明します。

    公開 API クラス

    公開 API クラスは、アプリケーション開発者が Web アプリケーションのメッセージフローに正しい値を渡し、アクセストークンの検証やイントロスペクションなどを実行するために使用されます。

    これらのクラスは %SYS.OAuth2 パッケージで実装されています。 次の表に、実装されているクラスの一部を掲載しています。

      <td>
        Registered Object(登録オブジェクト)
    

    %SYS.OAuth2.AccessToken クラスは、リソースサーバーへの認証にアクセストークンを使用できるようにするクライアント操作を定義します。基本となるトークンは、CACHESYS データベースの OAuth2.AccessToken に格納されます。 OAuth2.AccessToken は、SessionId と ApplicationName の組み合わせによってインデックス化されます。 したがって、SessionId/ApplicationName ごとに 1 つのスコープのみをリクエストできます。 2 回目のリクエストが別のスコープで行われ、アクセストークンがまだ付与されている場合は、新しいリクエストのスコープが予期されるスコープになります。

    <tr style="height:0px">
      <td>
        %SYS.OAuth2.Authorization
      </td>
      
      <td>
        Registered Object(登録オブジェクト)
    

    %SYS.OAuth2.Authorization クラスには、アクセストークンを取得してクライアントを認可するために使用される操作が含まれています。基本となるトークンは、CACHESYS データベースの OAuth2.AccessToken に格納されます。 OAuth2.AccessToken は、SessionId と ApplicationName の組み合わせによってインデックス化されます。 したがって、SessionId/ApplicationName ごとに 1 つのスコープのみをリクエストできます。 2 回目のリクエストが別のスコープで行われ、アクセストークンがまだ付与されている場合は、新しいリクエストのスコープが予期されるスコープになります。このクラスは CACHELIB にあるため、どこでも使用できることに注意してください。 ただし、トークンストレージは CACHESYS にあるため、ほとんどのコードでは直接使用できません。

    <tr style="height:0px">
      <td>
        %SYS.OAuth2.Validation
      </td>
      
      <td>
        Registered Object(登録オブジェクト)
    

    %SYS.OAuth2.Validation クラスは、アクセストークンの検証(または無効化)に使用されるメソッドを定義します。 基本となるトークンは、CACHESYS データベースの OAuth2.AccessToken に格納されます。 OAuth2.AccessToken は、SessionId と ApplicationName の組み合わせによってインデックス化されます。 したがって、SessionId/ApplicationName ごとに 1 つのスコープのみをリクエストできます。 2 回目のリクエストが別のスコープで行われ、アクセストークンがまだ付与されている場合は、新しいリクエストのスコープが予期されるスコープになります。

    %SYS.OAuth2.AccessToken

    このグループのいくつかのメソッドとクラスを詳しく見てみましょう。

    アクセストークンを使用するすべてのクライアントアプリケーションクラスは、その有効性をチェックする必要があります。 このチェックは、OnPage メソッド(または ZEN か ZENMojo ページの対応するメソッド)のどこかで実行されます。

    こちらがそのコードスニペットです。

     // OAuth2 サーバーからのアクセストークンがあるかどうかをチェックします。
     set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,"scope1,
         scope2",.accessToken,.idtoken,.responseProperties,.error)
    
     // アクセストークンがあるかどうかをさらにチェックします。
     // 以下は実行可能なすべてのテストであり、あらゆるケースで必要なわけではありません。
     // 各テストで返される JSON オブジェクトが単に表示されています。
     if isAuthorized {
        // 何らかの処理を実行します – リソースサーバーの API を呼び出して目的のデータを取得します。
     }
    

    リソースサーバーの API を呼び出すたびに、アクセストークンを提供する必要があります。 この処理は、%SYS.OAuth2.AccessToken メソッドの AddAccessToken メソッドによって実行されます。こちらがそのコードスニペットです。

     set httpRequest=##class(%Net.HttpRequest).%New()
      // AddAccessToken は現在のアクセストークンをリクエストに追加します。
      set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
        httpRequest,,
        ..#SSLCONFIG,
        ..#OAUTH2APPNAME)
     if $$$ISOK(sc) {
        set sc=httpRequest.Get(.. Service API url …)
     }
    

    この連載の前のパートで提供したサンプルコードでは、最初のアプリケーションページ(Cache1N)の OnPreHTTP メソッドでこのコードを確認することができました。 このコードは、アプリケーションの最初のページでアクセストークンチェックを実行するのに最適な場所です。

    ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
    {
     set scope="openid profile scope1 scope2"
        #dim %response as %CSP.Response
     if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,
        scope,.accessToken,.idtoken,.responseProperties,.error) {
          set %response.ServerSideRedirect="Web.OAUTH2.Cache2N.cls"
     }
     quit 1
    }

    上記のコードにある SYS.OAuth2.AccessToken クラスの IsAuthorized メソッドは有効なアクセストークンが存在するかどうかをチェックし、存在しない場合に認可サーバーの認証フォームを指すログインボタン/リンクを使用してページの内容を表示し、存在する場合に実際にデータ取得処理を実行する 2 番目のページにリダイレクトします。

    ただし、このコードは次のように変更できます。

    ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
    {
     set scope="openid profile scope1 scope2"
     set sc=##class(%SYS.OAuth2.Authorization).GetAccessTokenAuthorizationCode(
        ..#OAUTH2APPNAME,scope,..#OAUTH2CLIENTREDIRECTURI,.properties)
     quit +sc
    }

    この場合は、結果が異なります。 %SYS.OAuth2.Authorization クラスの GetAccessTokenAuthorizationCode メソッドを使用すると、アプリケーションの最初のページの内容を表示せずに、認可サーバーの認証フォームに直接移動します。

    これは、Web アプリケーションがモバイルデバイスのネイティブアプリケーションから呼び出され、一部のユーザー情報がネイティブアプリケーション(ランチャー)によってすでに表示されており、認可サーバーを指すボタンを含む Web ページを表示する必要がない場合に便利です。

    署名付き JWT トークンを使用する場合は、その内容を検証する必要があります。 この検証は次のメソッドで実行されます。

     set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(applicationName,accessToken,scope,,.jsonObject,.securityParameters,.sc)
    

    メソッドパラメーターの詳細については、Class Reference ドキュメントをご覧ください。

    カスタマイズ

    OAUTH が認証 / 承認 UI のカスタマイズ用に提供しているオプションについてもう少し説明します。

    勤務先のポリシーで、スコープの付与に関してより限定的な動作が要求されているとします。 たとえば、取引先銀行内のさまざまな金融システムに接続するホームバンキングアプリケーションを実行できるとしましょう。 銀行は、取得対象の実際の銀行口座に関する情報を含むスコープへのアクセスのみを許可します。 銀行は非常に多くの口座を運営しているため、すべての口座に静的なスコープを定義することは不可能です。 代わりに、認可処理中にその場でスコープを生成する処理をカスタム認可ページのコードに組み込むことができます。

    デモを行うため、ここではサーバー構成にもう 1 つのスコープを追加する必要があります。次の画像を参照してください。

    また、%OAuth2.Server.Authenticate.Bank という名前のカスタム Authenticate クラスへの参照も追加しました。

    では、銀行の認証クラスはどのようになるのでしょうか? 次は想定されるクラスの例です。 このクラスは、ユーザーが提供するデータを使用して標準の認証フォームと認可フォームを拡張します。 BeforeAuthenticateDisplayPermissionsAfterAuthenticate の各メソッド間を流れる情報は、%OAuth2.Server.Properties クラスの properties 変数によって渡されます。

    Class %OAuth2.Server.Authenticate.Bank Extends %OAuth2.Server.Authenticate
    {
    /// account(口座)のスコープに CUSTOM BESTBANK のサポートを追加します。
    ClassMethod BeforeAuthenticate(scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status
    {
     // 起動スコープが指定されていない場合は何もしません。
     If 'scope.IsDefined("account") Quit $$$OK
     // 起動クエリパラメーターから起動コンテキストを取得します。
     Set tContext=properties.RequestProperties.GetAt("accno")
     // コンテキストがない場合は何もしません。
     If tContext="" Quit $$$OK
        
     try {
        // ここで BestBank コンテキストを照会する必要があります。
        Set tBankAccountNumber=tContext
        // accno のスコープを追加します。 -> 動的にスコープを変更(account なし:<accno> スコープはサーバー構成に存在します)
        // この特定のスコープは、それが Cookie サポートを使用して account または account:accno によって
        // 以前に選択されていた場合に account 経由で同じ accno にアクセスできるようにするために使用されます。
        Do scope.SetAt("Access data for account "_tBankAccountNumber,"account:"_tBankAccountNumber)
        // 処理が終わった account のスコープはもう必要ありません。
        // これにより、account スコープが存在することで DisplayPermissions が強制的に呼び出されるのを防ぎます。
        Do scope.RemoveAt("account")
        
        // AfterAuthenticate が応答プロパティに変換する accno プロパティを追加します。
        Do properties.CustomProperties.SetAt(tBankAccountNumber,"account_number")
     } catch (e) {
        s ^dk("err",$i(^dk("err")))=e.DisplayString()
     }
     Quit $$$OK
    }
    
    /// account のスコープに CUSTOM BESTBANK のサポートを追加します。
    /// account_number カスタムプロパティが BeforeAuthenticate(account)または
    /// DisplayPermissions(account:accno)によって追加された場合は、必要な応答プロパティを追加します。
    ClassMethod AfterAuthenticate(scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status
    {
     // account_number(account)または accno(account:accno)プロパティが存在しない限り、ここで実行することは何もありません。
     try {
        // カスタムログを記録する例
        If $$$SysLogLevel>=3 {
         Do ##class(%OAuth2.Utils).LogServerScope("log ScopeArray-CUSTOM BESTBANK",%token)
        }
        If properties.CustomProperties.GetAt("account_number")'="" {
         // 応答に accno クエリパラメーターを追加します。
         Do properties.ResponseProperties.SetAt(properties.CustomProperties.GetAt("account_number"),"accno")
        }
     } catch (e) {
        s ^dk("err",$i(^dk("err")))=e.DisplayString()
     }
     Quit $$$OK
    }
    
    /// BEST BANK の account のテキストを含むように変更された DisplayPermissions
    ClassMethod DisplayPermissions(authorizationCode As %String, scopeArray As %ArrayOfDataTypes, currentScopeArray As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status
    {
     Set uilocales = properties.RequestProperties.GetAt("ui_locales")
     Set tLang = ##class(%OAuth2.Utils).SelectLanguage(uilocales,"%OAuth2Login")
     // $$$TextHTML(Text,Domain,Language)
     Set ACCEPTHEADTITLE = $$$TextHTML("OAuth2 Permissions Page","%OAuth2Login",tLang)
     Set USER = $$$TextHTML("User:","%OAuth2Login",tLang)
     Set POLICY = $$$TextHTML("Policy","%OAuth2Login",tLang)
     Set TERM = $$$TextHTML("Terms of service","%OAuth2Login",tLang)
     Set ACCEPTCAPTION = $$$TextHTML("Accept","%OAuth2Login",tLang)
     Set CANCELCAPTION = $$$TextHTML("Cancel","%OAuth2Login",tLang)
     &html<<html>>
     Do ..DrawAcceptHead(ACCEPTHEADTITLE)
     Set divClass = "permissionForm"
     Set logo = properties.ServerProperties.GetAt("logo_uri")
     Set clientName = properties.ServerProperties.GetAt("client_name")
     Set clienturi = properties.ServerProperties.GetAt("client_uri")
     Set policyuri = properties.ServerProperties.GetAt("policy_uri")
     Set tosuri = properties.ServerProperties.GetAt("tos_uri")
     Set user = properties.GetClaimValue("preferred_username")
     If user="" {
        Set user = properties.GetClaimValue("sub")
     }
     &html<<body>>
     &html<<div id="topLabel"></div>>
     &html<<div class="#(divClass)#">>
     If user '= "" {
        &html<
         <div>
         <span id="left" class="userBox">#(USER)#<br>#(##class(%CSP.Page).EscapeHTML(user))#</span>
         >
     }
     If logo '= "" {
        Set espClientName = ##class(%CSP.Page).EscapeHTML(clientName)
       &html<<span class="logoClass"><img src="#(logo)#" alt="#(espClientName)#" title="#(espClientName)#" align="middle"></span>>
     }
     If policyuri '= "" ! (tosuri '= "") {
       &html<<span id="right" class="linkBox">>
        If policyuri '= "" {
         &html<<a href="#(policyuri)#" target="_blank">#(POLICY)#</a><br>>
        }
        If tosuri '= "" {
         &html<<a href="#(tosuri)#" target="_blank">#(TERM)#</a>>
        }
       &html<</span>>
     }
     &html<</div>>
     &html<<form>>
     Write ##class(%CSP.Page).InsertHiddenField("","AuthorizationCode",authorizationCode),!
     &html<<div>>
     If $isobject(scopeArray), scopeArray.Count() > 0 {
        Set tTitle = $$$TextHTML(" is requesting these permissions:","%OAuth2Login",tLang)
       &html<<div class="permissionTitleRequest">>
        If clienturi '= "" {
         &html<<a href="#(clienturi)#" target="_blank">#(##class(%CSP.Page).EscapeHTML(clientName))#</a>>
        } Else {
         &html<#(##class(%CSP.Page).EscapeHTML(clientName))#>
        }
       &html<#(##class(%CSP.Page).EscapeHTML(tTitle))#</div>>
        Set tCount = 0
        Set scope = ""
        For {
         Set display = scopeArray.GetNext(.scope)
         If scope = "" Quit
         Set tCount = tCount + 1
         If display = "" Set display = scope
         Write "<div class='permissionItemRequest'>"_tCount_". "_##class(%CSP.Page).EscapeHTML(display)_"</div>"
        }
     }
    
     If $isobject(currentScopeArray), currentScopeArray.Count() > 0 {
        Set tTitle = $$$TextHTML(" already has these permissions:","%OAuth2Login",tLang)
       &html<<div>>
       &html<<div class="permissionTitleExisting">>
        If clienturi '= "" {
         &html<<a href="#(clienturi)#" target="_blank">#(##class(%CSP.Page).EscapeHTML(clientName))#</a>>
        } Else {
         &html<#(##class(%CSP.Page).EscapeHTML(clientName))#>
        }
       &html<#(##class(%CSP.Page).EscapeHTML(tTitle))#</div>>
        Set tCount = 0
        Set scope = ""
        For {
         Set display = currentScopeArray.GetNext(.scope)
         If scope = "" Quit
         Set tCount = tCount + 1
         If display = "" Set display = scope
         Write "<div class='permissionItemExisting'>"_tCount_". "_##class(%CSP.Page).EscapeHTML(display)_"</div>"
        }
       &html<</div>>
     }
    
     /*********************************/
     /*  BEST BANK CUSTOMIZATION      */
     /*********************************/
     try {
        If properties.CustomProperties.GetAt("account_number")'="" {
         // Display the account number obtained from account context.
         Write "<div class='permissionItemRequest'><b>Selected account is "_properties.CustomProperties.GetAt("account_number")_"</b></div>",!
    
         // or, alternatively, let user add some more information at this stage (e.g. linked account number)
         //Write "<div>Account Number: <input type='text' id='accno' name='p_accno' placeholder='accno' autocomplete='off' ></div>",!
        }
     } catch (e) {
        s ^dk("err",$i(^dk("err")))=e.DisplayString()
     }
    
     /* original implementation code continues here... */
     &html<
       <div><input type="submit" id="btnAccept" name="Accept" value="#(ACCEPTCAPTION)#"/></div>
       <div><input type="submit" id="btnCancel" name="Cancel" value="#(CANCELCAPTION)#"/></div>
        >
     &html<</form>
     </div>>
     Do ..DrawFooter()
     &html<</body>>
     &html<<html>>
     Quit 1
    }
    
    /// CUSTOM BESTBANK の場合、入力された患者を検証する必要があります。
    /// ! このメソッドの javascript はユーザーに追加データを DisplayPermissions メソッド内
    /// で入力させる場合にのみ必要です !
    ClassMethod DrawAcceptHead(ACCEPTHEADTITLE)
    {
     &html<<head><title>#(ACCEPTHEADTITLE)#</title>>
     Do ..DrawStyle()
     &html<
     <script type="text/javascript">
     function doAccept()
     {
        var accno = document.getElementById("accno").value;
        var errors = "";
        if (accno !== null) {
         if (accno.length < 1) {
           errors = "Please enter account number name";
         }
        }
        if (errors) {
         alert(errors);
         return false;
        }
        
        // submit the form
        return true;
     }
     </script>
     >
     &html<</head>>
    }
    
    }
    
    

    ご覧のとおり、%OAuth2.Server.Properties クラスにはいくつかの配列が含まれており、渡されています。 具体的には、以下の配列です。

    ·        RequestProperties – 認可リクエストのパラメーターが含まれています。

    ·        CustomProperties – 上記のコードの間でデータをやり取りするためのコンテナ。

    ·        ResponseProperties – トークンリクエストに対する JSON 応答オブジェクトに追加されるプロパティのコンテナ。

    ·        ServerProperties – 認可サーバーがカスタマイズコードに公開する共有プロパティが含まれます(logo_uri、client_uri など…)

    さらに、認可サーバーが返す必要のあるクレームを指定するのに使用されるいくつかの "claims" プロパティが含まれています。

    この認証ページを正しく呼び出すため、最初のクライアントページのコードを次のように変更しました。

     set scope="openid profile scope1 scope2 account"
     // このデータはアプリケーションに由来し(フォームデータなど)、リクエストのコンテキストを設定します。
     // ここでは Authenticate クラスをサブクラス化することで、このデータをユーザーに表示することができます。
     // それにより、該当ユーザーはアクセスを許可するかどうかを決めることができます。
     set properties("accno")="75-452152122-5320"
     set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
       ..#OAUTH2APPNAME,
        scope,
       ..#OAUTH2CLIENTREDIRECTURI,
        .properties,
       .isAuthorized,
        .sc)
     if $$$ISERR(sc) {
        write "GetAuthorizationCodeEndpoint Error="
       write ..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!
     }

    ご覧のとおり、ここではアプリケーションのさまざまな部分から発生する可能性のあるコンテキスト値を使用して account のスコープとプロパティ配列ノード “accno” を追加しました。 この値はアクセストークンの内部でリソースサーバーに渡され、さらに処理されます。

    上記のロジックは、電子的な患者記録を交換するための FHIR 標準で実際に使用されています。

    デバッグ

    OAUTH フレームワークには、デバッグ機能が組み込まれています。 クライアントとサーバー間の通信はすべて暗号化されているため、これは非常に便利です。 デバッグ機能を使用すると、API クラスによって生成されたトラフィックデータをネットワーク経由で送信する前にキャプチャできます。 コードをデバッグするため、以下のコードに従って単純なルーチンまたはクラスを実装できます。 InterSystems IRIS インスタンスのすべての通信でこのコードを実装する必要があることに注意してください! その場合、OAUTH フローのプロセス内での役割を示す名前をファイル名に指定することをお勧めします。 (以下のサンプルコードは rr.mac ルーチンとして保存されていますが、どんな名前を付けるかはあなた次第です。)

     // d start^rr()
    start() public {
     new $namespace
     set $namespace="%sys"
     kill ^%ISCLOG
     set ^%ISCLOG=5
     set ^%ISCLOG("Category","OAuth2")=5
     set ^%ISCLOG("Category","OAuth2Server")=5
     quit
    }
    
     // d stop^rr()
    stop() public {
     new $namespace
     set $namespace="%sys"
     set ^%ISCLOG=0
     set ^%ISCLOG("Category","OAuth2")=0
     set ^%ISCLOG("Category","OAuth2Server")=0
     quit
    
    }
    
     // display^rr()
    display() public {
     new $namespace
     set $namespace="%sys"
     do ##class(%OAuth2.Utils).DisplayLog("c:\temp\oauth2_auth_server.log")
     quit
    }

    次に、テストを開始する前にターミナルを開き、すべての InterSystems IRIS ノード(クライアント、認可サーバー、リソースサーバー)で d start^rr() を呼び出してください。 完了後、d stop^rr() d display^rr() を実行してログファイルを読み込んでください。

    最後に

    この連載記事では、InterSystems IRIS OAuth 2.0 の実装を使用する方法を学びました。 パート1では簡単なクライアントアプリケーションのデモを行い、パート2では複雑な例を説明しました。 最後に、OAuth 2.0 の実装で最も重要なクラスについて説明し、ユーザーアプリケーション内でそれらを呼び出す必要がある場合について説明しました。

    時々私が投げかけるくだらない質問に我慢強く回答し、この連載をレビューしてくれた Marvin Tener に心から感謝の意を表します。

     

    0
    0 374