2019年7月26日金曜日

Domino の CORS 対応

CORS (Cross-Origin Resource Sharing)とは、ブラウザがHTMLを読み込んだサーバー(オリジン)以外のサーバーのデータへのアクセスを可能にするための仕組みのことです。

たとえば、node.js アプリを実行中のサーバーへブラウザでアクセスすると、アプリが HTML を返します。そのHTMLに書かれた JavaScript が(オリジンが異なる)Domino サーバー上のデータへ REST API でアクセスしようとします。この時 Domino 側で node.js アプリからのアクセスを許可する設定を行なっていない場合、ブラウザ側でブロックする、というものです。

実際このような構成で、何も対策していない Domino を使ってテストしてみたところ 401 Unauthorized となりました。
※上の画像でメソッドが GET でなく OPTIONS になっていますが、これはプリフライト(サーバーから対応するメソッドの一覧を収集すること)によるものと思います

今回テスト環境として用意した node.js 側のアプリ「app.js」と、そこから呼び出す「index.html」の内容は次のとおりです。

「app.js」の内容
const app = require('express')();
const http = require('http').Server(app);

http.listen(3000, () => console.log('Server started'))

app.get('/', function(req, res) {
    res.sendFile(__dirname + '/index.html')
})


「index.html」の内容
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>10.0.1 FP2 CORS Test</title>
    <script type="text/javascript">
 function firstscript() {
      var url = 'http://localhost/statpub.nsf/api/data/collections';
      var req = new XMLHttpRequest();
      req.open( 'GET', url);
      req.onreadystatechange = function() {
        if(req.readyState === 4 && req.status === 200) {
          var element = document.getElementById('corstest');
          element.innerHTML = '<pre>' + req.responseText + '</pre>';
        }
      };
      var authBasic = window.btoa('testuser:password');
      req.setRequestHeader('Authorization', 'Basic ' + authBasic);
      req.send();
    }
    </script>
  </head>
  <body onload="firstscript();">
    <div id="corstest">test</div>
  </body>
</html>


node.js のアプリは ポート 3000番を指定しています。Domino の HTTP タスクはデフォルトのままですので 80 番が使用されます。
どちらも同じPC上で稼働しているため、ホストは localhost です。
しかしながらオリジンは「スキーム(http://)」、「ホスト(localhost)」、「ポート」の組み合わせですので node.js の http://localhost:3000 と Domino の http://localhost は同一オリジンとはなりません。


そこで、ブラウザが CORS によりブロックしないよう、Domino 側で CORS への対応を実施することが必要になります。

CORS への対応とは、許可する「オリジン」や「メソッド」等を設定することです。

Domino へアクセスした時、Domino はオリジンやメソッド等が許可されたものであるかを確認します。それらが許可しているものであれば、許可していることを示すヘッダー情報をブラウザへ返します。


さて、Domino のオンラインヘルプによれば、Domino 10.0.1 Fix Pack 2 以降で CORS に対応する、とあります。


実はそれまでのバージョンでも、Webサイトルール文書を作成することによって対応可能だったようです。
smaconne の利用マニュアルには「複数の IBM Domino サーバーを利用する場合のサーバー設定」として記載があります。※光安様、情報ありがとうございます。
また smaconne ではありませんが、Webサイトルール文書を使って設定する際の参考となりそうな情報はこちらにもありました。10.0.1 FP2 以前の Domino をご利用の場合は参考になるのではないでしょうか。

では FP2 ではどのようにして許可の設定を行うのでしょうか。

設定方法はこちらにありますが、次の3つの手順を踏みます。

  1. サーバー文書で CORS を有効にする
  2. CORS のルールを記述したファイル(ファイル名: cors-rules.json)を作成し、Domino\Data\Domino\CORS フォルダへ保存する
  3. HTTP タスクを再起動する

サーバー文書の設定は、Internet Protocols タブ - HTTP タブ - DSAPI のくくりにある 「DSAPI filter file name」に ncorsext を追加します。

手順の2番目で作成する json ファイルのサンプルはこちらにあります。

今回テスト環境用に作成した、CORS のルールを記述したファイル「cors-rules.json」の内容は次のとおりです。
{
  "version": "1.0",
  "rules": [
    {
      "resource": {
        "path": "/api/data/collections"
      },
      "allowOrigins": [ "http://localhost:3000" ],
      "allowMethods": [ "GET" ],
      "allowCredentials": true
    }
  ]
}


node.js アプリのオリジン「http://localhost:3000」から Domino の 「/api/data/collections」への GET 要求を許可しています。


CORS のルールが HTTP タスク起動時に正常にロードされると、コンソールに次のように表示されました。
2019/07/26 15:07:04   HTTP Server: DSAPI CORS Filter Loaded successfully

参考までに json ファイルに誤りがあった際にコンソールに表示されたメッセージがこちらです。
2019/07/25 20:45:11.36 cors::InitConfig> Unable to parse configuration C:\IBM\Domino\data\domino\cors\cors-rules.json
2019/07/25 20:45:11   HTTP Server: Failed to load DSAPI module ncorsext
※上で紹介しました「json ファイルのサンプル」のページに記載されている例には、不要なカンマが含まれており、そのままコピーするとロードに失敗します...

以上の設定を行い、http://localhost:3000 へアクセスしたところ、オリジンが異なる Domino (http://localhost)のデータにアクセスすることができ、取得したデータが表示されました。
左側が取得できた json を表示したもの。右側は取得した際のデバッグ情報

CORS に対応できたことが確認できました。


試しに CORS のルールで、allowOrigins のポート番号を変えたり、allowMethods を POST に変えたりしてみたところ、一致するルールが無いため 401 Unauthorized となりました。

なお allowMethods に "OPTIONS" も追加したほうが良いのかもしれませんが、今回の環境ではあってもなくても変化が見られませんでした。

0 件のコメント:

コメントを投稿