/**
* 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.sts.request;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.sts.common.PasswordCallbackHandler;
import org.apache.cxf.sts.token.canceller.SCTCanceller;
import org.apache.cxf.sts.token.validator.SCTValidator;
import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenType;
import org.apache.wss4j.common.crypto.Crypto;
import org.apache.wss4j.common.crypto.CryptoFactory;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.dom.engine.WSSecurityEngine;
import org.apache.wss4j.dom.handler.RequestData;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.apache.wss4j.dom.handler.WSHandlerResult;
public class RequestParserUnitTest extends org.junit.Assert {
private static final String SECURITY_HEADER =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><wsse:Security "
+ "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\""
+ " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""
+ "><wsse:UsernameToken wsu:Id=\"UsernameToken-5\"><wsse:Username>alice</wsse:Username>"
+ "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username"
+ "-token-profile-1.0#PasswordText\">clarinet</wsse:Password>"
+ "</wsse:UsernameToken><wsc:SecurityContextToken "
+ "xmlns:wsc=\"http://schemas.xmlsoap.org/ws/2005/02/sc\" "
+ "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" "
+ "wsu:Id=\"sct\"><wsc:Identifier>check</wsc:Identifier></wsc:SecurityContextToken></wsse:Security>";
private static final String SECURITY_HEADER_X509 =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><wsse:Security "
+ "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\""
+ " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""
+ "><wsse:UsernameToken wsu:Id=\"UsernameToken-5\"><wsse:Username>alice</wsse:Username>"
+ "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username"
+ "-token-profile-1.0#PasswordText\">clarinet</wsse:Password>"
+ "</wsse:UsernameToken><wsse:BinarySecurityToken "
+ "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" "
+ "EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0"
+ "#Base64Binary\" "
+ "ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0"
+ "#X509v3\" " + "wsu:Id=\"x509\">"
+ "MIIEFjCCA3+gAwIBAgIJAJORWX2Xsa8DMA0GCSqGSIb3DQEBBQUAMIG5MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcm"
+ "sxFjAUBgNVBAcTDU5pYWdhcmEgRmFsbHMxLDAqBgNVBAoTI1NhbXBsZSBDbGllbnQgLS0gTk9UIEZPUiBQUk9EVUNUSU9OMRYw"
+ "FAYDVQQLEw1JVCBEZXBhcnRtZW50MRcwFQYDVQQDEw53d3cuY2xpZW50LmNvbTEgMB4GCSqGSIb3DQEJARYRY2xpZW50QGNsaW"
+ "VudC5jb20wHhcNMTEwMjA5MTgzMDI3WhcNMjEwMjA2MTgzMDI3WjCBuTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3Jr"
+ "MRYwFAYDVQQHEw1OaWFnYXJhIEZhbGxzMSwwKgYDVQQKEyNTYW1wbGUgQ2xpZW50IC0tIE5PVCBGT1IgUFJPRFVDVElPTjEWMB"
+ "QGA1UECxMNSVQgRGVwYXJ0bWVudDEXMBUGA1UEAxMOd3d3LmNsaWVudC5jb20xIDAeBgkqhkiG9w0BCQEWEWNsaWVudEBjbGll"
+ "bnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDauFNVqi4B2+u/PC9ktDkn82bglEQYcL4o5JRUhQVEhTK2iEloz1"
+ "Rvo/qyfDhBPc1lzIUn4ams+DKBSSjZMCgop3XbeCXzIVP784ruC8HF5QrYsXUQfTc7lzqafXZXH8Bk89gSScA1fFme6TpvYzM0"
+ "zjBETSXADtKOs9oKB2VOIwIDAQABo4IBIjCCAR4wHQYDVR0OBBYEFFIz+0BSZlLtXkA/udRjRgphtREuMIHuBgNVHSMEgeYwge"
+ "OAFFIz+0BSZlLtXkA/udRjRgphtREuoYG/pIG8MIG5MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxFjAUBgNVBAcT"
+ "DU5pYWdhcmEgRmFsbHMxLDAqBgNVBAoTI1NhbXBsZSBDbGllbnQgLS0gTk9UIEZPUiBQUk9EVUNUSU9OMRYwFAYDVQQLEw1JVC"
+ "BEZXBhcnRtZW50MRcwFQYDVQQDEw53d3cuY2xpZW50LmNvbTEgMB4GCSqGSIb3DQEJARYRY2xpZW50QGNsaWVudC5jb22CCQCT"
+ "kVl9l7GvAzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAEjEr9QfaYsZf7ELnqB++OkWcKxpMt1Yj/VOyL99AekkVT"
+ "M+rRHCU9Bu+tncMNsfy8mIXUC1JqKQ+Cq5RlaDh/ujzt6i17G7uSGd6U1U/DPZBqTm3Dxwl1cMAGU/CoAKTWE+o+fS4Q2xHv7L"
+ "1KiXQQc9EWJ4C34Ik45fB6g3DiTj</wsse:BinarySecurityToken></wsse:Security>";
private static final String CANCEL_SCT_REFERENCE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<wst:RequestSecurityToken xmlns:wst=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\">"
+ "<wst:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</wst:TokenType>"
+ "<wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Cancel</wst:RequestType>"
+ "<wst:CancelTarget>"
+ "<wsse:SecurityTokenReference "
+ "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
+ "<wsse:Reference URI=\"#sct\"></wsse:Reference></wsse:SecurityTokenReference>"
+ "</wst:CancelTarget>" + "</wst:RequestSecurityToken>";
private static final String VALIDATE_SCT_REFERENCE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<wst:RequestSecurityToken xmlns:wst=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\">"
+ "<wst:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</wst:TokenType>"
+ "<wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Validate</wst:RequestType>"
+ "<wst:ValidateTarget>"
+ "<wsse:SecurityTokenReference "
+ "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
+ "<wsse:Reference URI=\"#sct\"></wsse:Reference></wsse:SecurityTokenReference>"
+ "</wst:ValidateTarget>" + "</wst:RequestSecurityToken>";
private static final String USE_KEY_X509_REFERENCE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<wst:RequestSecurityToken xmlns:wst=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\">"
+ "<wst:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</wst:TokenType>"
+ "<wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType>"
+ "<wst:UseKey>"
+ "<wsse:SecurityTokenReference "
+ "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
+ "<wsse:Reference URI=\"#x509\"></wsse:Reference></wsse:SecurityTokenReference>"
+ "</wst:UseKey>" + "</wst:RequestSecurityToken>";
/**
* Test for fetching (and cancelling) a referenced SecurityContextToken.
*/
@org.junit.Test
public void testCancelSCT() throws Exception {
Element secHeaderElement = (Element) parseStringToElement(SECURITY_HEADER).getFirstChild();
RequestSecurityTokenType request = createJaxbObject(CANCEL_SCT_REFERENCE);
RequestParser parser = new RequestParser();
// Mock up message context
MessageImpl msg = new MessageImpl();
WrappedMessageContext msgContext = new WrappedMessageContext(msg);
// Process the security header and store the results in the message context
WSSecurityEngine securityEngine = new WSSecurityEngine();
RequestData reqData = new RequestData();
reqData.setCallbackHandler(new PasswordCallbackHandler());
WSHandlerResult results =
securityEngine.processSecurityHeader(secHeaderElement, reqData);
List<WSHandlerResult> resultsList = new ArrayList<>();
resultsList.add(results);
msgContext.put(WSHandlerConstants.RECV_RESULTS, resultsList);
RequestRequirements requestRequirements = parser.parseRequest(request, msgContext, null, null);
SCTCanceller sctCanceller = new SCTCanceller();
assertTrue(sctCanceller.canHandleToken(requestRequirements.getTokenRequirements().getCancelTarget()));
}
/**
* Test for fetching (and validating) a referenced SecurityContextToken.
*/
@org.junit.Test
public void testValidateSCT() throws Exception {
Element secHeaderElement = (Element) parseStringToElement(SECURITY_HEADER).getFirstChild();
RequestSecurityTokenType request = createJaxbObject(VALIDATE_SCT_REFERENCE);
RequestParser parser = new RequestParser();
// Mock up message context
MessageImpl msg = new MessageImpl();
WrappedMessageContext msgContext = new WrappedMessageContext(msg);
// Process the security header and store the results in the message context
WSSecurityEngine securityEngine = new WSSecurityEngine();
RequestData reqData = new RequestData();
reqData.setCallbackHandler(new PasswordCallbackHandler());
WSHandlerResult results =
securityEngine.processSecurityHeader(secHeaderElement, reqData);
List<WSHandlerResult> resultsList = new ArrayList<>();
resultsList.add(results);
msgContext.put(WSHandlerConstants.RECV_RESULTS, resultsList);
RequestRequirements requestRequirements = parser.parseRequest(request, msgContext, null, null);
SCTValidator sctValidator = new SCTValidator();
assertTrue(sctValidator.canHandleToken(requestRequirements.getTokenRequirements().getValidateTarget()));
}
/**
* Test for fetching (and validating) a referenced BinarySecurityToken from a UseKey Element.
*/
@org.junit.Test
public void testUseKeyX509() throws Exception {
Element secHeaderElement = (Element) parseStringToElement(SECURITY_HEADER_X509).getFirstChild();
RequestSecurityTokenType request = createJaxbObject(USE_KEY_X509_REFERENCE);
RequestParser parser = new RequestParser();
// Mock up message context
MessageImpl msg = new MessageImpl();
WrappedMessageContext msgContext = new WrappedMessageContext(msg);
// Process the security header and store the results in the message context
WSSecurityEngine securityEngine = new WSSecurityEngine();
RequestData reqData = new RequestData();
reqData.setSigVerCrypto(getCrypto());
reqData.setCallbackHandler(new PasswordCallbackHandler());
WSHandlerResult results =
securityEngine.processSecurityHeader(secHeaderElement, reqData);
List<WSHandlerResult> resultsList = new ArrayList<>();
resultsList.add(results);
msgContext.put(WSHandlerConstants.RECV_RESULTS, resultsList);
RequestRequirements requestRequirements = parser.parseRequest(request, msgContext, null, null);
assertNotNull(requestRequirements.getKeyRequirements().getReceivedKey().getX509Cert());
}
private Document parseStringToElement(String str) throws Exception {
DocumentBuilderFactory builderFac = DocumentBuilderFactory.newInstance();
builderFac.setNamespaceAware(true);
builderFac.setValidating(false);
builderFac.setIgnoringElementContentWhitespace(true);
DocumentBuilder docBuilder = builderFac.newDocumentBuilder();
return docBuilder.parse(new InputSource(new StringReader(str)));
}
private RequestSecurityTokenType createJaxbObject(String str) throws Exception {
JAXBContext jaxbContext =
JAXBContext.newInstance("org.apache.cxf.ws.security.sts.provider.model");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<?> jaxbElement =
(JAXBElement<?>) unmarshaller.unmarshal(new InputSource(new StringReader(str)));
return (RequestSecurityTokenType) jaxbElement.getValue();
}
private Crypto getCrypto() throws WSSecurityException {
Properties properties = new Properties();
properties.put(
"org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"
);
properties.put("org.apache.wss4j.crypto.merlin.keystore.password", "stsspass");
properties.put("org.apache.wss4j.crypto.merlin.keystore.file", "keys/stsstore.jks");
return CryptoFactory.getInstance(properties);
}
}