4.6. 安全令牌服务(STS)


WS-Trust 上下文中发布、更新和验证安全令牌。

4.6.1. Maven 协调

code.quarkus.redhat.com 上使用 quarkus-cxf-services-sts 创建新项目,或将这些协调添加到现有项目中:

<dependency>
    <groupId>io.quarkiverse.cxf</groupId>
    <artifactId>quarkus-cxf-services-sts</artifactId>
</dependency>
Copy to Clipboard Toggle word wrap

4.6.2. 支持的标准

4.6.3. 使用方法

以下是基本 WS-Trust 情境的关键部分:

  • WS-SecurityPolicy - 除定义安全要求外,如传输协议、加密和签名,它也可以包含 < IssuedToken& gt; 断言。它指定这些安全令牌的要求和约束,客户端在访问服务时必须遵循这些安全令牌。
  • 安全令牌服务(STS) 问题,在请求时验证和更新安全令牌。它充当可信颁发机构,用于验证客户端的身份和权限的令牌。
  • 客户端 - 从 STS 请求令牌以访问 Web 服务。它必须通过 STS 验证自己,并提供有关所需令牌类型的详情。
  • Service -依赖于 STS 验证客户端并验证其令牌。

4.6.3.1. runnable 示例

在 Quarkus CXF 源树中有一个涵盖 WS-Trust 的集成测试。https://github.com/quarkiverse/quarkus-cxf/tree/main/integration-tests/ws-trust让我们来浏览它,了解各个部分是如何一起工作。

4.6.3.1.1. WS-SecurityPolicy

该策略位于 asymmetric-saml2-policy.xml 文件中。其关键部分是 < IssuedToken> 断言需要 SAML 2.0 令牌:

asymmetric-saml2-policy.xml

                            <sp:IssuedToken
                                sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                                <sp:RequestSecurityTokenTemplate>
                                    <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
                                    <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey</t:KeyType>
                                </sp:RequestSecurityTokenTemplate>
                                <wsp:Policy>
                                    <sp:RequireInternalReference />
                                </wsp:Policy>
                                <sp:Issuer>
                                    <wsaws:Address>http://localhost:8081/services/sts</wsaws:Address>
                                    <wsaws:Metadata xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                                                    wsdli:wsdlLocation="http://localhost:8081/services/sts?wsdl">
                                        <wsaw:ServiceName xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                                                        xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                                                        EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                                    </wsaws:Metadata>
                                </sp:Issuer>
                            </sp:IssuedToken>
Copy to Clipboard Toggle word wrap

4.6.3.1.2. 安全令牌服务(STS)

STS 在 Sts.java 中实施:

Sts.java

