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

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

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

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

  • Python SDKのメソッドおよび関数

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

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

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

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

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

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

図- ユースケース1: ユーザー認証

図の説明が続きます
「図- ユースケース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: ユーザーの詳細の取得

図の説明が続きます
「図- ユースケース2: ユーザー詳細の取得」の説明

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

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

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

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

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

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

Python SDKは、Webアプリケーションに含める必要がある2つのpythonファイルIdcsClient.pyおよびConstants.pyとして使用できます。

これらのpythonファイルは、アプリケーションにも含める必要があるサード・パーティ・ライブラリに依存します。これらを含めるには、SDK zipファイルを開き、README.txtファイルとrequirements.txtファイルの両方を一時フォルダに抽出して、pip install -r requirements.txtコマンドを実行します。

サンプルWebアプリケーションは、関数の形式でURLルートを実装するPython DJangoフレームワークを使用して開発されました。

Python SDKには、Oracle Identity Cloud Service接続情報とともにロードされるJSON変数が必要です。Python Webアプリケーションは、次の情報を提供するconfig.jsonファイルを使用します。

{
   "ClientId" : "123456789abcdefghij",
   "ClientSecret" : "abcde-12345-zyxvu-98765-qwerty",
   "BaseUrl" : "https://idcs-abcd1234.identity.oraclecloud.com",
   "AudienceServiceUrl" : "https://idcs-abcd1234.identity.oraclecloud.com",  
   "scope" : "urn:opc:idm:t.user.me openid",
   "TokenIssuer" : "https://identity.oraclecloud.com/",
   "redirectURL": "http://localhost:8000/callback",
   "logoutSufix":"/oauth2/v1/userlogout",
   "LogLevel":"INFO",
   "ConsoleLog":"True" 
}

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

表- Python SDKに必要な属性

属性名 属性の説明
ClientId Oracle Identity Cloud Serviceコンソールを使用してWebアプリケーションを登録した後に生成されるクライアントIDの値。
ClientSecret Oracle Identity Cloud Serviceコンソールを使用してWebアプリケーションを登録した後に生成されるクライアント・シークレットの値。
BaseUrl Oracle Identity Cloud ServiceインスタンスのドメインURL。
AdminServiceUrl Oracle Identity Cloud Serviceインスタンスのドメイン名URL。通常はBaseUrlと同じです。
TokenIssuer ここに示した値を保持します。
scope スコープによって、ユーザーがアクセスまたは処理できるデータが制御されます。アプリケーションは認証にSDKを使用するため、スコープはopenidです。アプリケーションはget user detailsユースケースも実装します。このユースケースでは、スコープurn:opc:idm:t.user.meも使用する必要があります。
ConsoleLog SDKログを有効にします。
LogLevel SDKのログ・レベルを示します。

logoutSufix属性とredirectURL属性はどちらもアプリケーションで使用されます。そのため、SDKでは必要ありません。

アプリケーションは、/auth URLをマップするauth関数定義を実装します。ユーザーがOracle Identity Cloud Serviceで認証されると、ブラウザはこのURLに対してリクエストを行います。

auth関数は、認証マネージャを初期化し、JSON構成属性をパラメータとして使用し、SDKを使用してOracle Identity Cloud Service認可コードURLを生成してから、ブラウザをこのURLにリダイレクトします。

#Loading the SDK Python file.
from . import IdcsClient
 
#Function used to load the configurations from the config.json file
def getOptions():
    fo = open("config.json", "r")
    config = fo.read()
    options = json.loads(config)
    return options
 
# Definition of the /auth route
def auth(request):
    #Loading the configurations
    options = getOptions()
    print "config.json file = %s" % options
    #Authentication Manager loaded with the configurations.   
    am = IdcsClient.AuthenticationManager(options)
    #Using Authentication Manager to generate the Authorization Code URL, passing the 
    #application's callback URL as parameter, along with code value and code parameter.    
    url = am.getAuthorizationCodeUrl(options["redirectURL"], options["scope"], "1234", "code")
    #Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
    return HttpResponseRedirect(url)

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

表- 認可コードURLの生成に使用されるパラメータ

