|
7 | 7 |
|
8 | 8 | import org.joda.time.DateTime;
|
9 | 9 | import org.joda.time.DateTimeZone;
|
| 10 | +import org.opensaml.saml.common.xml.SAMLConstants; |
10 | 11 | import org.opensaml.saml.saml2.core.Issuer;
|
11 | 12 | import org.opensaml.saml.saml2.core.LogoutRequest;
|
12 | 13 | import org.opensaml.saml.saml2.core.NameID;
|
| 14 | +import org.opensaml.saml.saml2.metadata.EntityDescriptor; |
13 | 15 | import org.opensaml.security.x509.X509Credential;
|
14 | 16 |
|
15 | 17 | import java.io.UnsupportedEncodingException;
|
|
19 | 21 | import java.security.NoSuchAlgorithmException;
|
20 | 22 | import java.security.Signature;
|
21 | 23 | import java.security.SignatureException;
|
| 24 | +import java.time.Clock; |
22 | 25 | import java.util.Base64;
|
| 26 | +import java.util.Collections; |
23 | 27 |
|
24 | 28 | import static java.util.Collections.emptySet;
|
25 | 29 | import static java.util.Collections.singleton;
|
|
29 | 33 | public class SamlRedirectTests extends SamlTestCase {
|
30 | 34 |
|
31 | 35 | private static final String IDP_ENTITY_ID = "https://idp.test/";
|
| 36 | + private static final String SP_ENTITY_ID = "https://sp.example.com/"; |
| 37 | + private static final String ACS_URL = "https://sp.example.com/saml/acs"; |
| 38 | + private static final String IDP_URL = "https://idp.test/saml/sso/redirect"; |
32 | 39 | private static final String LOGOUT_URL = "https://idp.test/saml/logout";
|
33 | 40 |
|
34 | 41 | private static final SigningConfiguration NO_SIGNING = new SigningConfiguration(emptySet(), null);
|
@@ -87,33 +94,58 @@ public void testLogoutRequestSigning() throws Exception {
|
87 | 94 | final SamlRedirect redirect = new SamlRedirect(buildLogoutRequest(LOGOUT_URL + "?"), spConfig);
|
88 | 95 | final String url = redirect.getRedirectUrl();
|
89 | 96 | final String queryParam = url.split("\\?")[1].split("&Signature")[0];
|
90 |
| - final String params[] = url.split("\\?")[1].split("&"); |
91 |
| - assert (params.length == 3); |
92 |
| - String sigAlg = parseAndUrlDecodeParameter(params[1]); |
93 |
| - // We currently only support signing with SHA256withRSA, this test should be updated if we add support for more |
94 |
| - assertThat(sigAlg, equalTo("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")); |
95 |
| - sigAlg = "SHA256withRSA"; |
96 |
| - final String signature = parseAndUrlDecodeParameter(params[2]); |
97 |
| - assertThat(validateSignature(queryParam, sigAlg, signature, credential), equalTo(true)); |
98 |
| - assertThat(validateSignature(queryParam, sigAlg, signature, invalidCredential), equalTo(false)); |
99 |
| - assertThat(validateSignature(queryParam.substring(0, queryParam.length() - 5), sigAlg, signature, credential), equalTo(false)); |
| 97 | + final String signature = validateUrlAndGetSignature(redirect.getRedirectUrl()); |
| 98 | + assertThat(validateSignature(queryParam, signature, credential), equalTo(true)); |
| 99 | + assertThat(validateSignature(queryParam, signature, invalidCredential), equalTo(false)); |
| 100 | + assertThat(validateSignature(queryParam.substring(0, queryParam.length() - 5), signature, credential), equalTo(false)); |
| 101 | + } |
| 102 | + |
| 103 | + public void testAuthnRequestSigning() throws Exception { |
| 104 | + final X509Credential credential = (X509Credential) buildOpenSamlCredential(readRandomKeyPair()).get(0); |
| 105 | + X509Credential invalidCredential = (X509Credential) buildOpenSamlCredential(readRandomKeyPair()).get(0); |
| 106 | + while (invalidCredential.getEntityCertificate().getSerialNumber().equals(credential.getEntityCertificate().getSerialNumber())) { |
| 107 | + invalidCredential = (X509Credential) buildOpenSamlCredential(readRandomKeyPair()).get(0); |
| 108 | + } |
| 109 | + final SigningConfiguration signingConfig = new SigningConfiguration(singleton("*"), credential); |
| 110 | + SpConfiguration sp = new SpConfiguration(SP_ENTITY_ID, ACS_URL, LOGOUT_URL, signingConfig, null, Collections.emptyList()); |
| 111 | + |
| 112 | + EntityDescriptor idpDescriptor = buildIdPDescriptor(IDP_URL, IDP_ENTITY_ID); |
| 113 | + |
| 114 | + final SamlRedirect redirect = new SamlRedirect(new SamlAuthnRequestBuilder(sp, SAMLConstants.SAML2_POST_BINDING_URI, |
| 115 | + idpDescriptor, SAMLConstants.SAML2_REDIRECT_BINDING_URI, Clock.systemUTC()).build(), signingConfig); |
| 116 | + final String url = redirect.getRedirectUrl(); |
| 117 | + final String queryParam = url.split("\\?")[1].split("&Signature")[0]; |
| 118 | + final String signature = validateUrlAndGetSignature(redirect.getRedirectUrl()); |
| 119 | + assertThat(validateSignature(queryParam, signature, credential), equalTo(true)); |
| 120 | + assertThat(validateSignature(queryParam, signature, invalidCredential), equalTo(false)); |
| 121 | + assertThat(validateSignature(queryParam.substring(0, queryParam.length() - 5), signature, credential), |
| 122 | + equalTo(false)); |
100 | 123 | }
|
101 | 124 |
|
102 | 125 | private String parseAndUrlDecodeParameter(String parameter) throws UnsupportedEncodingException {
|
103 | 126 | final String value = parameter.split("=", 2)[1];
|
104 | 127 | return URLDecoder.decode(value, "UTF-8");
|
105 | 128 | }
|
106 | 129 |
|
107 |
| - private boolean validateSignature(String queryParam, String sigAlg, String signature, X509Credential credential) { |
| 130 | + private String validateUrlAndGetSignature(String url) throws UnsupportedEncodingException { |
| 131 | + final String params[] = url.split("\\?")[1].split("&"); |
| 132 | + assert (params.length == 3); |
| 133 | + String sigAlg = parseAndUrlDecodeParameter(params[1]); |
| 134 | + // We currently only support signing with SHA256withRSA, this test should be updated if we add support for more |
| 135 | + assertThat(sigAlg, equalTo("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")); |
| 136 | + return parseAndUrlDecodeParameter(params[2]); |
| 137 | + } |
| 138 | + |
| 139 | + private boolean validateSignature(String queryParam, String signature, X509Credential credential) { |
108 | 140 | try {
|
109 |
| - Signature sig = Signature.getInstance(sigAlg); |
| 141 | + // We currently only support signing with SHA256withRSA, this test should be updated if we add support for more |
| 142 | + Signature sig = Signature.getInstance("SHA256withRSA"); |
110 | 143 | sig.initVerify(credential.getPublicKey());
|
111 | 144 | sig.update(queryParam.getBytes(StandardCharsets.UTF_8));
|
112 | 145 | return sig.verify(Base64.getDecoder().decode(signature));
|
113 | 146 | } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
|
114 | 147 | return false;
|
115 | 148 | }
|
116 |
| - |
117 | 149 | }
|
118 | 150 |
|
119 | 151 | private LogoutRequest buildLogoutRequest(String logoutUrl) {
|
|
0 commit comments