Repository: cxf-fediz Updated Branches: refs/heads/master d65d3978e -> 139fb6bd4
Added more SAML SSO negative tests + some bug fixing in the IdP Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/139fb6bd Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/139fb6bd Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/139fb6bd Branch: refs/heads/master Commit: 139fb6bd4ac36ebc7b0ace371041878b869993e1 Parents: d65d397 Author: Colm O hEigeartaigh <[email protected]> Authored: Tue Apr 12 11:02:33 2016 +0100 Committer: Colm O hEigeartaigh <[email protected]> Committed: Tue Apr 12 11:02:33 2016 +0100 ---------------------------------------------------------------------- .../beans/samlsso/AuthnRequestValidator.java | 71 +-- .../apache/cxf/fediz/systests/idp/IdpTest.java | 472 ++++++++++++++++++- 2 files changed, 498 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/139fb6bd/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestValidator.java ---------------------------------------------------------------------- diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestValidator.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestValidator.java index 11be3f7..cc87432 100644 --- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestValidator.java +++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestValidator.java @@ -103,42 +103,47 @@ public class AuthnRequestValidator { private void validateSignature(RequestContext context, AuthnRequest authnRequest, Idp idp, String signature, String relayState, String samlRequest, - String realm) throws Exception { - if (authnRequest.isSigned()) { - // Check destination - checkDestination(context, authnRequest); - - // Check signature - X509Certificate validatingCert = getValidatingCertificate(idp, realm); - Crypto issuerCrypto = - new CertificateStore(Collections.singletonList(validatingCert).toArray(new X509Certificate[0])); - validateAuthnRequestSignature(authnRequest.getSignature(), issuerCrypto); - } else if (signature != null) { - // Check destination - checkDestination(context, authnRequest); - - // Check signature - X509Certificate validatingCert = getValidatingCertificate(idp, realm); - - java.security.Signature sig = java.security.Signature.getInstance("SHA1withRSA"); - sig.initVerify(validatingCert); - - // Recreate request to sign - String requestToSign = SSOConstants.SAML_REQUEST + "=" + URLEncoder.encode(samlRequest, "UTF-8") - + "&" + SSOConstants.RELAY_STATE + "=" + relayState + "&" + SSOConstants.SIG_ALG - + "=" + URLEncoder.encode(SSOConstants.RSA_SHA1, StandardCharsets.UTF_8.name()); - - sig.update(requestToSign.getBytes(StandardCharsets.UTF_8)); - - if (!sig.verify(Base64.decode(signature))) { - LOG.debug("Signature validation failed"); + String realm) throws ProcessingException { + try { + if (authnRequest.isSigned()) { + // Check destination + checkDestination(context, authnRequest); + + // Check signature + X509Certificate validatingCert = getValidatingCertificate(idp, realm); + Crypto issuerCrypto = + new CertificateStore(Collections.singletonList(validatingCert).toArray(new X509Certificate[0])); + validateAuthnRequestSignature(authnRequest.getSignature(), issuerCrypto); + } else if (signature != null) { + // Check destination + checkDestination(context, authnRequest); + + // Check signature + X509Certificate validatingCert = getValidatingCertificate(idp, realm); + + java.security.Signature sig = java.security.Signature.getInstance("SHA1withRSA"); + sig.initVerify(validatingCert); + + // Recreate request to sign + String requestToSign = SSOConstants.SAML_REQUEST + "=" + URLEncoder.encode(samlRequest, "UTF-8") + + "&" + SSOConstants.RELAY_STATE + "=" + relayState + "&" + SSOConstants.SIG_ALG + + "=" + URLEncoder.encode(SSOConstants.RSA_SHA1, StandardCharsets.UTF_8.name()); + + sig.update(requestToSign.getBytes(StandardCharsets.UTF_8)); + + if (!sig.verify(Base64.decode(signature))) { + LOG.debug("Signature validation failed"); + throw new ProcessingException(TYPE.BAD_REQUEST); + } + } else if (requireSignature) { + LOG.debug("No signature is present, therefore the request is rejected"); throw new ProcessingException(TYPE.BAD_REQUEST); + } else { + LOG.debug("No signature is present, but this is allowed by configuration"); } - } else if (requireSignature) { - LOG.debug("No signature is present, therefore the request is rejected"); + } catch (Exception ex) { + LOG.debug("Error validating SAML Signature", ex); throw new ProcessingException(TYPE.BAD_REQUEST); - } else { - LOG.debug("No signature is present, but this is allowed by configuration"); } } http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/139fb6bd/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java ---------------------------------------------------------------------- diff --git a/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java b/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java index 6a4df36..91a82d1 100644 --- a/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java +++ b/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java @@ -30,6 +30,7 @@ import java.nio.charset.StandardCharsets; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collections; import java.util.UUID; import javax.servlet.ServletException; @@ -56,6 +57,7 @@ import org.apache.cxf.fediz.core.util.DOMUtils; import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder; import org.apache.cxf.rs.security.saml.sso.DefaultAuthnRequestBuilder; import org.apache.cxf.rs.security.saml.sso.SSOConstants; +import org.apache.cxf.rs.security.saml.sso.SamlpRequestComponentBuilder; import org.apache.cxf.staxutils.StaxUtils; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -70,8 +72,14 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.opensaml.core.xml.XMLObject; +import org.opensaml.saml.common.SAMLVersion; import org.opensaml.saml.common.SignableSAMLObject; +import org.opensaml.saml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration; import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.NameIDPolicy; +import org.opensaml.saml.saml2.core.RequestedAuthnContext; import org.opensaml.security.x509.BasicX509Credential; import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory; import org.opensaml.xmlsec.signature.KeyInfo; @@ -179,6 +187,10 @@ public class IdpTest { return "fedizhelloworld"; } + // + // Successful tests + // + @org.junit.Test public void testSuccessfulInvokeOnIdP() throws Exception { OpenSAMLUtil.initSamlEngine(); @@ -304,6 +316,91 @@ public class IdpTest { } @org.junit.Test + public void testSeparateSignature() throws Exception { + OpenSAMLUtil.initSamlEngine(); + + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + AuthnRequest authnRequest = + new DefaultAuthnRequestBuilder().createAuthnRequest( + null, "urn:org:apache:cxf:fediz:fedizhelloworld", consumerURL + ); + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String relayState = UUID.randomUUID().toString(); + + // Sign request + Crypto crypto = CryptoFactory.getInstance("stsKeystoreA.properties"); + + CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); + cryptoType.setAlias("realma"); + + // Get the private key + PrivateKey privateKey = crypto.getPrivateKey("realma", "realma"); + + java.security.Signature signature = java.security.Signature.getInstance("SHA1withRSA"); + signature.initSign(privateKey); + + String requestToSign = SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + requestToSign += "&" + SSOConstants.RELAY_STATE + "=" + relayState; + requestToSign += "&" + SSOConstants.SIG_ALG + "=" + + URLEncoder.encode(SSOConstants.RSA_SHA1, StandardCharsets.UTF_8.name()); + + signature.update(requestToSign.getBytes(StandardCharsets.UTF_8)); + byte[] signBytes = signature.sign(); + + String encodedSignature = Base64.encode(signBytes); + + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml/up?"; + url += SSOConstants.RELAY_STATE + "=" + relayState; + url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + url += "&" + SSOConstants.SIGNATURE + "=" + URLEncoder.encode(encodedSignature, StandardCharsets.UTF_8.name()); + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage = webClient.getPage(url); + webClient.getOptions().setJavaScriptEnabled(true); + Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText()); + + org.opensaml.saml.saml2.core.Response samlResponse = + parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); + String expected = "urn:oasis:names:tc:SAML:2.0:status:Success"; + Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); + + // Check claims + String parsedResponse = DOM2Writer.nodeToString(samlResponse.getDOM().getOwnerDocument()); + String claim = ClaimTypes.FIRSTNAME.toString(); + Assert.assertTrue(parsedResponse.contains(claim)); + claim = ClaimTypes.LASTNAME.toString(); + Assert.assertTrue(parsedResponse.contains(claim)); + claim = ClaimTypes.EMAILADDRESS.toString(); + Assert.assertTrue(parsedResponse.contains(claim)); + + webClient.close(); + } + + // + // Negative tests + // + + @org.junit.Test public void testBadIssuer() throws Exception { OpenSAMLUtil.initSamlEngine(); @@ -351,6 +448,128 @@ public class IdpTest { } @org.junit.Test + public void testNoIssuer() throws Exception { + OpenSAMLUtil.initSamlEngine(); + + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + AuthnRequest authnRequest = + new DefaultAuthnRequestBuilder().createAuthnRequest( + null, null, consumerURL + ); + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + signAuthnRequest(authnRequest); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String relayState = UUID.randomUUID().toString(); + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml?"; + url += SSOConstants.RELAY_STATE + "=" + relayState; + url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage = webClient.getPage(url); + + org.opensaml.saml.saml2.core.Response samlResponse = + parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); + String expected = "urn:oasis:names:tc:SAML:2.0:status:Requester"; + Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); + + webClient.close(); + } + + @org.junit.Test + public void testBadIssuerFormat() throws Exception { + OpenSAMLUtil.initSamlEngine(); + + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + + String issuerId = "urn:org:apache:cxf:fediz:fedizhelloworld"; + Issuer issuer = + SamlpRequestComponentBuilder.createIssuer(issuerId); + issuer.setFormat("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"); + + String nameIDFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"; + NameIDPolicy nameIDPolicy = + SamlpRequestComponentBuilder.createNameIDPolicy(true, nameIDFormat, issuerId); + + AuthnContextClassRef authnCtxClassRef = + SamlpRequestComponentBuilder.createAuthnCtxClassRef( + "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" + ); + RequestedAuthnContext authnCtx = + SamlpRequestComponentBuilder.createRequestedAuthnCtxPolicy( + AuthnContextComparisonTypeEnumeration.EXACT, + Collections.singletonList(authnCtxClassRef), null + ); + + String protocolBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"; + AuthnRequest authnRequest = SamlpRequestComponentBuilder.createAuthnRequest( + consumerURL, + false, + false, + protocolBinding, + SAMLVersion.VERSION_20, + issuer, + nameIDPolicy, + authnCtx + ); + + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + signAuthnRequest(authnRequest); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String relayState = UUID.randomUUID().toString(); + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml?"; + url += SSOConstants.RELAY_STATE + "=" + relayState; + url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage = webClient.getPage(url); + + org.opensaml.saml.saml2.core.Response samlResponse = + parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); + String expected = "urn:oasis:names:tc:SAML:2.0:status:Requester"; + Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); + + webClient.close(); + } + + @org.junit.Test public void testMissingDestination() throws Exception { OpenSAMLUtil.initSamlEngine(); @@ -397,6 +616,51 @@ public class IdpTest { } @org.junit.Test + public void testMissingRelayState() throws Exception { + OpenSAMLUtil.initSamlEngine(); + + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + AuthnRequest authnRequest = + new DefaultAuthnRequestBuilder().createAuthnRequest( + null, "urn:org:apache:cxf:fediz:fedizhelloworld", consumerURL + ); + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + signAuthnRequest(authnRequest); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml?"; + url += SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + try { + webClient.getPage(url); + Assert.fail("Failure expected on not sending the RelayState"); + } catch (FailingHttpStatusCodeException ex) { + Assert.assertEquals(ex.getStatusCode(), 400); + } + + webClient.close(); + } + + @org.junit.Test public void testUnsignedRequest() throws Exception { OpenSAMLUtil.initSamlEngine(); @@ -443,7 +707,55 @@ public class IdpTest { } @org.junit.Test - public void testSeparateSignature() throws Exception { + public void testEmptySeparateSignature() throws Exception { + OpenSAMLUtil.initSamlEngine(); + + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + AuthnRequest authnRequest = + new DefaultAuthnRequestBuilder().createAuthnRequest( + null, "urn:org:apache:cxf:fediz:fedizhelloworld", consumerURL + ); + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String relayState = UUID.randomUUID().toString(); + + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml/up?"; + url += SSOConstants.RELAY_STATE + "=" + relayState; + url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + url += "&" + SSOConstants.SIGNATURE + "="; + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage = webClient.getPage(url); + + org.opensaml.saml.saml2.core.Response samlResponse = + parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); + String expected = "urn:oasis:names:tc:SAML:2.0:status:Requester"; + Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); + + webClient.close(); + } + + @org.junit.Test + public void testBase64DecodingErrorSeparateSignature() throws Exception { OpenSAMLUtil.initSamlEngine(); // Create SAML AuthnRequest @@ -491,6 +803,7 @@ public class IdpTest { url += SSOConstants.RELAY_STATE + "=" + relayState; url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; url += "&" + SSOConstants.SIGNATURE + "=" + URLEncoder.encode(encodedSignature, StandardCharsets.UTF_8.name()); + url += "-xyz"; String user = "alice"; String password = "ecila"; @@ -503,22 +816,157 @@ public class IdpTest { webClient.getOptions().setJavaScriptEnabled(false); final HtmlPage idpPage = webClient.getPage(url); - webClient.getOptions().setJavaScriptEnabled(true); - Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText()); org.opensaml.saml.saml2.core.Response samlResponse = parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); - String expected = "urn:oasis:names:tc:SAML:2.0:status:Success"; + String expected = "urn:oasis:names:tc:SAML:2.0:status:Requester"; Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); + + webClient.close(); + } + + @org.junit.Test + public void testChangedSeparateSignature() throws Exception { + OpenSAMLUtil.initSamlEngine(); - // Check claims - String parsedResponse = DOM2Writer.nodeToString(samlResponse.getDOM().getOwnerDocument()); - String claim = ClaimTypes.FIRSTNAME.toString(); - Assert.assertTrue(parsedResponse.contains(claim)); - claim = ClaimTypes.LASTNAME.toString(); - Assert.assertTrue(parsedResponse.contains(claim)); - claim = ClaimTypes.EMAILADDRESS.toString(); - Assert.assertTrue(parsedResponse.contains(claim)); + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + AuthnRequest authnRequest = + new DefaultAuthnRequestBuilder().createAuthnRequest( + null, "urn:org:apache:cxf:fediz:fedizhelloworld", consumerURL + ); + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String relayState = UUID.randomUUID().toString(); + + // Sign request + Crypto crypto = CryptoFactory.getInstance("stsKeystoreA.properties"); + + CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); + cryptoType.setAlias("realma"); + + // Get the private key + PrivateKey privateKey = crypto.getPrivateKey("realma", "realma"); + + java.security.Signature signature = java.security.Signature.getInstance("SHA1withRSA"); + signature.initSign(privateKey); + + String requestToSign = SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + requestToSign += "&" + SSOConstants.RELAY_STATE + "=" + relayState; + requestToSign += "&" + SSOConstants.SIG_ALG + "=" + + URLEncoder.encode(SSOConstants.RSA_SHA1, StandardCharsets.UTF_8.name()); + + signature.update(requestToSign.getBytes(StandardCharsets.UTF_8)); + byte[] signBytes = signature.sign(); + if (signBytes[1] != (byte)1) { + signBytes[1] = (byte)1; + } else { + signBytes[1] = (byte)2; + } + + String encodedSignature = Base64.encode(signBytes); + + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml/up?"; + url += SSOConstants.RELAY_STATE + "=" + relayState; + url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + url += "&" + SSOConstants.SIGNATURE + "=" + URLEncoder.encode(encodedSignature, StandardCharsets.UTF_8.name()); + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage = webClient.getPage(url); + + org.opensaml.saml.saml2.core.Response samlResponse = + parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); + String expected = "urn:oasis:names:tc:SAML:2.0:status:Requester"; + Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); + + webClient.close(); + } + + @org.junit.Test + public void testSeparateSignatureWrongSignedContent() throws Exception { + OpenSAMLUtil.initSamlEngine(); + + // Create SAML AuthnRequest + Document doc = DOMUtils.createDocument(); + doc.appendChild(doc.createElement("root")); + // Create the AuthnRequest + String consumerURL = "https://localhost:" + getRpHttpsPort() + "/" + + getServletContextName() + "/secure/fedservlet"; + AuthnRequest authnRequest = + new DefaultAuthnRequestBuilder().createAuthnRequest( + null, "urn:org:apache:cxf:fediz:fedizhelloworld", consumerURL + ); + authnRequest.setDestination("https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml"); + + Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); + String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); + + String urlEncodedRequest = URLEncoder.encode(authnRequestEncoded, "UTF-8"); + + String relayState = UUID.randomUUID().toString(); + + // Sign request + Crypto crypto = CryptoFactory.getInstance("stsKeystoreA.properties"); + + CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); + cryptoType.setAlias("realma"); + + // Get the private key + PrivateKey privateKey = crypto.getPrivateKey("realma", "realma"); + + java.security.Signature signature = java.security.Signature.getInstance("SHA1withRSA"); + signature.initSign(privateKey); + + String requestToSign = SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + requestToSign += "&" + SSOConstants.RELAY_STATE + "=" + relayState; + requestToSign += "&" + SSOConstants.SIG_ALG + "=" + + URLEncoder.encode(SSOConstants.RSA_SHA1, StandardCharsets.UTF_8.name()) + + "asf=xyz"; + + signature.update(requestToSign.getBytes(StandardCharsets.UTF_8)); + byte[] signBytes = signature.sign(); + + String encodedSignature = Base64.encode(signBytes); + + String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml/up?"; + url += SSOConstants.RELAY_STATE + "=" + relayState; + url += "&" + SSOConstants.SAML_REQUEST + "=" + urlEncodedRequest; + url += "&" + SSOConstants.SIGNATURE + "=" + URLEncoder.encode(encodedSignature, StandardCharsets.UTF_8.name()); + + String user = "alice"; + String password = "ecila"; + + final WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + webClient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials(user, password)); + + webClient.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage = webClient.getPage(url); + + org.opensaml.saml.saml2.core.Response samlResponse = + parseSAMLResponse(idpPage, relayState, consumerURL, authnRequest.getID()); + String expected = "urn:oasis:names:tc:SAML:2.0:status:Requester"; + Assert.assertEquals(expected, samlResponse.getStatus().getStatusCode().getValue()); webClient.close(); }
