Node.jsアプリケーションとOracle Identity Cloud Service間の認証について学習

Node.js WebアプリケーションとOracle Identity Cloud Service間の認証について学習する準備ができました。これには、次の内容の理解が含まれます。

  • Oracle Identity Cloud ServiceがNode.js SDKに対してサポートする3-legged認証フロー

  • Node.jsアプリケーションでSDKを使用してOracle Identity Cloud Serviceで認証する場合のユース・ケース

  • Node.js SDKのメソッドおよび関数

3-Legged認証フローについて学習

Oracle Identity Cloud Serviceでは、Node.js SDKの3-legged認証フローがサポートされています。このフローでは、ユーザーはOracle Identity Cloud Serviceと直接対話します。ユーザーがサインインすると、Oracle Identity Cloud Serviceは、SDKがユーザー・アクセス・トークンと交換する認可コードを発行します。Node.js Webアプリケーションは、このアクセス・トークンを使用して、アプリケーション内の保護されたリソースへのアクセス権をユーザーに付与します。3-leggedフローでは、認可コード付与タイプが使用されます。

セキュリティを強化するために、Oracleでは、3レッグ・フローを使用して、認証のためにNode.js WebアプリケーションをOracle Identity Cloud Serviceと統合することをお薦めします。認可コード付与タイプを使用すると、再認証しなくても、Oracle Identity Cloud Serviceによって保護されている他のアプリケーションにアクセスすることもできます。

Node.jsアプリケーションでSDKを使用するための主なユースケースについて学習

Node.js Webアプリケーションは、2つのユースケースを実装します。1つはユーザーの認証用、もう1つはログイン・ユーザーに関する詳細情報へのアクセス用です。

次のデータ・フロー図は、各ユース・ケースのWebブラウザ、WebアプリケーションおよびOracle Identity Cloud Service間のイベント、コールおよびレスポンスのフローを示しています。

ユースケース1: ユーザーの認証

データ・フローは次のようになります。

  1. ユーザーが保護されたリソースをリクエストします。

  2. 認証モジュールは、SDKを使用してOracle Identity Cloud Serviceのrequest-authorization-code URLを生成し、このURLをWebブラウザへのリダイレクト・レスポンスとして送信します。

  3. WebブラウザがURLをコールします。

  4. Oracle Identity Cloud Service「サインイン」ページが表示されます。

  5. ユーザーがOracle Identity Cloud Serviceのサインイン資格証明を送信します。

  6. ユーザーがサインインすると、Oracle Identity Cloud Serviceによってユーザーのセッションが作成され、認可コードが発行されます。

  7. Webアプリケーションは、認可コードをアクセス・トークンと交換するためのバックエンド(またはサーバー間)呼出しを行います。

  8. Oracle Identity Cloud Serviceは、アクセス・トークンとIDトークンを発行します。

  9. セッションが確立され、ユーザーはホーム・ページにリダイレクトされます。

  10. Webアプリケーションの「ホーム」ページが表示されます。

ユースケース2: ユーザーの詳細の取得

データ・フローは次のようになります。

  1. ユーザーは/myProfileリソースをリクエストします。

  2. Webアプリケーションは、Oracle Identity Cloud ServiceのSDKを使用してIDトークンを検証します。

  3. IDトークン検証から返されるデータには、JSONオブジェクトの形式でユーザーの詳細が含まれます。

  4. 「マイ・プロファイル」ページでは、JSONオブジェクトがHTMLコンテンツとしてレンダリングされます。

メソッドおよび関数について学習

Node.js SDKは、Node.js modulesフォルダに追加するNode.jsパスポート戦略です。このSDKは、Node.js Promiseにも基づいています。

Node.js SDKで必要なすべてのサード・パーティの依存関係は、Oracle Identity Cloud ServiceコンソールからダウンロードするNode.js SDK zipファイル内のSDKの package.jsonファイルで定義されます。Node.js Webアプリケーションで、少なくともこのモジュール・セットを使用する必要があります。

"dependencies": {
    "async": "^2.1.2",
    "bunyan": "^1.8.5",
    "cache-manager": "^2.2.0",
    "json-web-token": "^2.1.3",
    "jsonwebtoken": "^8.2.1",
    "jwk-to-pem": "^1.2.6",
    "jws": "^3.1.5",
    "lru": "^3.1.0",
    "passport": "^0.4.0",
    "promise": "^8.0.1",
    "querystring": "^0.2.0",
    "request": "^2.81.0",
    "rsa-pem-to-jwk": "^1.1.3",
    "util": "^0.10.3"
  },

Node.js Webアプリケーションは、URLごとにapp.get()関数の形式でURLルートを実装するNode.js expressおよびexpress-handlebarsモジュールを使用して開発されました。

