验证消息的安全性-SAML令牌时发生错误

问题描述 投票:0回答:1

几年前,我们开发了一个使用usi-ws v2的客户端,此Web服务使用STS service v2。运行正常。

但是,现在soap-ws v2被更新为usi-ws v3,后者依次使用STS service v3

主要区别是

1] usi-ws v3使用<sp:Basic256Sha256Rsa15/>作为与AlgorithmSuiteSTS service v3策略匹配的AlgorithmSuite策略。

2)usi-ws v3使用STS service v3而不是STS service v2

我可以通过两种不同的方法整合变更

第一种方法

我在usi-ws v3上使用apache-cxf wsdl2java生成客户端代码。下面是示例端点代码

private static void SetupRequestContext(IUSIService endpoint, X509Certificate certificate, PrivateKey privateKey)   {

        Map<String, Object> requestContext = ((BindingProvider)endpoint).getRequestContext();

        requestContext.put(XWSSConstants.CERTIFICATE_PROPERTY, certificate);
        requestContext.put(XWSSConstants.PRIVATEKEY_PROPERTY, privateKey);
        requestContext.put(STSIssuedTokenConfiguration.STS_ENDPOINT, "https://thirdparty.authentication.business.gov.au/R3.0/vanguard/S007v1.3/Service.svc");
        requestContext.put(STSIssuedTokenConfiguration.STS_NAMESPACE, "http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice");
        requestContext.put(STSIssuedTokenConfiguration.STS_WSDL_LOCATION, "https://thirdparty.authentication.business.gov.au/R3.0/vanguard/S007v1.3/Service.svc");
        requestContext.put(STSIssuedTokenConfiguration.STS_SERVICE_NAME, "SecurityTokenService");
        requestContext.put(STSIssuedTokenConfiguration.LIFE_TIME, 30);
        requestContext.put(STSIssuedTokenConfiguration.STS_PORT_NAME, "S007SecurityTokenServiceEndpoint");
        requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, REQUEST_TIMEOUT);
        requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT);
    }

配置端点上下文之后,我尝试创建USI

endpoint.createUSI(createUsiRequest);

它抛出以下错误(日志)

