/*
* 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.keycloaksaml;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.rules.ExternalResource;
import org.keycloak.adapters.saml.SamlAuthenticationError;
import org.keycloak.adapters.saml.SamlPrincipal;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.common.util.*;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
import org.keycloak.protocol.saml.mappers.GroupMembershipMapper;
import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
import org.keycloak.protocol.saml.mappers.HardcodedRole;
import org.keycloak.protocol.saml.mappers.RoleListMapper;
import org.keycloak.protocol.saml.mappers.RoleNameMapper;
import org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.saml.*;
import org.keycloak.saml.common.constants.*;
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.KeycloakServer;
import org.keycloak.testsuite.Retry;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.ErrorServlet;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
import org.w3c.dom.Document;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.URI;
import java.security.*;
import java.security.spec.*;
import java.util.*;
import java.util.Base64;
import java.util.logging.*;
import static org.junit.Assert.assertEquals;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SamlAdapterTestStrategy extends ExternalResource {
protected String AUTH_SERVER_URL = "http://localhost:8081/auth";
protected String APP_SERVER_BASE_URL = "http://localhost:8081";
protected AbstractKeycloakRule keycloakRule;
private static final String REALM_PRIVATE_KEY_STR = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=";
private static PrivateKey REALM_PRIVATE_KEY;
private static final String REALM_PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
private static PublicKey REALM_PUBLIC_KEY;
static {
try {
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] encoded = Base64.getDecoder().decode(REALM_PUBLIC_KEY_STR);
REALM_PUBLIC_KEY = (PublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
encoded = Base64.getDecoder().decode(REALM_PRIVATE_KEY_STR);
REALM_PRIVATE_KEY = (PrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
} catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
Logger.getLogger(SamlAdapterTestStrategy.class.getName()).log(Level.SEVERE, null, ex);
}
}
public SamlAdapterTestStrategy(String AUTH_SERVER_URL, String APP_SERVER_BASE_URL, AbstractKeycloakRule keycloakRule) {
this.AUTH_SERVER_URL = AUTH_SERVER_URL;
this.APP_SERVER_BASE_URL = APP_SERVER_BASE_URL;
this.keycloakRule = keycloakRule;
}
public WebRule webRule = new WebRule(this);
@WebResource
protected WebDriver driver;
@WebResource
protected LoginPage loginPage;
@WebResource
protected InputPage inputPage;
@Override
protected void before() throws Throwable {
super.before();
webRule.before();
}
@Override
protected void after() {
super.after();
webRule.after();
}
public static RealmModel baseAdapterTestInitialization(KeycloakSession session, RealmManager manager, RealmModel adminRealm, Class<?> clazz) {
RealmRepresentation representation = KeycloakServer.loadJson(clazz.getResourceAsStream("/keycloak-saml/testsaml.json"), RealmRepresentation.class);
RealmModel demoRealm = manager.importRealm(representation);
return demoRealm;
}
protected void checkLoggedOut(String mainUrl, boolean postBinding) {
String pageSource = driver.getPageSource();
System.out.println("*** logout pagesource ***");
System.out.println(pageSource);
System.out.println("driver url: " + driver.getCurrentUrl());
Assert.assertTrue(pageSource.contains("request-path: /logout.jsp"));
driver.navigate().to(mainUrl);
checkAtLoginPage(postBinding);
}
protected void checkAtLoginPage(boolean postBinding) {
if (postBinding) assertAtLoginPagePostBinding();
else assertAtLoginPageRedirectBinding();
}
protected void assertAtLoginPageRedirectBinding() {
Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml"));
}
protected void assertAtLoginPagePostBinding() {
Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/login-actions/authenticate"));
}
public void testSavedPostRequest() throws Exception {
// test login to customer-portal which does a bearer request to customer-db
driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal");
System.err.println("*********** Current url: " + driver.getCurrentUrl());
Assert.assertTrue(driver.getCurrentUrl().startsWith(APP_SERVER_BASE_URL + "/input-portal"));
inputPage.execute("hello");
assertAtLoginPagePostBinding();
loginPage.login("bburke@redhat.com", "password");
System.out.println("Current url: " + driver.getCurrentUrl());
Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/input-portal/secured/post");
String pageSource = driver.getPageSource();
System.out.println(pageSource);
Assert.assertTrue(pageSource.contains("parameter=hello"));
// test that user principal and KeycloakSecurityContext available
driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal/insecure");
System.out.println("insecure: ");
System.out.println(driver.getPageSource());
Assert.assertTrue(driver.getPageSource().contains("Insecure Page"));
if (System.getProperty("insecure.user.principal.unsupported") == null) Assert.assertTrue(driver.getPageSource().contains("UserPrincipal"));
// test logout
driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal?GLO=true");
// test unsecured POST KEYCLOAK-901
Client client = ClientBuilder.newClient();
Form form = new Form();
form.param("parameter", "hello");
String text = client.target(APP_SERVER_BASE_URL + "/input-portal/unsecured").request().post(Entity.form(form), String.class);
Assert.assertTrue(text.contains("parameter=hello"));
client.close();
}
public void testErrorHandlingUnsigned() throws Exception {
ErrorServlet.authError = null;
Client client = ClientBuilder.newClient();
// make sure
Response response = client.target(APP_SERVER_BASE_URL + "/employee-sig/").request().get();
response.close();
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
.destination(APP_SERVER_BASE_URL + "/employee-sig/saml")
.issuer(AUTH_SERVER_URL + "/realms/demo")
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder()
.relayState(null);
Document document = builder.buildDocument();
URI uri = binding.redirectBinding(document).generateURI(APP_SERVER_BASE_URL + "/employee-sig/saml", false);
response = client.target(uri).request().get();
String errorPage = response.readEntity(String.class);
response.close();
Assert.assertTrue(errorPage.contains("Error Page"));
client.close();
Assert.assertNotNull(ErrorServlet.authError);
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
Assert.assertNotNull(error.getStatus());
ErrorServlet.authError = null;
}
public void testErrorHandlingSigned() throws Exception {
ErrorServlet.authError = null;
Client client = ClientBuilder.newClient();
// make sure
Response response = client.target(APP_SERVER_BASE_URL + "/employee-sig/").request().get();
response.close();
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
.destination(APP_SERVER_BASE_URL + "/employee-sig/saml")
.issuer(AUTH_SERVER_URL + "/realms/demo")
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder()
.relayState(null)
.signatureAlgorithm(SignatureAlgorithm.RSA_SHA256)
.signWith(KeyUtils.createKeyId(REALM_PRIVATE_KEY), REALM_PRIVATE_KEY, REALM_PUBLIC_KEY)
.signDocument();
Document document = builder.buildDocument();
URI uri = binding.generateRedirectUri(GeneralConstants.SAML_RESPONSE_KEY, APP_SERVER_BASE_URL + "/employee-sig/saml", document);
response = client.target(uri).request().get();
String errorPage = response.readEntity(String.class);
response.close();
Assert.assertTrue(errorPage.contains("Error Page"));
client.close();
Assert.assertNotNull(ErrorServlet.authError);
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
Assert.assertEquals(SamlAuthenticationError.Reason.ERROR_STATUS, error.getReason());
Assert.assertNotNull(error.getStatus());
ErrorServlet.authError = null;
}
public void testPostSimpleLoginLogout() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post/");
System.out.println(driver.getPageSource());
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post/", true);
}
public void testPostPassiveLoginLogout(boolean forbiddenIfNotauthenticated) {
// first request on passive app - no login page shown, user not logged in as we are in passive mode.
// Shown page depends on used authentication mechanism, some may return forbidden error, some return requested page with anonymous user (not logged in)
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-passive/");
assertEquals(APP_SERVER_BASE_URL + "/sales-post-passive/saml", driver.getCurrentUrl());
System.out.println(driver.getPageSource());
if (forbiddenIfNotauthenticated) {
Assert.assertTrue(driver.getPageSource().contains("HTTP status code: 403"));
} else {
Assert.assertTrue(driver.getPageSource().contains("principal=null"));
}
// login user by asking login from other app
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post/");
loginPage.login("bburke", "password");
// navigate to the passive app again, we have to be logged in now
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-passive/");
assertEquals(APP_SERVER_BASE_URL + "/sales-post-passive/", driver.getCurrentUrl());
System.out.println(driver.getPageSource());
Assert.assertTrue(driver.getPageSource().contains("bburke"));
// logout from both app
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-passive?GLO=true");
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post?GLO=true");
// refresh passive app page, not logged in again as we are in passive mode
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-passive/");
assertEquals(APP_SERVER_BASE_URL + "/sales-post-passive/saml", driver.getCurrentUrl());
Assert.assertFalse(driver.getPageSource().contains("bburke"));
}
public void testPostSimpleUnauthorized(CheckAuthError error) {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post/");
assertAtLoginPagePostBinding();
loginPage.login("unauthorized", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post/");
System.out.println(driver.getPageSource());
error.check(driver);
}
public void testPostSimpleLoginLogoutIdpInitiated() {
driver.navigate().to(AUTH_SERVER_URL + "/realms/demo/protocol/saml/clients/sales-post");
loginPage.login("bburke", "password");
Assert.assertTrue(driver.getCurrentUrl().startsWith(APP_SERVER_BASE_URL + "/sales-post"));
System.out.println(driver.getPageSource());
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post/", true);
}
public void testPostSimpleLoginLogoutIdpInitiatedRedirectTo() {
driver.navigate().to(AUTH_SERVER_URL + "/realms/demo/protocol/saml/clients/sales-post2");
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post2/foo");
System.out.println(driver.getPageSource());
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post2?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post2/", true);
}
public void testPostSignedLoginLogout() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig/", true);
}
public void testPostSignedResponseAndAssertionLoginLogout() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/", true);
}
public void testPostSignedLoginLogoutTransientNameID() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig-transient/");
System.out.println(driver.getPageSource());
Assert.assertFalse(driver.getPageSource().contains("bburke"));
Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig-transient/", true);
}
public void testPostSignedLoginLogoutPersistentNameID() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-persistent/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig-persistent/");
System.out.println(driver.getPageSource());
Assert.assertFalse(driver.getPageSource().contains("bburke"));
Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-persistent?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig-persistent/", true);
}
public void testPostSignedLoginLogoutEmailNameID() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-email/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig-email/");
System.out.println(driver.getPageSource());
Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-email?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig-email/", true);
}
public void testRelayStateEncoding() throws Exception {
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
// at the relay state
SamlSPFacade.samlResponse = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/employee/");
assertAtLoginPageRedirectBinding();
System.out.println(driver.getCurrentUrl());
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee/");
assertEquals(SamlSPFacade.sentRelayState, SamlSPFacade.RELAY_STATE);
Assert.assertNotNull(SamlSPFacade.samlResponse);
}
public void testAttributes() throws Exception {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
ClientModel app = appRealm.getClientByClientId(APP_SERVER_BASE_URL + "/employee2/");
app.addProtocolMapper(GroupMembershipMapper.create("groups", "group", null, null, true));
app.addProtocolMapper(UserAttributeStatementMapper.createAttributeMapper("topAttribute", "topAttribute", "topAttribute", "Basic", null, false, null));
app.addProtocolMapper(UserAttributeStatementMapper.createAttributeMapper("level2Attribute", "level2Attribute", "level2Attribute", "Basic", null, false, null));
}
}, "demo");
{
SendUsernameServlet.sentPrincipal = null;
SendUsernameServlet.checkRoles = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/");
assertAtLoginPagePostBinding();
List<String> requiredRoles = new LinkedList<>();
requiredRoles.add("manager");
requiredRoles.add("user");
SendUsernameServlet.checkRoles = requiredRoles;
loginPage.login("level2GroupUser", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee2/");
SendUsernameServlet.checkRoles = null;
SamlPrincipal principal = (SamlPrincipal) SendUsernameServlet.sentPrincipal;
Assert.assertNotNull(principal);
assertEquals("level2@redhat.com", principal.getAttribute(X500SAMLProfileConstants.EMAIL.get()));
assertEquals("true", principal.getAttribute("topAttribute"));
assertEquals("true", principal.getAttribute("level2Attribute"));
List<String> groups = principal.getAttributes("group");
Assert.assertNotNull(groups);
Set<String> groupSet = new HashSet<>();
assertEquals("level2@redhat.com", principal.getFriendlyAttribute("email"));
driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/employee2/", true);
}
{
SendUsernameServlet.sentPrincipal = null;
SendUsernameServlet.checkRoles = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/");
assertAtLoginPagePostBinding();
List<String> requiredRoles = new LinkedList<>();
requiredRoles.add("manager");
requiredRoles.add("employee");
requiredRoles.add("user");
SendUsernameServlet.checkRoles = requiredRoles;
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee2/");
SendUsernameServlet.checkRoles = null;
SamlPrincipal principal = (SamlPrincipal) SendUsernameServlet.sentPrincipal;
Assert.assertNotNull(principal);
assertEquals("bburke@redhat.com", principal.getAttribute(X500SAMLProfileConstants.EMAIL.get()));
assertEquals("bburke@redhat.com", principal.getFriendlyAttribute("email"));
assertEquals("617", principal.getAttribute("phone"));
Assert.assertNull(principal.getFriendlyAttribute("phone"));
driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/employee2/", true);
}
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
ClientModel app = appRealm.getClientByClientId(APP_SERVER_BASE_URL + "/employee2/");
for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
if (mapper.getName().equals("role-list")) {
app.removeProtocolMapper(mapper);
mapper.setId(null);
mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
app.addProtocolMapper(mapper);
}
}
app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", APP_SERVER_BASE_URL + "/employee/.employee", "pee-on"));
}
}, "demo");
System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
{
SendUsernameServlet.sentPrincipal = null;
SendUsernameServlet.checkRoles = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/");
assertAtLoginPagePostBinding();
List<String> requiredRoles = new LinkedList<>();
requiredRoles.add("el-jefe");
requiredRoles.add("user");
requiredRoles.add("hardcoded-role");
requiredRoles.add("pee-on");
SendUsernameServlet.checkRoles = requiredRoles;
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee2/");
SendUsernameServlet.checkRoles = null;
SamlPrincipal principal = (SamlPrincipal) SendUsernameServlet.sentPrincipal;
Assert.assertNotNull(principal);
assertEquals("hard", principal.getAttribute("hardcoded-attribute"));
}
}
public void testRedirectSignedLoginLogout() {
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig/");
assertAtLoginPageRedirectBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/employee-sig/", false);
}
public void testRedirectSignedLoginLogoutFrontNoSSO() {
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front/");
assertAtLoginPageRedirectBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig-front/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/employee-sig-front/", false);
}
public void testRedirectSignedLoginLogoutFront() {
// visit 1st app an logg in
System.out.println("visit 1st app ");
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig/");
assertAtLoginPageRedirectBinding();
System.out.println("login to form");
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
// visit 2nd app
System.out.println("visit 2nd app ");
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front/");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig-front/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
// visit 3rd app
System.out.println("visit 3rd app ");
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig/");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig/");
Assert.assertTrue(driver.getPageSource().contains("bburke"));
// logout of first app
System.out.println("GLO");
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/employee-sig/", false);
driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front/");
String currentUrl = driver.getCurrentUrl();
Assert.assertTrue(currentUrl.startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig/");
assertAtLoginPagePostBinding();
}
public void testPostEncryptedLoginLogout() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-enc/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
Retry.execute(new Runnable() {
@Override
public void run() {
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-enc/");
}
}, 10, 100);
Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-enc?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-enc/", true);
}
public void testPostBadClientSignature() {
driver.navigate().to(APP_SERVER_BASE_URL + "/bad-client-sales-post-sig/");
System.out.println(driver.getCurrentUrl());
Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml"));
assertEquals(driver.getTitle(), "We're sorry...");
}
public static interface CheckAuthError {
void check(WebDriver driver);
}
public void testPostBadRealmSignature() {
ErrorServlet.authError = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/bad-realm-sales-post-sig/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/bad-realm-sales-post-sig/saml");
System.out.println(driver.getPageSource());
Assert.assertNotNull(ErrorServlet.authError);
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
ErrorServlet.authError = null;
}
public void testPostBadAssertionSignature() {
ErrorServlet.authError = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/bad-assertion-sales-post-sig/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/bad-assertion-sales-post-sig/saml");
System.out.println(driver.getPageSource());
Assert.assertNotNull(ErrorServlet.authError);
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
ErrorServlet.authError = null;
}
public void testMissingAssertionSignature() {
ErrorServlet.authError = null;
driver.navigate().to(APP_SERVER_BASE_URL + "/missing-assertion-sig/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/missing-assertion-sig/saml");
System.out.println(driver.getPageSource());
Assert.assertNotNull(ErrorServlet.authError);
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
ErrorServlet.authError = null;
}
public void testMetadataPostSignedLoginLogout() throws Exception {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata/");
assertAtLoginPagePostBinding();
loginPage.login("bburke", "password");
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-metadata/");
String pageSource = driver.getPageSource();
Assert.assertTrue(pageSource.contains("bburke"));
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata?GLO=true");
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-metadata/", true);
}
public static void uploadSP(String AUTH_SERVER_URL) {
try {
Keycloak keycloak = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID, null);
RealmResource admin = keycloak.realm("demo");
admin.toRepresentation();
ClientRepresentation clientRep = admin.convertClientDescription(IOUtils.toString(SamlAdapterTestStrategy.class.getResourceAsStream("/keycloak-saml/sp-metadata.xml")));
Response response = admin.clients().create(clientRep);
assertEquals(201, response.getStatus());
keycloak.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}