/* * 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; import org.apache.commons.io.IOUtils; import org.jboss.arquillian.graphene.page.Page; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.asset.StringAsset; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractAuthTest; import org.keycloak.testsuite.adapter.page.AppServerContextRoot; import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * * @author tkyjovsk */ @AppServerContainer public abstract class AbstractAdapterTest extends AbstractAuthTest { @Page protected AppServerContextRoot appServerContextRootPage; public static final String JBOSS_DEPLOYMENT_STRUCTURE_XML = "jboss-deployment-structure.xml"; public static final URL jbossDeploymentStructure = AbstractServletsAdapterTest.class .getResource("/adapter-test/" + JBOSS_DEPLOYMENT_STRUCTURE_XML); public static final String TOMCAT_CONTEXT_XML = "context.xml"; public static final URL tomcatContext = AbstractServletsAdapterTest.class .getResource("/adapter-test/" + TOMCAT_CONTEXT_XML); @Override public void addTestRealms(List<RealmRepresentation> testRealms) { addAdapterTestRealms(testRealms); for (RealmRepresentation tr : testRealms) { log.info("Setting redirect-uris in test realm '" + tr.getRealm() + "' as " + (isRelative() ? "" : "non-") + "relative"); modifyClientRedirectUris(tr, "http://localhost:8080", ""); modifyClientUrls(tr, "http://localhost:8080", ""); if (isRelative()) { modifyClientRedirectUris(tr, appServerContextRootPage.toString(), ""); modifyClientUrls(tr, appServerContextRootPage.toString(), ""); modifyClientWebOrigins(tr, "8080", System.getProperty("auth.server.http.port", null)); modifySamlMasterURLs(tr, "/", "http://localhost:" + System.getProperty("auth.server.http.port", null) + "/"); modifySAMLClientsAttributes(tr, "8080", System.getProperty("auth.server.http.port", "8180")); } else { modifyClientRedirectUris(tr, "^(/.*/\\*)", appServerContextRootPage.toString() + "$1"); modifyClientUrls(tr, "^(/.*)", appServerContextRootPage.toString() + "$1"); modifyClientWebOrigins(tr, "8080", System.getProperty("app.server.http.port", null)); modifySamlMasterURLs(tr, "8080", System.getProperty("auth.server.http.port", null)); modifySAMLClientsAttributes(tr, "http://localhost:8080", appServerContextRootPage.toString()); modifyClientJWKSUrl(tr, "^(/.*)", appServerContextRootPage.toString() + "$1"); } if ("true".equals(System.getProperty("auth.server.ssl.required"))) { tr.setSslRequired("all"); } } } // TODO: Fix to not require re-import @Override protected boolean isImportAfterEachMethod() { return true; } private void modifyClientJWKSUrl(RealmRepresentation realm, String regex, String replacement) { if (realm.getClients() != null) { realm.getClients().stream(). filter(client -> "client-jwt".equals(client.getClientAuthenticatorType()) && client.getAttributes().containsKey("jwks.url")). forEach(client -> { Map<String, String> attr = client.getAttributes(); attr.put("jwks.url", attr.get("jwks.url").replaceFirst(regex, replacement)); client.setAttributes(attr); }); } } public abstract void addAdapterTestRealms(List<RealmRepresentation> testRealms); public boolean isRelative() { return testContext.isRelativeAdapterTest(); } protected void modifyClientRedirectUris(RealmRepresentation realm, String regex, String replacement) { if (realm.getClients() != null) { for (ClientRepresentation client : realm.getClients()) { List<String> redirectUris = client.getRedirectUris(); if (redirectUris != null) { List<String> newRedirectUris = new ArrayList<>(); for (String uri : redirectUris) { newRedirectUris.add(uri.replaceAll(regex, replacement)); } client.setRedirectUris(newRedirectUris); } } } } protected void modifyClientUrls(RealmRepresentation realm, String regex, String replacement) { if (realm.getClients() != null) { for (ClientRepresentation client : realm.getClients()) { String baseUrl = client.getBaseUrl(); if (baseUrl != null) { client.setBaseUrl(baseUrl.replaceAll(regex, replacement)); } String adminUrl = client.getAdminUrl(); if (adminUrl != null) { client.setAdminUrl(adminUrl.replaceAll(regex, replacement)); } } } } protected void modifyClientWebOrigins(RealmRepresentation realm, String regex, String replacement) { if (realm.getClients() != null) { for (ClientRepresentation client : realm.getClients()) { List<String> webOrigins = client.getWebOrigins(); if (webOrigins != null) { List<String> newWebOrigins = new ArrayList<>(); for (String uri : webOrigins) { newWebOrigins.add(uri.replaceAll(regex, replacement)); } client.setWebOrigins(newWebOrigins); } } } } protected void modifySAMLClientsAttributes(RealmRepresentation realm, String regex, String replacement) { if (realm.getClients() != null) { for (ClientRepresentation client : realm.getClients()) { if (client.getProtocol() != null && client.getProtocol().equals("saml")) { log.info("Modifying attributes of SAML client: " + client.getClientId()); for (Map.Entry<String, String> entry : client.getAttributes().entrySet()) { client.getAttributes().put(entry.getKey(), entry.getValue().replaceAll(regex, replacement)); } } } } } protected void modifySamlMasterURLs(RealmRepresentation realm, String regex, String replacement) { if (realm.getClients() != null) { for (ClientRepresentation client : realm.getClients()) { if (client.getProtocol() != null && client.getProtocol().equals("saml")) { log.info("Modifying master URL of SAML client: " + client.getClientId()); String masterUrl = client.getAdminUrl(); if (masterUrl == null) { masterUrl = client.getBaseUrl(); } masterUrl = masterUrl.replaceFirst(regex, replacement); client.setAdminUrl(masterUrl + ((!masterUrl.endsWith("/saml")) ? "/saml" : "")); } } } } /** * Modifies baseUrl, adminUrl and redirectUris for client based on real * deployment url of the app. * * @param realm * @param clientId * @param deploymentUrl */ protected void fixClientUrisUsingDeploymentUrl(RealmRepresentation realm, String clientId, String deploymentUrl) { for (ClientRepresentation client : realm.getClients()) { if (clientId.equals(client.getClientId())) { if (client.getBaseUrl() != null) { client.setBaseUrl(deploymentUrl); } if (client.getAdminUrl() != null) { client.setAdminUrl(deploymentUrl); } List<String> redirectUris = client.getRedirectUris(); if (redirectUris != null) { List<String> newRedirectUris = new ArrayList<>(); for (String uri : redirectUris) { newRedirectUris.add(deploymentUrl + "/*"); } client.setRedirectUris(newRedirectUris); } } } } public static void addContextXml(Archive archive, String contextPath) { try { String contextXmlContent = IOUtils.toString(tomcatContext.openStream()) .replace("%CONTEXT_PATH%", contextPath); archive.add(new StringAsset(contextXmlContent), "/META-INF/context.xml"); } catch (IOException ex) { throw new RuntimeException(ex); } } }