Node.js SDKには、Oracle Identity Cloud Service接続情報とともにロードされるJSON変数が必要です。Node.js Webアプリケーションでは、ids変数を使用して次の情報を格納します。

var ids = {
    oracle: {
    "ClientId": "123456789abcdefghij'",
    "ClientSecret": "abcde-12345-zyxvu-98765-qwerty",
    "ClientTenant": "idcs-abcd1234",
    "IDCSHost": "https://%tenant%.identity.oraclecloud.com",
    "AudienceServiceUrl" : "https://idcs-abcd1234.identity.oraclecloud.com",
    "TokenIssuer": "https://identity.oraclecloud.com/",
    "scope": "urn:opc:idm:t.user.me openid",
    "logoutSufix": "/oauth2/v1/userlogout",
    "redirectURL": "http://localhost:3000/callback",
    "LogLevel":"INFO",
    "ConsoleLog":"True"
    }
};
module.exports = ids;

次に、このSDKの各必須属性の簡単な説明を示します:

名前 説明
ClientId Oracle Identity Cloud ServiceコンソールでNode.js Webアプリケーションを登録した後に生成されるクライアントIDの値。
ClientSecret Oracle Identity Cloud ServiceコンソールでNode.js Webアプリケーションを登録した後に生成されるクライアント・シークレットの値。
ClientTenant Oracle Identity Cloud Serviceインスタンスのドメイン接頭辞。通常、この接頭辞はidcs-abcd1234に似ています。
IDCSHost Oracle Identity Cloud Serviceインスタンスのドメイン接尾辞。実行時には、%tenant%プレースホルダがClientTenant属性の値に置き換えられます。
AudienceServiceUrl Oracle Identity Cloud Serviceインスタンスの完全修飾ドメイン名URL。
TokenIssuer この属性については、Oracleでは値https://identity.oraclecloud.com/を保持することをお薦めします。
scope

スコープは、アプリケーションがOracle Identity Cloud Serviceユーザーのかわりにアクセスまたは処理できるデータを制御します。

アプリケーションがSDKを使用してユーザーを認証する場合、スコープはopenidです。アプリケーションがSDKを使用してユーザーの詳細を取得する場合、スコープはurn:opc:idm:t.user.me openidです。

ConsoleLog SDKログを有効にします。
LogLevel SDKのログ・レベルを示します。

アプリケーションは、logoutSufix属性とredirectURL属性の両方を使用して、これらの値をハード・コードしないようにします。SDKには必要ありません。

Node.jsアプリケーションは、/oauth/oracle URLルートを実装します。ユーザーがOracle Identity Cloud Serviceで認証されると、WebブラウザはこのURLに対してGETリクエストを行います。このルートでは、SDKを使用してOracle Identity Cloud Serviceの認可URLが生成されます。

//Loading the configurations
var auth = require('./auth.js');
 
//Route for /oauth/oracle
app.get("/auth/oracle", function(req, res){
    //Authentication Manager loaded with the configurations.
    am = new IdcsAuthenticationManager(auth.oracle);
    //Using Authentication Manager to generate the Authorization Code URL, passing the
    //application's callback URL as parameter, along with code value and code parameter.
    am.getAuthorizationCodeUrl(auth.oracle.redirectURL, auth.oracle.scope, "1234", "code")
        .then(function(authZurl){
            //Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
            res.redirect(authZurl);
        }).catch(function(err){
            res.end(err);
        })
});

このファンクションは、JSONパラメータを変数にロードし、認証マネージャを初期化し、Node.js SDKのIdcsAuthenticationManager.getAuthorizationCodeUrl()関数を使用して認可コードURLを生成します。この関数は、promiseを使用して、認可コードURLの生成時にユーザーのWebブラウザをリダイレクトするか、ブラウザでエラーをレンダリングします。

認可コードURLの生成には、次のパラメータが使用されます。

名前 説明
auth.oracle.redirectURL ユーザーがサインインすると、Oracle Identity Cloud ServiceによってユーザーのWebブラウザがこのURLにリダイレクトされます。このURLは、Identity Cloud Serviceコンソールで信頼できるアプリケーション用に構成するURLと一致する必要があります。Node.js WebアプリケーションのリダイレクトURLの指定の詳細は、Node.jsアプリケーションの登録を参照してください。
auth.oracle.scope 認証のOAuthまたはOpenID Connectスコープ。このアプリケーションでは、openid認証のみが必要です。
state OAuthプロトコルは、このパラメータを定義します。サンプルNode.js Webアプリケーションでは、このコードを使用して、Oracle Identity Cloud Serviceへの通信を確立できるかどうかを確認します。この例では、このパラメータの値は1234です。
response_type 認可コード付与タイプに必要なパラメータ。この例では、このパラメータの値はcodeです。

