2.2. Elytron でのアイデンティティー伝搬および転送

2.2.1. リモート呼び出しのセキュリティーアイデンティティーの伝搬

JBoss EAP 7.1 では、リモーティング呼び出しのためにクライアントからサーバーにセキュリティアイデンティティーを伝搬するためのサーバーとアプリケーションを簡単に設定できる機能が導入されました。指定のユーザーのセキュリティーアイデンティティー内で実行するようにサーバーコンポーネントを設定することも可能です。

本セクションの例では、セキュリティーアイデンティティーの認証情報を転送する方法を説明します。これは、クライアントおよび Jakarta Enterprise Beans のセキュリティーアイデンティティーをリモート Jakarta Enterprise Beans に伝播します。これは、ユーザーの承認されたロール情報とともにリモート Jakarta Enterprise Beans を呼び出した Principal の名前が含まれる文字列を返します。この例では、以下のコンポーネントで構成されています。

  • 呼び出し元に関する承認情報を返す、すべてのユーザーがアクセスできる単一のメソッドを含むセキュアな Jakarta Enterprise Beans。
  • 単一のメソッドが含まれる中間 Jakarta Enterprise Beans。リモート接続を使用し、セキュアな Jakarta Enterprise Beans でメソッドを呼び出します。
  • 中間 Jakarta Enterprise Beans を呼び出すリモートスタンドアロンクライアントアプリケーション。
  • 認証に使用されるアイデンティティー情報が含まれる META-INF/wildfly-config.xml ファイル。

最初に、サーバーを設定してセキュリティーアイデンティティー伝搬を有効化する必要があります。次に 、リモート Jakarta Enterprise Beans を検索して呼び出すために WildFlyInitialContextFactory を使用するサンプルアプリケーションコードを確認します

セキュリティーの伝搬のためのサーバーの設定
  1. ApplicationDomain を使用するように ejb3 サブシステムを設定します。

    /subsystem=ejb3/application-security-domain=quickstart-domain:add(security-domain=ApplicationDomain)

    これにより、以下の application-security-domain 設定が ejb3 サブシステムに追加されます。

    <subsystem xmlns="urn:jboss:domain:ejb3:5.0">
        ....
        <application-security-domains>
            <application-security-domain name="quickstart-domain" security-domain="ApplicationDomain"/>
        </application-security-domains>
    </subsystem>
  2. PLAIN 認証設定を追加して、プレーンテキストのユーザー名とパスワードと、アウトバウンド接続に使用される認証コンテキストを送信します。アイデンティティー伝搬に対応しているメカニズムのリストは、「Mechanisms That Support Security Identity Propagation」を参照してください。

    /subsystem=elytron/authentication-configuration=ejb-outbound-configuration:add(security-domain=ApplicationDomain,sasl-mechanism-selector="PLAIN")
    /subsystem=elytron/authentication-context=ejb-outbound-context:add(match-rules=[{authentication-configuration=ejb-outbound-configuration}])

    これにより、以下の authentication-client 設定が elytron サブシステムに追加されます。

    <subsystem xmlns="urn:wildfly:elytron:4.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
        <authentication-client>
            <authentication-configuration name="ejb-outbound-configuration" security-domain="ApplicationDomain" sasl-mechanism-selector="PLAIN"/>
            <authentication-context name="ejb-outbound-context">
                <match-rule authentication-configuration="ejb-outbound-configuration"/>
            </authentication-context>
        </authentication-client>
        ....
    </subsystem>
  3. リモート宛先アウトバウンドソケットバインディングを standard-sockets ソケットバインディンググループに追加します。

    /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=ejb-outbound:add(host=localhost,port=8080)

    これにより、以下の ejb-outbound アウトバウンドソケットバインディングが standard-sockets ソケットバインディンググループに追加されます。

    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        ....
        <outbound-socket-binding name="ejb-outbound">
            <remote-destination host="localhost" port="8080"/>
        </outbound-socket-binding>
    </socket-binding-group>
  4. リモートアウトバウンド接続を追加し、HTTP コネクターに SASL 認証ファクトリーを設定します。

    /subsystem=remoting/remote-outbound-connection=ejb-outbound-connection:add(outbound-socket-binding-ref=ejb-outbound, authentication-context=ejb-outbound-context)
    /subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=sasl-authentication-factory,value=application-sasl-authentication)

    これにより、http-remoting-connector および ejb-outbound-connection 設定が remoting サブシステムに追加されます。

    <subsystem xmlns="urn:jboss:domain:remoting:4.0">
        ....
        <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm" sasl-authentication-factory="application-sasl-authentication"/>
        <outbound-connections>
            <remote-outbound-connection name="ejb-outbound-connection" outbound-socket-binding-ref="ejb-outbound" authentication-context="ejb-outbound-context"/>
        </outbound-connections>
    </subsystem>
  5. Elytron SASL 認証が PLAIN メカニズムを使用するように設定します。

    /subsystem=elytron/sasl-authentication-factory=application-sasl-authentication:write-attribute(name=mechanism-configurations,value=[{mechanism-name=PLAIN},{mechanism-name=JBOSS-LOCAL-USER,realm-mapper=local},{mechanism-name=DIGEST-MD5,mechanism-realm-configurations=[{realm-name=ApplicationRealm}]}])

    これにより、以下の application-sasl-authentication 設定が elytron サブシステムに追加されます。

    <subsystem xmlns="urn:wildfly:elytron:4.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
        ....
        <sasl>
          ....
          <sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
              <mechanism-configuration>
                  <mechanism mechanism-name="PLAIN"/>
                  <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
                  <mechanism mechanism-name="DIGEST-MD5">
                      <mechanism-realm realm-name="ApplicationRealm"/>
                  </mechanism>
              </mechanism-configuration>
          </sasl-authentication-factory>
      </sasl>
      ....
    </subsystem>

