/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cxf.ws.security.wss4j.policyhandlers; import java.io.IOException; import java.security.Key; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.crypto.spec.SecretKeySpec; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import javax.xml.namespace.QName; import javax.xml.soap.SOAPException; import org.w3c.dom.Element; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.message.MessageUtils; import org.apache.cxf.rt.security.utils.SecurityUtils; import org.apache.cxf.ws.policy.AssertionInfo; import org.apache.cxf.ws.policy.AssertionInfoMap; import org.apache.cxf.ws.security.SecurityConstants; import org.apache.cxf.ws.security.policy.PolicyUtils; import org.apache.cxf.ws.security.tokenstore.SecurityToken; import org.apache.wss4j.common.ext.WSPasswordCallback; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.saml.SAMLCallback; import org.apache.wss4j.common.saml.bean.KeyInfoBean; import org.apache.wss4j.common.saml.bean.SubjectBean; import org.apache.wss4j.common.saml.bean.Version; import org.apache.wss4j.common.util.KeyUtils; import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.policy.SPConstants; import org.apache.wss4j.policy.SPConstants.IncludeTokenType; import org.apache.wss4j.policy.model.AbstractBinding; import org.apache.wss4j.policy.model.AbstractToken; import org.apache.wss4j.policy.model.AlgorithmSuite.AlgorithmSuiteType; import org.apache.wss4j.policy.model.Attachments; import org.apache.wss4j.policy.model.ContentEncryptedElements; import org.apache.wss4j.policy.model.EncryptedElements; import org.apache.wss4j.policy.model.EncryptedParts; import org.apache.wss4j.policy.model.Header; import org.apache.wss4j.policy.model.IssuedToken; import org.apache.wss4j.policy.model.KerberosToken; import org.apache.wss4j.policy.model.KeyValueToken; import org.apache.wss4j.policy.model.Layout; import org.apache.wss4j.policy.model.Layout.LayoutType; import org.apache.wss4j.policy.model.SamlToken; import org.apache.wss4j.policy.model.SamlToken.SamlTokenType; import org.apache.wss4j.policy.model.SignedElements; import org.apache.wss4j.policy.model.SignedParts; import org.apache.wss4j.policy.model.SupportingTokens; import org.apache.wss4j.policy.model.SymmetricBinding; import org.apache.wss4j.policy.model.UsernameToken; import org.apache.wss4j.policy.model.UsernameToken.PasswordType; import org.apache.wss4j.policy.model.Wss10; import org.apache.wss4j.policy.model.Wss11; import org.apache.wss4j.policy.model.X509Token; import org.apache.wss4j.policy.model.X509Token.TokenType; import org.apache.wss4j.policy.model.XPath; import org.apache.wss4j.stax.ext.WSSConstants; import org.apache.wss4j.stax.ext.WSSConstants.UsernameTokenPasswordType; import org.apache.wss4j.stax.ext.WSSSecurityProperties; import org.apache.wss4j.stax.impl.securityToken.KerberosClientSecurityToken; import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants; import org.apache.xml.security.algorithms.JCEMapper; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.stax.ext.OutboundSecurityContext; import org.apache.xml.security.stax.ext.SecurePart; import org.apache.xml.security.stax.ext.SecurePart.Modifier; import org.apache.xml.security.stax.impl.securityToken.GenericOutboundSecurityToken; import org.apache.xml.security.stax.securityEvent.SecurityEvent; import org.apache.xml.security.stax.securityEvent.SecurityEventConstants; import org.apache.xml.security.stax.securityEvent.TokenSecurityEvent; import org.apache.xml.security.stax.securityToken.OutboundSecurityToken; import org.apache.xml.security.stax.securityToken.SecurityTokenConstants; import org.apache.xml.security.stax.securityToken.SecurityTokenProvider; /** * */ public abstract class AbstractStaxBindingHandler extends AbstractCommonBindingHandler { protected boolean timestampAdded; protected boolean signatureConfirmationAdded; protected Set<SecurePart> encryptedTokensList = new HashSet<>(); protected Map<AbstractToken, SecurePart> endEncSuppTokMap; protected Map<AbstractToken, SecurePart> endSuppTokMap; protected Map<AbstractToken, SecurePart> sgndEndEncSuppTokMap; protected Map<AbstractToken, SecurePart> sgndEndSuppTokMap; protected final OutboundSecurityContext outboundSecurityContext; private final WSSSecurityProperties properties; private AbstractBinding binding; public AbstractStaxBindingHandler( WSSSecurityProperties properties, SoapMessage msg, AbstractBinding binding, OutboundSecurityContext outboundSecurityContext ) { super(msg); this.properties = properties; this.binding = binding; this.outboundSecurityContext = outboundSecurityContext; } protected SecurePart addUsernameToken(UsernameToken usernameToken) { assertToken(usernameToken); IncludeTokenType includeToken = usernameToken.getIncludeTokenType(); if (!isTokenRequired(includeToken)) { return null; } // Action properties.addAction(WSSConstants.USERNAMETOKEN); // Password Type PasswordType passwordType = usernameToken.getPasswordType(); if (passwordType == PasswordType.HashPassword) { properties.setUsernameTokenPasswordType(UsernameTokenPasswordType.PASSWORD_DIGEST); } else if (passwordType == PasswordType.NoPassword) { properties.setUsernameTokenPasswordType(UsernameTokenPasswordType.PASSWORD_NONE); } else { properties.setUsernameTokenPasswordType(UsernameTokenPasswordType.PASSWORD_TEXT); } // Nonce + Created if (usernameToken.isNonce()) { properties.setAddUsernameTokenNonce(true); } if (usernameToken.isCreated()) { properties.setAddUsernameTokenCreated(true); } // Check if a CallbackHandler was specified if (properties.getCallbackHandler() == null) { String password = (String)SecurityUtils.getSecurityPropertyValue(SecurityConstants.PASSWORD, message); if (password != null) { String username = (String)SecurityUtils.getSecurityPropertyValue(SecurityConstants.USERNAME, message); UTCallbackHandler callbackHandler = new UTCallbackHandler(username, password); properties.setCallbackHandler(callbackHandler); } } return new SecurePart(WSSConstants.TAG_WSSE_USERNAME_TOKEN, Modifier.Element); } private static class UTCallbackHandler implements CallbackHandler { private final String username; private final String password; UTCallbackHandler(String username, String password) { this.username = username; this.password = password; } @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback callback : callbacks) { if (callback instanceof WSPasswordCallback) { WSPasswordCallback pwcb = (WSPasswordCallback)callback; if (pwcb.getIdentifier().equals(username)) { pwcb.setPassword(password); } } } } } protected SecurePart addKerberosToken( KerberosToken token, boolean signed, boolean endorsing, boolean encrypting ) throws WSSecurityException { assertToken(token); IncludeTokenType includeToken = token.getIncludeTokenType(); if (!isTokenRequired(includeToken)) { return null; } final SecurityToken secToken = getSecurityToken(); if (secToken == null) { unassertPolicy(token, "Could not find KerberosToken"); } // Convert to WSS4J token final KerberosClientSecurityToken wss4jToken = new KerberosClientSecurityToken(secToken.getData(), secToken.getKey(), secToken.getId()) { @Override public Key getSecretKey(String algorithmURI) throws XMLSecurityException { if (secToken.getSecret() != null && algorithmURI != null && !"".equals(algorithmURI)) { return KeyUtils.prepareSecretKey(algorithmURI, secToken.getSecret()); } return secToken.getKey(); } }; wss4jToken.setSha1Identifier(secToken.getSHA1()); final SecurityTokenProvider<OutboundSecurityToken> kerberosSecurityTokenProvider = new SecurityTokenProvider<OutboundSecurityToken>() { @Override public OutboundSecurityToken getSecurityToken() throws WSSecurityException { return wss4jToken; } @Override public String getId() { return wss4jToken.getId(); } }; outboundSecurityContext.registerSecurityTokenProvider( kerberosSecurityTokenProvider.getId(), kerberosSecurityTokenProvider); outboundSecurityContext.put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_KERBEROS, kerberosSecurityTokenProvider.getId()); if (encrypting) { outboundSecurityContext.put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION, kerberosSecurityTokenProvider.getId()); } if (endorsing) { outboundSecurityContext.put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, kerberosSecurityTokenProvider.getId()); } // Action properties.addAction(WSSConstants.KERBEROS_TOKEN); /* if (endorsing) { String action = (String)config.get(ConfigurationConstants.ACTION); config.put(ConfigurationConstants.ACTION, ConfigurationConstants.SIGNATURE_WITH_KERBEROS_TOKEN + " " + action); // config.put(ConfigurationConstants.SIG_KEY_ID, "DirectReference"); } */ SecurePart securePart = new SecurePart(WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN, Modifier.Element); securePart.setIdToSign(wss4jToken.getId()); return securePart; } protected SecurePart addSamlToken( SamlToken token, boolean signed, boolean endorsing ) throws WSSecurityException { assertToken(token); IncludeTokenType includeToken = token.getIncludeTokenType(); if (!isTokenRequired(includeToken)) { return null; } // // Get the SAML CallbackHandler // Object o = SecurityUtils.getSecurityPropertyValue(SecurityConstants.SAML_CALLBACK_HANDLER, message); try { CallbackHandler handler = SecurityUtils.getCallbackHandler(o); if (handler == null) { unassertPolicy(token, "No SAML CallbackHandler available"); return null; } properties.setSamlCallbackHandler(handler); } catch (Exception ex) { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex); } // Action WSSConstants.Action actionToPerform = WSSConstants.SAML_TOKEN_UNSIGNED; if (signed || endorsing) { actionToPerform = WSSConstants.SAML_TOKEN_SIGNED; } properties.addAction(actionToPerform); QName qname = WSSConstants.TAG_SAML2_ASSERTION; SamlTokenType tokenType = token.getSamlTokenType(); if (tokenType == SamlTokenType.WssSamlV11Token10 || tokenType == SamlTokenType.WssSamlV11Token11) { qname = WSSConstants.TAG_SAML_ASSERTION; } return new SecurePart(qname, Modifier.Element); } protected SecurePart addIssuedToken(AbstractToken token, SecurityToken secToken, boolean signed, boolean endorsing) { assertToken(token); if (isTokenRequired(token.getIncludeTokenType())) { final Element el = secToken.getToken(); if (el != null && "Assertion".equals(el.getLocalName()) && (WSSConstants.NS_SAML.equals(el.getNamespaceURI()) || WSSConstants.NS_SAML2.equals(el.getNamespaceURI()))) { WSSConstants.Action actionToPerform = WSSConstants.SAML_TOKEN_UNSIGNED; if (endorsing) { actionToPerform = WSSConstants.SAML_TOKEN_SIGNED; } properties.addAction(actionToPerform); // Mock up a Subject so that the SAMLTokenOutProcessor can get access to the certificate final SubjectBean subjectBean; if (signed || endorsing) { KeyInfoBean keyInfo = new KeyInfoBean(); keyInfo.setCertificate(secToken.getX509Certificate()); keyInfo.setEphemeralKey(secToken.getSecret()); subjectBean = new SubjectBean("", "", ""); subjectBean.setKeyInfo(keyInfo); } else { subjectBean = null; } CallbackHandler callbackHandler = new CallbackHandler() { @Override public void handle(Callback[] callbacks) { for (Callback callback : callbacks) { if (callback instanceof SAMLCallback) { SAMLCallback samlCallback = (SAMLCallback)callback; samlCallback.setAssertionElement(el); samlCallback.setSubject(subjectBean); if (WSConstants.SAML_NS.equals(el.getNamespaceURI())) { samlCallback.setSamlVersion(Version.SAML_11); } else { samlCallback.setSamlVersion(Version.SAML_20); } } } } }; properties.setSamlCallbackHandler(callbackHandler); QName qname = WSSConstants.TAG_SAML2_ASSERTION; if (WSConstants.SAML_NS.equals(el.getNamespaceURI())) { qname = WSSConstants.TAG_SAML_ASSERTION; } return new SecurePart(qname, Modifier.Element); } else if (isRequestor()) { // An Encrypted Token...just include it as is properties.addAction(WSSConstants.CUSTOM_TOKEN); } } return null; } protected void storeSecurityToken(AbstractToken policyToken, SecurityToken tok) { SecurityTokenConstants.TokenType tokenType = WSSecurityTokenConstants.EncryptedKeyToken; if (tok.getTokenType() != null) { if (tok.getTokenType().startsWith(WSSConstants.NS_KERBEROS11_TOKEN_PROFILE)) { tokenType = WSSecurityTokenConstants.KERBEROS_TOKEN; } else if (tok.getTokenType().startsWith(WSSConstants.NS_SAML10_TOKEN_PROFILE) || tok.getTokenType().startsWith(WSSConstants.NS_SAML11_TOKEN_PROFILE)) { tokenType = WSSecurityTokenConstants.SAML_11_TOKEN; } else if (tok.getTokenType().startsWith(WSSConstants.NS_WSC_05_02) || tok.getTokenType().startsWith(WSSConstants.NS_WSC_05_12)) { tokenType = WSSecurityTokenConstants.SECURE_CONVERSATION_TOKEN; } } final Key key = tok.getKey(); final byte[] secret = tok.getSecret(); final X509Certificate[] certs = new X509Certificate[1]; if (tok.getX509Certificate() != null) { certs[0] = tok.getX509Certificate(); } final GenericOutboundSecurityToken encryptedKeySecurityToken = new GenericOutboundSecurityToken(tok.getId(), tokenType, key, certs) { @Override public Key getSecretKey(String algorithmURI) throws XMLSecurityException { if (secret != null && algorithmURI != null && !"".equals(algorithmURI)) { return KeyUtils.prepareSecretKey(algorithmURI, secret); } if (key != null) { return key; } if (secret != null) { String jceAlg = JCEMapper.getJCEKeyAlgorithmFromURI(algorithmURI); if (jceAlg == null || "".equals(jceAlg)) { jceAlg = "HmacSHA1"; } return new SecretKeySpec(secret, jceAlg); } return super.getSecretKey(algorithmURI); } }; // Store a DOM Element reference if it exists Element ref; if (isTokenRequired(policyToken.getIncludeTokenType())) { ref = tok.getAttachedReference(); } else { ref = tok.getUnattachedReference(); } if (ref != null && policyToken instanceof IssuedToken) { encryptedKeySecurityToken.setCustomTokenReference(ref); } final SecurityTokenProvider<OutboundSecurityToken> encryptedKeySecurityTokenProvider = new SecurityTokenProvider<OutboundSecurityToken>() { @Override public OutboundSecurityToken getSecurityToken() throws XMLSecurityException { return encryptedKeySecurityToken; } @Override public String getId() { return encryptedKeySecurityToken.getId(); } }; encryptedKeySecurityToken.setSha1Identifier(tok.getSHA1()); outboundSecurityContext.registerSecurityTokenProvider( encryptedKeySecurityTokenProvider.getId(), encryptedKeySecurityTokenProvider); outboundSecurityContext.put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION, encryptedKeySecurityTokenProvider.getId()); outboundSecurityContext.put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, encryptedKeySecurityTokenProvider.getId()); outboundSecurityContext.put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_CUSTOM_TOKEN, encryptedKeySecurityTokenProvider.getId()); } protected void configureTimestamp(AssertionInfoMap aim) { if (binding != null && binding.isIncludeTimestamp()) { timestampAdded = true; assertPolicy(new QName(binding.getName().getNamespaceURI(), SPConstants.INCLUDE_TIMESTAMP)); } } protected void configureLayout(AssertionInfoMap aim) { AssertionInfo ai = PolicyUtils.getFirstAssertionByLocalname(aim, SPConstants.LAYOUT); Layout layout = null; if (ai != null) { layout = (Layout)ai.getAssertion(); ai.setAsserted(true); } if (layout != null && layout.getLayoutType() != null) { assertPolicy(new QName(layout.getName().getNamespaceURI(), layout.getLayoutType().name())); } if (!timestampAdded) { return; } boolean timestampLast = layout != null && layout.getLayoutType() == LayoutType.LaxTsLast; WSSConstants.Action actionToPerform = WSSConstants.TIMESTAMP; List<WSSConstants.Action> actionList = properties.getActions(); if (timestampLast) { actionList.add(0, actionToPerform); } else { actionList.add(actionToPerform); } } protected WSSSecurityProperties getProperties() { return properties; } protected void configureSignature( AbstractToken token, boolean attached ) throws WSSecurityException { if (token instanceof X509Token) { X509Token x509Token = (X509Token) token; TokenType tokenType = x509Token.getTokenType(); if (tokenType == TokenType.WssX509PkiPathV1Token10 || tokenType == TokenType.WssX509PkiPathV1Token11) { properties.setUseSingleCert(false); } } properties.setSignatureKeyIdentifier(getKeyIdentifierType(token)); // Find out do we also need to include the token as per the Inclusion requirement WSSecurityTokenConstants.KeyIdentifier keyIdentifier = properties.getSignatureKeyIdentifier(); if (token instanceof X509Token && isTokenRequired(token.getIncludeTokenType()) && (WSSecurityTokenConstants.KeyIdentifier_IssuerSerial.equals(keyIdentifier) || WSSecurityTokenConstants.KEYIDENTIFIER_THUMBPRINT_IDENTIFIER.equals(keyIdentifier) || WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE.equals( keyIdentifier))) { properties.setIncludeSignatureToken(true); } else { properties.setIncludeSignatureToken(false); } String userNameKey = SecurityConstants.SIGNATURE_USERNAME; if (binding instanceof SymmetricBinding) { userNameKey = SecurityConstants.ENCRYPT_USERNAME; properties.setSignatureAlgorithm( binding.getAlgorithmSuite().getSymmetricSignature()); } else { properties.setSignatureAlgorithm( binding.getAlgorithmSuite().getAsymmetricSignature()); } properties.setSignatureCanonicalizationAlgorithm( binding.getAlgorithmSuite().getC14n().getValue()); String sigUser = (String)SecurityUtils.getSecurityPropertyValue(userNameKey, message); if (sigUser == null) { sigUser = (String)SecurityUtils.getSecurityPropertyValue(SecurityConstants.USERNAME, message); } if (sigUser != null && properties.getSignatureUser() == null) { properties.setSignatureUser(sigUser); } AlgorithmSuiteType algType = binding.getAlgorithmSuite().getAlgorithmSuiteType(); properties.setSignatureDigestAlgorithm(algType.getDigest()); // sig.setSigCanonicalization(binding.getAlgorithmSuite().getC14n().getValue()); boolean includePrefixes = MessageUtils.getContextualBoolean( message, SecurityConstants.ADD_INCLUSIVE_PREFIXES, true ); properties.setAddExcC14NInclusivePrefixes(includePrefixes); } protected WSSecurityTokenConstants.KeyIdentifier getKeyIdentifierType( AbstractToken token ) { WSSecurityTokenConstants.KeyIdentifier identifier = null; if (token instanceof X509Token) { X509Token x509Token = (X509Token)token; if (x509Token.isRequireIssuerSerialReference()) { identifier = WSSecurityTokenConstants.KeyIdentifier_IssuerSerial; } else if (x509Token.isRequireKeyIdentifierReference()) { identifier = WSSecurityTokenConstants.KeyIdentifier_SkiKeyIdentifier; } else if (x509Token.isRequireThumbprintReference()) { identifier = WSSecurityTokenConstants.KEYIDENTIFIER_THUMBPRINT_IDENTIFIER; } } else if (token instanceof KeyValueToken) { identifier = WSSecurityTokenConstants.KeyIdentifier_KeyValue; } if (identifier != null) { return identifier; } if (token.getIncludeTokenType() == IncludeTokenType.INCLUDE_TOKEN_NEVER) { Wss10 wss = getWss10(); if (wss == null || wss.isMustSupportRefKeyIdentifier()) { identifier = WSSecurityTokenConstants.KeyIdentifier_SkiKeyIdentifier; } else if (wss.isMustSupportRefIssuerSerial()) { identifier = WSSecurityTokenConstants.KeyIdentifier_IssuerSerial; } else if (wss instanceof Wss11 && ((Wss11) wss).isMustSupportRefThumbprint()) { identifier = WSSecurityTokenConstants.KEYIDENTIFIER_THUMBPRINT_IDENTIFIER; } } else if (token.getIncludeTokenType() == IncludeTokenType.INCLUDE_TOKEN_ALWAYS_TO_RECIPIENT && !isRequestor() && token instanceof X509Token) { identifier = WSSecurityTokenConstants.KeyIdentifier_IssuerSerial; } else if (token.getIncludeTokenType() == IncludeTokenType.INCLUDE_TOKEN_ALWAYS_TO_INITIATOR && isRequestor() && token instanceof X509Token) { identifier = WSSecurityTokenConstants.KeyIdentifier_IssuerSerial; } if (identifier != null) { return identifier; } return WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE; } protected Map<AbstractToken, SecurePart> handleSupportingTokens( Collection<AssertionInfo> tokenAssertions, boolean signed, boolean endorse ) throws Exception { if (tokenAssertions != null && !tokenAssertions.isEmpty()) { Map<AbstractToken, SecurePart> ret = new HashMap<>(); for (AssertionInfo assertionInfo : tokenAssertions) { if (assertionInfo.getAssertion() instanceof SupportingTokens) { assertionInfo.setAsserted(true); handleSupportingTokens((SupportingTokens)assertionInfo.getAssertion(), signed, endorse, ret); } } return ret; } return Collections.emptyMap(); } protected Map<AbstractToken, SecurePart> handleSupportingTokens( SupportingTokens suppTokens, boolean signed, boolean endorse ) throws Exception { return handleSupportingTokens(suppTokens, signed, endorse, new HashMap<AbstractToken, SecurePart>()); } protected Map<AbstractToken, SecurePart> handleSupportingTokens( SupportingTokens suppTokens, boolean signed, boolean endorse, Map<AbstractToken, SecurePart> ret ) throws Exception { if (suppTokens == null) { return ret; } for (AbstractToken token : suppTokens.getTokens()) { assertToken(token); if (!isTokenRequired(token.getIncludeTokenType())) { continue; } if (token instanceof UsernameToken) { handleUsernameTokenSupportingToken( (UsernameToken)token, endorse, suppTokens.isEncryptedToken(), ret ); /* TODO else if (isRequestor() && (token instanceof IssuedToken || token instanceof SecureConversationToken || token instanceof SecurityContextToken || token instanceof KerberosToken)) { } */ } else if (token instanceof IssuedToken) { SecurityToken sigTok = getSecurityToken(); SecurePart securePart = addIssuedToken((IssuedToken)token, sigTok, signed, endorse); if (securePart != null) { ret.put(token, securePart); if (suppTokens.isEncryptedToken()) { encryptedTokensList.add(securePart); } } } else if (token instanceof KerberosToken) { SecurePart securePart = addKerberosToken((KerberosToken)token, signed, endorse, false); if (securePart != null) { ret.put(token, securePart); if (suppTokens.isEncryptedToken()) { encryptedTokensList.add(securePart); } } } else if (token instanceof X509Token || token instanceof KeyValueToken) { assertToken(token); configureSignature(token, false); if (suppTokens.isEncryptedToken()) { SecurePart part = new SecurePart(WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN, Modifier.Element); encryptedTokensList.add(part); } ret.put(token, new SecurePart(WSSConstants.TAG_dsig_Signature, Modifier.Element)); } else if (token instanceof SamlToken) { SecurePart securePart = addSamlToken((SamlToken)token, signed, endorse); if (securePart != null) { ret.put(token, securePart); if (suppTokens.isEncryptedToken()) { encryptedTokensList.add(securePart); } } } } return ret; } protected void handleUsernameTokenSupportingToken( UsernameToken token, boolean endorse, boolean encryptedToken, Map<AbstractToken, SecurePart> ret ) throws Exception { if (endorse) { throw new Exception("Endorsing UsernameTokens are not supported in the streaming code"); } else { SecurePart securePart = addUsernameToken(token); if (securePart != null) { ret.put(token, securePart); //WebLogic and WCF always encrypt these //See: http://e-docs.bea.com/wls/docs103/webserv_intro/interop.html //encryptedTokensIdList.add(utBuilder.getId()); if (encryptedToken || MessageUtils.getContextualBoolean(message, SecurityConstants.ALWAYS_ENCRYPT_UT, true)) { encryptedTokensList.add(securePart); } } } } protected void addSupportingTokens() throws Exception { Collection<AssertionInfo> sgndSuppTokens = getAllAssertionsByLocalname(SPConstants.SIGNED_SUPPORTING_TOKENS); if (!sgndSuppTokens.isEmpty()) { Map<AbstractToken, SecurePart> sigSuppTokMap = this.handleSupportingTokens(sgndSuppTokens, true, false); addSignatureParts(sigSuppTokMap); } Collection<AssertionInfo> endSuppTokens = getAllAssertionsByLocalname(SPConstants.ENDORSING_SUPPORTING_TOKENS); if (!endSuppTokens.isEmpty()) { endSuppTokMap = this.handleSupportingTokens(endSuppTokens, false, true); } Collection<AssertionInfo> sgndEndSuppTokens = getAllAssertionsByLocalname(SPConstants.SIGNED_ENDORSING_SUPPORTING_TOKENS); if (!sgndEndSuppTokens.isEmpty()) { sgndEndSuppTokMap = this.handleSupportingTokens(sgndEndSuppTokens, true, true); addSignatureParts(sgndEndSuppTokMap); } Collection<AssertionInfo> sgndEncryptedSuppTokens = getAllAssertionsByLocalname(SPConstants.SIGNED_ENCRYPTED_SUPPORTING_TOKENS); if (!sgndEncryptedSuppTokens.isEmpty()) { Map<AbstractToken, SecurePart> sgndEncSuppTokMap = this.handleSupportingTokens(sgndEncryptedSuppTokens, true, false); addSignatureParts(sgndEncSuppTokMap); } Collection<AssertionInfo> endorsingEncryptedSuppTokens = getAllAssertionsByLocalname(SPConstants.ENDORSING_ENCRYPTED_SUPPORTING_TOKENS); if (!endorsingEncryptedSuppTokens.isEmpty()) { endEncSuppTokMap = this.handleSupportingTokens(endorsingEncryptedSuppTokens, false, true); } Collection<AssertionInfo> sgndEndEncSuppTokens = getAllAssertionsByLocalname(SPConstants.SIGNED_ENDORSING_ENCRYPTED_SUPPORTING_TOKENS); if (!sgndEndEncSuppTokens.isEmpty()) { sgndEndEncSuppTokMap = this.handleSupportingTokens(sgndEndEncSuppTokens, true, true); addSignatureParts(sgndEndEncSuppTokMap); } Collection<AssertionInfo> supportingToks = getAllAssertionsByLocalname(SPConstants.SUPPORTING_TOKENS); if (!supportingToks.isEmpty()) { this.handleSupportingTokens(supportingToks, false, false); } Collection<AssertionInfo> encryptedSupportingToks = getAllAssertionsByLocalname(SPConstants.ENCRYPTED_SUPPORTING_TOKENS); if (!encryptedSupportingToks.isEmpty()) { this.handleSupportingTokens(encryptedSupportingToks, false, false); } } protected void addSignatureParts(Map<AbstractToken, SecurePart> tokenMap) { if (tokenMap != null) { for (Map.Entry<AbstractToken, SecurePart> entry : tokenMap.entrySet()) { SecurePart part = entry.getValue(); QName name = part.getName(); List<WSSConstants.Action> actionList = properties.getActions(); // Don't add a signed SAML Token as a part, as it will be automatically signed by WSS4J if (!((WSSConstants.TAG_SAML_ASSERTION.equals(name) || WSSConstants.TAG_SAML2_ASSERTION.equals(name)) && actionList != null && actionList.contains(WSSConstants.SAML_TOKEN_SIGNED))) { properties.addSignaturePart(part); } } } } protected void addSignatureConfirmation(List<SecurePart> sigParts) { Wss10 wss10 = getWss10(); if (!(wss10 instanceof Wss11) || !((Wss11)wss10).isRequireSignatureConfirmation()) { //If we don't require sig confirmation simply go back :-) return; } // Enable SignatureConfirmation if (isRequestor()) { properties.setEnableSignatureConfirmationVerification(true); } else { properties.getActions().add(WSSConstants.SIGNATURE_CONFIRMATION); } if (sigParts != null) { SecurePart securePart = new SecurePart(WSSConstants.TAG_WSSE11_SIG_CONF, Modifier.Element); sigParts.add(securePart); } signatureConfirmationAdded = true; } /** * Identifies the portions of the message to be signed */ protected List<SecurePart> getSignedParts() throws SOAPException { SignedParts parts = null; SignedElements elements = null; AssertionInfoMap aim = message.get(AssertionInfoMap.class); AssertionInfo assertionInfo = PolicyUtils.getFirstAssertionByLocalname(aim, SPConstants.SIGNED_PARTS); if (assertionInfo != null) { parts = (SignedParts)assertionInfo.getAssertion(); assertionInfo.setAsserted(true); } assertionInfo = PolicyUtils.getFirstAssertionByLocalname(aim, SPConstants.SIGNED_ELEMENTS); if (assertionInfo != null) { elements = (SignedElements)assertionInfo.getAssertion(); assertionInfo.setAsserted(true); } List<SecurePart> signedParts = new ArrayList<>(); if (parts != null) { if (parts.isBody()) { QName soapBody = new QName(WSSConstants.NS_SOAP12, "Body"); SecurePart securePart = new SecurePart(soapBody, Modifier.Element); signedParts.add(securePart); } for (Header head : parts.getHeaders()) { String localName = head.getName(); if (localName == null) { localName = "*"; } QName qname = new QName(head.getNamespace(), localName); SecurePart securePart = new SecurePart(qname, Modifier.Element); securePart.setRequired(false); signedParts.add(securePart); } Attachments attachments = parts.getAttachments(); if (attachments != null) { Modifier modifier = Modifier.Element; if (attachments.isContentSignatureTransform()) { modifier = Modifier.Content; } SecurePart securePart = new SecurePart("cid:Attachments", modifier); securePart.setRequired(false); signedParts.add(securePart); } } if (elements != null && elements.getXPaths() != null) { for (XPath xPath : elements.getXPaths()) { List<QName> qnames = org.apache.wss4j.policy.stax.PolicyUtils.getElementPath(xPath); if (!qnames.isEmpty()) { SecurePart securePart = new SecurePart(qnames.get(qnames.size() - 1), Modifier.Element); signedParts.add(securePart); } } } return signedParts; } /** * Identifies the portions of the message to be encrypted */ protected List<SecurePart> getEncryptedParts() throws SOAPException { EncryptedParts parts = null; EncryptedElements elements = null; ContentEncryptedElements celements = null; AssertionInfoMap aim = message.get(AssertionInfoMap.class); Collection<AssertionInfo> ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.ENCRYPTED_PARTS); if (!ais.isEmpty()) { for (AssertionInfo ai : ais) { parts = (EncryptedParts)ai.getAssertion(); ai.setAsserted(true); } } ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.ENCRYPTED_ELEMENTS); if (!ais.isEmpty()) { for (AssertionInfo ai : ais) { elements = (EncryptedElements)ai.getAssertion(); ai.setAsserted(true); } } ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.CONTENT_ENCRYPTED_ELEMENTS); if (!ais.isEmpty()) { for (AssertionInfo ai : ais) { celements = (ContentEncryptedElements)ai.getAssertion(); ai.setAsserted(true); } } List<SecurePart> encryptedParts = new ArrayList<>(); if (parts != null) { if (parts.isBody()) { QName soapBody = new QName(WSSConstants.NS_SOAP12, "Body"); SecurePart securePart = new SecurePart(soapBody, Modifier.Content); encryptedParts.add(securePart); } for (Header head : parts.getHeaders()) { String localName = head.getName(); if (localName == null) { localName = "*"; } QName qname = new QName(head.getNamespace(), localName); SecurePart securePart = new SecurePart(qname, Modifier.Element); securePart.setRequired(false); encryptedParts.add(securePart); } Attachments attachments = parts.getAttachments(); if (attachments != null) { SecurePart securePart = new SecurePart("cid:Attachments", Modifier.Element); if (MessageUtils.getContextualBoolean( message, SecurityConstants.USE_ATTACHMENT_ENCRYPTION_CONTENT_ONLY_TRANSFORM, false)) { securePart.setModifier(Modifier.Content); } securePart.setRequired(false); encryptedParts.add(securePart); } } if (elements != null && elements.getXPaths() != null) { for (XPath xPath : elements.getXPaths()) { List<QName> qnames = org.apache.wss4j.policy.stax.PolicyUtils.getElementPath(xPath); if (!qnames.isEmpty()) { SecurePart securePart = new SecurePart(qnames.get(qnames.size() - 1), Modifier.Element); encryptedParts.add(securePart); } } } if (celements != null && celements.getXPaths() != null) { for (XPath xPath : celements.getXPaths()) { List<QName> qnames = org.apache.wss4j.policy.stax.PolicyUtils.getElementPath(xPath); if (!qnames.isEmpty()) { SecurePart securePart = new SecurePart(qnames.get(qnames.size() - 1), Modifier.Content); encryptedParts.add(securePart); } } } return encryptedParts; } protected org.apache.xml.security.stax.securityToken.SecurityToken findInboundSecurityToken(SecurityEventConstants.Event event) throws XMLSecurityException { @SuppressWarnings("unchecked") final List<SecurityEvent> incomingEventList = (List<SecurityEvent>) message.getExchange().get(SecurityEvent.class.getName() + ".in"); if (incomingEventList != null) { for (SecurityEvent incomingEvent : incomingEventList) { if (event == incomingEvent.getSecurityEventType()) { return ((TokenSecurityEvent<?>)incomingEvent).getSecurityToken(); } } } return null; } // Signature + Signed SAML Token actions are not allowed together protected void removeSignatureIfSignedSAML() { if (properties.getActions() != null) { List<WSSConstants.Action> actionList = properties.getActions(); if (actionList.contains(WSSConstants.SAML_TOKEN_SIGNED) && actionList.contains(WSSConstants.SIGNATURE)) { actionList.remove(WSSConstants.SIGNATURE); } } } // Put the Signature action before the SignatureConfirmation action protected void prependSignatureToSC() { if (properties.getActions() != null) { List<WSSConstants.Action> actionList = properties.getActions(); boolean sigConf = actionList.contains(WSSConstants.SIGNATURE_CONFIRMATION); if (sigConf && actionList.contains(WSSConstants.SIGNATURE)) { actionList.remove(WSSConstants.SIGNATURE_CONFIRMATION); actionList.add(actionList.indexOf(WSSConstants.SIGNATURE) + 1, WSSConstants.SIGNATURE_CONFIRMATION); } else if (sigConf && actionList.contains(WSSConstants.SIGNATURE_WITH_DERIVED_KEY)) { actionList.remove(WSSConstants.SIGNATURE_CONFIRMATION); actionList.add(actionList.indexOf(WSSConstants.SIGNATURE_WITH_DERIVED_KEY) + 1, WSSConstants.SIGNATURE_CONFIRMATION); } } } // If we have EncryptBeforeSigning, then we want to have the Signature component after // the Encrypt action, which is not the case if we have a Signed SAML Supporting Token protected void enforceEncryptBeforeSigningWithSignedSAML() { if (properties.getActions() != null) { List<WSSConstants.Action> actionList = properties.getActions(); if (actionList.contains(WSSConstants.SAML_TOKEN_SIGNED)) { actionList.remove(WSSConstants.SAML_TOKEN_SIGNED); actionList.add(WSSConstants.SAML_TOKEN_SIGNED); } } } // Reshuffle so that a IssuedToken/SecureConveration is above a Signature that references it protected void putCustomTokenAfterSignature() { if (properties.getActions() != null) { List<WSSConstants.Action> actionList = properties.getActions(); if ((actionList.contains(WSSConstants.SIGNATURE) || actionList.contains(WSSConstants.SIGNATURE_WITH_DERIVED_KEY) || actionList.contains(WSSConstants.SIGNATURE_WITH_KERBEROS_TOKEN)) && actionList.contains(WSSConstants.CUSTOM_TOKEN)) { getProperties().getActions().remove(WSSConstants.CUSTOM_TOKEN); getProperties().getActions().add(WSSConstants.CUSTOM_TOKEN); } } } }