package org.picketlink.test.identity.federation.web.saml.signatures;
import org.junit.Before;
import org.junit.Test;
import org.picketlink.common.constants.GeneralConstants;
import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.config.federation.SPType;
import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
import org.picketlink.identity.federation.core.interfaces.ProtocolContext;
import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder;
import org.picketlink.identity.federation.core.saml.v2.holders.IssuerInfoHolder;
import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerChainConfig;
import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerConfig;
import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerRequest;
import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerResponse;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChainConfig;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerConfig;
import org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil;
import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType;
import org.picketlink.identity.federation.web.core.HTTPContext;
import org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureGenerationHandler;
import org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureValidationHandler;
import org.picketlink.test.identity.federation.web.mock.MockHttpServletRequest;
import org.picketlink.test.identity.federation.web.mock.MockHttpServletResponse;
import org.picketlink.test.identity.federation.web.mock.MockHttpSession;
import org.picketlink.test.identity.federation.web.mock.MockServletContext;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.net.URI;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.HashMap;
import java.util.Map;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.picketlink.common.constants.GeneralConstants.SAML_SIGNATURE_REQUEST_KEY;
/**
* @author Pedro Igor
*/
public class SAML2AuthnRequestSignatureTestCase {
private SAML2SignatureGenerationHandler generationhandler;
private SAML2SignatureValidationHandler validationHandler;
private KeyPair keypair;
@Before
public void onSetup() throws Exception {
// create a temporary RSA key pair
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
this.keypair = kpg.genKeyPair();
SAML2HandlerChainConfig chainConfig = new DefaultSAML2HandlerChainConfig();
SAML2HandlerConfig handlerConfig = new DefaultSAML2HandlerConfig();
Map<String, Object> chainOptions = new HashMap<String, Object>();
SPType spType = new SPType();
chainOptions.put(GeneralConstants.CONFIGURATION, spType);
chainOptions.put(GeneralConstants.KEYPAIR, keypair);
chainConfig.set(chainOptions);
this.generationhandler = new SAML2SignatureGenerationHandler();
// Initialize the generationhandler
this.generationhandler.initChainConfig(chainConfig);
this.generationhandler.initHandlerConfig(handlerConfig);
this.validationHandler = new SAML2SignatureValidationHandler();
// Initialize the validationHandler
this.validationHandler.initChainConfig(chainConfig);
this.validationHandler.initHandlerConfig(handlerConfig);
}
@Test
public void testSignatureWithHttpPostBinding() throws Exception {
String relayingPartyUrl = "http://post-relyingparty.com";
AuthnRequestType authnRequestType = new SAML2Request().createAuthnRequestType("response", relayingPartyUrl, relayingPartyUrl, relayingPartyUrl);
DefaultSAML2HandlerRequest handlerRequest = createHandlerRequest("POST", relayingPartyUrl, authnRequestType);
DefaultSAML2HandlerResponse handlerResponse = createHandlerResponse("POST", authnRequestType);
this.generationhandler.handleRequestType(handlerRequest, handlerResponse);
Document resultingDocument = handlerResponse.getResultingDocument();
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//*[local-name()='Signature']");
Node signatureElement = (Node) expr.evaluate(resultingDocument, XPathConstants.NODE);
assertNotNull(signatureElement);
assertEquals(resultingDocument.getDocumentElement(), signatureElement.getParentNode());
DefaultSAML2HandlerRequest handlerValidationRequest = createHandlerRequest(
"POST",
relayingPartyUrl,
new SAML2Request().getAuthnRequestType(DocumentUtil.getNodeAsStream(resultingDocument)));
handlerValidationRequest.addOption(GeneralConstants.SENDER_PUBLIC_KEY, this.keypair.getPublic());
DefaultSAML2HandlerResponse handlerValidationResponse = createHandlerResponse("POST", authnRequestType);
this.validationHandler.handleStatusResponseType(handlerValidationRequest, handlerValidationResponse);
}
@Test
public void testSignatureWithHttpRedirectBinding() throws Exception {
String relayingPartyUrl = "http://redirect-relyingparty.com";
AuthnRequestType authnRequestType = new SAML2Request().createAuthnRequestType("response", relayingPartyUrl, relayingPartyUrl, relayingPartyUrl);
authnRequestType.setProtocolBinding(URI.create(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get()));
DefaultSAML2HandlerRequest handlerRequest = createHandlerRequest("GET", relayingPartyUrl, authnRequestType);
DefaultSAML2HandlerResponse handlerResponse = createHandlerResponse("GET", authnRequestType);
this.generationhandler.handleRequestType(handlerRequest, handlerResponse);
Document resultingDocument = handlerResponse.getResultingDocument();
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//*[local-name()='Signature']");
Node signatureElement = (Node) expr.evaluate(resultingDocument, XPathConstants.NODE);
assertNull(signatureElement);
String queryStringWithSignature = handlerResponse.getDestinationQueryStringWithSignature();
assertNotNull(queryStringWithSignature);
assertTrue(queryStringWithSignature.contains("&" + GeneralConstants.SAML_SIG_ALG_REQUEST_KEY + "="));
assertTrue(queryStringWithSignature.contains("&" + GeneralConstants.SAML_SIGNATURE_REQUEST_KEY + "="));
DefaultSAML2HandlerRequest handlerValidationRequest = createHandlerRequest("GET", relayingPartyUrl, authnRequestType);
handlerValidationRequest.addOption(GeneralConstants.SENDER_PUBLIC_KEY, this.keypair.getPublic());
HTTPContext httpContext = (HTTPContext) handlerValidationRequest.getContext();
MockHttpServletRequest mockRequest = (MockHttpServletRequest) httpContext.getRequest();
mockRequest.setQueryString(queryStringWithSignature);
DefaultSAML2HandlerResponse handlerValidationResponse = createHandlerResponse("GET", authnRequestType);
mockRequest.addParameter(SAML_SIGNATURE_REQUEST_KEY, queryStringWithSignature);
this.validationHandler.handleStatusResponseType(handlerValidationRequest, handlerValidationResponse);
}
private DefaultSAML2HandlerResponse createHandlerResponse(final String httpMethod, final AuthnRequestType authnRequestType) throws Exception {
DefaultSAML2HandlerResponse handlerResponse = new DefaultSAML2HandlerResponse();
handlerResponse.setResultingDocument(new SAML2Request().convert(authnRequestType));
handlerResponse.setPostBindingForResponse(httpMethod.equals("POST"));
return handlerResponse;
}
private DefaultSAML2HandlerRequest createHandlerRequest(String httpMethod, final String relayingPartyUrl, final AuthnRequestType authnRequestType) throws Exception {
IssuerInfoHolder issuerInfo = new IssuerInfoHolder(relayingPartyUrl);
SAMLDocumentHolder docHolder = new SAMLDocumentHolder(authnRequestType, new SAML2Request().convert(authnRequestType));
return new DefaultSAML2HandlerRequest(createProtocolContext(httpMethod), issuerInfo.getIssuer(), docHolder, SAML2Handler.HANDLER_TYPE.IDP);
}
private ProtocolContext createProtocolContext(final String httpMethod) {
MockHttpSession session = new MockHttpSession();
MockServletContext servletContext = new MockServletContext();
MockHttpServletRequest servletRequest = new MockHttpServletRequest(session, httpMethod);
MockHttpServletResponse servletResponse = new MockHttpServletResponse();
return new HTTPContext(servletRequest, servletResponse, servletContext);
}
}