/* * Copyright 2005-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ws.soap.security.wss4j2; import java.io.IOException; import java.security.Principal; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.wss4j.common.ConfigurationConstants; import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.principal.WSUsernameTokenPrincipalImpl; import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.dom.engine.WSSConfig; import org.apache.wss4j.dom.engine.WSSecurityEngine; import org.apache.wss4j.dom.engine.WSSecurityEngineResult; import org.apache.wss4j.dom.handler.HandlerAction; import org.apache.wss4j.dom.handler.RequestData; import org.apache.wss4j.dom.handler.WSHandlerConstants; import org.apache.wss4j.dom.handler.WSHandlerResult; import org.apache.wss4j.dom.message.token.Timestamp; import org.apache.wss4j.dom.util.WSSecurityUtil; import org.apache.wss4j.dom.validate.Credential; import org.apache.wss4j.dom.validate.SignatureTrustValidator; import org.apache.wss4j.dom.validate.TimestampValidator; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor; import org.springframework.ws.soap.security.WsSecuritySecurementException; import org.springframework.ws.soap.security.WsSecurityValidationException; import org.springframework.ws.soap.security.callback.CallbackHandlerChain; import org.springframework.ws.soap.security.callback.CleanupCallback; import org.springframework.ws.soap.security.wss4j2.callback.UsernameTokenPrincipalCallback; /** * A WS-Security endpoint interceptor based on Apache's WSS4J. This interceptor supports messages created by the {@link * org.springframework.ws.soap.axiom.AxiomSoapMessageFactory} and the {@link org.springframework.ws.soap.saaj.SaajSoapMessageFactory}. * * <p>The validation and securement actions executed by this interceptor are configured via {@code validationActions} * and {@code securementActions} properties, respectively. Actions should be passed as a space-separated strings. * * <p>Valid <strong>validation</strong> actions are: * * <blockquote> * <table> * <tr><th>Validation action</th><th>Description</th></tr> * <tr><td>{@code UsernameToken}</td><td>Validates username token</td></tr> * <tr><td>{@code Timestamp}</td><td>Validates the timestamp</td></tr> * <tr><td>{@code Encrypt}</td><td>Decrypts the message</td></tr> * <tr><td>{@code Signature}</td><td>Validates the signature</td></tr> * <tr><td>{@code NoSecurity}</td><td>No action performed</td></tr> * </table></blockquote> * <p> * <strong>Securement</strong> actions are: * * <blockquote> * <table> * <tr><th>Securement action</th><th>Description</th></tr> * <tr><td>{@code UsernameToken}</td><td>Adds a username token</td></tr> * <tr><td>{@code UsernameTokenSignature}</td><td>Adds a username token and a signature username token secret key</td></tr> * <tr><td>{@code Timestamp}</td><td>Adds a timestamp</td></tr> * <tr><td>{@code Encrypt}</td><td>Encrypts the response</td></tr> * <tr><td>{@code Signature}</td><td>Signs the response</td></tr> * <tr><td>{@code NoSecurity}</td><td>No action performed</td></tr> * </table></blockquote> * * <p>The order of the actions that the client performed to secure the messages is significant and is enforced by the * interceptor. * * @author Tareq Abed Rabbo * @author Arjen Poutsma * @author Greg Turnquist * @author Jamin Hitchcock * @see <a href="http://ws.apache.org/wss4j/">Apache WSS4J 2.0</a> * @since 2.3.0 */ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor implements InitializingBean { public static final String SECUREMENT_USER_PROPERTY_NAME = "Wss4jSecurityInterceptor.securementUser"; private String securementActions; private String securementUsername; private CallbackHandler validationCallbackHandler; private String validationActions; private List<Integer> validationActionsVector; private String validationActor; private Crypto validationDecryptionCrypto; private Crypto validationSignatureCrypto; private boolean timestampStrict = true; private boolean enableSignatureConfirmation; private int validationTimeToLive = 300; private int securementTimeToLive = 300; private int futureTimeToLive = 60; private WSSConfig wssConfig; private final Wss4jHandler handler = new Wss4jHandler(); private final WSSecurityEngine securityEngine; private boolean enableRevocation; private boolean bspCompliant; private boolean securementUseDerivedKey; // Allow RSA 15 to maintain default behavior private boolean allowRSA15KeyTransportAlgorithm = true; // To maintain same behavior as default, this flag is set to true private boolean removeSecurityHeader = true; /** * Create a {@link WSSecurityEngine} by default. */ public Wss4jSecurityInterceptor() { this.securityEngine = new WSSecurityEngine(); } /** * Inject a customize {@link WSSecurityEngine}. * @param securityEngine */ public Wss4jSecurityInterceptor(WSSecurityEngine securityEngine) { this.securityEngine = securityEngine; } public void setSecurementActions(String securementActions) { this.securementActions = securementActions; } /** * The actor name of the {@code wsse:Security} header. * * <p>If this parameter is omitted, the actor name is not set. * * <p>The value of the actor or role has to match the receiver's setting or may contain standard values. */ public void setSecurementActor(String securementActor) { handler.setOption(WSHandlerConstants.ACTOR, securementActor); } public void setSecurementEncryptionCrypto(Crypto securementEncryptionCrypto) { handler.setSecurementEncryptionCrypto(securementEncryptionCrypto); } /** * Defines which key identifier type to use. The WS-Security specifications recommends to use the identifier type * {@code IssuerSerial}. For possible encryption key identifier types refer to {@link * org.apache.ws.security.handler.WSHandlerConstants#keyIdentifier}. For encryption {@code IssuerSerial}, * {@code X509KeyIdentifier}, {@code DirectReference}, {@code Thumbprint}, * {@code SKIKeyIdentifier}, and {@code EmbeddedKeyName} are valid only. */ public void setSecurementEncryptionKeyIdentifier(String securementEncryptionKeyIdentifier) { handler.setOption(WSHandlerConstants.ENC_KEY_ID, securementEncryptionKeyIdentifier); } /** * Defines which algorithm to use to encrypt the generated symmetric key. Currently WSS4J supports {@link * WSConstants#KEYTRANSPORT_RSA15} and {@link WSConstants#KEYTRANSPORT_RSAOEP}. */ public void setSecurementEncryptionKeyTransportAlgorithm(String securementEncryptionKeyTransportAlgorithm) { handler.setOption(WSHandlerConstants.ENC_KEY_TRANSPORT, securementEncryptionKeyTransportAlgorithm); } /** * Property to define which parts of the request shall be encrypted. * * <p>The value of this property is a list of semicolon separated element names that identify the elements to encrypt. * An encryption mode specifier and a namespace identification, each inside a pair of curly brackets, may precede * each element name. * * <p>The encryption mode specifier is either {@code {Content}} or {@code {Element}}. Please refer to the W3C * XML Encryption specification about the differences between Element and Content encryption. The encryption mode * defaults to {@code Content} if it is omitted. Example of a list: * <pre> * <property name="securementEncryptionParts" * value="{Content}{http://example.org/paymentv2}CreditCard; * {Element}{}UserName" /> * </pre> * The first entry of the list identifies the element {@code CreditCard} in the namespace * {@code http://example.org/paymentv2}, and will encrypt its content. Be aware that the element name, the * namespace identifier, and the encryption modifier are case sensitive. * * <p>The encryption modifier and the namespace identifier can be omitted. In this case the encryption mode defaults to * {@code Content} and the namespace is set to the SOAP namespace. * * <p>An empty encryption mode defaults to {@code Content}, an empty namespace identifier defaults to the SOAP * namespace. The second line of the example defines {@code Element} as encryption mode for an * {@code UserName} element in the SOAP namespace. * * <p>To specify an element without a namespace use the string {@code Null} as the namespace name (this is a case * sensitive string) * * <p>If no list is specified, the handler encrypts the SOAP Body in {@code Content} mode by default. */ public void setSecurementEncryptionParts(String securementEncryptionParts) { handler.setOption(WSHandlerConstants.ENCRYPTION_PARTS, securementEncryptionParts); } /** * Defines which symmetric encryption algorithm to use. WSS4J supports the following alorithms: {@link * WSConstants#TRIPLE_DES}, {@link WSConstants#AES_128}, {@link WSConstants#AES_256}, and {@link * WSConstants#AES_192}. Except for AES 192 all of these algorithms are required by the XML Encryption * specification. */ public void setSecurementEncryptionSymAlgorithm(String securementEncryptionSymAlgorithm) { this.handler.setOption(WSHandlerConstants.ENC_SYM_ALGO, securementEncryptionSymAlgorithm); } /** * The user's name for encryption. * * <p>The encryption functions uses the public key of this user's certificate to encrypt the generated symmetric key. * * <p>If this parameter is not set, then the encryption function falls back to the {@link * org.apache.ws.security.handler.WSHandlerConstants#USER} parameter to get the certificate. * * <p>If <b>only</b> encryption of the SOAP body data is requested, it is recommended to use this parameter to define * the username. The application can then use the standard user and password functions (see example at {@link * org.apache.ws.security.handler.WSHandlerConstants#USER} to enable HTTP authentication functions. * * <p>Encryption only does not authenticate a user / sender, therefore it does not need a password. * * <p>Placing the username of the encryption certificate in the configuration file is not a security risk, because the * public key of that certificate is used only. */ public void setSecurementEncryptionUser(String securementEncryptionUser) { handler.setOption(WSHandlerConstants.ENCRYPTION_USER, securementEncryptionUser); } public void setSecurementPassword(String securementPassword) { this.handler.setSecurementPassword(securementPassword); } /** * Specific parameter for UsernameToken action to define the encoding of the passowrd. * * <p>The parameter can be set to either {@link WSConstants#PW_DIGEST} or to {@link WSConstants#PW_TEXT}. * * <p>The default setting is PW_DIGEST. */ public void setSecurementPasswordType(String securementUsernameTokenPasswordType) { handler.setOption(WSHandlerConstants.PASSWORD_TYPE, securementUsernameTokenPasswordType); } /** * Defines which signature algorithm to use. * @see WSConstants#RSA * @see WSConstants#DSA */ public void setSecurementSignatureAlgorithm(String securementSignatureAlgorithm) { handler.setOption(WSHandlerConstants.SIG_ALGO, securementSignatureAlgorithm); } /** * Defines which signature digest algorithm to use. */ public void setSecurementSignatureDigestAlgorithm(String digestAlgorithm) { handler.setOption(WSHandlerConstants.SIG_DIGEST_ALGO, digestAlgorithm); } public void setSecurementSignatureCrypto(Crypto securementSignatureCrypto) { handler.setSecurementSignatureCrypto(securementSignatureCrypto); } /** * Defines which key identifier type to use. The WS-Security specifications recommends to use the identifier type * {@code IssuerSerial}. For possible signature key identifier types refer to {@link * org.apache.ws.security.handler.WSHandlerConstants#keyIdentifier}. For signature {@code IssuerSerial} and * {@code DirectReference} are valid only. */ public void setSecurementSignatureKeyIdentifier(String securementSignatureKeyIdentifier) { handler.setOption(WSHandlerConstants.SIG_KEY_ID, securementSignatureKeyIdentifier); } /** * Property to define which parts of the request shall be signed. * * <p>Refer to {@link #setSecurementEncryptionParts(String)} for a detailed description of the format of the value * string. * * <p>If this property is not specified the handler signs the SOAP Body by default. * * <p>The WS Security specifications define several formats to transfer the signature tokens (certificates) or * references to these tokens. Thus, the plain element name {@code Token} signs the token and takes care of the * different formats. * * <p>To sign the SOAP body <b>and</b> the signature token the value of this parameter must contain: * <pre> * <property name="securementSignatureParts" * value="{}{http://schemas.xmlsoap.org/soap/envelope/}Body; Token" /> * </pre> * To specify an element without a namespace use the string {@code Null} as the namespace name (this is a case * sensitive string) * * <p>If there is no other element in the request with a local name of {@code Body} then the SOAP namespace * identifier can be empty ({@code {}}). */ public void setSecurementSignatureParts(String securementSignatureParts) { handler.setOption(WSHandlerConstants.SIGNATURE_PARTS, securementSignatureParts); } /** * The user's name for signature. * * <p>This name is used as the alias name in the keystore to get user's * certificate and private key to perform signing. * * <p>If this parameter is not set, then the signature * function falls back to the alias specified by {@link #setSecurementUsername(String)}. * */ public void setSecurementSignatureUser(String securementSignatureUser) { handler.setOption(WSHandlerConstants.SIGNATURE_USER, securementSignatureUser); } /** Sets the username for securement username token or/and the alias of the private key for securement signature */ public void setSecurementUsername(String securementUsername) { this.securementUsername = securementUsername; } /** Sets the time to live on the outgoing message */ public void setSecurementTimeToLive(int securementTimeToLive) { if (securementTimeToLive <= 0) { throw new IllegalArgumentException("timeToLive must be positive"); } this.securementTimeToLive = securementTimeToLive; } /** * Enables the derivation of keys as per the UsernameTokenProfile 1.1 spec. Default is {@code true}. */ public void setSecurementUseDerivedKey(boolean securementUseDerivedKey) { this.securementUseDerivedKey = securementUseDerivedKey; } /** Sets the server-side time to live */ public void setValidationTimeToLive(int validationTimeToLive) { if (validationTimeToLive <= 0) { throw new IllegalArgumentException("timeToLive must be positive"); } this.validationTimeToLive = validationTimeToLive; } /** Sets the validation actions to be executed by the interceptor. */ public void setValidationActions(String actions) { this.validationActions = actions; try { validationActionsVector = WSSecurityUtil.decodeAction(actions); } catch (WSSecurityException ex) { throw new IllegalArgumentException(ex); } } public void setValidationActor(String validationActor) { this.validationActor = validationActor; } /** * Sets the {@link org.apache.ws.security.WSPasswordCallback} handler to use when validating messages. * * @see #setValidationCallbackHandlers(CallbackHandler[]) */ public void setValidationCallbackHandler(CallbackHandler callbackHandler) { this.validationCallbackHandler = callbackHandler; } /** * Sets the {@link org.apache.ws.security.WSPasswordCallback} handlers to use when validating messages. * * @see #setValidationCallbackHandler(CallbackHandler) */ public void setValidationCallbackHandlers(CallbackHandler[] callbackHandler) { this.validationCallbackHandler = new CallbackHandlerChain(callbackHandler); } /** Sets the Crypto to use to decrypt incoming messages */ public void setValidationDecryptionCrypto(Crypto decryptionCrypto) { this.validationDecryptionCrypto = decryptionCrypto; } /** Sets the Crypto to use to verify the signature of incoming messages */ public void setValidationSignatureCrypto(Crypto signatureCrypto) { this.validationSignatureCrypto = signatureCrypto; } /** Whether to enable signatureConfirmation or not. By default signatureConfirmation is enabled */ public void setEnableSignatureConfirmation(boolean enableSignatureConfirmation) { handler.setOption(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, enableSignatureConfirmation); this.enableSignatureConfirmation = enableSignatureConfirmation; } /** Sets if the generated timestamp header's precision is in milliseconds. */ public void setTimestampPrecisionInMilliseconds(boolean timestampPrecisionInMilliseconds) { handler.setOption(WSHandlerConstants.TIMESTAMP_PRECISION, timestampPrecisionInMilliseconds); } /** Sets whether or not timestamp verification is done with the server-side time to live */ public void setTimestampStrict(boolean timestampStrict) { this.timestampStrict = timestampStrict; } /** * Enables the {@code mustUnderstand} attribute on WS-Security headers on outgoing messages. Default is * {@code true}. */ public void setSecurementMustUnderstand(boolean securementMustUnderstand) { handler.setOption(WSHandlerConstants.MUST_UNDERSTAND, securementMustUnderstand); } /** * Sets whether or not a {@code Nonce} element is added to the * {@code UsernameToken}s. Default is {@code false}. */ public void setSecurementUsernameTokenNonce(boolean securementUsernameTokenNonce) { handler.setOption(ConfigurationConstants.ADD_USERNAMETOKEN_NONCE, securementUsernameTokenNonce); } /** * Sets whether or not a {@code Created} element is added to the * {@code UsernameToken}s. Default is {@code false}. */ public void setSecurementUsernameTokenCreated(boolean securementUsernameTokenCreated) { handler.setOption(ConfigurationConstants.ADD_USERNAMETOKEN_CREATED, securementUsernameTokenCreated); } /** * Sets the web service specification settings. * <p> * The default settings follow the latest OASIS and changing anything might violate the OASIS specs. * * @param config web service security configuration or {@code null} to use default settings */ public void setWssConfig(WSSConfig config) { securityEngine.setWssConfig(config); wssConfig = config; } /** * Set whether to enable CRL checking or not when verifying trust in a certificate. */ public void setEnableRevocation(boolean enableRevocation) { this.enableRevocation = enableRevocation; } /** * Set the WS-I Basic Security Profile compliance mode. Default is {@code true}. */ public void setBspCompliant(boolean bspCompliant) { this.handler.setOption(WSHandlerConstants.IS_BSP_COMPLIANT, bspCompliant); this.bspCompliant = bspCompliant; } /** * Sets whether the RSA 1.5 key transport algorithm is allowed. */ public void setAllowRSA15KeyTransportAlgorithm(boolean allow) { this.allowRSA15KeyTransportAlgorithm = allow; } /** * Sets the time in seconds in the future within which the Created time of an * incoming Timestamp is valid. The default is 60 seconds. */ public void setFutureTimeToLive(int futureTimeToLive) { if (futureTimeToLive <= 0) { throw new IllegalArgumentException("futureTimeToLive must be positive"); } this.futureTimeToLive = futureTimeToLive; } public boolean getRemoveSecurityHeader() { return removeSecurityHeader; } public void setRemoveSecurityHeader(boolean removeSecurityHeader) { this.removeSecurityHeader = removeSecurityHeader; } @Override public void afterPropertiesSet() throws Exception { Assert.isTrue(validationActions != null || securementActions != null, "validationActions or securementActions are required"); if (validationActions != null) { if (validationActionsVector.contains(WSConstants.UT)) { Assert.notNull(validationCallbackHandler, "validationCallbackHandler is required"); } if (validationActionsVector.contains(WSConstants.SIGN)) { Assert.notNull(validationSignatureCrypto, "validationSignatureCrypto is required"); } } // securement actions are not to be validated at start up as they could // be configured dynamically via the message context } @Override protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext) throws WsSecuritySecurementException { List<HandlerAction> securementActionsVector = new ArrayList<HandlerAction>(); try { securementActionsVector = WSSecurityUtil.decodeHandlerAction(securementActions, wssConfig); } catch (WSSecurityException ex) { throw new Wss4jSecuritySecurementException(ex.getMessage(), ex); } if (securementActionsVector.isEmpty() && !enableSignatureConfirmation) { return; } if (logger.isDebugEnabled()) { logger.debug("Securing message [" + soapMessage + "] with actions [" + securementActions + "]"); } RequestData requestData = initializeRequestData(messageContext); Document envelopeAsDocument = soapMessage.getDocument(); try { handler.doSenderAction(envelopeAsDocument, requestData, securementActionsVector, false); } catch (WSSecurityException ex) { throw new Wss4jSecuritySecurementException(ex.getMessage(), ex); } soapMessage.setDocument(envelopeAsDocument); } /** * Creates and initializes a request data for the given message context. * * @param messageContext the message context * @return the request data */ protected RequestData initializeRequestData(MessageContext messageContext) { RequestData requestData = new RequestData(); requestData.setMsgContext(messageContext); // reads securementUsername first from the context then from the property String contextUsername = (String) messageContext.getProperty(SECUREMENT_USER_PROPERTY_NAME); if (StringUtils.hasLength(contextUsername)) { requestData.setUsername(contextUsername); } else { requestData.setUsername(securementUsername); } requestData.setTimeStampTTL(securementTimeToLive); requestData.setUseDerivedKeyForMAC(securementUseDerivedKey); requestData.setWssConfig(wssConfig); messageContext.setProperty(WSHandlerConstants.TTL_TIMESTAMP, Integer.toString(securementTimeToLive)); // allow for qualified password types for .Net interoperability requestData.setAllowNamespaceQualifiedPasswordTypes(true); return requestData; } /** * Creates and initializes a request data for the given message context. * * @param messageContext the message context * @return the request data */ protected RequestData initializeValidationRequestData(MessageContext messageContext) { RequestData requestData = new RequestData(); requestData.setMsgContext(messageContext); requestData.setWssConfig(wssConfig); requestData.setDecCrypto(validationDecryptionCrypto); requestData.setSigVerCrypto(validationSignatureCrypto); requestData.setCallbackHandler(validationCallbackHandler); messageContext.setProperty(WSHandlerConstants.TTL_TIMESTAMP, Integer.toString(validationTimeToLive)); requestData.setAllowRSA15KeyTransportAlgorithm(allowRSA15KeyTransportAlgorithm); requestData.setDisableBSPEnforcement(!bspCompliant); if (requestData.getBSPEnforcer() != null) { requestData.getBSPEnforcer().setDisableBSPRules(!bspCompliant); } // allow for qualified password types for .Net interoperability requestData.setAllowNamespaceQualifiedPasswordTypes(true); return requestData; } @Override protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext) throws WsSecurityValidationException { if (logger.isDebugEnabled()) { logger.debug("Validating message [" + soapMessage + "] with actions [" + validationActions + "]"); } if (validationActionsVector.contains(WSConstants.NO_SECURITY)) { return; } Document envelopeAsDocument = soapMessage.getDocument(); // Header processing try { RequestData validationData = initializeValidationRequestData(messageContext); String actor = validationActor; if (actor == null) { actor = ""; } Element elem = WSSecurityUtil.getSecurityHeader(envelopeAsDocument, actor); WSHandlerResult result = securityEngine .processSecurityHeader(elem, validationData); // Results verification if (CollectionUtils.isEmpty(result.getResults())) { throw new Wss4jSecurityValidationException("No WS-Security header found"); } checkResults(result.getResults(), validationActionsVector); // puts the results in the context // useful for Signature Confirmation updateContextWithResults(messageContext, result.getResults()); verifyCertificateTrust(result); verifyTimestamp(result); processPrincipal(result); } catch (WSSecurityException ex) { throw new Wss4jSecurityValidationException(ex.getMessage(), ex); } soapMessage.setDocument(envelopeAsDocument); if (this.getRemoveSecurityHeader()) { soapMessage.getEnvelope().getHeader().removeHeaderElement(WS_SECURITY_NAME); } } /** * Checks whether the received headers match the configured validation actions. Subclasses could override this method * for custom verification behavior. * * * @param results the results of the validation function * @param validationActions the decoded validation actions * @throws Wss4jSecurityValidationException if the results are deemed invalid */ protected void checkResults(List<WSSecurityEngineResult> results, List<Integer> validationActions) throws Wss4jSecurityValidationException { if (!handler.checkReceiverResultsAnyOrder(results, validationActions)) { throw new Wss4jSecurityValidationException("Security processing failed (actions mismatch)"); } } /** * Puts the results of WS-Security headers processing in the message context. Some actions like Signature * Confirmation require this. */ @SuppressWarnings("unchecked") private void updateContextWithResults(MessageContext messageContext, List<WSSecurityEngineResult> results) { List<WSHandlerResult> handlerResults; if ((handlerResults = (List<WSHandlerResult>) messageContext.getProperty(WSHandlerConstants.RECV_RESULTS)) == null) { handlerResults = new ArrayList<WSHandlerResult>(); messageContext.setProperty(WSHandlerConstants.RECV_RESULTS, handlerResults); } WSHandlerResult rResult = new WSHandlerResult(validationActor, results, Collections.<Integer, List<WSSecurityEngineResult>>emptyMap()); handlerResults.add(0, rResult); messageContext.setProperty(WSHandlerConstants.RECV_RESULTS, handlerResults); } /** Verifies the trust of a certificate. * @param result*/ protected void verifyCertificateTrust(WSHandlerResult result) throws WSSecurityException { List<WSSecurityEngineResult> results = result.getActionResults().get(WSConstants.SIGN); if (!CollectionUtils.isEmpty(results)) { WSSecurityEngineResult actionResult = results.get(0); X509Certificate returnCert = (X509Certificate) actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE); Credential credential = new Credential(); credential.setCertificates(new X509Certificate[] { returnCert}); RequestData requestData = new RequestData(); requestData.setSigVerCrypto(validationSignatureCrypto); requestData.setEnableRevocation(enableRevocation); SignatureTrustValidator validator = new SignatureTrustValidator(); validator.validate(credential, requestData); } } /** Verifies the timestamp. * @param result*/ protected void verifyTimestamp(WSHandlerResult result) throws WSSecurityException { List<WSSecurityEngineResult> results = result.getActionResults().get(WSConstants.TS); if (!CollectionUtils.isEmpty(results)) { WSSecurityEngineResult actionResult = results.get(0); Timestamp timestamp = (Timestamp) actionResult.get(WSSecurityEngineResult.TAG_TIMESTAMP); if (timestamp != null && timestampStrict) { Credential credential = new Credential(); credential.setTimestamp(timestamp); RequestData requestData = new RequestData(); requestData.setWssConfig(WSSConfig.getNewInstance()); requestData.setTimeStampTTL(validationTimeToLive); requestData.setTimeStampStrict(timestampStrict); requestData.setTimeStampFutureTTL(futureTimeToLive); TimestampValidator validator = new TimestampValidator(); validator.validate(credential, requestData); } } } private void processPrincipal(WSHandlerResult result) { List<WSSecurityEngineResult> results = result.getActionResults().get(WSConstants.UT); if (!CollectionUtils.isEmpty(results)) { WSSecurityEngineResult actionResult = results.get(0); Principal principal = (Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL); if (principal != null && principal instanceof WSUsernameTokenPrincipalImpl) { WSUsernameTokenPrincipalImpl usernameTokenPrincipal = (WSUsernameTokenPrincipalImpl) principal; UsernameTokenPrincipalCallback callback = new UsernameTokenPrincipalCallback(usernameTokenPrincipal); try { validationCallbackHandler.handle(new Callback[]{callback}); } catch (IOException ex) { logger.warn("Principal callback resulted in IOException", ex); } catch (UnsupportedCallbackException ex) { // ignore } } } } @Override protected void cleanUp() { if (validationCallbackHandler != null) { try { CleanupCallback cleanupCallback = new CleanupCallback(); validationCallbackHandler.handle(new Callback[]{cleanupCallback}); } catch (IOException ex) { logger.warn("Cleanup callback resulted in IOException", ex); } catch (UnsupportedCallbackException ex) { // ignore } } } }