KEYCLOAK-4897 Tests for assertion-only signatures with encrypted assertions

This commit is contained in:
Hynek Mlnarik 2017-05-17 10:45:38 +02:00 committed by Frederik Libert
parent 71f0db0837
commit 10c9e0f00f
9 changed files with 265 additions and 4 deletions

View file

@ -27,6 +27,7 @@ import java.net.URL;
*/ */
public class SalesPostEncServlet extends SAMLServlet { public class SalesPostEncServlet extends SAMLServlet {
public static final String DEPLOYMENT_NAME = "sales-post-enc"; public static final String DEPLOYMENT_NAME = "sales-post-enc";
public static final String CLIENT_NAME = "http://localhost:8081/sales-post-enc/";
@ArquillianResource @ArquillianResource
@OperateOnDeployment(DEPLOYMENT_NAME) @OperateOnDeployment(DEPLOYMENT_NAME)

View file

@ -0,0 +1,40 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.testsuite.adapter.page;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.test.api.ArquillianResource;
import java.net.URL;
/**
* @author mhajas
*/
public class SalesPostEncSignAssertionsOnlyServlet extends SAMLServlet {
public static final String DEPLOYMENT_NAME = "sales-post-enc-sign-assertions-only";
public static final String CLIENT_NAME = "http://localhost:8081/sales-post-enc-sign-assertions-only/";
@ArquillianResource
@OperateOnDeployment(DEPLOYMENT_NAME)
private URL url;
@Override
public URL getInjectedUrl() {
return url;
}
}

View file

@ -0,0 +1,55 @@
package org.keycloak.testsuite.util;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.representations.idm.ClientRepresentation;
import java.io.Closeable;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author hmlnarik
*/
public class ClientAttributeUpdater {
private final Map<String, String> originalAttributes = new HashMap<>();
private final ClientResource clientResource;
private final ClientRepresentation rep;
public ClientAttributeUpdater(ClientResource clientResource) {
this.clientResource = clientResource;
this.rep = clientResource.toRepresentation();
if (this.rep.getAttributes() == null) {
this.rep.setAttributes(new HashMap<>());
}
}
public ClientAttributeUpdater setAttribute(String name, String value) {
if (! originalAttributes.containsKey(name)) {
this.originalAttributes.put(name, this.rep.getAttributes().put(name, value));
} else {
this.rep.getAttributes().put(name, value);
}
return this;
}
public ClientAttributeUpdater removeAttribute(String name) {
if (! originalAttributes.containsKey(name)) {
this.originalAttributes.put(name, this.rep.getAttributes().put(name, null));
} else {
this.rep.getAttributes().put(name, null);
}
return this;
}
public Closeable update() {
clientResource.update(rep);
return () -> {
rep.getAttributes().putAll(originalAttributes);
clientResource.update(rep);
};
}
}

View file

@ -0,0 +1,55 @@
package org.keycloak.testsuite.util;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.RealmRepresentation;
import java.io.Closeable;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author hmlnarik
*/
public class RealmAttributeUpdater {
private final Map<String, String> originalAttributes = new HashMap<>();
private final RealmResource realmResource;
private final RealmRepresentation rep;
public RealmAttributeUpdater(RealmResource realmResource) {
this.realmResource = realmResource;
this.rep = realmResource.toRepresentation();
if (this.rep.getAttributes() == null) {
this.rep.setAttributes(new HashMap<>());
}
}
public RealmAttributeUpdater setAttribute(String name, String value) {
if (! originalAttributes.containsKey(name)) {
this.originalAttributes.put(name, this.rep.getAttributes().put(name, value));
} else {
this.rep.getAttributes().put(name, value);
}
return this;
}
public RealmAttributeUpdater removeAttribute(String name) {
if (! originalAttributes.containsKey(name)) {
this.originalAttributes.put(name, this.rep.getAttributes().put(name, null));
} else {
this.rep.getAttributes().put(name, null);
}
return this;
}
public Closeable update() {
realmResource.update(rep);
return () -> {
rep.getAttributes().putAll(originalAttributes);
realmResource.update(rep);
};
}
}

View file

@ -24,6 +24,7 @@ public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLS
salesMetadataServletPage.checkRoles(true); salesMetadataServletPage.checkRoles(true);
salesPostServletPage.checkRoles(true); salesPostServletPage.checkRoles(true);
salesPostEncServletPage.checkRoles(true); salesPostEncServletPage.checkRoles(true);
salesPostEncSignAssertionsOnlyServletPage.checkRoles(true);
salesPostSigServletPage.checkRoles(true); salesPostSigServletPage.checkRoles(true);
salesPostPassiveServletPage.checkRoles(true); salesPostPassiveServletPage.checkRoles(true);
salesPostSigPersistentServletPage.checkRoles(true); salesPostSigPersistentServletPage.checkRoles(true);
@ -56,6 +57,7 @@ public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLS
salesMetadataServletPage.checkRoles(false); salesMetadataServletPage.checkRoles(false);
salesPostServletPage.checkRoles(false); salesPostServletPage.checkRoles(false);
salesPostEncServletPage.checkRoles(false); salesPostEncServletPage.checkRoles(false);
salesPostEncSignAssertionsOnlyServletPage.checkRoles(false);
salesPostSigServletPage.checkRoles(false); salesPostSigServletPage.checkRoles(false);
salesPostPassiveServletPage.checkRoles(false); salesPostPassiveServletPage.checkRoles(false);
salesPostSigEmailServletPage.checkRoles(false); salesPostSigEmailServletPage.checkRoles(false);

View file

@ -86,14 +86,13 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator; import javax.xml.validation.Validator;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.LinkedHashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
@ -107,7 +106,6 @@ import static org.keycloak.testsuite.util.IOUtil.loadXML;
import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute; import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute;
import static org.keycloak.testsuite.util.Matchers.bodyHC; import static org.keycloak.testsuite.util.Matchers.bodyHC;
import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC; import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
import static org.keycloak.testsuite.util.SamlClient.Binding.POST;
import static org.keycloak.testsuite.util.SamlClient.idpInitiatedLogin; import static org.keycloak.testsuite.util.SamlClient.idpInitiatedLogin;
import static org.keycloak.testsuite.util.SamlClient.login; import static org.keycloak.testsuite.util.SamlClient.login;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
@ -156,6 +154,9 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
@Page @Page
protected SalesPostEncServlet salesPostEncServletPage; protected SalesPostEncServlet salesPostEncServletPage;
@Page
protected SalesPostEncSignAssertionsOnlyServlet salesPostEncSignAssertionsOnlyServletPage;
@Page @Page
protected SalesPostPassiveServlet salesPostPassiveServletPage; protected SalesPostPassiveServlet salesPostPassiveServletPage;
@ -259,6 +260,11 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
return samlServletDeployment(SalesPostEncServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); return samlServletDeployment(SalesPostEncServlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
} }
@Deployment(name = SalesPostEncSignAssertionsOnlyServlet.DEPLOYMENT_NAME)
protected static WebArchive salesPostEncSignAssertionsOnly() {
return samlServletDeployment(SalesPostEncSignAssertionsOnlyServlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
}
@Deployment(name = SalesPostPassiveServlet.DEPLOYMENT_NAME) @Deployment(name = SalesPostPassiveServlet.DEPLOYMENT_NAME)
protected static WebArchive salesPostPassive() { protected static WebArchive salesPostPassive() {
return samlServletDeployment(SalesPostPassiveServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); return samlServletDeployment(SalesPostPassiveServlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
@ -625,6 +631,24 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
testSuccessfulAndUnauthorizedLogin(salesPostEncServletPage, testRealmSAMLPostLoginPage); testSuccessfulAndUnauthorizedLogin(salesPostEncServletPage, testRealmSAMLPostLoginPage);
} }
@Test
public void salesPostEncSignedAssertionsOnlyTest() throws Exception {
testSuccessfulAndUnauthorizedLogin(salesPostEncSignAssertionsOnlyServletPage, testRealmSAMLPostLoginPage);
}
@Test
public void salesPostEncSignedAssertionsAndDocumentTest() throws Exception {
ClientRepresentation salesPostEncClient = testRealmResource().clients().findByClientId(SalesPostEncServlet.CLIENT_NAME).get(0);
try (Closeable client = new ClientAttributeUpdater(testRealmResource().clients().get(salesPostEncClient.getId()))
.setAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, "true")
.setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true")
.update()) {
testSuccessfulAndUnauthorizedLogin(salesPostEncServletPage, testRealmSAMLPostLoginPage);
} finally {
salesPostEncServletPage.logout();
}
}
@Test @Test
public void salesPostPassiveTest() { public void salesPostPassiveTest() {
salesPostPassiveServletPage.navigateTo(); salesPostPassiveServletPage.navigateTo();

View file

@ -0,0 +1,65 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ 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.
-->
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_7.xsd">
<SP entityID="http://localhost:8081/sales-post-enc-sign-assertions-only/"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
logoutPage="/logout.jsp"
forceAuthentication="false">
<Keys>
<Key signing="true" encryption="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
<Certificate alias="http://localhost:8080/sales-post-enc/"/>
</KeyStore>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_NAME_ID"/>
<RoleIdentifiers>
<Attribute name="Role"/>
</RoleIdentifiers>
<IDP entityID="idp">
<SingleSignOnService signRequest="true"
validateResponseSignature="false"
validateAssertionSignature="true"
requestBinding="POST"
bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="false"
signRequest="true"
signResponse="true"
requestBinding="POST"
responseBinding="POST"
postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
/>
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>

View file

@ -331,6 +331,25 @@
"saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==" "saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
} }
}, },
{
"clientId": "http://localhost:8081/sales-post-enc-sign-assertions-only/",
"enabled": true,
"protocol": "saml",
"fullScopeAllowed": true,
"baseUrl": "http://localhost:8080/sales-post-enc-sign-assertions-only",
"redirectUris": [
],
"attributes": {
"saml.server.signature": "false",
"saml.assertion.signature": "true",
"saml.signature.algorithm": "RSA_SHA512",
"saml.client.signature": "true",
"saml.encrypt": "true",
"saml.authnstatement": "true",
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
"saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
}
},
{ {
"clientId": "http://localhost:8081/employee-sig/", "clientId": "http://localhost:8081/employee-sig/",
"enabled": true, "enabled": true,