/**
* 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.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.interceptor.Fault;
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.cxf.ws.security.tokenstore.TokenStoreUtils;
import org.apache.cxf.ws.security.wss4j.TokenStoreCallbackHandler;
import org.apache.wss4j.policy.SP11Constants;
import org.apache.wss4j.policy.SP12Constants;
import org.apache.wss4j.policy.SPConstants;
import org.apache.wss4j.policy.model.AbstractToken;
import org.apache.wss4j.policy.model.AbstractToken.DerivedKeys;
import org.apache.wss4j.policy.model.AlgorithmSuite.AlgorithmSuiteType;
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.SamlToken;
import org.apache.wss4j.policy.model.SecureConversationToken;
import org.apache.wss4j.policy.model.SecurityContextToken;
import org.apache.wss4j.policy.model.SignedElements;
import org.apache.wss4j.policy.model.SignedParts;
import org.apache.wss4j.policy.model.SpnegoContextToken;
import org.apache.wss4j.policy.model.SupportingTokens;
import org.apache.wss4j.policy.model.TransportBinding;
import org.apache.wss4j.policy.model.TransportToken;
import org.apache.wss4j.policy.model.UsernameToken;
import org.apache.wss4j.policy.model.X509Token;
import org.apache.wss4j.policy.model.XPath;
import org.apache.wss4j.stax.ext.WSSConstants;
import org.apache.wss4j.stax.ext.WSSSecurityProperties;
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;
/**
*
*/
public class StaxTransportBindingHandler extends AbstractStaxBindingHandler {
private static final Logger LOG = LogUtils.getL7dLogger(StaxTransportBindingHandler.class);
private TransportBinding tbinding;
public StaxTransportBindingHandler(
WSSSecurityProperties properties,
SoapMessage msg,
TransportBinding tbinding,
OutboundSecurityContext outboundSecurityContext
) {
super(properties, msg, tbinding, outboundSecurityContext);
this.tbinding = tbinding;
}
public void handleBinding() {
AssertionInfoMap aim = getMessage().get(AssertionInfoMap.class);
configureTimestamp(aim);
if (this.isRequestor()) {
if (tbinding != null) {
assertPolicy(tbinding.getName());
String asymSignatureAlgorithm =
(String)getMessage().getContextualProperty(SecurityConstants.ASYMMETRIC_SIGNATURE_ALGORITHM);
if (asymSignatureAlgorithm != null && tbinding.getAlgorithmSuite() != null) {
tbinding.getAlgorithmSuite().setAsymmetricSignature(asymSignatureAlgorithm);
}
String symSignatureAlgorithm =
(String)getMessage().getContextualProperty(SecurityConstants.SYMMETRIC_SIGNATURE_ALGORITHM);
if (symSignatureAlgorithm != null && tbinding.getAlgorithmSuite() != null) {
tbinding.getAlgorithmSuite().setSymmetricSignature(symSignatureAlgorithm);
}
TransportToken token = tbinding.getTransportToken();
if (token.getToken() instanceof IssuedToken) {
SecurityToken secToken = getSecurityToken();
if (secToken == null) {
unassertPolicy(token.getToken(), "No transport token id");
return;
}
addIssuedToken((IssuedToken)token.getToken(), secToken, false, false);
}
assertToken(token.getToken());
assertTokenWrapper(token);
}
try {
handleNonEndorsingSupportingTokens(aim);
handleEndorsingSupportingTokens(aim);
} catch (Exception e) {
LOG.log(Level.FINE, e.getMessage(), e);
throw new Fault(e);
}
} else {
try {
handleNonEndorsingSupportingTokens(aim);
} catch (Exception e) {
LOG.log(Level.FINE, e.getMessage(), e);
throw new Fault(e);
}
if (tbinding != null) {
assertPolicy(tbinding.getName());
if (tbinding.getTransportToken() != null) {
assertTokenWrapper(tbinding.getTransportToken());
assertToken(tbinding.getTransportToken().getToken());
try {
handleEndorsingSupportingTokens(aim);
} catch (Exception e) {
LOG.log(Level.FINE, e.getMessage(), e);
throw new Fault(e);
}
}
}
addSignatureConfirmation(null);
}
configureLayout(aim);
if (tbinding != null) {
assertAlgorithmSuite(tbinding.getAlgorithmSuite());
assertWSSProperties(tbinding.getName().getNamespaceURI());
assertTrustProperties(tbinding.getName().getNamespaceURI());
}
assertPolicy(SP12Constants.SIGNED_PARTS);
assertPolicy(SP11Constants.SIGNED_PARTS);
assertPolicy(SP12Constants.ENCRYPTED_PARTS);
assertPolicy(SP11Constants.ENCRYPTED_PARTS);
putCustomTokenAfterSignature();
}
/**
* Handle the non-endorsing supporting tokens
*/
private void handleNonEndorsingSupportingTokens(AssertionInfoMap aim) throws Exception {
Collection<AssertionInfo> ais;
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.SIGNED_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
for (AssertionInfo ai : ais) {
SupportingTokens sgndSuppTokens = (SupportingTokens)ai.getAssertion();
if (sgndSuppTokens != null) {
addSignedSupportingTokens(sgndSuppTokens);
}
ai.setAsserted(true);
}
}
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.SIGNED_ENCRYPTED_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
for (AssertionInfo ai : ais) {
SupportingTokens sgndSuppTokens = (SupportingTokens)ai.getAssertion();
if (sgndSuppTokens != null) {
addSignedSupportingTokens(sgndSuppTokens);
}
ai.setAsserted(true);
}
}
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.ENCRYPTED_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
for (AssertionInfo ai : ais) {
SupportingTokens encrSuppTokens = (SupportingTokens)ai.getAssertion();
if (encrSuppTokens != null) {
addSignedSupportingTokens(encrSuppTokens);
}
ai.setAsserted(true);
}
}
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
for (AssertionInfo ai : ais) {
SupportingTokens suppTokens = (SupportingTokens)ai.getAssertion();
if (suppTokens != null && suppTokens.getTokens() != null
&& suppTokens.getTokens().size() > 0) {
handleSupportingTokens(suppTokens, false, false);
}
ai.setAsserted(true);
}
}
}
private void addSignedSupportingTokens(SupportingTokens sgndSuppTokens)
throws Exception {
for (AbstractToken token : sgndSuppTokens.getTokens()) {
assertToken(token);
if (token != null && !isTokenRequired(token.getIncludeTokenType())) {
continue;
}
if (token instanceof UsernameToken) {
addUsernameToken((UsernameToken)token);
} else if (token instanceof IssuedToken) {
addIssuedToken((IssuedToken)token, getSecurityToken(), false, false);
} else if (token instanceof KerberosToken) {
addKerberosToken((KerberosToken)token, false, false, false);
} else if (token instanceof SamlToken) {
addSamlToken((SamlToken)token, false, false);
} else if (token != null) {
throw new Exception(token.getName() + " is not supported in the streaming code");
} else {
throw new Exception("A null token was supplied to the streaming code");
}
}
}
/**
* Handle the endorsing supporting tokens
*/
private void handleEndorsingSupportingTokens(AssertionInfoMap aim) throws Exception {
Collection<AssertionInfo> ais;
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.SIGNED_ENDORSING_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
SupportingTokens sgndSuppTokens = null;
for (AssertionInfo ai : ais) {
sgndSuppTokens = (SupportingTokens)ai.getAssertion();
ai.setAsserted(true);
}
if (sgndSuppTokens != null) {
for (AbstractToken token : sgndSuppTokens.getTokens()) {
handleEndorsingToken(token, sgndSuppTokens);
}
}
}
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.ENDORSING_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
SupportingTokens endSuppTokens = null;
for (AssertionInfo ai : ais) {
endSuppTokens = (SupportingTokens)ai.getAssertion();
ai.setAsserted(true);
}
if (endSuppTokens != null) {
for (AbstractToken token : endSuppTokens.getTokens()) {
handleEndorsingToken(token, endSuppTokens);
}
}
}
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.ENDORSING_ENCRYPTED_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
SupportingTokens endSuppTokens = null;
for (AssertionInfo ai : ais) {
endSuppTokens = (SupportingTokens)ai.getAssertion();
ai.setAsserted(true);
}
if (endSuppTokens != null) {
for (AbstractToken token : endSuppTokens.getTokens()) {
handleEndorsingToken(token, endSuppTokens);
}
}
}
ais = PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.SIGNED_ENDORSING_ENCRYPTED_SUPPORTING_TOKENS);
if (!ais.isEmpty()) {
SupportingTokens endSuppTokens = null;
for (AssertionInfo ai : ais) {
endSuppTokens = (SupportingTokens)ai.getAssertion();
ai.setAsserted(true);
}
if (endSuppTokens != null) {
for (AbstractToken token : endSuppTokens.getTokens()) {
handleEndorsingToken(token, endSuppTokens);
}
}
}
}
private void handleEndorsingToken(
AbstractToken token, SupportingTokens wrapper
) throws Exception {
assertToken(token);
if (token != null && !isTokenRequired(token.getIncludeTokenType())) {
return;
}
if (token instanceof IssuedToken) {
SecurityToken securityToken = getSecurityToken();
addIssuedToken(token, securityToken, false, true);
signPartsAndElements(wrapper.getSignedParts(), wrapper.getSignedElements());
} else if (token instanceof SecureConversationToken
|| token instanceof SecurityContextToken || token instanceof SpnegoContextToken) {
SecurityToken securityToken = getSecurityToken();
addIssuedToken(token, securityToken, false, true);
WSSSecurityProperties properties = getProperties();
if (securityToken != null) {
storeSecurityToken(token, securityToken);
// Set up CallbackHandler which wraps the configured Handler
TokenStoreCallbackHandler callbackHandler =
new TokenStoreCallbackHandler(
properties.getCallbackHandler(), TokenStoreUtils.getTokenStore(message)
);
properties.setCallbackHandler(callbackHandler);
}
doSignature(token, wrapper);
properties.setIncludeSignatureToken(true);
properties.setSignatureAlgorithm(
tbinding.getAlgorithmSuite().getSymmetricSignature());
properties.setSignatureCanonicalizationAlgorithm(
tbinding.getAlgorithmSuite().getC14n().getValue());
AlgorithmSuiteType algType = tbinding.getAlgorithmSuite().getAlgorithmSuiteType();
properties.setSignatureDigestAlgorithm(algType.getDigest());
} else if (token instanceof X509Token || token instanceof KeyValueToken) {
doSignature(token, wrapper);
} else if (token instanceof SamlToken) {
addSamlToken((SamlToken)token, false, true);
signPartsAndElements(wrapper.getSignedParts(), wrapper.getSignedElements());
WSSSecurityProperties properties = getProperties();
properties.setSignatureAlgorithm(
tbinding.getAlgorithmSuite().getAsymmetricSignature());
properties.setSignatureCanonicalizationAlgorithm(
tbinding.getAlgorithmSuite().getC14n().getValue());
AlgorithmSuiteType algType = tbinding.getAlgorithmSuite().getAlgorithmSuiteType();
properties.setSignatureDigestAlgorithm(algType.getDigest());
} else if (token instanceof UsernameToken) {
throw new Exception("Endorsing UsernameTokens are not supported in the streaming code");
} else if (token instanceof KerberosToken) {
WSSSecurityProperties properties = getProperties();
properties.addAction(WSSConstants.SIGNATURE);
configureSignature(token, false);
addKerberosToken((KerberosToken)token, false, true, false);
signPartsAndElements(wrapper.getSignedParts(), wrapper.getSignedElements());
properties.setSignatureAlgorithm(
tbinding.getAlgorithmSuite().getSymmetricSignature());
properties.setSignatureCanonicalizationAlgorithm(
tbinding.getAlgorithmSuite().getC14n().getValue());
AlgorithmSuiteType algType = tbinding.getAlgorithmSuite().getAlgorithmSuiteType();
properties.setSignatureDigestAlgorithm(algType.getDigest());
}
}
private void doSignature(AbstractToken token, SupportingTokens wrapper)
throws Exception {
signPartsAndElements(wrapper.getSignedParts(), wrapper.getSignedElements());
// Action
WSSSecurityProperties properties = getProperties();
WSSConstants.Action actionToPerform = WSSConstants.SIGNATURE;
if (token.getDerivedKeys() == DerivedKeys.RequireDerivedKeys) {
actionToPerform = WSSConstants.SIGNATURE_WITH_DERIVED_KEY;
}
properties.addAction(actionToPerform);
configureSignature(token, false);
if (token.getDerivedKeys() == DerivedKeys.RequireDerivedKeys) {
properties.setSignatureAlgorithm(
tbinding.getAlgorithmSuite().getSymmetricSignature());
}
}
/**
* Identifies the portions of the message to be signed/encrypted.
*/
private void signPartsAndElements(
SignedParts signedParts,
SignedElements signedElements
) throws SOAPException {
WSSSecurityProperties properties = getProperties();
List<SecurePart> signatureParts = properties.getSignatureSecureParts();
// Add timestamp
if (timestampAdded) {
SecurePart part =
new SecurePart(new QName(WSSConstants.NS_WSU10, "Timestamp"), Modifier.Element);
signatureParts.add(part);
}
// Add SignedParts
if (signedParts != null) {
if (signedParts.isBody()) {
SecurePart part =
new SecurePart(new QName(WSSConstants.NS_SOAP11, "Body"), Modifier.Element);
signatureParts.add(part);
}
for (Header head : signedParts.getHeaders()) {
SecurePart part =
new SecurePart(new QName(head.getNamespace(), head.getName()), Modifier.Element);
part.setRequired(false);
signatureParts.add(part);
}
}
// Handle SignedElements
if (signedElements != null && signedElements.getXPaths() != null) {
for (XPath xPath : signedElements.getXPaths()) {
List<QName> qnames =
org.apache.wss4j.policy.stax.PolicyUtils.getElementPath(xPath);
if (!qnames.isEmpty()) {
SecurePart part =
new SecurePart(qnames.get(qnames.size() - 1), Modifier.Element);
signatureParts.add(part);
}
}
}
}
}