@WebServiceProvider(serviceName = "SecurityTokenService", portName = "UT_Port", targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/", wsdlLocation = "ws-trust-1.4-service.wsdl")
public class Sts extends SecurityTokenServiceProvider {

    public Sts() throws Exception {
        super();

        StaticSTSProperties props = new StaticSTSProperties();
        props.setSignatureCryptoProperties("stsKeystore.properties");
        props.setSignatureUsername("sts");
        props.setCallbackHandlerClass(StsCallbackHandler.class.getName());
        props.setIssuer("SampleSTSIssuer");

        List<ServiceMBean> services = new LinkedList<ServiceMBean>();
        StaticService service = new StaticService();
        final Config config = ConfigProvider.getConfig();
        final int port = LaunchMode.current().equals(LaunchMode.TEST) ? config.getValue("quarkus.http.test-port", Integer.class)
                : config.getValue("quarkus.http.port", Integer.class);
        service.setEndpoints(Arrays.asList(
                "http://localhost:" + port + "/services/hello-ws-trust",
                "http://localhost:" + port + "/services/hello-ws-trust-actas",
                "http://localhost:" + port + "/services/hello-ws-trust-onbehalfof"));
        services.add(service);

        TokenIssueOperation issueOperation = new TokenIssueOperation();
        issueOperation.setServices(services);
        issueOperation.getTokenProviders().add(new SAMLTokenProvider());
        // required for OnBehalfOf
        issueOperation.getTokenValidators().add(new UsernameTokenValidator());
        // added for OnBehalfOf and ActAs
        issueOperation.getDelegationHandlers().add(new UsernameTokenDelegationHandler());
        issueOperation.setStsProperties(props);

        TokenValidateOperation validateOperation = new TokenValidateOperation();
        validateOperation.getTokenValidators().add(new SAMLTokenValidator());
        validateOperation.setStsProperties(props);

        this.setIssueOperation(issueOperation);
        this.setValidateOperation(validateOperation);
    }
}
Copy to Clipboard Toggle word wrap

并在 application.properties 中配置:

application.properties

quarkus.cxf.endpoint."/sts".implementor = io.quarkiverse.cxf.it.ws.trust.sts.Sts
quarkus.cxf.endpoint."/sts".logging.enabled = pretty

quarkus.cxf.endpoint."/sts".security.signature.username = sts
quarkus.cxf.endpoint."/sts".security.signature.password = password
quarkus.cxf.endpoint."/sts".security.validate.token = false

quarkus.cxf.endpoint."/sts".security.signature.properties."org.apache.ws.security.crypto.provider" = org.apache.ws.security.components.crypto.Merlin
quarkus.cxf.endpoint."/sts".security.signature.properties."org.apache.ws.security.crypto.merlin.keystore.type" = pkcs12
quarkus.cxf.endpoint."/sts".security.signature.properties."org.apache.ws.security.crypto.merlin.keystore.password" = password
quarkus.cxf.endpoint."/sts".security.signature.properties."org.apache.ws.security.crypto.merlin.keystore.file" = sts.pkcs12
Copy to Clipboard Toggle word wrap

4.6.3.1.3. Service

该服务在 TrustHelloServiceImpl.java 中实施:

TrustHelloServiceImpl.java

@WebService(portName = "TrustHelloServicePort", serviceName = "TrustHelloService", targetNamespace = "https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test/ws-trust", endpointInterface = "io.quarkiverse.cxf.it.ws.trust.server.TrustHelloService")
public class TrustHelloServiceImpl implements TrustHelloService {
    @WebMethod
    @Override
    public String hello(String person) {
        return "Hello " + person + "!";
    }
}
Copy to Clipboard Toggle word wrap

上面提到的 asymmetric-saml2-policy.xml 在 Service Endpoint Interface TrustHelloService.java 中设置:

TrustHelloServiceImpl.java

@WebService(targetNamespace = "https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test/ws-trust")
@Policy(placement = Policy.Placement.BINDING, uri = "classpath:/asymmetric-saml2-policy.xml")
public interface TrustHelloService {
    @WebMethod
    @Policies({
            @Policy(placement = Policy.Placement.BINDING_OPERATION_INPUT, uri = "classpath:/io-policy.xml"),
            @Policy(placement = Policy.Placement.BINDING_OPERATION_OUTPUT, uri = "classpath:/io-policy.xml")
    })
    String hello(String person);
}
Copy to Clipboard Toggle word wrap

服务端点在 application.properties 中配置:

application.properties

quarkus.cxf.endpoint."/hello-ws-trust".implementor = io.quarkiverse.cxf.it.ws.trust.server.TrustHelloServiceImpl
quarkus.cxf.endpoint."/hello-ws-trust".logging.enabled = pretty

quarkus.cxf.endpoint."/hello-ws-trust".security.signature.username = service
quarkus.cxf.endpoint."/hello-ws-trust".security.signature.password = password
quarkus.cxf.endpoint."/hello-ws-trust".security.signature.properties."org.apache.ws.security.crypto.provider" = org.apache.ws.security.components.crypto.Merlin
quarkus.cxf.endpoint."/hello-ws-trust".security.signature.properties."org.apache.ws.security.crypto.merlin.keystore.type" = pkcs12
quarkus.cxf.endpoint."/hello-ws-trust".security.signature.properties."org.apache.ws.security.crypto.merlin.keystore.password" = password
quarkus.cxf.endpoint."/hello-ws-trust".security.signature.properties."org.apache.ws.security.crypto.merlin.keystore.alias" = service
quarkus.cxf.endpoint."/hello-ws-trust".security.signature.properties."org.apache.ws.security.crypto.merlin.file" = service.pkcs12

quarkus.cxf.endpoint."/hello-ws-trust".security.encryption.properties."org.apache.ws.security.crypto.provider" = org.apache.ws.security.components.crypto.Merlin
quarkus.cxf.endpoint."/hello-ws-trust".security.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.type" = pkcs12
quarkus.cxf.endpoint."/hello-ws-trust".security.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.password" = password
quarkus.cxf.endpoint."/hello-ws-trust".security.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.alias" = service
quarkus.cxf.endpoint."/hello-ws-trust".security.encryption.properties."org.apache.ws.security.crypto.merlin.file" = service.pkcs12
Copy to Clipboard Toggle word wrap

4.6.3.1.4. 客户端

最后,要使 SOAP 客户端能够与服务通信,需要配置其 STSClient。它可以在 application.properties 中完成:

application.properties

quarkus.cxf.client.hello-ws-trust.security.sts.client.wsdl = http://localhost:${quarkus.http.test-port}/services/sts?wsdl
quarkus.cxf.client.hello-ws-trust.security.sts.client.service-name = {http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService
quarkus.cxf.client.hello-ws-trust.security.sts.client.endpoint-name = {http://docs.oasis-open.org/ws-sx/ws-trust/200512/}UT_Port
quarkus.cxf.client.hello-ws-trust.security.sts.client.username = client
quarkus.cxf.client.hello-ws-trust.security.sts.client.password = password
quarkus.cxf.client.hello-ws-trust.security.sts.client.encryption.username = sts
quarkus.cxf.client.hello-ws-trust.security.sts.client.encryption.properties."org.apache.ws.security.crypto.provider" = org.apache.ws.security.components.crypto.Merlin
quarkus.cxf.client.hello-ws-trust.security.sts.client.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.type" = pkcs12
quarkus.cxf.client.hello-ws-trust.security.sts.client.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.password" = password
quarkus.cxf.client.hello-ws-trust.security.sts.client.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.alias" = client
quarkus.cxf.client.hello-ws-trust.security.sts.client.encryption.properties."org.apache.ws.security.crypto.merlin.keystore.file" = client.pkcs12
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.username = client
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.properties."org.apache.ws.security.crypto.provider" = org.apache.ws.security.components.crypto.Merlin
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.properties."org.apache.ws.security.crypto.merlin.keystore.type" = pkcs12
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.properties."org.apache.ws.security.crypto.merlin.keystore.password" = password
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.properties."org.apache.ws.security.crypto.merlin.keystore.alias" = client
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.properties."org.apache.ws.security.crypto.merlin.keystore.file" = client.pkcs12
quarkus.cxf.client.hello-ws-trust.security.sts.client.token.usecert = true
Copy to Clipboard Toggle word wrap

提示

配置 STS 客户端的属性由 io.quarkiverse.cxf:quarkus-cxf-rt-ws-security 扩展提供,并记录在其 参考页面中

另外,客户端也可以设置为 bean 引用:

application.properties

quarkus.cxf.client.hello-ws-trust-bean.security.sts.client = #stsClientBean
Copy to Clipboard Toggle word wrap

在这种情况下,需要以编程方式生成 @Named bean,如使用 @jakarta.enterprise.inject.Produces

BeanProducers.java

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Named;

import org.apache.cxf.ws.security.SecurityConstants;

import io.quarkiverse.cxf.ws.security.sts.client.STSClientBean;

public class BeanProducers {

    /**
     * Create and configure an STSClient for use by the TrustHelloService client.
     */
    @Produces
    @ApplicationScoped
    @Named("stsClientBean")
    STSClientBean createSTSClient() {
        /*
         * We cannot use org.apache.cxf.ws.security.trust.STSClient as a return type of this bean producer method
         * because it does not have a no-args constructor. STSClientBean is a subclass of STSClient having one.
         */
        STSClientBean stsClient = STSClientBean.create();
        stsClient.setWsdlLocation("http://localhost:8081/services/sts?wsdl");
        stsClient.setServiceQName(new QName("http://docs.oasis-open.org/ws-sx/ws-trust/200512/", "SecurityTokenService"));
        stsClient.setEndpointQName(new QName("http://docs.oasis-open.org/ws-sx/ws-trust/200512/", "UT_Port"));
        Map<String, Object> props = stsClient.getProperties();
        props.put(SecurityConstants.USERNAME, "client");
        props.put(SecurityConstants.PASSWORD, "password");
        props.put(SecurityConstants.ENCRYPT_PROPERTIES,
                Thread.currentThread().getContextClassLoader().getResource("clientKeystore.properties"));
        props.put(SecurityConstants.ENCRYPT_USERNAME, "sts");
        props.put(SecurityConstants.STS_TOKEN_USERNAME, "client");
        props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
                Thread.currentThread().getContextClassLoader().getResource("clientKeystore.properties"));
        props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");
        return stsClient;
    }
}
Copy to Clipboard Toggle word wrap

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat