This commit is contained in:
Bill Burke committed 2016-09-22 19:57:39 -04:00
commit 8e65356891
288 files changed
+7282 -1082

No files matched your search

@@ -43,7 +43,7 @@
<xsl:param name="pool.prefill" select="'true'"/>
<xsl:variable name="newDatasourceDefinition">
<datasource jndi-name="java:jboss/datasources/KeycloakDS" jta="false" pool-name="KeycloakDS" use-java-context="true">
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" use-java-context="true">
<connection-url>
<xsl:value-of select="$jdbc.url"/>
</connection-url>
@@ -42,8 +42,8 @@
</modules>
</xsl:variable>
<!--inject provider-->
<xsl:template match="//*[local-name()='providers']/*[local-name()='provider']">
<!--inject provider; note: due to ibmjdk issues it tries to find out provider which has no attributes-->
<xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsKS)]//*[local-name()='provider' and not(@*)]">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
@@ -18,10 +18,8 @@
package org.keycloak.testsuite.rest;
import org.keycloak.Config.Scope;
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.representations.adapters.action.AdminAction;
import org.keycloak.representations.adapters.action.LogoutAction;
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
@@ -29,6 +27,7 @@ import org.keycloak.services.resource.RealmResourceProvider;
import org.keycloak.services.resource.RealmResourceProviderFactory;
import java.security.KeyPair;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
@@ -70,6 +69,7 @@ public class TestApplicationResourceProviderFactory implements RealmResourceProv
private KeyPair signingKeyPair;
private String oidcRequest;
private List<String> sectorIdentifierRedirectUris;
public KeyPair getSigningKeyPair() {
return signingKeyPair;
@@ -86,5 +86,13 @@ public class TestApplicationResourceProviderFactory implements RealmResourceProv
public void setOidcRequest(String oidcRequest) {
this.oidcRequest = oidcRequest;
}
public List<String> getSectorIdentifierRedirectUris() {
return sectorIdentifierRedirectUris;
}
public void setSectorIdentifierRedirectUris(List<String> sectorIdentifierRedirectUris) {
this.sectorIdentifierRedirectUris = sectorIdentifierRedirectUris;
}
}
}
@@ -591,7 +591,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
RealmModel realm = getRealmByName(realmName);
UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(new FederatedIdentityModel(identityProvider, userId, userName), realm);
if (foundFederatedUser == null) return null;
return ModelToRepresentation.toRepresentation(foundFederatedUser);
return ModelToRepresentation.toRepresentation(session, realm, foundFederatedUser);
}
@GET
@@ -603,7 +603,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
UserModel user = factory.getInstance(session, null).getUserByUsername(realm, userName);
if (user == null) return null;
return ModelToRepresentation.toRepresentation(user);
return ModelToRepresentation.toRepresentation(session, realm, user);
}
@GET
@@ -634,7 +634,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
ClientModel client = realm.getClientByClientId(clientId);
UserModel user = session.users().getServiceAccount(client);
if (user == null) return null;
return ModelToRepresentation.toRepresentation(user);
return ModelToRepresentation.toRepresentation(session, realm, user);
}
@Path("/export-import")
@@ -17,19 +17,6 @@
package org.keycloak.testsuite.rest.resource;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.BadRequestException;
import org.keycloak.OAuth2Constants;
@@ -42,6 +29,19 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.testsuite.rest.TestApplicationResourceProviderFactory;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -134,4 +134,19 @@ public class TestingOIDCEndpointsApplicationResource {
public String getOIDCRequest() {
return clientData.getOidcRequest();
}
@GET
@Path("/set-sector-identifier-redirect-uris")
@Produces(MediaType.APPLICATION_JSON)
public void setSectorIdentifierRedirectUris(@QueryParam("redirectUris") List<String> redirectUris) {
clientData.setSectorIdentifierRedirectUris(new ArrayList<>());
clientData.getSectorIdentifierRedirectUris().addAll(redirectUris);
}
@GET
@Path("/get-sector-identifier-redirect-uris")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getSectorIdentifierRedirectUris() {
return clientData.getSectorIdentifierRedirectUris();
}
}
@@ -50,7 +50,7 @@
"mavenArtifactVersion": "2.1.0-SNAPSHOT",
"mavenArtifactId": "photoz-authz-policy",
"sessionName": "MainOwnerSession",
"mavenArtifactGroupId": "org.keycloak",
"mavenArtifactGroupId": "org.keycloak.testsuite",
"moduleName": "PhotozAuthzOwnerPolicy",
"applyPolicies": "[]",
"scannerPeriod": "1",
@@ -86,13 +86,24 @@ public class AggregateResultsReporter extends RunListener {
}
private File createReportFile() throws Exception {
PropertiesConfiguration config = new PropertiesConfiguration(System.getProperty("testsuite.constants"));
config.setThrowExceptionOnMissing(true);
String logDirPath = null;
final File logDir = new File(config.getString("log-dir"));
try {
PropertiesConfiguration config = new PropertiesConfiguration(System.getProperty("testsuite.constants"));
config.setThrowExceptionOnMissing(true);
logDirPath = config.getString("log-dir");
} catch (Exception e) {
logDirPath = System.getProperty("project.build.directory");
if (logDirPath == null) {
throw new RuntimeException("Could not determine the path to the log directory.");
}
logDirPath += File.separator + "surefire-reports";
}
final File logDir = new File(logDirPath);
logDir.mkdirs();
final File reportFile = new File(logDir, "junit-report.xml").getAbsoluteFile();
final File reportFile = new File(logDir, "junit-single-report.xml").getAbsoluteFile();
reportFile.createNewFile();
return reportFile;
@@ -0,0 +1,36 @@
/*
* 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;
import org.junit.Assume;
import org.keycloak.common.Profile;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ProfileAssume {
public static void assumePreview() {
Assume.assumeTrue("Ignoring test as community/preview profile is not enabled", Profile.isPreviewEnabled());
}
public static void assumePreviewDisabled() {
Assume.assumeFalse("Ignoring test as community/preview profile is enabled", Profile.isPreviewEnabled());
}
}
@@ -27,8 +27,13 @@ import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.logging.Logger;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
import org.keycloak.common.util.Time;
/**
@@ -38,6 +43,11 @@ import org.keycloak.common.util.Time;
*/
public class AdapterActionsFilter implements Filter {
public static final String TIME_OFFSET_PARAM = "timeOffset";
public static final String RESET_PUBLIC_KEY_PARAM = "resetPublicKey";
private static final Logger log = Logger.getLogger(AdapterActionsFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
@@ -45,16 +55,28 @@ public class AdapterActionsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletReq = (HttpServletRequest) request;
HttpServletResponse servletResp = (HttpServletResponse) response;
//Accept timeOffset as argument to enforce timeouts
String timeOffsetParam = request.getParameter("timeOffset");
if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
Time.setOffset(Integer.parseInt(timeOffsetParam));
}
String timeOffsetParam = request.getParameter(TIME_OFFSET_PARAM);
String resetPublicKey = request.getParameter(RESET_PUBLIC_KEY_PARAM);
// Continue request
chain.doFilter(request, response);
if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
int timeOffset = Integer.parseInt(timeOffsetParam);
log.infof("Time offset updated to %d for application %s", timeOffset, servletReq.getRequestURI());
Time.setOffset(timeOffset);
writeResponse(servletResp, "Offset set successfully");
} else if (resetPublicKey != null && !resetPublicKey.isEmpty()) {
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext) request.getServletContext().getAttribute(AdapterDeploymentContext.class.getName());
KeycloakDeployment deployment = deploymentContext.resolveDeployment(null);
deployment.setPublicKeyLocator(new JWKPublicKeyLocator());
log.infof("Restarted publicKey locator for application %s", servletReq.getRequestURI());
writeResponse(servletResp, "PublicKeyLocator restarted successfully");
} else {
// Continue request
chain.doFilter(request, response);
}
}
@@ -64,8 +86,9 @@ public class AdapterActionsFilter implements Filter {
}
private void writeResponse(HttpServletResponse response, String responseText) throws IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println(responseText);
writer.println("<html><body>" + responseText + "</body></html>");
writer.flush();
}
}
@@ -23,6 +23,7 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
import org.keycloak.util.JsonSerialization;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@@ -43,6 +44,8 @@ public abstract class AbstractShowTokensPage extends AbstractPageWithInjectedUrl
return JsonSerialization.readValue(accessToken.getText(), AccessToken.class);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchElementException nsee) {
log.warn("No accessToken element found on the page");
}
return null;
@@ -53,7 +56,10 @@ public abstract class AbstractShowTokensPage extends AbstractPageWithInjectedUrl
return JsonSerialization.readValue(refreshToken.getText(), RefreshToken.class);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchElementException nsee) {
log.warn("No idToken element found on the page");
}
return null;
}
}
@@ -0,0 +1,61 @@
/*
* 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 org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
import javax.ws.rs.core.UriBuilder;
import java.net.URL;
/**
*
* @author tkyjovsk
*/
public class BasicAuth extends AbstractPageWithInjectedUrl {
public static final String DEPLOYMENT_NAME = "basic-auth";
@ArquillianResource
@OperateOnDeployment(DEPLOYMENT_NAME)
private URL url;
@Override
public URL getInjectedUrl() {
//EAP6 URL fix
URL fixedUrl = createInjectedURL("basic-auth");
return fixedUrl != null ? fixedUrl : url;
}
@Override
public UriBuilder createUriBuilder() {
return super.createUriBuilder()
.userInfo("{user}:{password}")
.path("basic-auth")
.queryParam("value", "{value}");
}
public BasicAuth setTemplateValues(String user, String password, String value) {
setUriParameter("user", user);
setUriParameter("password", password);
setUriParameter("value", value);
return this;
}
}
@@ -0,0 +1,27 @@
package org.keycloak.testsuite.adapter.servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author mhajas
*/
@WebServlet("/basic-auth")
public class BasicAuthServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String value = req.getParameter("value");
System.out.println("In BasicAuthServlet with value: " + value);
resp.setContentType("text/plain");
PrintWriter pw = resp.getWriter();
pw.printf(value);
pw.flush();
}
}
@@ -49,8 +49,6 @@ import static org.keycloak.testsuite.util.IOUtil.*;
*/
public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
public static final String REALM_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
protected final Logger log = org.jboss.logging.Logger.getLogger(this.getClass());
private final boolean authServerSslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required"));
@@ -129,7 +127,6 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
// ac.setRealmKey(null); // TODO verify if realm key is required for relative scneario
} else {
adapterConfig.setAuthServerUrl(getAuthServerContextRoot() + "/auth");
adapterConfig.setRealmKey(REALM_KEY);
}
if ("true".equals(System.getProperty("app.server.ssl.required"))) {
@@ -17,10 +17,10 @@
package org.keycloak.testsuite.client.resources;
import javax.ws.rs.core.UriBuilder;
import org.keycloak.testsuite.util.OAuthClient;
import javax.ws.rs.core.UriBuilder;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -45,4 +45,10 @@ public class TestApplicationResourceUrls {
return builder.build().toString();
}
public static String pairwiseSectorIdentifierUri() {
UriBuilder builder = oidcClientEndpoints()
.path(TestOIDCEndpointsApplicationResource.class, "getSectorIdentifierRedirectUris");
return builder.build().toString();
}
}
@@ -17,15 +17,15 @@
package org.keycloak.testsuite.client.resources;
import java.util.Map;
import org.keycloak.jose.jwk.JSONWebKeySet;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.keycloak.jose.jwk.JSONWebKeySet;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -55,4 +55,15 @@ public interface TestOIDCEndpointsApplicationResource {
@Path("/get-oidc-request")
@Produces(org.keycloak.utils.MediaType.APPLICATION_JWT)
String getOIDCRequest();
@GET
@Path("/set-sector-identifier-redirect-uris")
@Produces(MediaType.APPLICATION_JSON)
void setSectorIdentifierRedirectUris(@QueryParam("redirectUris") List<String> redirectUris);
@GET
@Path("/get-sector-identifier-redirect-uris")
@Produces(MediaType.APPLICATION_JSON)
List<String> getSectorIdentifierRedirectUris();
}
@@ -71,6 +71,9 @@ public class LoginPage extends AbstractPage {
@FindBy(className = "alert-info")
private WebElement loginInfoMessage;
@FindBy(className = "instruction")
private WebElement instruction;
@FindBy(id = "kc-current-locale-link")
private WebElement languageText;
@@ -128,6 +131,10 @@ public class LoginPage extends AbstractPage {
return loginErrorMessage != null ? loginErrorMessage.getText() : null;
}
public String getInstruction() {
return instruction != null ? instruction.getText() : null;
}
public String getSuccessMessage() {
return loginSuccessMessage != null ? loginSuccessMessage.getText() : null;
}
@@ -377,12 +377,15 @@ public class AccountTest extends TestRealmKeycloakTest {
}
@Test
public void changeProfile() {
public void changeProfile() throws Exception {
setEditUsernameAllowed(false);
profilePage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent();
Assert.assertEquals("test-user@localhost", profilePage.getUsername());
Assert.assertEquals("Tom", profilePage.getFirstName());
Assert.assertEquals("Brady", profilePage.getLastName());
Assert.assertEquals("test-user@localhost", profilePage.getEmail());
@@ -391,6 +394,7 @@ public class AccountTest extends TestRealmKeycloakTest {
profilePage.updateProfile("", "New last", "new@email.com");
Assert.assertEquals("Please specify first name.", profilePage.getError());
Assert.assertEquals("test-user@localhost", profilePage.getUsername());
Assert.assertEquals("", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail());
@@ -417,6 +421,7 @@ public class AccountTest extends TestRealmKeycloakTest {
profilePage.clickCancel();
Assert.assertEquals("test-user@localhost", profilePage.getUsername());
Assert.assertEquals("Tom", profilePage.getFirstName());
Assert.assertEquals("Brady", profilePage.getLastName());
Assert.assertEquals("test-user@localhost", profilePage.getEmail());
@@ -426,6 +431,7 @@ public class AccountTest extends TestRealmKeycloakTest {
profilePage.updateProfile("New first", "New last", "new@email.com");
Assert.assertEquals("Your account has been updated.", profilePage.getSuccess());
Assert.assertEquals("test-user@localhost", profilePage.getUsername());
Assert.assertEquals("New first", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail());
@@ -436,18 +442,21 @@ public class AccountTest extends TestRealmKeycloakTest {
// reset user for other tests
profilePage.updateProfile("Tom", "Brady", "test-user@localhost");
events.clear();
// Revert
setEditUsernameAllowed(true);
}
private void setEditUsernameAllowed() {
private void setEditUsernameAllowed(boolean allowed) {
RealmRepresentation testRealm = testRealm().toRepresentation();
testRealm.setEditUsernameAllowed(true);
testRealm.setEditUsernameAllowed(allowed);
testRealm().update(testRealm);
}
@Test
public void changeUsername() {
// allow to edit the username in realm
setEditUsernameAllowed();
setEditUsernameAllowed(true);
profilePage.open();
loginPage.login("test-user@localhost", "password");
@@ -504,7 +513,7 @@ public class AccountTest extends TestRealmKeycloakTest {
@Test
public void changeUsernameLoginWithOldUsername() {
addUser("change-username", "change-username@localhost");
setEditUsernameAllowed();
setEditUsernameAllowed(true);
profilePage.open();
loginPage.login("change-username", "password");
@@ -530,7 +539,7 @@ public class AccountTest extends TestRealmKeycloakTest {
@Test
public void changeEmailLoginWithOldEmail() {
addUser("change-email", "change-username@localhost");
setEditUsernameAllowed();
setEditUsernameAllowed(true);
profilePage.open();
loginPage.login("change-username@localhost", "password");
@@ -17,11 +17,6 @@
package org.keycloak.testsuite.adapter;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Paths;
import org.apache.commons.io.IOUtils;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
@@ -29,6 +24,11 @@ import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Paths;
/**
*
* @author tkyjovsk
@@ -50,11 +50,11 @@ public abstract class AbstractExampleAdapterTest extends AbstractAdapterTest {
Assert.assertNotNull("Property ${examples.version.suffix} must bet set.", EXAMPLES_VERSION_SUFFIX);
System.out.println(EXAMPLES_VERSION_SUFFIX);
EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/example-realms";
if (!System.getProperty("unpacked.container.folder.name","").isEmpty()) {
EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/" + System.getProperty("unpacked.container.folder.name","") + "-examples";
TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/" + System.getProperty("unpacked.container.folder.name","") + "-test-apps";
} else {
EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/keycloak-examples-" + EXAMPLES_VERSION_SUFFIX;
TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/Keycloak-" + EXAMPLES_VERSION_SUFFIX + "-test-apps";
}
@@ -22,6 +22,7 @@ import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
@@ -113,7 +114,7 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
protected void setAdapterAndServerTimeOffset(int timeOffset, String servletUri) {
setTimeOffset(timeOffset);
String timeOffsetUri = UriBuilder.fromUri(servletUri)
.queryParam("timeOffset", timeOffset)
.queryParam(AdapterActionsFilter.TIME_OFFSET_PARAM, timeOffset)
.build().toString();
driver.navigate().to(timeOffsetUri);
@@ -98,7 +98,7 @@ public abstract class AbstractDemoExampleAdapterTest extends AbstractExampleAdap
@Override
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
testRealms.add(
loadRealm(new File(EXAMPLES_HOME_DIR + "/preconfigured-demo/testrealm.json")));
loadRealm(new File(EXAMPLES_HOME_DIR + "/demo-template/testrealm.json")));
}
@Override
@@ -17,22 +17,23 @@
package org.keycloak.testsuite.adapter.example;
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
import java.io.File;
import java.util.List;
import org.jboss.arquillian.graphene.page.Page;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.auth.page.account.Account;
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
import static org.keycloak.testsuite.adapter.AbstractExampleAdapterTest.EXAMPLES_HOME_DIR;
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
import org.keycloak.testsuite.adapter.page.fuse.AdminInterface;
import org.keycloak.testsuite.adapter.page.fuse.CustomerListing;
import org.keycloak.testsuite.adapter.page.fuse.CustomerPortalFuseExample;
import org.keycloak.testsuite.adapter.page.fuse.ProductPortalFuseExample;
import org.keycloak.testsuite.auth.page.account.Account;
import java.io.File;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
import static org.keycloak.testsuite.util.WaitUtils.pause;
@@ -23,13 +23,7 @@ import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.ResourcesResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.admin.client.resource.*;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
@@ -45,11 +39,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -80,8 +70,15 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
}
@Before
public void beforePhotozExampleAdapterTest() {
public void beforePhotozExampleAdapterTest() throws FileNotFoundException {
deleteAllCookiesForClientPage();
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
if ("Only Owner Policy".equals(policy.getName())) {
policy.getConfig().put("mavenArtifactVersion", System.getProperty("project.version"));
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
}
}
@Override
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.adapter.servlet;
import org.apache.commons.io.FileUtils;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.shrinkwrap.api.spec.WebArchive;
@@ -25,19 +26,31 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.common.Version;
import org.keycloak.common.util.Time;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.Constants;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.VersionRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
import org.keycloak.testsuite.adapter.page.*;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.auth.page.account.Applications;
import org.keycloak.testsuite.auth.page.login.OAuthGrant;
import org.keycloak.testsuite.console.page.events.Config;
import org.keycloak.testsuite.console.page.events.LoginEvents;
import org.keycloak.testsuite.util.URLAssert;
import org.keycloak.testsuite.util.URLUtils;
import org.keycloak.util.BasicAuthHelper;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
@@ -46,15 +59,23 @@ import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.Assert.*;
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/**
*
@@ -78,6 +99,16 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
private InputPortal inputPortal;
@Page
private TokenMinTTLPage tokenMinTTLPage;
@Page
private OAuthGrant oAuthGrantPage;
@Page
private Applications applicationsPage;
@Page
private LoginEvents loginEventsPage;
@Page
private BasicAuth basicAuthPage;
@Page
private Config configPage;
@Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
protected static WebArchive customerPortal() {
@@ -119,6 +150,20 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
return servletDeployment(TokenMinTTLPage.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, TokenMinTTLServlet.class, ErrorServlet.class);
}
@Deployment(name = BasicAuth.DEPLOYMENT_NAME)
protected static WebArchive basicAuth() {
return servletDeployment(BasicAuth.DEPLOYMENT_NAME, BasicAuthServlet.class);
}
@Override
public void setDefaultPageUriParameters() {
super.setDefaultPageUriParameters();
configPage.setConsoleRealm(DEMO);
loginEventsPage.setConsoleRealm(DEMO);
applicationsPage.setAuthRealm(DEMO);
loginEventsPage.setConsoleRealm(DEMO);
}
@Before
public void beforeDemoServletsAdapterTest() {
// Delete all cookies from token-min-ttl page to be sure we are logged out
@@ -166,6 +211,59 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
client.close();
}
@Test
public void testRealmKeyRotationWithNewKeyDownload() throws Exception {
// Login success first
tokenMinTTLPage.navigateTo();
testRealmLoginPage.form().waitForUsernameInputPresent();
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
testRealmLoginPage.form().login("bburke@redhat.com", "password");
assertCurrentUrlEquals(tokenMinTTLPage);
AccessToken token = tokenMinTTLPage.getAccessToken();
Assert.assertEquals("bburke@redhat.com", token.getPreferredUsername());
// Logout
String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
.queryParam(OAuth2Constants.REDIRECT_URI, tokenMinTTLPage.toString())
.build("demo").toString();
driver.navigate().to(logoutUri);
// Generate new realm key
RealmRepresentation realmRep = testRealmResource().toRepresentation();
String oldPublicKey = realmRep.getPublicKey();
String oldPrivateKey = realmRep.getPrivateKey();
realmRep.setPublicKey(Constants.GENERATE);
testRealmResource().update(realmRep);
// Try to login again. It should fail now
tokenMinTTLPage.navigateTo();
testRealmLoginPage.form().waitForUsernameInputPresent();
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
testRealmLoginPage.form().login("bburke@redhat.com", "password");
URLAssert.assertCurrentUrlStartsWith(driver, tokenMinTTLPage.getInjectedUrl().toString());
assertNull(tokenMinTTLPage.getAccessToken());
String adapterActionsUrl = tokenMinTTLPage.toString() + "/unsecured/foo";
setAdapterAndServerTimeOffset(300, adapterActionsUrl);
// Try to login. Should work now due to realm key change
tokenMinTTLPage.navigateTo();
assertCurrentUrlEquals(tokenMinTTLPage);
token = tokenMinTTLPage.getAccessToken();
Assert.assertEquals("bburke@redhat.com", token.getPreferredUsername());
driver.navigate().to(logoutUri);
// Revert public keys change
String timeOffsetUri = UriBuilder.fromUri(adapterActionsUrl)
.queryParam(AdapterActionsFilter.RESET_PUBLIC_KEY_PARAM, "true")
.build().toString();
driver.navigate().to(timeOffsetUri);
waitUntilElement(By.tagName("body")).is().visible();
setAdapterAndServerTimeOffset(0, adapterActionsUrl);
}
@Test
public void testLoginSSOAndLogout() {
// test login to customer-portal which does a bearer request to customer-db
@@ -261,7 +359,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
demoRealmRep.setSsoSessionIdleTimeout(1);
testRealmResource().update(demoRealmRep);
pause(2000);
pause(2000);
productPortal.navigateTo();
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
@@ -323,6 +421,10 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
testRealmResource().update(demoRealmRep);
String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
.queryParam(OAuth2Constants.REDIRECT_URI, securePortal.toString()).build("demo").toString();
driver.navigate().to(logoutUri);
}
@Test
@@ -444,6 +546,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
// Sets 5 minutes offset and assert access token will be still the same
setAdapterAndServerTimeOffset(300, tokenMinTTLPage.toString());
tokenMinTTLPage.navigateTo();
token = tokenMinTTLPage.getAccessToken();
int tokenIssued2 = token.getIssuedAt();
Assert.assertEquals(tokenIssued1, tokenIssued2);
@@ -451,6 +554,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
// Sets 9 minutes offset and assert access token will be refreshed (accessTokenTimeout is 10 minutes, token-min-ttl is 2 minutes. Hence 8 minutes or more should be sufficient)
setAdapterAndServerTimeOffset(540, tokenMinTTLPage.toString());
tokenMinTTLPage.navigateTo();
token = tokenMinTTLPage.getAccessToken();
int tokenIssued3 = token.getIssuedAt();
Assert.assertTrue(tokenIssued3 > tokenIssued1);
@@ -486,5 +590,193 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
setAdapterAndServerTimeOffset(0, tokenMinTTLPage.toString());
}
@Test
public void testBasicAuth() {
String value = "hello";
Client client = ClientBuilder.newClient();
Response response = client.target(basicAuthPage
.setTemplateValues("mposolda", "password", value).buildUri()).request().get();
assertEquals(200, response.getStatus());
assertEquals(value, response.readEntity(String.class));
response.close();
response = client.target(basicAuthPage
.setTemplateValues("invalid-user", "password", value).buildUri()).request().get();
assertEquals(401, response.getStatus());
String readResponse = response.readEntity(String.class);
assertTrue(readResponse.contains("Unauthorized") || readResponse.contains("Status 401"));
response.close();
response = client.target(basicAuthPage
.setTemplateValues("admin", "invalid-password", value).buildUri()).request().get();
assertEquals(401, response.getStatus());
readResponse = response.readEntity(String.class);
assertTrue(readResponse.contains("Unauthorized") || readResponse.contains("Status 401"));
response.close();
client.close();
}
@Test
public void grantServerBasedApp() {
ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "customer-portal");
ClientRepresentation client = clientResource.toRepresentation();
client.setConsentRequired(true);
clientResource.update(client);
RealmRepresentation realm = testRealmResource().toRepresentation();
realm.setEventsEnabled(true);
realm.setEnabledEventTypes(Arrays.asList("REVOKE_GRANT", "LOGIN"));
testRealmResource().update(realm);
customerPortal.navigateTo();
loginPage.form().login("bburke@redhat.com", "password");
assertTrue(oAuthGrantPage.isCurrent());
oAuthGrantPage.accept();
waitUntilElement(By.xpath("//body")).text().contains("Bill Burke");
waitUntilElement(By.xpath("//body")).text().contains("Stian Thorgersen");
applicationsPage.navigateTo();
applicationsPage.revokeGrantForApplication("customer-portal");
customerPortal.navigateTo();
assertTrue(oAuthGrantPage.isCurrent());
loginEventsPage.navigateTo();
if (!testContext.isAdminLoggedIn()) {
loginPage.form().login(adminUser);
testContext.setAdminLoggedIn(true);
}
loginEventsPage.table().filter();
loginEventsPage.table().filterForm().addEventType("REVOKE_GRANT");
loginEventsPage.table().update();
List<WebElement> resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='REVOKE_GRANT']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='account']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='revoked_client']/../td[text()='customer-portal']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("LOGIN");
loginEventsPage.table().update();
resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='LOGIN']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='customer-portal']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='username']/../td[text()='bburke@redhat.com']"));
resultList.get(0).findElement(By.xpath(".//td[text()='consent']/../td[text()='consent_granted']"));
configPage.navigateTo();
configPage.form().clearLoginEvents();
driver.findElement(By.xpath("//div[@class='modal-dialog']//button[text()='Delete']")).click();
}
@Test
public void historyOfAccessResourceTest() throws IOException {
RealmRepresentation realm = testRealmResource().toRepresentation();
realm.setEventsEnabled(true);
realm.setEnabledEventTypes(Arrays.asList("LOGIN", "LOGIN_ERROR", "LOGOUT", "CODE_TO_TOKEN"));
testRealmResource().update(realm);
customerPortal.navigateTo();
testRealmLoginPage.form().login("bburke@redhat.com", "password");
waitUntilElement(By.xpath("//body")).text().contains("Bill Burke");
waitUntilElement(By.xpath("//body")).text().contains("Stian Thorgersen");
driver.navigate().to(testRealmPage.getOIDCLogoutUrl() + "?redirect_uri=" + customerPortal);
loginEventsPage.navigateTo();
if (!testContext.isAdminLoggedIn()) {
loginPage.form().login(adminUser);
testContext.setAdminLoggedIn(true);
}
loginEventsPage.table().filter();
loginEventsPage.table().filterForm().addEventType("LOGOUT");
loginEventsPage.table().update();
List<WebElement> resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='LOGOUT']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("LOGIN");
loginEventsPage.table().update();
resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='LOGIN']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='customer-portal']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='username']/../td[text()='bburke@redhat.com']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("CODE_TO_TOKEN");
loginEventsPage.table().update();
resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='CODE_TO_TOKEN']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='customer-portal']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='refresh_token_type']/../td[text()='Refresh']"));
configPage.navigateTo();
configPage.form().clearLoginEvents();
driver.findElement(By.xpath("//div[@class='modal-dialog']//button[text()='Delete']")).click();
String serverLogPath = null;
if (System.getProperty("app.server").equals("wildfly") || System.getProperty("app.server").equals("eap6") || System.getProperty("app.server").equals("eap")) {
serverLogPath = System.getProperty("app.server.home") + "/standalone/log/server.log";
}
String appServerUrl;
if (Boolean.parseBoolean(System.getProperty("app.server.ssl.required"))) {
appServerUrl = "https://localhost:" + System.getProperty("app.server.https.port", "8543") + "/";
} else {
appServerUrl = "http://localhost:" + System.getProperty("app.server.http.port", "8280") + "/";
}
if (serverLogPath != null) {
log.info("Checking app server log at: " + serverLogPath);
File serverLog = new File(serverLogPath);
String serverLogContent = FileUtils.readFileToString(serverLog);
UserRepresentation bburke = ApiUtil.findUserByUsername(testRealmResource(), "bburke@redhat.com");
Pattern pattern = Pattern.compile("User '" + bburke.getId() + "' invoking '" + appServerUrl + "customer-portal[^\\s]+' on client 'customer-portal'");
Matcher matcher = pattern.matcher(serverLogContent);
assertTrue(matcher.find());
assertTrue(serverLogContent.contains("User '" + bburke.getId() + "' invoking '" + appServerUrl + "customer-db/' on client 'customer-db'"));
} else {
log.info("Checking app server log on app-server: \"" + System.getProperty("app.server") + "\" is not supported.");
}
}
}
@@ -85,7 +85,7 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
String refreshTokenId = offlineTokenPage.getRefreshToken().getId();
setAdapterAndServerTimeOffset(9999);
offlineTokenPage.navigateTo();
assertCurrentUrlStartsWith(offlineTokenPage);
Assert.assertNotEquals(offlineTokenPage.getRefreshToken().getId(), refreshTokenId);
Assert.assertNotEquals(offlineTokenPage.getAccessToken().getId(), accessTokenId);
@@ -327,8 +327,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
salesPostPassiveServletPage.navigateTo();
if (forbiddenIfNotAuthenticated) {
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
assertOnForbiddenPage();
} else {
waitUntilElement(By.xpath("//body")).text().contains("principal=null");
}
@@ -407,9 +406,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
salesPostPassiveServletPage.navigateTo();
if (forbiddenIfNotAuthenticated) {
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
//Different 403 status page on EAP and Wildfly
assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
assertOnForbiddenPage();
} else {
waitUntilElement(By.xpath("//body")).text().contains("principal=null");
}
@@ -422,9 +419,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
salesPostPassiveServletPage.navigateTo();
if (forbiddenIfNotAuthenticated) {
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
//Different 403 status page on EAP and Wildfly
assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
assertOnForbiddenPage();
} else {
waitUntilElement(By.xpath("//body")).text().contains("principal=null");
}
@@ -724,4 +719,16 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
driver.navigate().to(employee2ServletPage.toString() + "/setCheckRoles?roles=" + roles);
employee2ServletPage.logout();
}
private void assertOnForbiddenPage() {
switch (System.getProperty("app.server")) {
case "eap6":
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
String source = driver.getPageSource();
assertTrue(source.isEmpty() || source.contains("<body></body>"));
break;
default:
waitUntilElement(By.xpath("//body")).text().contains(FORBIDDEN_TEXT);
}
}
}
@@ -17,10 +17,12 @@
package org.keycloak.testsuite.admin;
import org.apache.bcel.generic.RETURN;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants;
@@ -45,6 +47,10 @@ import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserFederationMapperRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.resources.admin.RealmAuth.Resource;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
@@ -68,6 +74,8 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.*;
import static org.keycloak.services.resources.admin.RealmAuth.Resource.AUTHORIZATION;
import static org.keycloak.services.resources.admin.RealmAuth.Resource.CLIENT;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -770,6 +778,123 @@ public class PermissionsTest extends AbstractKeycloakTest {
}, Resource.CLIENT, true);
}
@Test
public void clientAuthorization() {
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
realm.clients().create(ClientBuilder.create().clientId("foo-authz").build());
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
foo.setServiceAccountsEnabled(true);
foo.setAuthorizationServicesEnabled(true);
realm.clients().get(foo.getId()).update(foo);
}
}, CLIENT, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
realm.clients().get(foo.getId()).authorization().getSettings();
}
}, AUTHORIZATION, false);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
ResourceServerRepresentation settings = authorization.getSettings();
authorization.update(settings);
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.resources().resources();
}
}, AUTHORIZATION, false);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.scopes().scopes();
}
}, AUTHORIZATION, false);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.policies().policies();
}
}, AUTHORIZATION, false);
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
response.set(authorization.resources().create(new ResourceRepresentation("Test", Collections.emptySet())));
}
}, AUTHORIZATION, true);
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
response.set(authorization.scopes().create(new ScopeRepresentation("Test")));
}
}, AUTHORIZATION, true);
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
PolicyRepresentation representation = new PolicyRepresentation();
representation.setName("Test PermissionsTest");
representation.setType("js");
HashMap<String, String> config = new HashMap<>();
config.put("code", "");
representation.setConfig(config);
response.set(authorization.policies().create(representation));
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.resources().resource("nosuch").update(new ResourceRepresentation());
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.scopes().scope("nosuch").update(new ScopeRepresentation());
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.policies().policy("nosuch").update(new PolicyRepresentation());
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.resources().resource("nosuch").remove();
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.scopes().scope("nosuch").remove();
}
}, AUTHORIZATION, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
authorization.policies().policy("nosuch").remove();
}
}, AUTHORIZATION, true);
}
@Test
public void roles() {
invoke(new Invocation() {
@@ -1543,6 +1668,8 @@ public class PermissionsTest extends AbstractKeycloakTest {
return AdminRoles.VIEW_EVENTS;
case IDENTITY_PROVIDER:
return AdminRoles.VIEW_IDENTITY_PROVIDERS;
case AUTHORIZATION:
return AdminRoles.VIEW_AUTHORIZATION;
default:
throw new RuntimeException("Unexpected resouce");
}
@@ -1560,6 +1687,8 @@ public class PermissionsTest extends AbstractKeycloakTest {
return AdminRoles.MANAGE_EVENTS;
case IDENTITY_PROVIDER:
return AdminRoles.MANAGE_IDENTITY_PROVIDERS;
case AUTHORIZATION:
return AdminRoles.MANAGE_AUTHORIZATION;
default:
throw new RuntimeException("Unexpected resouce");
}
@@ -1577,6 +1706,8 @@ public class PermissionsTest extends AbstractKeycloakTest {
return AdminRoles.VIEW_IDENTITY_PROVIDERS;
case IDENTITY_PROVIDER:
return AdminRoles.VIEW_REALM;
case AUTHORIZATION:
return AdminRoles.VIEW_IDENTITY_PROVIDERS;
default:
throw new RuntimeException("Unexpected resouce");
}
@@ -1594,6 +1725,8 @@ public class PermissionsTest extends AbstractKeycloakTest {
return AdminRoles.MANAGE_IDENTITY_PROVIDERS;
case IDENTITY_PROVIDER:
return AdminRoles.MANAGE_REALM;
case AUTHORIZATION:
return AdminRoles.MANAGE_IDENTITY_PROVIDERS;
default:
throw new RuntimeException("Unexpected resouce");
}
@@ -51,7 +51,7 @@ public class UserFederationTest extends AbstractAdminTest {
@Test
public void testProviderFactories() {
List<UserFederationProviderFactoryRepresentation> providerFactories = userFederation().getProviderFactories();
Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable", "sssd");
Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable");
// Builtin provider without properties
UserFederationProviderFactoryRepresentation ldapProvider = userFederation().getProviderFactory("ldap");
@@ -104,7 +104,7 @@ public abstract class AbstractAuthenticationTest extends AbstractKeycloakTest {
}
void compareExecution(AuthenticationExecutionExportRepresentation expected, AuthenticationExecutionExportRepresentation actual) {
Assert.assertEquals("Execution flowAlias - " + actual.getAuthenticator(), expected.getFlowAlias(), actual.getFlowAlias());
Assert.assertEquals("Execution flowAlias - " + actual.getFlowAlias(), expected.getFlowAlias(), actual.getFlowAlias());
Assert.assertEquals("Execution authenticator - " + actual.getAuthenticator(), expected.getAuthenticator(), actual.getAuthenticator());
Assert.assertEquals("Execution userSetupAllowed - " + actual.getAuthenticator(), expected.isUserSetupAllowed(), actual.isUserSetupAllowed());
Assert.assertEquals("Execution authenticatorFlow - " + actual.getAuthenticator(), expected.isAutheticatorFlow(), actual.isAutheticatorFlow());
@@ -94,7 +94,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
// we'll need auth-cookie later
AuthenticationExecutionInfoRepresentation authCookieExec = findExecutionByProvider("auth-cookie", executionReps);
compareExecution(newExecInfo("Review Profile", "idp-review-profile", true, 0, 3, DISABLED, null, new String[]{REQUIRED, DISABLED}), exec);
compareExecution(newExecInfo("Review Profile", "idp-review-profile", true, 0, 4, DISABLED, null, new String[]{REQUIRED, DISABLED}), exec);
// remove execution
authMgmtResource.removeExecution(exec.getId());
@@ -164,7 +164,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
// Note: there is no checking in addExecution if requirement is one of requirementChoices
// Thus we can have OPTIONAL which is neither ALTERNATIVE, nor DISABLED
compareExecution(newExecInfo("Cookie", "auth-cookie", false, 0, 2, OPTIONAL, null, new String[]{ALTERNATIVE, DISABLED}), exec);
compareExecution(newExecInfo("Cookie", "auth-cookie", false, 0, 3, OPTIONAL, null, new String[]{ALTERNATIVE, DISABLED}), exec);
}
@Test
@@ -203,7 +203,7 @@ public class FlowTest extends AbstractAuthenticationTest {
// adjust expected values before comparing
browser.setAlias("Copy of browser");
browser.setBuiltIn(false);
browser.getAuthenticationExecutions().get(2).setFlowAlias("Copy of browser forms");
browser.getAuthenticationExecutions().get(3).setFlowAlias("Copy of browser forms");
compareFlows(browser, copyOfBrowser);
// get new flow directly and compare
@@ -125,12 +125,14 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
AuthenticationFlowRepresentation flow = newFlow("browser", "browser based authentication", "basic-flow", true, true);
addExecExport(flow, null, false, "auth-cookie", false, null, ALTERNATIVE, 10);
addExecExport(flow, null, false, "auth-spnego", false, null, DISABLED, 20);
addExecExport(flow, null, false, "identity-provider-redirector", false, null, ALTERNATIVE, 25);
addExecExport(flow, "forms", false, null, true, null, ALTERNATIVE, 30);
List<AuthenticationExecutionInfoRepresentation> execs = new LinkedList<>();
addExecInfo(execs, "Cookie", "auth-cookie", false, 0, 0, ALTERNATIVE, null, new String[]{ALTERNATIVE, DISABLED});
addExecInfo(execs, "Kerberos", "auth-spnego", false, 0, 1, DISABLED, null, new String[]{ALTERNATIVE, REQUIRED, DISABLED});
addExecInfo(execs, "forms", null, false, 0, 2, ALTERNATIVE, true, new String[]{ALTERNATIVE, REQUIRED, DISABLED});
addExecInfo(execs, "Identity Provider Redirector", "identity-provider-redirector", true, 0, 2, ALTERNATIVE, null, new String[]{ALTERNATIVE, DISABLED});
addExecInfo(execs, "forms", null, false, 0, 3, ALTERNATIVE, true, new String[]{ALTERNATIVE, REQUIRED, DISABLED});
addExecInfo(execs, "Username Password Form", "auth-username-password-form", false, 1, 0, REQUIRED, null, new String[]{REQUIRED});
addExecInfo(execs, "OTP Form", "auth-otp-form", false, 1, 1, OPTIONAL, null, new String[]{REQUIRED, OPTIONAL, DISABLED});
expected.add(new FlowExecutions(flow, execs));
@@ -146,6 +146,7 @@ public class ProvidersTest extends AbstractAuthenticationTest {
addProviderInfo(result, "direct-grant-validate-username", "Username Validation",
"Validates the username supplied as a 'username' form parameter in direct grant request");
addProviderInfo(result, "http-basic-authenticator", "HTTP Basic Authentication", "Validates username and password from Authorization HTTP header");
addProviderInfo(result, "identity-provider-redirector", "Identity Provider Redirector", "Redirects to default Identity Provider or Identity Provider specified with kc_idp_hint query parameter");
addProviderInfo(result, "idp-confirm-link", "Confirm link existing account", "Show the form where user confirms if he wants " +
"to link identity provider with existing account or rather edit user profile data retrieved from identity provider to avoid conflict");
addProviderInfo(result, "idp-create-user-if-unique", "Create User If Unique", "Detect if there is existing Keycloak account " +
@@ -21,11 +21,11 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
/**
* Test getting the installation/configuration files for OIDC and SAML.
@@ -81,7 +81,7 @@ public class InstallationTest extends AbstractClientTest {
private void assertOidcInstallationConfig(String config) {
RealmRepresentation realmRep = realmRep();
assertTrue(config.contains(realmRep.getId()));
assertTrue(config.contains(realmRep.getPublicKey()));
assertFalse(config.contains(realmRep.getPublicKey()));
assertTrue(config.contains(authServerUrl()));
}
@@ -19,11 +19,13 @@ package org.keycloak.testsuite.admin.client.authorization;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ResourceScopeResource;
import org.keycloak.admin.client.resource.ResourceScopesResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.admin.client.AbstractClientTest;
import javax.ws.rs.core.Response;
@@ -38,6 +40,11 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
protected static final String RESOURCE_SERVER_CLIENT_ID = "test-resource-server";
@BeforeClass
public static void enabled() {
ProfileAssume.assumePreview();
}
@Before
public void onBeforeAuthzTests() {
createOidcClient(RESOURCE_SERVER_CLIENT_ID);
@@ -0,0 +1,50 @@
/*
* 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.admin.client.authorization;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.admin.client.AbstractClientTest;
import javax.ws.rs.ServerErrorException;
import javax.ws.rs.core.Response;
import static org.junit.Assert.assertEquals;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class AuthorizationDisabledInPreviewTest extends AbstractClientTest {
@BeforeClass
public static void enabled() {
ProfileAssume.assumePreviewDisabled();
}
@Test
public void testAuthzServicesRemoved() {
String id = testRealmResource().clients().findAll().get(0).getId();
try {
testRealmResource().clients().get(id).authorization().getSettings();
} catch (ServerErrorException e) {
assertEquals(Response.Status.NOT_IMPLEMENTED.getStatusCode(), e.getResponse().getStatus());
}
}
}
@@ -57,14 +57,10 @@ import java.util.LinkedList;
import java.util.List;
import java.util.HashSet;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -237,6 +233,7 @@ public class RealmTest extends AbstractAdminTest {
assertEquals(Boolean.FALSE, rep.isRegistrationAllowed());
assertEquals(Boolean.FALSE, rep.isRegistrationEmailAsUsername());
assertEquals(Boolean.FALSE, rep.isEditUsernameAllowed());
}
@Test
@@ -266,6 +263,45 @@ public class RealmTest extends AbstractAdminTest {
assertEquals(2, rep.getSupportedLocales().size());
}
@Test
public void updateRealmAttributes() {
// first change
RealmRepresentation rep = new RealmRepresentation();
rep.setAttributes(new HashMap<>());
rep.getAttributes().put("foo1", "bar1");
rep.getAttributes().put("foo2", "bar2");
rep.setBruteForceProtected(true);
rep.setDisplayName("dn1");
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
rep = realm.toRepresentation();
assertEquals("bar1", rep.getAttributes().get("foo1"));
assertEquals("bar2", rep.getAttributes().get("foo2"));
assertTrue(rep.isBruteForceProtected());
assertEquals("dn1", rep.getDisplayName());
// second change
rep.setBruteForceProtected(false);
rep.setDisplayName("dn2");
rep.getAttributes().put("foo1", "bar11");
rep.getAttributes().remove("foo2");
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
rep = realm.toRepresentation();
assertFalse(rep.isBruteForceProtected());
assertEquals("dn2", rep.getDisplayName());
assertEquals("bar11", rep.getAttributes().get("foo1"));
assertFalse(rep.getAttributes().containsKey("foo2"));
}
@Test
public void getRealmRepresentation() {
RealmRepresentation rep = realm.toRepresentation();
@@ -393,6 +429,13 @@ public class RealmTest extends AbstractAdminTest {
assertEquals(realm.getBrowserSecurityHeaders(), storedRealm.getBrowserSecurityHeaders());
}
if (realm.getAttributes() != null) {
HashMap<String, String> attributes = new HashMap<>();
attributes.putAll(storedRealm.getAttributes());
attributes.entrySet().retainAll(realm.getAttributes().entrySet());
assertEquals(realm.getAttributes(), attributes);
}
}
@Test
@@ -515,6 +558,26 @@ public class RealmTest extends AbstractAdminTest {
assertEquals(certificate, realm.toRepresentation().getCertificate());
}
@Test
public void rotateRealmKeys() {
RealmRepresentation realmRep = realm.toRepresentation();
String publicKey = realmRep.getPublicKey();
String cert = realmRep.getCertificate();
assertNotNull(publicKey);
assertNotNull(cert);
RealmRepresentation newRealmRep = new RealmRepresentation();
newRealmRep.setRealm(REALM_NAME);
newRealmRep.setPublicKey("GENERATE");
realm.update(newRealmRep);
realmRep = realm.toRepresentation();
assertNotNull(realmRep.getPublicKey());
assertNotNull(realmRep.getCertificate());
assertNotEquals(publicKey, realmRep.getPublicKey());
assertNotEquals(cert, realmRep.getCertificate());
}
@Test
public void clearRealmCache() {
RealmRepresentation realmRep = realm.toRepresentation();
@@ -35,14 +35,11 @@ public class AdapterInstallationConfigTest extends AbstractClientRegistrationTes
private ClientRepresentation client;
private ClientRepresentation client2;
private ClientRepresentation clientPublic;
private String publicKey;
@Before
public void before() throws Exception {
super.before();
publicKey = adminClient.realm(REALM_NAME).toRepresentation().getPublicKey();
client = new ClientRepresentation();
client.setEnabled(true);
client.setClientId("RegistrationAccessTokenTest");
@@ -92,7 +89,6 @@ public class AdapterInstallationConfigTest extends AbstractClientRegistrationTes
assertEquals(1, config.getCredentials().size());
assertEquals(client.getSecret(), config.getCredentials().get("secret"));
assertEquals(publicKey, config.getRealmKey());
assertEquals(client.getClientId(), config.getResource());
assertEquals(SslRequired.EXTERNAL.name().toLowerCase(), config.getSslRequired());
}
@@ -132,7 +128,6 @@ public class AdapterInstallationConfigTest extends AbstractClientRegistrationTes
assertEquals(0, config.getCredentials().size());
assertEquals(publicKey, config.getRealmKey());
assertEquals(clientPublic.getClientId(), config.getResource());
assertEquals(SslRequired.EXTERNAL.name().toLowerCase(), config.getSslRequired());
}
@@ -55,11 +55,7 @@ import org.keycloak.testsuite.client.resources.TestOIDCEndpointsApplicationResou
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource;
import org.keycloak.testsuite.util.OAuthClient;
import java.security.PrivateKey;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
@@ -286,6 +282,137 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
Assert.assertEquals(response.getClientId(), accessToken.getAudience()[0]);
}
@Test
public void createPairwiseClient() throws Exception {
OIDCClientRepresentation clientRep = createRep();
clientRep.setSubjectType("pairwise");
OIDCClientRepresentation response = reg.oidc().create(clientRep);
Assert.assertEquals("pairwise", response.getSubjectType());
}
@Test
public void updateClientToPairwise() throws Exception {
OIDCClientRepresentation response = create();
Assert.assertEquals("public", response.getSubjectType());
reg.auth(Auth.token(response));
response.setSubjectType("pairwise");
OIDCClientRepresentation updated = reg.oidc().update(response);
Assert.assertEquals("pairwise", updated.getSubjectType());
}
@Test
public void updateSectorIdentifierUri() throws Exception {
OIDCClientRepresentation clientRep = createRep();
clientRep.setSubjectType("pairwise");
OIDCClientRepresentation response = reg.oidc().create(clientRep);
Assert.assertEquals("pairwise", response.getSubjectType());
Assert.assertNull(response.getSectorIdentifierUri());
reg.auth(Auth.token(response));
// Push redirect uris to the sector identifier URI
List<String> sectorRedirects = new ArrayList<>();
sectorRedirects.addAll(response.getRedirectUris());
TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
oidcClientEndpointsResource.setSectorIdentifierRedirectUris(sectorRedirects);
response.setSectorIdentifierUri(TestApplicationResourceUrls.pairwiseSectorIdentifierUri());
OIDCClientRepresentation updated = reg.oidc().update(response);
Assert.assertEquals("pairwise", updated.getSubjectType());
Assert.assertEquals(TestApplicationResourceUrls.pairwiseSectorIdentifierUri(), updated.getSectorIdentifierUri());
}
@Test
public void createPairwiseClientWithSectorIdentifierURI() throws Exception {
OIDCClientRepresentation clientRep = createRep();
// Push redirect uris to the sector identifier URI
List<String> sectorRedirects = new ArrayList<>();
sectorRedirects.addAll(clientRep.getRedirectUris());
TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
oidcClientEndpointsResource.setSectorIdentifierRedirectUris(sectorRedirects);
clientRep.setSubjectType("pairwise");
clientRep.setSectorIdentifierUri(TestApplicationResourceUrls.pairwiseSectorIdentifierUri());
OIDCClientRepresentation response = reg.oidc().create(clientRep);
Assert.assertEquals("pairwise", response.getSubjectType());
Assert.assertEquals(TestApplicationResourceUrls.pairwiseSectorIdentifierUri(), response.getSectorIdentifierUri());
}
@Test
public void createPairwiseClientWithRedirectsToMultipleHostsWithoutSectorIdentifierURI() throws Exception {
OIDCClientRepresentation clientRep = createRep();
List<String> redirects = new ArrayList<>();
redirects.add("http://redirect1");
redirects.add("http://redirect2");
clientRep.setSubjectType("pairwise");
clientRep.setRedirectUris(redirects);
assertCreateFail(clientRep, 400, "Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components.");
}
@Test
public void createPairwiseClientWithRedirectsToMultipleHosts() throws Exception {
OIDCClientRepresentation clientRep = createRep();
// Push redirect URIs to the sector identifier URI
List<String> redirects = new ArrayList<>();
redirects.add("http://redirect1");
redirects.add("http://redirect2");
TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
oidcClientEndpointsResource.setSectorIdentifierRedirectUris(redirects);
clientRep.setSubjectType("pairwise");
clientRep.setSectorIdentifierUri(TestApplicationResourceUrls.pairwiseSectorIdentifierUri());
clientRep.setRedirectUris(redirects);
OIDCClientRepresentation response = reg.oidc().create(clientRep);
Assert.assertEquals("pairwise", response.getSubjectType());
Assert.assertEquals(TestApplicationResourceUrls.pairwiseSectorIdentifierUri(), response.getSectorIdentifierUri());
Assert.assertNames(response.getRedirectUris(), "http://redirect1", "http://redirect2");
}
@Test
public void createPairwiseClientWithSectorIdentifierURIContainingMismatchedRedirects() throws Exception {
OIDCClientRepresentation clientRep = createRep();
// Push redirect uris to the sector identifier URI
List<String> sectorRedirects = new ArrayList<>();
sectorRedirects.add("http://someotherredirect");
TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
oidcClientEndpointsResource.setSectorIdentifierRedirectUris(sectorRedirects);
clientRep.setSubjectType("pairwise");
clientRep.setSectorIdentifierUri(TestApplicationResourceUrls.pairwiseSectorIdentifierUri());
assertCreateFail(clientRep, 400, "Client redirect URIs does not match redirect URIs fetched from the Sector Identifier URI.");
}
@Test
public void createPairwiseClientWithInvalidSectorIdentifierURI() throws Exception {
OIDCClientRepresentation clientRep = createRep();
clientRep.setSubjectType("pairwise");
clientRep.setSectorIdentifierUri("malformed");
assertCreateFail(clientRep, 400, "Invalid Sector Identifier URI.");
}
@Test
public void createPairwiseClientWithUnreachableSectorIdentifierURI() throws Exception {
OIDCClientRepresentation clientRep = createRep();
clientRep.setSubjectType("pairwise");
clientRep.setSectorIdentifierUri("http://localhost/dummy");
assertCreateFail(clientRep, 400, "Failed to get redirect URIs from the Sector Identifier URI.");
}
@Test
public void testSignaturesRequired() throws Exception {
OIDCClientRepresentation clientRep = createRep();
@@ -16,6 +16,8 @@
*/
package org.keycloak.testsuite.forms;
import com.fasterxml.jackson.jaxrs.json.annotation.JSONP;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -25,6 +27,7 @@ import org.keycloak.events.Errors;
import org.keycloak.models.Constants;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.DefaultBruteForceProtector;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.AssertEvents.ExpectedEvent;
import org.keycloak.testsuite.pages.AppPage;
@@ -71,6 +74,12 @@ public class BruteForceTest extends TestRealmKeycloakTest {
}
@After
public void slowItDown() throws Exception {
Thread.sleep(100);
}
@Rule
public AssertEvents events = new AssertEvents(this);
@@ -164,6 +173,7 @@ public class BruteForceTest extends TestRealmKeycloakTest {
@Test
public void testGrantInvalidOtp() throws Exception {
clearVariables();
{
String totpSecret = totp.generateTOTP("totpSecret");
OAuthClient.AccessTokenResponse response = getTestToken("password", totpSecret);
@@ -188,7 +198,7 @@ public class BruteForceTest extends TestRealmKeycloakTest {
{
String totpSecret = totp.generateTOTP("totpSecret");
OAuthClient.AccessTokenResponse response = getTestToken("password", totpSecret);
Assert.assertNull(response.getAccessToken());
assertTokenNull(response);
Assert.assertNotNull(response.getError());
Assert.assertEquals(response.getError(), "invalid_grant");
Assert.assertEquals(response.getErrorDescription(), "Account temporarily disabled");
@@ -205,8 +215,40 @@ public class BruteForceTest extends TestRealmKeycloakTest {
}
public void clearVariables() {
DefaultBruteForceProtector.testCount = 0;
DefaultBruteForceProtector.markNotBefore = -1;
DefaultBruteForceProtector.markCheck = -1;
DefaultBruteForceProtector.testCount = 0;
DefaultBruteForceProtector.clearCount = 0;
DefaultBruteForceProtector.logFailure = 0;
DefaultBruteForceProtector.logFailureCalled = 0;
DefaultBruteForceProtector.didntWait = 0;
DefaultBruteForceProtector.nullFailureCount = 0;
DefaultBruteForceProtector.notFoundUserId = null;
}
public void assertTokenNull(OAuthClient.AccessTokenResponse response) {
if (response.getAccessToken() != null) {
if (DefaultBruteForceProtector.exceptionObject != null) {
DefaultBruteForceProtector.exceptionObject.printStackTrace();
}
}
Assert.assertNull("was mark set: " + DefaultBruteForceProtector.markNotBefore + " time test: " + DefaultBruteForceProtector.markCheck
+ " test count " + DefaultBruteForceProtector.testCount
+ " nullFailure: " + DefaultBruteForceProtector.nullFailureCount
+ " logFailureCalled: " + DefaultBruteForceProtector.logFailureCalled
+ " logFailure: " + DefaultBruteForceProtector.logFailure
+ " notFoundUserId: " + DefaultBruteForceProtector.notFoundUserId
+ " exception: " + DefaultBruteForceProtector.exception
, response.getAccessToken());
}
@Test
public void testGrantMissingOtp() throws Exception {
clearVariables();
{
String totpSecret = totp.generateTOTP("totpSecret");
OAuthClient.AccessTokenResponse response = getTestToken("password", totpSecret);
@@ -231,7 +273,7 @@ public class BruteForceTest extends TestRealmKeycloakTest {
{
String totpSecret = totp.generateTOTP("totpSecret");
OAuthClient.AccessTokenResponse response = getTestToken("password", totpSecret);
Assert.assertNull(response.getAccessToken());
assertTokenNull(response);
Assert.assertNotNull(response.getError());
Assert.assertEquals(response.getError(), "invalid_grant");
Assert.assertEquals(response.getErrorDescription(), "Account temporarily disabled");
@@ -482,6 +482,40 @@ public class LoginTest extends TestRealmKeycloakTest {
setRememberMe(false);
}
}
@Test
// KEYCLOAK-3181
public void loginWithEmailUserAndRememberMe() {
setRememberMe(true);
try {
loginPage.open();
loginPage.setRememberMe(true);
assertTrue(loginPage.isRememberMeChecked());
loginPage.login("login@test.com", "password");
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
EventRepresentation loginEvent = events.expectLogin().user(userId)
.detail(Details.USERNAME, "login@test.com")
.detail(Details.REMEMBER_ME, "true")
.assertEvent();
String sessionId = loginEvent.getSessionId();
// Expire session
testingClient.testing().removeUserSession("test", sessionId);
// Assert rememberMe checked and username/email prefilled
loginPage.open();
assertTrue(loginPage.isRememberMeChecked());
Assert.assertEquals("login@test.com", loginPage.getUsername());
loginPage.setRememberMe(false);
} finally {
setRememberMe(false);
}
}
// KEYCLOAK-1037
@Test
@@ -36,6 +36,8 @@ import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentatio
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.representations.IDToken;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.clientregistration.ClientRegistrationService;
import org.keycloak.services.clientregistration.oidc.OIDCClientRegistrationProviderFactory;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
@@ -79,12 +81,21 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
Assert.assertEquals(oidcConfig.getUserinfoEndpoint(), OIDCLoginProtocolService.userInfoUrl(UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT)).build("test").toString());
Assert.assertEquals(oidcConfig.getJwksUri(), oauth.getCertsUrl("test"));
String registrationUri = UriBuilder
.fromUri(OAuthClient.AUTH_SERVER_ROOT)
.path(RealmsResource.class)
.path(RealmsResource.class, "getClientsService")
.path(ClientRegistrationService.class, "provider")
.build("test", OIDCClientRegistrationProviderFactory.ID)
.toString();
Assert.assertEquals(oidcConfig.getRegistrationEndpoint(), registrationUri);
// Support standard + implicit + hybrid flow
assertContains(oidcConfig.getResponseTypesSupported(), OAuth2Constants.CODE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token");
assertContains(oidcConfig.getGrantTypesSupported(), OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT);
assertContains(oidcConfig.getResponseModesSupported(), "query", "fragment");
Assert.assertNames(oidcConfig.getSubjectTypesSupported(), "public");
Assert.assertNames(oidcConfig.getSubjectTypesSupported(), "pairwise", "public");
Assert.assertNames(oidcConfig.getIdTokenSigningAlgValuesSupported(), Algorithm.RS256.toString());
Assert.assertNames(oidcConfig.getUserInfoSigningAlgValuesSupported(), Algorithm.RS256.toString());
Assert.assertNames(oidcConfig.getRequestObjectSigningAlgValuesSupported(), Algorithm.none.toString(), Algorithm.RS256.toString());
@@ -0,0 +1,20 @@
<!--
~ 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.
-->
<Context path="/basic-auth">
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
</Context>
@@ -0,0 +1,46 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="securityHandler">
<Set name="authenticator">
<New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
<!--
<Set name="adapterConfig">
<New class="org.keycloak.representations.adapters.config.AdapterConfig">
<Set name="realm">tomcat</Set>
<Set name="resource">customer-portal</Set>
<Set name="authServerUrl">http://localhost:8180/auth</Set>
<Set name="sslRequired">external</Set>
<Set name="credentials">
<Map>
<Entry>
<Item>secret</Item>
<Item>password</Item>
</Entry>
</Map>
</Set>
<Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
</New>
</Set>
-->
</New>
</Set>
</Get>
</Configure>
@@ -0,0 +1,11 @@
{
"realm" : "demo",
"resource" : "basic-auth-service",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "/auth",
"ssl-required" : "external",
"enable-basic-auth" : "true",
"credentials": {
"secret": "password"
}
}
@@ -0,0 +1,11 @@
{
"realm" : "demo",
"resource" : "basic-auth-service",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "/auth",
"ssl-required" : "external",
"enable-basic-auth" : "true",
"credentials": {
"secret": "password"
}
}
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>basic-auth</module-name>
<security-constraint>
<web-resource-collection>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<!-- <user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint> -->
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>KEYCLOAK</auth-method>
<realm-name>demo</realm-name>
</login-config>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
@@ -1,10 +1,10 @@
{
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8180/auth",
"auth-server-url": "http://localhostt:8180/auth",
"ssl-required" : "external",
"expose-token": true,
"min-time-between-jwks-requests": 120,
"credentials": {
"secret": "password"
}
@@ -226,6 +226,15 @@
"/oauth-client-cdi/*"
],
"secret": "password"
},
{
"clientId": "basic-auth-service",
"standardFlowEnabled": false,
"directAccessGrantsEnabled": true,
"enabled": true,
"adminUrl": "/basic-auth",
"baseUrl": "/basic-auth",
"secret": "password"
}
]
}
@@ -1,9 +1,9 @@
{
"realm" : "demo",
"resource" : "input-portal",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url" : "http://${my.host.name}:8180/auth",
"ssl-required" : "external",
"min-time-between-jwks-requests": 120,
"credentials" : {
"secret": "password"
}
@@ -1,11 +1,11 @@
{
"realm": "demo",
"resource": "token-min-ttl",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required" : "external",
"credentials": {
"secret": "password"
},
"token-minimum-time-to-live": 120
"token-minimum-time-to-live": 120,
"min-time-between-jwks-requests": 120
}
@@ -68,6 +68,12 @@
<url-pattern>/error.html</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Unsecured</web-resource-name>
<url-pattern>/unsecured/*</url-pattern>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>KEYCLOAK</auth-method>
@@ -95,5 +95,11 @@
"roles": ["customer-user"]
}
]
},
"attributes": {
"string-attr": "foo",
"int-attr": "123",
"long-attr": "1234567890123456",
"bool-attr": "true"
}
}
@@ -61,3 +61,5 @@ log4j.logger.org.hibernate=off
log4j.logger.org.jboss.resteasy=warn
log4j.logger.org.apache.directory.api=warn
log4j.logger.org.apache.directory.server.core=warn
log4j.logger.org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticator=trace
@@ -0,0 +1,30 @@
/*
* 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.example.authorization;
import org.keycloak.testsuite.adapter.example.authorization.AbstractDefaultAuthzConfigAdapterTest;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
/**
*
* @author tkyjovsk
*/
@AppServerContainer("app-server-eap")
//@AdapterLibsLocationProperty("adapter.libs.wildfly")
public class EAPDefaultAuthzConfigAdapterTest extends AbstractDefaultAuthzConfigAdapterTest {
}
@@ -0,0 +1,30 @@
/*
* 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.example.authorization;
import org.keycloak.testsuite.adapter.example.authorization.AbstractPhotozExampleAdapterTest;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
/**
*
* @author tkyjovsk
*/
@AppServerContainer("app-server-eap")
//@AdapterLibsLocationProperty("adapter.libs.wildfly")
public class EAPPhotozExampleAdapterTest extends AbstractPhotozExampleAdapterTest {
}
@@ -0,0 +1,33 @@
/*
* 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.example.authorization;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.keycloak.testsuite.adapter.example.authorization.AbstractDefaultAuthzConfigAdapterTest;
import org.keycloak.testsuite.adapter.example.authorization.AbstractServletAuthzAdapterTest;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
/**
*
* @author tkyjovsk
*/
@RunAsClient
@AppServerContainer("app-server-eap")
//@AdapterLibsLocationProperty("adapter.libs.wildfly")
public class EAPServletAuthzAdapterTest extends AbstractServletAuthzAdapterTest {
}
@@ -53,7 +53,10 @@
<app.server.memory.settings>-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</app.server.memory.settings>
<app.server.ssl.required>false</app.server.ssl.required>
<settings.path></settings.path>
<repo.url></repo.url>
<adapter.test.props>
-Dapp.server.base.url=http://localhost:${app.server.http.port}
-Dauth.server.base.url=http://localhost:${auth.server.http.port}
@@ -63,11 +66,14 @@
-Dauth.server.ssl.required=${auth.server.ssl.required}
-Dmy.host.name=localhost
-Djava.security.krb5.conf=${project.build.directory}/dependency/kerberos/test-krb5.conf
-Dkie.maven.settings.custom=${settings.path}
-Drepo.url=${repo.url}
</adapter.test.props>
<app.server.home>${containers.home}/app-server-${app.server}</app.server.home>
<adapter.config.bundled>true</adapter.config.bundled>
<examples.basedir>${main.basedir}/examples</examples.basedir>
</properties>
<modules>
@@ -87,6 +93,23 @@
</activation>
<build>
<plugins>
<plugin>
<groupId>org.commonjava.maven.plugins</groupId>
<artifactId>directory-maven-plugin</artifactId>
<version>0.1</version>
<executions>
<execution>
<id>directories</id>
<goals>
<goal>highest-basedir</goal>
</goals>
<phase>initialize</phase>
<configuration>
<property>main.basedir</property>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xml-maven-plugin</artifactId>
@@ -311,20 +334,13 @@
</configuration>
</execution>
<execution>
<id>example-realms</id>
<id>test-apps-realms</id>
<phase>generate-test-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-examples-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
<includes>**/*realm.json,**/testsaml.json</includes>
</artifactItem>
<artifactItem>
<groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-test-apps-dist</artifactId>
@@ -336,9 +352,35 @@
<outputDirectory>${examples.home}</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</execution>
</executions>
</plugin>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>example-realms</id>
<phase>generate-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${examples.home}/example-realms</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<resources>
<resource>
<directory>${examples.basedir}</directory>
<filtering>true</filtering>
<includes>
<include>**/*realm.json</include>
<include>**/testsaml.json</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
@@ -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.
*/
package org.keycloak.testsuite.console.clients;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Test;
import org.keycloak.common.Profile;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
import org.openqa.selenium.By;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.auth.page.login.Login.OIDC;
/**
*
* @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
*/
public class ClientAuthorizationServicesAvailableTest extends AbstractClientTest {
private ClientRepresentation newClient;
@Page
private ClientSettings clientSettingsPage;
@Test
public void authzServicesAvailable() {
ProfileAssume.assumePreview();
newClient = createClientRep("oidc-public", OIDC);
createClient(newClient);
assertEquals("oidc-public", clientSettingsPage.form().getClientId());
assertTrue(driver.findElement(By.xpath("//*[@for='authorizationServicesEnabled']")).isDisplayed());
}
@Test
public void authzServicesUnavailable() throws InterruptedException {
ProfileAssume.assumePreviewDisabled();
newClient = createClientRep("oidc-public", OIDC);
createClient(newClient);
assertEquals("oidc-public", clientSettingsPage.form().getClientId());
assertFalse(driver.findElement(By.xpath("//*[@for='authorizationServicesEnabled']")).isDisplayed());
}
}
@@ -38,8 +38,9 @@
<modules>
<module>adapters</module>
<module>sssd</module>
</modules>
<build>
<pluginManagement>
<plugins>
@@ -65,7 +66,7 @@
</configuration>
</execution>
</executions>
</plugin>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
@@ -0,0 +1,27 @@
What is this module about?
-------------------------
This module containes integration tests for testing the SSSD features of Keycloak.
Prerequisites
-------------
To run tests inside this module, one needs to have a linux machine configured as an `IPA` client having sssd
service started with infopipe support.
How does one run the tests?
--------------------------
*All the commands are intended to be run from the root `keycloak` project directory.*
First build the distribution of keycloak:
`mvn clean install -B -DskipTests -Pdistribution`
It may fail in the end, but it's not a problem as far as it creates a zip distribution of Keycloak inside
distribution/server-dist/target.
Then build the integration-arquillian-servers-auth-server-wildfly artifact:
`mvn clean install -B -Pauth-server-wildfly -f testsuite/integration-arquillian/servers/pom.xml`
And then, finally, it's possible to run the tests:
`mvn test -f testsuite/integration-arquillian/tests/other/sssd/ -Pauth-server-wildfly -Psssd-testing`
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>integration-arquillian-tests-other</artifactId>
<groupId>org.keycloak.testsuite</groupId>
<version>2.2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integration-arquillian-tests-sssd</artifactId>
<name>SSSD tests</name>
<properties>
<exclude.sssd>**/sssd/**/*Test.java</exclude.sssd>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>${exclude.sssd}</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sssd-testing</id>
<properties>
<exclude.sssd>-</exclude.sssd>
</properties>
</profile>
</profiles>
</project>
@@ -0,0 +1,174 @@
package org.keycloak.testsuite.sssd;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.pages.AccountPasswordPage;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.LoginPage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SSSDTest extends AbstractKeycloakTest {
private static final String DISPLAY_NAME = "Test user federation";
private static final String PROVIDER_NAME = "sssd";
private static final String REALM_NAME = "test";
private static final String USERNAME = "emily";
private static final String PASSWORD = "emily123";
private static final String DISABLED_USER = "david";
private static final String DISABLED_USER_PASSWORD = "emily123";
private static final String DEFINITELY_NOT_PASSWORD = "not" + PASSWORD;
private static final String ADMIN_USERNAME = "admin";
private static final String ADMIN_PASSWORD = "password";
@Page
protected LoginPage accountLoginPage;
@Page
protected AccountPasswordPage changePasswordPage;
@Page
protected AccountUpdateProfilePage profilePage;
@Rule
public AssertEvents events = new AssertEvents(this);
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation realm = new RealmRepresentation();
realm.setRealm(REALM_NAME);
realm.setEnabled(true);
testRealms.add(realm);
}
@Before
public void createUserFederation() {
UserFederationProviderRepresentation userFederation = new UserFederationProviderRepresentation();
Map<String, String> config = new HashMap<>();
userFederation.setConfig(config);
userFederation.setDisplayName(DISPLAY_NAME);
userFederation.setPriority(0);
userFederation.setProviderName(PROVIDER_NAME);
adminClient.realm(REALM_NAME).userFederation().create(userFederation);
}
@Test
public void testWrongUser() {
log.debug("Testing wrong password for user " + USERNAME);
driver.navigate().to(getAccountUrl());
Assert.assertEquals("Browser should be on login page now", "Log in to " + REALM_NAME, driver.getTitle());
accountLoginPage.login(USERNAME, DEFINITELY_NOT_PASSWORD);
Assert.assertEquals("Invalid username or password.", accountLoginPage.getError());
}
@Test
public void testDisabledUser() {
log.debug("Testing disabled user " + USERNAME);
driver.navigate().to(getAccountUrl());
Assert.assertEquals("Browser should be on login page now", "Log in to " + REALM_NAME, driver.getTitle());
accountLoginPage.login(DISABLED_USER, DISABLED_USER_PASSWORD);
Assert.assertEquals("Invalid username or password.", accountLoginPage.getError());
}
@Test
public void testAdmin() {
log.debug("Testing wrong password for user " + ADMIN_USERNAME);
driver.navigate().to(getAccountUrl());
Assert.assertEquals("Browser should be on login page now", "Log in to " + REALM_NAME, driver.getTitle());
accountLoginPage.login(ADMIN_USERNAME, ADMIN_PASSWORD);
Assert.assertEquals("Unexpected error when handling authentication request to identity provider.", accountLoginPage.getInstruction());
}
@Test
public void testExistingUserLogIn() {
log.debug("Testing correct password");
driver.navigate().to(getAccountUrl());
Assert.assertEquals("Browser should be on login page now", "Log in to " + REALM_NAME, driver.getTitle());
accountLoginPage.login(USERNAME, PASSWORD);
Assert.assertEquals("Browser should be on account page now, logged in", "Keycloak Account Management", driver.getTitle());
testUserGroups();
}
@Test
public void changeReadOnlyProfile() throws Exception {
profilePage.open();
accountLoginPage.login(USERNAME, PASSWORD);
Assert.assertEquals("emily", profilePage.getUsername());
Assert.assertEquals("Emily", profilePage.getFirstName());
Assert.assertEquals("Jones", profilePage.getLastName());
Assert.assertEquals("emily@jones.com", profilePage.getEmail());
profilePage.updateProfile("New first", "New last", "new@email.com");
Assert.assertEquals("You can't update your account as it is read only.", profilePage.getError());
}
@Test
public void changeReadOnlyPassword() {
changePasswordPage.open();
accountLoginPage.login(USERNAME, PASSWORD);
changePasswordPage.changePassword(PASSWORD, "new-password", "new-password");
Assert.assertEquals("You can't update your password as your account is read only.", profilePage.getError());
}
private void testUserGroups() {
log.debug("Testing user groups");
List<UserRepresentation> users = adminClient.realm(REALM_NAME).users().search(USERNAME, 0, 1);
Assert.assertTrue("There must be at least one user", users.size() > 0);
Assert.assertEquals("Exactly our test user", USERNAME, users.get(0).getUsername());
List<GroupRepresentation> groups = adminClient.realm(REALM_NAME).users().get(users.get(0).getId()).groups();
Assert.assertEquals("User must have exactly two groups", 2, groups.size());
boolean wrongGroup = false;
for (GroupRepresentation group : groups) {
if (!group.getName().equalsIgnoreCase("ipausers") && !group.getName().equalsIgnoreCase("testgroup")) {
wrongGroup = true;
break;
}
}
Assert.assertFalse("There exists some wrong group", wrongGroup);
}
private String getAccountUrl() {
return getAuthRoot() + "/auth/realms/" + REALM_NAME + "/account";
}
private String getAuthRoot() {
return suiteContext.getAuthServerInfo().getContextRoot().toString();
}
}
@@ -20,19 +20,19 @@ package org.keycloak.testsuite.broker;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.KeycloakServer;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.keycloak.testsuite.KeycloakServer;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
@@ -94,6 +94,16 @@ public class IdentityProviderHintTest {
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
assertEquals("Could not find an identity provider with the identifier.", this.driver.findElement(By.className("instruction")).getText());
System.out.println(driver.getPageSource());
assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
}
private AuthenticationExecutionInfoRepresentation findExecution(RealmResource realm) {
for (AuthenticationExecutionInfoRepresentation e : realm.flows().getExecutions("browser")) {
if (e.getProviderId().equals("identity-provider-redirector")) {
return e;
}
}
return null;
}
}
@@ -89,7 +89,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
try {
RealmModel realmByName = session.realms().getRealmByName(realm);
UserModel user = session.users().getUserByUsername(name, realmByName);
UserRepresentation userRep = user != null ? ModelToRepresentation.toRepresentation(user) : null;
UserRepresentation userRep = user != null ? ModelToRepresentation.toRepresentation(session, realmByName, user) : null;
session.getTransactionManager().commit();
return userRep;
} finally {
@@ -102,7 +102,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
session.getTransactionManager().begin();
try {
RealmModel realmByName = session.realms().getRealmByName(realm);
UserRepresentation userRep = ModelToRepresentation.toRepresentation(session.users().getUserById(id, realmByName));
UserRepresentation userRep = ModelToRepresentation.toRepresentation(session, realmByName, session.users().getUserById(id, realmByName));
session.getTransactionManager().commit();
return userRep;
} finally {
@@ -74,4 +74,7 @@ log4j.logger.org.apache.directory.server.core=warn
log4j.logger.org.apache.directory.server.ldap.LdapProtocolHandler=error
# Enable to view HttpClient connection pool activity
#log4j.logger.org.apache.http.impl.conn=debug
#log4j.logger.org.apache.http.impl.conn=debug
# Enable to view details from identity provider authenticator
# log4j.logger.org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticator=trace