WebSphere Application Server には、システム・ログインを構成する、 複数の Java Authentication and Authorization Service (JAAS) のプラグイン・ポイントがあります。 WebSphere Application Server ではシステム・ログイン構成を使って、受信される要求、発信される要求、および内部サーバー・ログインを認証します。
WEB_INBOUND ログイン構成は Web 要求を認証します。 図 1 は、WEB_INBOUND ログイン構成に渡される初期情報でサブジェクトを作成する トラスト・アソシエーション・インターセプター (TAI) を使用した構成の例です。 トラスト・アソシエーション・インターセプターが構成されていない場合、 認証プロセスは、図 1 で結合されているすべてのログイン・モジュールで構成される WEB_INBOUND システム・ログイン構成に 直接移動します。図 1 は、カスタム・ログイン・モジュールにプラグインできる場所、 および ltpaLoginModule ログイン・モジュールと wsMapDefaultInboundLoginModule ログイン・モジュールが必要とされる場所を示しています。
図 1
WEB_INBOUND 構成とその関連のコールバックに関する詳細については、Java Authentication and Authorization Service 用のシステム・ログイン構成エントリー設定 の『RMI_INBOUND, WEB_INBOUND, DEFAULT』を参照してください。
RMI_OUTBOUND ログイ ン構成は、アウトバウンド要求を処理するためのプラグ・ポイントです。 WebSphere Application Server はこのプラグ・ポイントを使用して、 渡された呼び出しサブジェクトに基づいてダウンストリームに送信されるシリアライズ情報および、 他のセキュリティー・コンテキスト情報 (伝搬トークンなど) を作成します。 カスタム・ログイン・モジュールはこのプラグ・ポイントを使用して、その ID を変更することができます。 詳しくは、異なるターゲット・レルムへのアウトバウンド・マッピングの構成 を参照してください。 図 2 では、カスタム・ログイン・モジュールに接続できる場所、 および wsMapCSIv2OutboundLoginModule ログイン・モジュールが必要とされる場所を示しています。
図 2
RMI_OUTBOUND ログイン構成とその関連コールバックの詳細については、 Java Authentication and Authorization Service 用のシステム・ログイン構成エントリー設定 の『RMI_OUTBOUND』を参照してください。
RMI_INBOUND ログイン 構成は、Enterprise Bean 要求のインバウンド認証を処理するプラグ・ポイントです。 WebSphere Application Server は、初期ログインまたは伝搬ログインのいずれかにこのプラグ・ポイントを使用します。 これら 2 つのログイン・タイプについて詳しくは、セキュリティー属性の伝搬 を参照してください。 伝搬ログイン時に、このプラグ・ポイントは、アップストリーム・サーバーから受信する情報を デシリアライズするために使用されます。 カスタム・ログイン・モジュールは、このプラグ・ポイントを使用して ID を変更したり、 カスタム・トークンを処理したり、カスタム・オブジェクトをサブジェクトに追加します。 図 3 で参照されている Hashtable オブジェクトを使用した ID の変更について詳しくは、 インバウンド ID マッピングの構成 を参照してください。 図 3 では、カスタム・ログイン・モジュールにプラグインできる場所、 および ltpaLoginModule ログイン・モジュールおよび wsMapDefaultInboundLoginModule ログイン・モジュールが 必要とされる場所を示しています。
図 3
RMI_INBOUND ログイン構成とその関連の コールバックに関する詳細については、Java Authentication and Authorization Service 用のシステム・ログイン構成エントリー設定 の『RMI_INBOUND、WEB_INBOUND、DEFAULT』を参照してください。
DEFAULT ログイン構成は、 管理 SOAP 要求およびサーバー ID の内部認証を含む、他のタイプの認証要求をすべて処理するプラグ・ポイントです。 伝搬ログインは、通常、このプラグ・ポイントでは行われません。
DEFAULT ログイン構成とその関連の コールバックに関する詳細については、Java Authentication and Authorization Service 用のシステム・ログイン構成エントリー設定 の『RMI_INBOUND, WEB_INBOUND, DEFAULT』を参照してください。
各ログイン構成は、ログイン構成によって認識されるコールバックを文書化する必要があります。 ただし、コールバックは必ずしも常にパス済みデータではありません。 ログイン構成には、特定の情報がいつ現れ、 どのようにその情報を使用するかがわかるようなロジックが含まれている必要があります。 例えば、前述のあらかじめ構成された 4 つのシステム・ログイン構成すべてに接続することができる カスタム・ログイン・モジュールを書き込む場合は、要求を認証するために 3 つのコールバックが提示されます。 その他のコールバックは、伝搬、ログイン構成での他の情報の使用可能化など、その他の理由で提示されます。
com.ibm.wsspi.security.token.AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY の共有状態変数は、行使される特権属性について WebSphere Application Server のログイン構成に通知します。 この変数は com.ibm.wsspi.security.cred.propertiesObject のプロパティーを参照します。java.util.Hashtable とこのプロパティーを関連付けます。この hashtable は、 ログインのために WebSphere Application Server で使用されるプロパティーを含んでいて、コールバック情報は無視します。 この hashtable により、ログイン構成で最初に実行されるカスタム・ログイン・モジュールが、 ユーザー ID をマップすることができ、あるいは WebSphere Application Server が、既に必要な情報がある場合に、 不必要なユーザー・レジストリー呼び出しを行うのを避けることができます。 詳しくは、インバウンド ID マッピングの構成 を参照してください。
WSTokenHolderCallback コールバックが存在し、 そこに送信側サーバーからの、WebSphere Application Server ランタイムに必要なすべての必須オブジェク トを再作成するのに十分な情報が含まれている場合、他のログインは伝搬ログインと見なされます。 WebSphere Application Server ランタイムの情報が十分ある場合は、 サブジェクトに追加する可能性がある情報は、直前のログインから存在していたと考えられます。 オブジェクトが存在するかどうかを確認するには、 WSTokenHolderCallback コールバックにある ArrayList オブジェクトにアクセスし、 このリストを検索して、各 TokenHolder getName メソッドを参照します。 この検索を使用して、WebSphere Application Server がこのログイン中に ご使用のカスタム・オブジェクトをデシリアライズしているかどうかを判別します。 デシリアライゼーション後にカスタム・オブジェクトを追加するように設定されているサブジェクトを見つけるために、 ランタイムが名前の最後に追加情報を追加する可能性があるため、 ストリングの startsWith メソッドを使用して getName メソッドから戻されるクラス名を確認してください。
以下のコード断片をユーザーの login() メソッドに使用して、 十分な情報が揃った時点を判別することができます。 他の例については、インバウンド ID マッピングの構成 を参照してください。
// This is a hint provided by WebSphere Application Server that // sufficient propagation information does not exist and, therefore, // a login is required to provide the sufficient information. In this // situation, a Hashtable login might be used. boolean requiresLogin = ((com.ibm.wsspi.security.auth.callback. WSTokenHolderCallback) callbacks[1]).requiresLogin(); if (requiresLogin) { // Check to see if your object exists in the TokenHolder list, if not, add it. java.util.ArrayList authzTokenList = ((WSTokenHolderCallback) callbacks[6]). getTokenHolderList();boolean found = false; if (authzTokenList != null) { Iterator tokenListIterator = authzTokenList.iterator(); while (tokenListIterator.hasNext()) { com.ibm.wsspi.security.token.TokenHolder th = (com.ibm.wsspi.security.token. TokenHolder) tokenListIterator.next(); if (th != null && th.getName().startsWith("com.acme.myCustomClass")) { found=true; break; } } if (!found) { // go ahead and add your custom object. } } } else { // This code indicates that sufficient propagation information is present. // User registry calls are not needed by WebSphere Application Server to // create a valid Subject. This code might be a no-op in your login module. }
カスタム・ログイン・モジュールのサンプル
次のサンプルを使っていくつかのコールバックや共有状態変数の使い方についての知識を得ることができます。
{ // Defines your login module variables com.ibm.wsspi.security.token.AuthenticationToken customAuthzToken = null; com.ibm.wsspi.security.token.AuthenticationToken defaultAuthzToken = null; com.ibm.websphere.security.cred.WSCredential credential = null; com.ibm.websphere.security.auth.WSPrincipal principal = null; private javax.security.auth.Subject _subject; private javax.security.auth.callback.CallbackHandler _callbackHandler; private java.util.Map _sharedState; private java.util.Map _options; public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { _subject = subject; _callbackHandler = callbackHandler; _sharedState = sharedState; _options = options; } public boolean login() throws LoginException { boolean succeeded = true; // Gets the CALLBACK information javax.security.auth.callback.Callback callbacks[] = new javax.security.auth.callback.Callback[7]; callbacks[0] = new javax.security.auth.callback.NameCallback("Username: "); callbacks[1] = new javax.security.auth.callback.PasswordCallback("Password: ", false); callbacks[2] = new com.ibm.websphere.security.auth.callback. WSCredTokenCallbackImpl ("Credential Token: "); callbacks[3] = new com.ibm.wsspi.security.auth.callback. WSServletRequestCallback ("HttpServletRequest: "); callbacks[4] = new com.ibm.wsspi.security.auth.callback. WSServletResponseCallback ("HttpServletResponse: "); callbacks[5] = new com.ibm.wsspi.security.auth.callback. WSAppContextCallback ("ApplicationContextCallback: "); callbacks[6] = new com.ibm.wsspi.security.auth.callback. WSTokenHolderCallback ("Authz Token List: "); try { callbackHandler.handle(callbacks); } catch (Exception e) { // Handles exceptions throw new WSLoginFailedException (e.getMessage(), e); } // Sees which callbacks contain information uid = ((NameCallback) callbacks[0]).getName(); char password[] = ((PasswordCallback) callbacks[1]).getPassword(); byte[] credToken = ((WSCredTokenCallbackImpl) callbacks[2]).getCredToken(); javax.servlet.http.HttpServletRequest request = ((WSServletRequestCallback) callbacks[3]).getHttpServletRequest(); javax.servlet.http.HttpServletResponse response = ((WSServletResponseCallback) callbacks[4]).getHttpServletResponse(); java.util.Map appContext = ((WSAppContextCallback) callbacks[5]).getContext(); java.util.List authzTokenList = ((WSTokenHolderCallback) callbacks[6]).getTokenHolderList(); // Gets the SHARED STATE information principal = (WSPrincipal) _sharedState.get(com.ibm.wsspi.security. auth.callback.Constants.WSPRINCIPAL_KEY); credential = (WSCredential) _sharedState.get(com.ibm.wsspi.security. auth.callback.Constants.WSCREDENTIAL_KEY); defaultAuthzToken = (AuthorizationToken) _sharedState.get(com.ibm. wsspi.security.auth.callback.Constants.WSAUTHZTOKEN_KEY); // What you tend to do with this information depends upon the scenario // that you are trying to accomplish. This example demonstrates how to // access various different information: // - Determine if a login is initial versus propagation // - Deserialize a custom authorization token (For more information, see // セキュリティー属性の伝搬 // - Add a new custom authorization token (For more information, see // セキュリティー属性の伝搬 // - Look for a WSCredential and read attributes, if found. // - Look for a WSPrincipal and read attributes, if found. // - Look for a default AuthorizationToken and add attributes, if found. // - Read the header attributes from the HttpServletRequest, if found. // - Add an attribute to the HttpServletResponse, if found. // - Get the Web application name from the appContext, if found. // - Determines if a login is initial versus propagation. This is most // useful when login module is first. boolean requiresLogin = ((WSTokenHolderCallback) callbacks[6]).requiresLogin(); // initial login - asserts privilege attributes based on user identity if (requiresLogin) { // If you are validating a token from another server, there is an // application programming interface (API) to get the uniqueID from it. if (credToken != null && uid == null) { try { String uniqueID = WSSecurityPropagationHelper. validateLTPAToken(credToken); String realm = WSSecurityPropagationHelper.getRealmFromUniqueID (uniqueID); // Now set it to the UID so you can use that to either map or // login with. uid = WSSecurityPropagationHelper.getUserFromUniqueID (uniqueID); } catch (Exception e) { // handle exception } } // Adds a Hashtable to shared state. // Note: You can perform custom mapping on the NameCallback value returned // to change the identity based upon your own mapping rules. uid = mapUser (uid); // Gets the default InitialContext for this server. javax.naming.InitialContext ctx = new javax.naming.InitialContext(); // Gets the local UserRegistry object. com.ibm.websphere.security.UserRegistry reg = (com.ibm.websphere.security. UserRegistry) ctx.lookup("UserRegistry"); // Gets the user registry uniqueID based on the uid specified in the // NameCallback. String uniqueid = reg.getUniqueUserId(uid); uid = WSSecurityPropagationHelper.getUserFromUniqueID (uniqueID); // Gets the display name from the user registry based on the uniqueID. String securityName = reg.getUserSecurityName(uid); // Gets the groups associated with this uniqueID. java.util.List groupList = reg.getUniqueGroupIds(uid); // Creates the java.util.Hashtable with the information you gathered from // the UserRegistry. java.util.Hashtable hashtable = new java.util.Hashtable(); hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants. WSCREDENTIAL_UNIQUEID, uniqueid); hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants. WSCREDENTIAL_SECURITYNAME, securityName); hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants. WSCREDENTIAL_GROUPS, groupList); // Adds a cache key that is used as part of the lookup mechanism for // the created Subject. The cache key can be an Object, but should // implement the toString() method. Make sure the cacheKey contains // enough information to scope it to the user and any additional // attributes that you use. If you do not specify this property the // Subject is scoped to the WSCREDENTIAL_UNIQUEID returned, by default. hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants. WSCREDENTIAL_CACHE_KEY, "myCustomAttribute" + uniqueid); // Adds the hashtable to the sharedState of the Subject. _sharedState.put(com.ibm.wsspi.security.token.AttributeNameConstants. WSCREDENTIAL_PROPERTIES_KEY,hashtable); } // propagation login - process propagated tokens else { // - Deserializes a custom authorization token. For more information, see // セキュリティー属性の伝搬 . // This can be done at any login module plug in point (first, // middle, or last). if (authzTokenList != null) { // Iterates through the list looking for your custom token for (int i=0; i<authzTokenList.size(); i++) { TokenHolder tokenHolder = (TokenHolder)authzTokenList.get(i); // Looks for the name and version of your custom AuthorizationToken // implementation if (tokenHolder.getName().equals("com.ibm.websphere.security.token. CustomAuthorizationTokenImpl") && tokenHolder.getVersion() == 1) { // Passes the bytes into your custom AuthorizationToken constructor // to deserialize customAuthzToken = new com.ibm.websphere.security.token. CustomAuthorizationTokenImpl(tokenHolder.getBytes()); } } } // - Adds a new custom authorization token (For more information, // see セキュリティー属性の伝搬 ) // This can be done at any login module plug in point (first, middle, // or last). else { // Gets the PRINCIPAL from the default AuthenticationToken. This must // match all of the tokens. defaultAuthToken = (com.ibm.wsspi.security.token.AuthenticationToken) sharedState.get(com.ibm.wsspi.security.auth.callback.Constants. WSAUTHTOKEN_KEY); String principal = defaultAuthToken.getPrincipal(); // Adds a new custom authorization token. This is an initial login. // Pass the principal into the constructor customAuthzToken = new com.ibm.websphere.security.token. CustomAuthorizationTokenImpl(principal); // Adds any initial attributes if (customAuthzToken != null) { customAuthzToken.addAttribute("key1", "value1"); customAuthzToken.addAttribute("key1", "value2"); customAuthzToken.addAttribute("key2", "value1"); customAuthzToken.addAttribute("key3", "something different"); } } } // - Looks for a WSCredential and read attributes, if found. // This is most useful when plugged in as the last login module. if (credential != null) { try { // Reads some data from the credential String securityName = credential.getSecurityName(); java.util.ArrayList = credential.getGroupIds(); } catch (Exception e) { // Handles exceptions throw new WSLoginFailedException (e.getMessage(), e); } } // - Looks for a WSPrincipal and read attributes, if found. // This is most useful when plugged as the last login module. if (principal != null) { try { // Reads some data from the principal String principalName = principal.getName(); } catch (Exception e) { // Handles exceptions throw new WSLoginFailedException (e.getMessage(), e); } } // - Looks for a default AuthorizationToken and add attributes, if found. // This is most useful when plugged in as the last login module. if (defaultAuthzToken != null) { try { // Reads some data from the defaultAuthzToken String[] myCustomValue = defaultAuthzToken.getAttributes ("myKey"); // Adds some data if not present in the defaultAuthzToken if (myCustomValue == null) defaultAuthzToken.addAttribute ("myKey", "myCustomData"); } catch (Exception e) { // Handles exceptions throw new WSLoginFailedException (e.getMessage(), e); } } // - Reads the header attributes from the HttpServletRequest, if found. // This can be done at any login module plug in point (first, middle, // or last). if (request != null) { java.util.Enumeration headerEnum = request.getHeaders(); while (headerEnum.hasMoreElements()) { System.out.println ("Header element: " + (String)headerEnum.nextElement()); } } // - Adds an attribute to the HttpServletResponse, if found // This can be done at any login module plug in point (first, middle, // or last). if (response != null) { response.addHeader ("myKey", "myValue"); } // - Gets the Web application name from the appContext, if found // This can be done at any login module plug in point (first, middle, // or last). if (appContext != null) { String appName = (String) appContext.get(com.ibm.wsspi.security.auth. callback.Constants.WEB_APP_NAME); } return succeeded; } public boolean commit() throws LoginException { boolean succeeded = true; // Add any objects here that you have created and belong in the // Subject. Make sure the objects are not already added. If you added // any sharedState variables, remove them before you exit. If the abort() // method gets called, make sure you cleanup anything added to the // Subject here. if (customAuthzToken != null) { // Sets the customAuthzToken token into the Subject try { // Do this in a doPrivileged code block so that application code // does not need to add additional permissions java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { try { // Adds the custom authorization token if it is not // null and not already in the Subject if ((customAuthzTokenPriv != null) && (!_subject.getPrivateCredentials().contains(customAuthzTokenPriv))) { _subject.getPrivateCredentials().add(customAuthzTokenPriv); } } catch (Exception e) { throw new WSLoginFailedException (e.getMessage(), e); } return null; } }); } catch (Exception e) { throw new WSLoginFailedException (e.getMessage(), e); } } return succeeded; } public boolean abort() throws LoginException { boolean succeeded = true; // Makes sure to remove all objects that have already been added (both into the // Subject and shared state). if (customAuthzToken != null) { // remove the customAuthzToken token from the Subject try { final AuthorizationToken customAuthzTokenPriv = customAuthzToken; // Do this in a doPrivileged block so that application code does not need // to add additional permissions java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { try { // Removes the custom authorization token if it is not // null and not already in the Subject if ((customAuthzTokenPriv != null) && (_subject.getPrivateCredentials(). contains(customAuthzTokenPriv))) { _subject.getPrivateCredentials(). remove(customAuthzTokenPriv); } } catch (Exception e) { throw new WSLoginFailedException (e.getMessage(), e); } return null; } }); } catch (Exception e) { throw new WSLoginFailedException (e.getMessage(), e); } } return succeeded; } public boolean logout() throws LoginException { boolean succeeded = true; // Makes sure to remove all objects that have already been added // (both into the Subject and shared state). if (customAuthzToken != null) { // Removes the customAuthzToken token from the Subject try { final AuthorizationToken customAuthzTokenPriv = customAuthzToken; // Do this in a doPrivileged code block so that application code does // not need to add additional permissions java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { try { // Removes the custom authorization token if it is not null and not // already in the Subject if ((customAuthzTokenPriv != null) && (_subject.getPrivateCredentials(). contains(customAuthzTokenPriv))) { _subject.getPrivateCredentials().remove(customAuthzTokenPriv); } } catch (Exception e) { throw new WSLoginFailedException (e.getMessage(), e); } return null; } }); } catch (Exception e) { throw new WSLoginFailedException (e.getMessage(), e); } } return succeeded; } }
システム・ログイン構成のカスタム・ログイン・モジュールを開発したら、管理コンソールまたは wsadmin ユーティリティーを使って、システム・ログインを構成できます。 管理コンソールを使ってシステム・ログインを構成するには、 「セキュリティー」>「管理、アプリケーション、およびインフラストラクチャーの保護」とクリックします。 「Java Authentication and Authorization Service」の下の「システム・ログイン」をクリックします。システム・ログイン構成のための wsadmin ユーティリティーの使い方について詳しくは、サーバー・サイドの Java Authentication and Authorization Service の認証およびログイン構成のカスタマイズ を参照してください。 また、システム・ログイン・モジュールおよび新たなログイン・モジュールの追加を判断するためには、サーバー・サイドの Java Authentication and Authorization Service の認証およびログイン構成のカスタマイズ を参照してください。