2.2. 使用 Elytron 传播和转发身份
2.2.1. 为远程调用传播安全标识符 复制链接链接已复制到粘贴板!
JBoss EAP 7.1 引入了轻松配置服务器和应用,从而将安全身份从客户端传播到服务器以进行远程调用。您还可以将服务器组件配置为在给定用户的安全身份中运行。
本节中的示例演示了如何转发安全身份凭据。它将客户端和 EJB 的安全身份传播到远程 EJB。它返回一个字符串,其中包含名为远程 EJB 的 Principal 的名称,以及用户的授权角色信息。该示例由以下组件组成:
- 个安全的 EJB,它包含一个可由所有用户访问的方法,它将返回有关调用者的授权信息。
- 包含单一方法的中间 EJB。它利用远程连接,并在受保护的 EJB 上调用方法。
- 调用中间 EJB 的远程独立客户端应用。
-
META-INF/wildfly-config.xml文件,其中包含用于身份验证的身份信息。
您必须首先通过配置服务器来启用安全身份传播。接下来 查看使用 WildFlyInitialContextFactory 查找和调用远程 EJB 的示例应用代码。
配置服务器以进行安全传播
配置
ejb3子系统,以使用 ElytronApplicationDomain。/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>添加
PLAIN身份验证配置,以发送纯文本用户名和密码,以及用于出站连接的身份验证上下文。有关支持身份传播的机制列表,请参阅支持安全身份传播的机制。/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>将远程目的地出站套接字绑定到
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>添加远程出站连接,并在 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配置添加到远程子系统:<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>将 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>
服务器现在已配置为为以下示例应用启用安全传播:
查看传播安全身份的应用程序代码示例
在服务器配置中启用了安全身份传播后,EJB 客户端应用可以使用 WildFlyInitialContextFactory 来查找并调用 EJB 代理。EJB 将作为在客户端示例中验证的用户身份调用,如下所示:以下缩写的代码示例取自 JBoss EAP 7.3 附带的 ejb-security-context-propagation 快速入门:有关安全身份传播的完整工作示例,请参见 Quickstart。
若要以其他用户身份调用 EJB,您可以在上下文属性中设置 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());
}
}
示例:中间 EJB
@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);
}
}
}
示例:Secured EJB
@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>