[TEST] Add SAML Redirect Signing test
Add a test to verify that we generate correct signatures for our
SAML2 Single Logout requests when using the redirect binding.
@@ -12,6 +12,15 @@ import org.opensaml.saml.saml2.core.LogoutRequest;
import org.opensaml.saml.saml2.core.NameID;
import org.opensaml.security.x509.X509Credential;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Base64;
+
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static org.hamcrest.Matchers.equalTo;
@@ -67,6 +76,46 @@ public class SamlRedirectTests extends SamlTestCase {
"1yHnLOX4Edtz0eDuf2uJjHy9Z%2Fl5ZEapyLQvGraBZdZm6ER59RV%2F8izGKwLg38VL4B1sji%2FPxxgeIb"));
}
+ public void testLogoutRequestSigning() throws Exception {
+ final X509Credential credential = (X509Credential) buildOpenSamlCredential(readRandomKeyPair()).get(0);
+ X509Credential invalidCredential = (X509Credential) buildOpenSamlCredential(readRandomKeyPair()).get(0);
+ while (invalidCredential.getEntityCertificate().getSerialNumber().equals(credential.getEntityCertificate().getSerialNumber())) {
+ invalidCredential = (X509Credential) buildOpenSamlCredential(readRandomKeyPair()).get(0);
+ }
+ final SigningConfiguration spConfig =
+ new SigningConfiguration(singleton("*"), credential);
+ final SamlRedirect redirect = new SamlRedirect(buildLogoutRequest(LOGOUT_URL + "?"), spConfig);
+ final String url = redirect.getRedirectUrl();
+ final String queryParam = url.split("\\?")[1].split("&Signature")[0];
+ final String params[] = url.split("\\?")[1].split("&");
+ assert (params.length == 3);
+ String sigAlg = parseAndUrlDecodeParameter(params[1]);
+ // We currently only support signing with SHA256withRSA, this test should be updated if we add support for more
+ assertThat(sigAlg, equalTo("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"));
+ sigAlg = "SHA256withRSA";
+ final String signature = parseAndUrlDecodeParameter(params[2]);
+ assertThat(validateSignature(queryParam, sigAlg, signature, credential), equalTo(true));
+ assertThat(validateSignature(queryParam, sigAlg, signature, invalidCredential), equalTo(false));
+ assertThat(validateSignature(queryParam.substring(0, queryParam.length() - 5), sigAlg, signature, credential), equalTo(false));
+ }
+
+ private String parseAndUrlDecodeParameter(String parameter) throws UnsupportedEncodingException {
+ final String value = parameter.split("=", 2)[1];
+ return URLDecoder.decode(value, "UTF-8");
+ }
+
+ private boolean validateSignature(String queryParam, String sigAlg, String signature, X509Credential credential) {
+ try {
+ Signature sig = Signature.getInstance(sigAlg);
+ sig.initVerify(credential.getPublicKey());
+ sig.update(queryParam.getBytes(StandardCharsets.UTF_8));
+ return sig.verify(Base64.getDecoder().decode(signature));
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ return false;
+ }
+
+ }
+
private LogoutRequest buildLogoutRequest(String logoutUrl) {
final LogoutRequest logoutRequest = SamlUtils.buildObject(LogoutRequest.class, LogoutRequest.DEFAULT_ELEMENT_NAME);
logoutRequest.setDestination(logoutUrl);
