/*
* Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
*
* 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.opensaml.saml2.binding.decoding;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyPair;
import org.opensaml.common.BaseTestCase;
import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.common.binding.decoding.SAMLMessageDecoder;
import org.opensaml.saml2.core.AttributeQuery;
import org.opensaml.saml2.core.Response;
import org.opensaml.ws.message.decoder.MessageDecodingException;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.ws.soap.soap11.Envelope;
import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.SecurityHelper;
import org.opensaml.xml.security.SecurityTestHelper;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.Signer;
import org.opensaml.xml.util.XMLHelper;
import org.springframework.mock.web.MockHttpServletRequest;
/**
* Test case for HTTP SOAP 1.1 decoder.
*/
public class HTTPSOAP11DecoderTest extends BaseTestCase {
private String attribQueryDestination = "https://idp.example.com/idp/aa";
private SAMLMessageDecoder decoder;
private BasicSAMLMessageContext messageContext;
private MockHttpServletRequest httpRequest;
/** {@inheritDoc} */
protected void setUp() throws Exception {
super.setUp();
httpRequest = new MockHttpServletRequest();
httpRequest.setMethod("POST");
messageContext = new BasicSAMLMessageContext();
messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(httpRequest));
decoder = new HTTPSOAP11Decoder();
}
/**
* Tests decoding a SOAP 1.1 message.
*/
public void testDecoding() throws Exception {
String requestContent = "<soap11:Envelope xmlns:soap11=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<soap11:Body><samlp:Response ID=\"foo\" IssueInstant=\"1970-01-01T00:00:00.000Z\" Version=\"2.0\" "
+ "xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"><samlp:Status><samlp:StatusCode "
+ "Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\"/></samlp:Status></samlp:Response>"
+ "</soap11:Body></soap11:Envelope>";
httpRequest.setContent(requestContent.getBytes());
decoder.decode(messageContext);
assertTrue(messageContext.getInboundMessage() instanceof Envelope);
assertTrue(messageContext.getInboundSAMLMessage() instanceof Response);
}
public void testMessageEndpointGood() throws Exception {
Envelope soapEnvelope = (Envelope) unmarshallElement("/data/org/opensaml/saml2/binding/AttributeQuerySOAP.xml");
AttributeQuery samlRequest = (AttributeQuery) soapEnvelope.getBody().getUnknownXMLObjects().get(0);
String deliveredEndpointURL = samlRequest.getDestination();
httpRequest.setContent(encodeMessage(soapEnvelope).getBytes());
populateRequestURL(httpRequest, deliveredEndpointURL);
try {
decoder.decode(messageContext);
} catch (SecurityException e) {
fail("Caught SecurityException: " + e.getMessage());
} catch (MessageDecodingException e) {
fail("Caught MessageDecodingException: " + e.getMessage());
}
}
public void testMessageEndpointGoodWithQueryParams() throws Exception {
Envelope soapEnvelope = (Envelope) unmarshallElement("/data/org/opensaml/saml2/binding/AttributeQuerySOAP.xml");
AttributeQuery samlRequest = (AttributeQuery) soapEnvelope.getBody().getUnknownXMLObjects().get(0);
String deliveredEndpointURL = samlRequest.getDestination() + "?paramFoo=bar¶mBar=baz";
httpRequest.setContent(encodeMessage(soapEnvelope).getBytes());
populateRequestURL(httpRequest, deliveredEndpointURL);
try {
decoder.decode(messageContext);
} catch (SecurityException e) {
fail("Caught SecurityException: " + e.getMessage());
} catch (MessageDecodingException e) {
fail("Caught MessageDecodingException: " + e.getMessage());
}
}
public void testMessageEndpointInvalidURI() throws Exception {
Envelope soapEnvelope = (Envelope) unmarshallElement("/data/org/opensaml/saml2/binding/AttributeQuerySOAP.xml");
AttributeQuery samlRequest = (AttributeQuery) soapEnvelope.getBody().getUnknownXMLObjects().get(0);
String deliveredEndpointURL = samlRequest.getDestination() + "/some/other/endpointURI";
httpRequest.setContent(encodeMessage(soapEnvelope).getBytes());
populateRequestURL(httpRequest, deliveredEndpointURL);
try {
decoder.decode(messageContext);
fail("Passed delivered endpoint check, should have failed");
} catch (SecurityException e) {
// do nothing, failure expected
} catch (MessageDecodingException e) {
fail("Caught MessageDecodingException: " + e.getMessage());
}
}
public void testMessageEndpointInvalidHost() throws Exception {
Envelope soapEnvelope = (Envelope) unmarshallElement("/data/org/opensaml/saml2/binding/AttributeQuerySOAP.xml");
String deliveredEndpointURL = "https://bogusidp.example.com/idp/sso";
httpRequest.setContent(encodeMessage(soapEnvelope).getBytes());
populateRequestURL(httpRequest, deliveredEndpointURL);
try {
decoder.decode(messageContext);
fail("Passed delivered endpoint check, should have failed");
} catch (SecurityException e) {
// do nothing, failure expected
} catch (MessageDecodingException e) {
fail("Caught MessageDecodingException: " + e.getMessage());
}
}
public void testMessageEndpointMissingDestinationNotSigned() throws Exception {
Envelope soapEnvelope = (Envelope) unmarshallElement("/data/org/opensaml/saml2/binding/AttributeQuerySOAP.xml");
AttributeQuery samlRequest = (AttributeQuery) soapEnvelope.getBody().getUnknownXMLObjects().get(0);
samlRequest.setDestination(null);
String deliveredEndpointURL = attribQueryDestination;
httpRequest.setContent(encodeMessage(soapEnvelope).getBytes());
populateRequestURL(httpRequest, deliveredEndpointURL);
try {
decoder.decode(messageContext);
} catch (SecurityException e) {
fail("Caught SecurityException: " + e.getMessage());
} catch (MessageDecodingException e) {
fail("Caught MessageDecodingException: " + e.getMessage());
}
}
public void testMessageEndpointMissingDestinationSigned() throws Exception {
Envelope soapEnvelope = (Envelope) unmarshallElement("/data/org/opensaml/saml2/binding/AttributeQuerySOAP.xml");
AttributeQuery samlRequest = (AttributeQuery) soapEnvelope.getBody().getUnknownXMLObjects().get(0);
samlRequest.setDestination(null);
Signature signature = (Signature) buildXMLObject(Signature.DEFAULT_ELEMENT_NAME);
KeyPair kp = SecurityTestHelper.generateKeyPair("RSA", 1024, null);
Credential signingCred = SecurityHelper.getSimpleCredential(kp.getPublic(), kp.getPrivate());
signature.setSigningCredential(signingCred);
samlRequest.setSignature(signature);
SecurityHelper.prepareSignatureParams(signature, signingCred, null, null);
marshallerFactory.getMarshaller(soapEnvelope).marshall(soapEnvelope);
Signer.signObject(signature);
String deliveredEndpointURL = attribQueryDestination;
httpRequest.setContent(encodeMessage(soapEnvelope).getBytes());
populateRequestURL(httpRequest, deliveredEndpointURL);
try {
decoder.decode(messageContext);
// SOAP binding doesn't require the Destination, even when signed
} catch (SecurityException e) {
fail("Caught SecurityException: " + e.getMessage());
} catch (MessageDecodingException e) {
fail("Caught MessageDecodingException: " + e.getMessage());
}
}
private void populateRequestURL(MockHttpServletRequest request, String requestURL) {
URL url = null;
try {
url = new URL(requestURL);
} catch (MalformedURLException e) {
fail("Malformed URL: " + e.getMessage());
}
request.setScheme(url.getProtocol());
request.setServerName(url.getHost());
if (url.getPort() != -1) {
request.setServerPort(url.getPort());
} else {
if ("https".equalsIgnoreCase(url.getProtocol())) {
request.setServerPort(443);
} else if ("http".equalsIgnoreCase(url.getProtocol())) {
request.setServerPort(80);
}
}
request.setRequestURI(url.getPath());
request.setQueryString(url.getQuery());
}
protected String encodeMessage(XMLObject message) throws MessageEncodingException, MarshallingException {
marshallerFactory.getMarshaller(message).marshall(message);
return XMLHelper.nodeToString(message.getDOM());
}
}