... LOGS before are removed
[main] WARN au.gov.abr.akm.credential.store.ABRRequester$ABRHttpPost - XML request is => <ns:requests  xmlns:ns="http://auth.sbr.gov.au/AutoRenew"><request id="ABRD:TESTDeviceID" credentialType="D"><cmsB64>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</cmsB64></request></ns:requests>
[main] INFO au.gov.abr.akm.credential.store.DaemonThreadFactory - Creating a new Thread in ThreadGroup: main
[pool-1-thread-1] WARN au.gov.abr.akm.credential.store.ABRRequester$ABRHttpPost - Constructing the response reader
[pool-1-thread-1] WARN au.gov.abr.akm.credential.store.ABRRequester$ABRHttpPost - java.net connection timeout = 0
[pool-1-thread-1] WARN au.gov.abr.akm.credential.store.ABRRequester$ABRHttpPost - java.net read timeout = 0
[main] INFO au.gov.abr.akm.credential.store.ABRKeyStoreImpl - correct password given, resetting bad password count to zero
[main] INFO au.gov.abr.akm.credential.store.ABRKeyStoreFactory - Will attempt to load the keystore, if the keystore doesn't exist then an exception will be thrown
[main] INFO au.gov.abr.akm.credential.store.ABRKeyStoreSerializerTransporterFactory - No custom Transporter specified, using the default File Transporter.
[main] INFO au.gov.abr.akm.credential.store.ABRKeyStoreSerializerTransporterFile - A keystore file has been passed through, keystore location is that of the provided file
[pool-1-thread-1] WARN au.gov.abr.akm.credential.store.ABRRequester - ABRRequester timeout = 60000ms
[pool-1-thread-1] INFO au.gov.abr.akm.cryptoOps.CredentialRequestResponse - XML Response length -> 358
[pool-1-thread-1] INFO au.gov.abr.akm.cryptoOps.CredentialRequestResponse - Auto-renew => ***BEGIN XML RESPONSE***
<?xml version="1.0" encoding="utf-8"?><responses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://auth.sbr.gov.au/AutoRenew"><response id="ABRD:TESTDeviceID" xmlns=""><error><errorId>2106</errorId><errorMessage>Unrecognised error - 1137</errorMessage></error></response></responses>
******END XML******
[pool-1-thread-1] WARN au.gov.abr.akm.cryptoOps.CredentialRequestResponse - CredentialRequestResponse.processResponse (2106) Unrecognised error - 1137
javax.xml.ws.soap.SOAPFaultException: An error occurred when verifying security for the message.
    at com.sun.xml.ws.fault.SOAP12Fault.getProtocolException(SOAP12Fault.java:225)
    at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:122)
    at com.sun.xml.ws.client.dispatch.DispatchImpl.doInvoke(DispatchImpl.java:195)
    at com.sun.xml.ws.client.dispatch.DispatchImpl.invoke(DispatchImpl.java:214)
    at com.sun.xml.ws.security.trust.impl.TrustPluginImpl.invokeRST(TrustPluginImpl.java:624)
    at com.sun.xml.ws.security.trust.impl.TrustPluginImpl.process(TrustPluginImpl.java:170)
    at com.sun.xml.ws.security.trust.impl.client.STSIssuedTokenProviderImpl.getIssuedTokenContext(STSIssuedTokenProviderImpl.java:136)
    at com.sun.xml.ws.security.trust.impl.client.STSIssuedTokenProviderImpl.issue(STSIssuedTokenProviderImpl.java:74)
    at com.sun.xml.ws.api.security.trust.client.IssuedTokenManager.getIssuedToken(IssuedTokenManager.java:79)
    at com.sun.xml.wss.jaxws.impl.SecurityClientTube.invokeTrustPlugin(SecurityClientTube.java:655)
    at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processClientRequestPacket(SecurityClientTube.java:264)
    at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:233)
    at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)
    at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)
    at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)
    at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)
    at com.sun.xml.ws.client.Stub.process(Stub.java:319)
    at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:157)
    at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:109)
    at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
    at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:140)
    at com.sun.proxy.$Proxy44.createUSI(Unknown Source)
    at usi.gov.au.USITest.main(USITest.java:83)

第二种方法

第二种方法是,我通过生成wsdl2java客户端类直接调用STS service v3。这种方法已经是answered here。但是我无法理解答案,也无法通过在signatureAlgorithm="SHA256withRSA"]中添加sp:AlgorithmSuite来获得结果

<sp:AlgorithmSuite signatureAlgorithm="SHA256withRSA">
  <wsp:Policy>
    <sp:Basic256 />
  </wsp:Policy>
</sp:AlgorithmSuite>

 <sp:AlgorithmSuite signatureAlgorithm="SHA256withRSA">
    <wsp:Policy>
      <sp:Basic256Sha256Rsa15 />
    </wsp:Policy>
 </sp:AlgorithmSuite>

每次我得到

com.microsoft.schemas.ws._2008._06.identity.securitytokenservice.IWSTrust13SyncTrust13IssueSTSFaultFaultMessage: Could not validate the ActAs token

我不知道哪种方法正确,以及如何修复WSDL或我的代码以更新SecurityPolicy,即使用RSA从Sha1切换到Sha256。

几年前,我们开发了一个使用usi-ws v2的客户端,该Web服务使用STS服务v2。工作正常。但是,现在soap-ws v2已更新为usi-ws v3,后者又使用了STS ...

java web-services soap wsdl sha256
1个回答
0
投票

您需要更新的STS 1.3 wsdl,它不需要旧版本的ActAs令牌

© www.soinside.com 2019 - 2024. All rights reserved.