パラメータ名 パラメータの説明
options["redirectURL"] サインインに成功すると、Oracle Identity Cloud ServiceはユーザーのWebブラウザをこのURLにリダイレクトします。このURLは、Oracle Identity Cloud Serviceコンソールで信頼できるアプリケーション用に構成するURLと一致する必要があります。
options["scope"] 認証のOAuthまたはOpenID Connectスコープ。このアプリケーションでは、openid認証のみが必要です。
state Webアプリケーションは、このコードを使用して、Oracle Identity Cloud Serviceへの通信を確立できるかどうかを確認します。このパラメータは、OAuthプロトコルによって定義されます。
response_type 認可コード付与タイプに必要な値(codeなど)。

callback関数は、認可コードURLパラメータを使用して、アクセス・トークンおよびIDトークンをリクエストします。どちらのトークンも、将来使用するためにユーザーセッションに格納されます。

# Definition of the /callback route
def callback(request):
   code = request.GET.get('code')
   #Authentication Manager loaded with the configurations.
   am = IdcsClient.AuthenticationManager(getOptions())
   #Using the Authentication Manager to exchange the Authorization Code to an Access Token.
   ar = am.authorizationCode(code)
   #Get the access token as a variable    
   access_token = ar.getAccessToken()    
   id_token = ar.getIdToken()

   #Validating id token to acquire information such as UserID, DisplayName, list of groups 
   #and AppRoles assigned to the user    
   id_token_verified = am.verifyIdToken(id_token)

   displayname = id_token_verified.getDisplayName()
   #The application then adds these information to the User Session.
   request.session['access_token'] = access_token
   request.session['id_token'] = id_token
   request.session['displayname'] = displayname
   #Rendering the home page and adding displayname to be printed in the page.
   return render(request,'sampleapp/home.html', {'displayname': displayname})

myProfileファンクションは、ユーザーのIDトークンにアクセスし、AuthenticationManager verifyIdTokenファンクションをコールして、ユーザーに割り当てられた名前、グループおよびアプリケーションなどのユーザーの情報をJSONテキストとして取得し、レンダリングのために情報をmyProfile.htmlに送信します。

# Definition of the /myProfile route
def myProfile(request):
   #Getting the Access Token value from the session
   access_token = request.session.get('access_token', 'none')
   if access_token == 'none':
       #If the access token isn't present redirects to login page.
       return render(request, 'sampleapp/login.html')
   else:
       #If the access token is present, validates the id token to acquire
       #information such as UserID, DisplayName, list of groups and AppRoles assigned to the user.

       #Authentication Manager loaded with the configurations.
       am = IdcsClient.AuthenticationManager(getOptions())        
       id_token = request.session.get('id_token', 'none')
       id_token_verified = am.verifyIdToken(id_token)

       #Getting the user details in json format.        
       jsonProfile = id_token_verified.getIdToken()
       #Getting User information to send to the My Profile page.        
       displayname = request.session.get('displayname', 'displayname')

       #Redenring json to be used in the html page.
       json_pretty = json.dumps(jsonProfile, sort_keys=True, indent=2)        
       context = {
          'displayname': displayname,
          "json_pretty": json_pretty,
       }
       #Rendering the content of the My Profile Page.
       return render(request, 'sampleapp/myProfile.html', context)

アプリケーションとOracle Identity Cloud Service間のシングルサインオンからユーザーをサインアウトするために、Python Webアプリケーションはlogout関数を実装します。このファンクションは、前に設定したユーザー・セッション属性をクリアしてから、ユーザーをOracle Identity Cloud ServiceのOAuthログアウトURLにリダイレクトします。このURLは、config.jsonファイルでlogoutSufixパラメータとして設定されます。

# Definition of the /logout route
def logout(request):
   #Getting the Access Token value from the session
   access_token = request.session.get('access_token', 'none')
   if access_token == 'none':
        #If the access token isn't present redirects to login page.
        return render(request, 'sampleapp/login.html') 
   else:
       options = getOptions()        
       url = options["BaseUrl"]        
       url += options["logoutSufix"]        
       url += '?post_logout_redirect_uri=http%3A//localhost%3A8000&id_token_hint='        
       url += request.session.get('id_token', 'none')
       #Clear session attributes
       del request.session['access_token']
       del request.session['id_token']
       del request.session['displayname']
       #Redirect to Oracle Identity Cloud Service logout URL.
       return HttpResponseRedirect(url)