3.2. 使用 Elytron 进行身份传播和转发
3.2.1. 为远程调用传播安全识别信息
JBoss EAP 7.1 引入了轻松配置服务器和应用的功能,以将安全身份从客户端传播到服务器以重新移动调用。您还可以配置服务器组件,以便在给定用户的安全身份内运行。
本节中的示例演示了如何转发安全身份凭证。它将客户端的安全身份和 Jakarta Enterprise Beans 传播到远程 Jakarta Enterprise Bean。它返回一个字符串,其中包含名为远程 Jakarta Enterprise Beans 的 Principal
名称以及用户的授权角色信息。示例由以下组件组成。
- 安全的 Jakarta Enterprise Beans 包含单一方法,可供所有用户访问,后者返回有关调用者的授权信息。
- 含有单一方法的中间 Jakarta Enterprise Beans。它利用远程连接,并调用受保护 Jakarta Enterprise Beans 的方法。
- 调用中间 Jakarta Enterprise Beans 的远程独立客户端应用。
-
META-INF/wildfly-config.xml
文件,其中包含用于身份验证的身份信息。
您必须首先通过 配置服务器来启用安全身份传播。接下来 查看使用 WildFlyInitialContext
onnectionFactoryy 查找并调用远程 Jakarta Enterprise Bean 的示例应用程序代码。
为安全传播配置服务器
将
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}])
这会在
elytron
子系统中添加以下authentication-client
配置。<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
配置添加到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>
将 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>
服务器现在已配置为启用以下示例应用程序的安全性传播。
查看应用程序代码示例(pagates a Security Identity)
在服务器配置中启用了安全身份传播后,Jakarta Enterprise Beans 客户端应用可以使用 WildFlyInitialContextonnectionFactory
y 查找并调用 Jakarta Enterprise Beans 代理。Jakarta Enterprise Beans 调用为在客户端示例中身份验证的用户,如下所示。以下缩写代码示例来自 JBoss EAP 7.4 附带的 ejb-security-context-propagation
Quickstart。有关安全身份传播的完整工作示例,请参阅快速入门。
要将 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()); } }
示例:Intermediate 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); } } }
示例:Example: Secured 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>
3.2.2. 使用授权转发模式
除了凭证转发外,Elytron 还支持在对等点之间使用身份。在以下情况下很有用。
- 要求是,您无法通过线路来发送密码。
- 身份验证类型不支持凭证转发。
- 环境需要限制哪些系统可以接收传播的请求。
要使用授权转发,您首先在 转发服务器上配置身份验证客户端,然后将 接收服务器配置为接受和处理授权。
在转发服务器上配置身份验证客户端
要启用授权转发,您必须在转发服务器配置中配置身份验证客户端配置。
以下管理 CLI 命令创建了默认的身份验证客户端配置,以启用身份验证转发。如果需要,您可以配置更加高级的基于规则的选择。
示例:管理 CLI 命令以创建身份验证客户端配置
/subsystem=elytron/authentication-configuration=forwardit:add(authentication-name=theserver1,security-domain=ApplicationDomain,realm=ApplicationRealm,forwarding-mode=authorization,credential-reference={clear-text=thereallysecretpassword}) /subsystem=elytron/authentication-context=forwardctx:add(match-rules=[{authentication-configuration=forwardit,match-no-user=true}])
这些命令将以下 authentication-configuration
和 authentication-context
配置添加到 elytron
子系统中。
示例:身份验证客户端配置
<authentication-client> <authentication-configuration name="forwardit" authentication-name="theserver1" security-domain="ApplicationDomain" forwarding-mode="authorization" realm="ApplicationRealm"> <credential-reference clear-text="thereallysecretpassword"/> </authentication-configuration> <authentication-context name="forwardctx"> <match-rule match-no-user="true" authentication-configuration="forwardit"/> </authentication-context> </authentication-client>
当转发服务器联系接收服务器时,不使用默认的基于身份验证的用户名和凭证,它使用预定义的服务器登录名 theserver1
来建立信任关系。
在接收服务器上配置授权转发
要使转发成功完成,需要使用与转发服务器传递的用户身份配置接收服务器配置。在这种情况下,您必须在接收服务器上配置名为 theserver1
的用户并使用正确的凭据。
您还必须在 elytron
子系统中配置"RunAs"权限映射,以允许从转发服务器传递的 server1
身份的身份切换。有关权限映射的更多信息,请参阅如何为 JBoss EAP 配置服务器安全性中的创建一个 Elytron 权限映射程序。
下面的命令添加一个名为 auth-forwarding-permission-mapper
的 simple-permission-mapper
,它包括以下配置。
-
用户
anonymous
的权限映射。此用户没有权限,这可以防止匿名用户可以登录。 -
用户
theserver1
的权限映射。此用户被分配了*
的RunAsPrincipalPermission
权限,这可让此用户全局权限作为任何身份运行。如果您愿意,您可以将权限限制为特定的身份。 - 所有其他用户的权限映射。
示例:管理 CLI 命令创建 Simple Permission Mapper
/subsystem=elytron/permission-set=run-as-principal-permission:add(permissions=[{class-name="org.wildfly.security.auth.permission.RunAsPrincipalPermission",target-name="*"}]) /subsystem=elytron/simple-permission-mapper=auth-forwarding-permission-mapper:add(permission-mappings=[{principals=["anonymous"]},{principals=["theserver1"],permission-sets=[{permission-set=login-permission},{permission-set=default-permissions},{permission-set=run-as-principal-permission}]},{match-all=true,permission-sets=[{permission-set=login-permission},{permission-set=default-permissions}]}]
此命令将以下 simple-permission-mapper
配置添加到 elytron
子系统:
示例:简单权限映射配置
<mappers> <simple-permission-mapper name="auth-forwarding-permission-mapper"> <permission-mapping> <principal name="anonymous"/> <!-- No permissions: Deny any permission to anonymous! --> </permission-mapping> <permission-mapping> <principal name="theserver1"/> <permission-set name="login-permission"/> <permission-set name="default-permissions"/> <permission-set name="run-as-principal-permission"/> </permission-mapping> <permission-mapping match-all="true"> <permission-set name="login-permission"/> <permission-set name="default-permissions"/> </permission-mapping> </simple-permission-mapper> </mappers> <permission-sets> <permission-set name="login-permission"> <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/> </permission-set> <permission-set name="default-permissions"> <permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/> <permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/> <permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/> </permission-set> <permission-set name="run-as-principal-permission"> <permission class-name="org.wildfly.security.auth.permission.RunAsPrincipalPermission" target-name="*"/> </permission-set> </permission-sets>
默认配置中已存在 login-permission
和 default-permissions
权限集。
在转发授权后使用主体转换器时,这些转换程序都会在验证和授权主体中应用。
3.2.3. 创建 case-principal-transformer
以更改主体用户名的问题单字符
elytron
子系统包括 case-principal-transformer
主体转换程序。您可以使用这个主体转换器将主体的用户名更改为大写或小写字符。
case-principal-transformer
主体转换器包括默认设置为 true
的 upper-case
属性。
要演示 case-principal-transformer
的用例,请考虑您使用身份验证机制将主体映射到安全域。realm mapper 操控映射的主体,以识别安全域并加载其身份之一。身份验证机制会将身份传递到 post-realm 映射阶段和最终主体转换阶段。随后,验证机制会验证身份以进行身份验证。您可以使用 case-principal-transformer
主体转换器来转换映射主体的字符大小写格式。
该流程示例中在安全域上下文中使用 case-principal-transformer
。您还可以在以下验证策略中使用内联主体转换器:
-
http-authentication-factory
-
sasl-authentication-factory
-
ssl-context
-
aggregate-realm
流程
将
case-principal-transformer
添加到elytron
子系统,然后选择用户名的字符大小写。要将转换器的用户名更改为大写字符,不要更改默认的
大写
属性值。显示添加到
elytron
子系统中的<transformer_name
> 示例,并定义了默认的大写
属性设置:/subsystem=elytron/case-principal-transformer=<transformer_name>:add(upper-case="true")
或者,您可以截断命令语法以使用默认的
大写
属性值:/subsystem=elytron/case-principal-transformer=<transformer_name>:add()
要将转换器的用户名更改为小写字符,请将
upper-case
属性设置为false
。显示添加到
elytron
子系统中的<transformer_name>
示例,并将upper-case
属性设置为false
:/subsystem=elytron/case-principal-transformer=<transformer_name>:add(upper-case="false")
可选:使用
elytron
子系统配置主体转换器。以下示例配置了一个主体转换器到由elytron
子系统提供的默认ApplicationDomain
配置。Elytron 将默认的ApplicationDomain
配置应用到pre-realm-principal-transformer
:/subsystem=elytron/security-domain=ApplicationDomain:write-attribute(name=pre-realm-principal-transformer,value=<transformer_name>)
注意您可以将
post-realm-principal-transformer
配置为在域映射程序标识了安全域后使用ApplicationDomain
配置。
其他资源
-
有关
upper-case
属性的详情,请查看 表 A.26case-principal-transformer
属性。
3.2.4. 检索安全身份凭证
在某些情况下,您可能需要检索用于传出调用的身份凭据,例如,由 HTTP 客户端使用。以下示例演示了如何以编程方式检索安全凭证。
import org.wildfly.security.auth.server.IdentityCredentials; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.credential.PasswordCredential; import org.wildfly.security.password.interfaces.ClearPassword; SecurityIdentity securityIdentity = null; ClearPassword password = null; // Obtain the SecurityDomain for the current deployment. // The calling code requires the // org.wildfly.security.permission.ElytronPermission("getSecurityDomain") permission // if running with a security manager. SecurityDomain securityDomain = SecurityDomain.getCurrent(); if (securityDomain != null) { // Obtain the current security identity from the security domain. // This always returns an identity, but it could be the representation // of the anonymous identity if no authenticated identity is available. securityIdentity = securityDomain.getCurrentSecurityIdentity(); // The private credentials can be accessed to obtain any credentials delegated to the identity. // The calling code requires the // org.wildfly.security.permission.ElytronPermission("getPrivateCredentials") // permission if running with a security manager. IdentityCredentials credentials = securityIdentity.getPrivateCredentials(); if (credentials.contains(PasswordCredential.class)) { password = credentials.getCredential(PasswordCredential.class).getPassword(ClearPassword.class); } }
3.2.5. 支持安全身份传播机制
以下 SASL 机制支持传播安全身份:
-
PLAIN
-
OAUTHBEARER
-
GSSAPI
-
GS2-KRB5
以下 HTTP 机制支持传播安全身份:
-
FORM
1 -
BASIC
-
BEARER_TOKEN
-
SPNEGO
1 FORM
身份验证不会由 Web 浏览器自动处理。因此,无法在 HA 集群中运行的使用 FORM
身份验证的 Web 应用程序传播。其他机制,如 BASIC
和 SPNEGO
,在 HA 集群环境中支持身份传播。