上記の例のアプリケーションでは、サーバーがセキュリティー伝搬を有効にするために設定されました。

セキュリティーアイデンティティーを伝搬するアプリケーションサンプルコードの確認

サーバー設定でセキュリティーアイデンティティーの伝搬が有効になっていると、Jakarta Enterprise Beans クライアントアプリケーションは WildFlyInitialContextFactory を使用して Jakarta Enterprise Beans プロキシーを検索し、呼び出すことができます。Jakarta Enterprise Beans は、以下の例で示されているクライアント例で認証されたユーザーとして呼び出されます。以下の簡単なコード例は、JBoss EAP 7.4 に同梱される ejb-security-context-propagation クイックスタートから取得されます。セキュリティーアイデンティティーの伝搬の完全な作業例は、クイックスタートを参照してください。

Jakarta Enterprise Beans を異なるユーザーとして呼び出すには、コンテキストプロパティーに Context.SECURITY_PRINCIPAL および Context.SECURITY_CREDENTIALS を設定します。

例: リモートクライアント

public class RemoteClient {

    public static void main(String[] args) throws Exception {
        // invoke the intermediate bean using the identity configured in wildfly-config.xml
        invokeIntermediateBean();

        // now lets programmatically setup an authentication context to switch users before invoking the intermediate bean
        AuthenticationConfiguration superUser = AuthenticationConfiguration.empty().setSaslMechanismSelector(SaslMechanismSelector.NONE.addMechanism("PLAIN")).
                useName("superUser").usePassword("superPwd1!");
        final AuthenticationContext authCtx = AuthenticationContext.empty().
                with(MatchRule.ALL, superUser);

        AuthenticationContext.getContextManager().setThreadDefault(authCtx);
        invokeIntermediateBean();
    }

    private static void invokeIntermediateBean() throws Exception {
        final Hashtable<String, String> jndiProperties = new Hashtable<>();
        jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
        jndiProperties.put(Context.PROVIDER_URL, "remote+http://localhost:8080");
        final Context context = new InitialContext(jndiProperties);
        IntermediateEJBRemote intermediate = (IntermediateEJBRemote) context.lookup("ejb:/ejb-security-context-propagation/IntermediateEJB!"
                + IntermediateEJBRemote.class.getName());
        // Call the intermediate EJB
        System.out.println(intermediate.makeRemoteCalls());
    }
}

例: 中間 Jakarta Enterprise Beans

@Stateless
@Remote(IntermediateEJBRemote.class)
@SecurityDomain("quickstart-domain")
@PermitAll
public class IntermediateEJB implements IntermediateEJBRemote {

    @EJB(lookup="ejb:/ejb-security-context-propagation/SecuredEJB!org.jboss.as.quickstarts.ejb_security_context_propagation.SecuredEJBRemote")
    private SecuredEJBRemote remote;

    @Resource
    private EJBContext context;

    public String makeRemoteCalls() {
        try {
            StringBuilder sb = new StringBuilder("** ").
                    append(context.getCallerPrincipal()).
                    append(" * * \n\n");
            sb.append("Remote Security Information: ").
                    append(remote.getSecurityInformation()).
                    append("\n");

            return sb.toString();
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            }
            throw new RuntimeException("Teasting failed.", e);
        }
    }
}

例: セキュアな Jakarta Enterprise Beans

@Stateless
@Remote(SecuredEJBRemote.class)
@SecurityDomain("quickstart-domain")
public class SecuredEJB implements SecuredEJBRemote {

    @Resource
    private SessionContext context;

    @PermitAll
    public String getSecurityInformation() {
        StringBuilder sb = new StringBuilder("[");
        sb.append("Principal=[").
                append(context.getCallerPrincipal().getName()).
                append("], ");
        userInRole("guest", sb).append(", ");
        userInRole("user", sb).append(", ");
        userInRole("admin", sb).append("]");
        return sb.toString();
    }
}

例: wildfly-config.xml ファイル

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <authentication-client xmlns="urn:elytron:client:1.2">
        <authentication-rules>
            <rule use-configuration="default"/>
        </authentication-rules>
        <authentication-configurations>
            <configuration name="default">
                <set-user-name name="quickstartUser"/>
                <credentials>
                    <clear-password password="quickstartPwd1!"/>
                </credentials>
                <sasl-mechanism-selector selector="PLAIN"/>
                <providers>
                    <use-service-loader />
                </providers>
            </configuration>
        </authentication-configurations>
    </authentication-client>
</configuration>