ユーザーがサインインすると、Oracle Identity Cloud Serviceは、開発者が実装する必要があるコールバックURLにユーザーのWebブラウザをリダイレクトします。Node.js Webアプリケーションは、/callbackルートを使用してこのリクエストを処理します。

//Route for /callback
app.get("/callback", function(req,res){
    //Authentication Manager loaded with the configurations.
    var am = new IdcsAuthenticationManager(auth.oracle);
    //Getting the authorization code from the "code" parameter
    var authZcode = req.query.code;
    //Using the Authentication Manager to exchange the Authorization Code to an Access Token.
    am.authorizationCode(authZcode)
        .then(function(result){
            //Getting the Access and Id Token Values to set in the session.
            req.session.access_token = result.access_token;
            req.session.id_token = result.id_token;
            res.cookie(config.IDCS_COOKIE_NAME, result.access_token);
            res.header('idcs_user_assertion', result.access_token)
            res.redirect('/auth.html');
        }).catch(function(err){
            res.end(err);
        })
});

Node.jsアプリケーションは、認可コードを使用してアクセス・トークンをリクエストします。アクセス・トークンはCookieとして格納され、その後、将来の使用のためにWebブラウザに送信されます。

Node.js SDKのIdcsAuthenticationManager.authorizationCode()関数は、promise (then-catch文)を使用してアクセス・トークンをCookieとして設定し、ブラウザを/auth.htmlページにリダイレクトします。

Node.js SDKは、Node.jsパスポート・フレームワークに基づいています。そのため、ブラウザはアクセス・トークンをヘッダー変数として/auth URLハンドラに転送し、Oracle Identity Cloud Service戦略名をパラメータとしてpassport.authenticate()メソッドを使用する必要があります。

//Uses passport to create a User Session in Node.js.
//Passport sets a user attribute in the request as a json object.
app.get('/auth', passport.authenticate(config.IDCS_STRATEGY_NAME, {}), function(req, res) {
   res.redirect('/home');
});

passport.authenticate()メソッドがアプリケーションのセッションを作成した後、ファンクションはユーザーのWebブラウザを/homeアプリケーションの保護されたURLにリダイレクトします。/homeに加えて、Node.js Webアプリケーションには、/myProfileという別の保護されたURLがあります。

保護されたURLは、ユーザーのセッションが以前に作成されたかどうかを確認する必要があります。これらのURLの各app.get()関数では、次の関数が使用されます。

function ensureAuthenticated(req, res, next) {
   if (req.isAuthenticated()) {
      return next();
   }
   res.redirect('/login')
}

Node.jsアプリケーションは、次のように/myProfileルートを処理し、セッションで設定された情報を取得します。

app.get("/myProfile", ensureAuthenticated, function(req,res){
   //User Manager loaded with the configurations
   var am = new IdcsAuthenticationManager(auth.oracle);
   //Validating id token to acquire information such as UserID, DisplayName, list of groups and AppRoles assigned to the user.
   am.validateIdToken(req.session['id_token'])
    .then(function(idToken){
      res.render('myProfile', {
         layout: 'privateLayout',
         title: 'My Profile',
         user: req.user,
         userInfo: JSON.stringify(idToken, null, 2)
         });
    }).catch(function(err1){
       res.end(err1);
   })
});

IdcsAuthenticationManagerオブジェクトの初期化後、/myProfileルートのハンドラは、SDKのIdcsAuthenticationManager.validateIdToken()関数を使用して、表示名、ユーザーID、ユーザーに割り当てられたグループおよびアプリケーション・ロールのリストなどのユーザー情報を取得します。JSONオブジェクトは、WebブラウザでレンダリングするためにmyProfile.handlebarsファイルに文字列として解析されます。

アプリケーションとOracle Identity Cloud Service間のシングル・サインオンからユーザーをサインアウトするために、Node.js Webアプリケーションは、次のように/logoutルートを実装します。

app.get('/logout', function(req, res){
  var id_token = req.session.id_token;
  var logouturl = auth.oracle.AudienceServiceUrl + auth.oracle.logoutSufix + '?post_logout_redirect_uri=http%3A//localhost%3A3000&id_token_hint='+ id_token;
  req.session.destroy(function(err) {
    if(err) {
      console.log(err);
    } else {
      req.logout();
      res.clearCookie();
      res.redirect(logouturl);
    }
  })
});

このルートにより、アプリケーションのセッションが無効になり、以前に設定されたオブジェクトおよびCookieが削除されてから、ユーザーのWebブラウザがOracle Identity Cloud ServiceのOAuthログアウトURLにリダイレクトされます。