keycloak-aplcache
Changes
testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java 5(+5 -0)
testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java 74(+74 -0)
testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProviderFactory.java 53(+53 -0)
testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory 3(+2 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/OAuthClientProvider.java 6(+3 -3)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/DeleteMeOAuthClient.java 4(+2 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java 12(+8 -4)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java 132(+132 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java 157(+157 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java 19(+3 -16)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java 20(+18 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/AbstractAuthenticationTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/ExecutionTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/FlowTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/InitialFlowsTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/ProvidersTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/RequiredActionsTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/authentication/ShiftExecutionTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/AbstractClientTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/ClientProtocolMapperTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/ClientRolesTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/ClientTemplateTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/ClientTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/CredentialsTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/InstallationTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/client/SessionTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/event/AbstractEventTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/event/AdminEventTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/event/EventConfigTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/event/LoginEventsTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/group/AbstractGroupTest.java 3(+2 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/group/GroupMappersTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/group/GroupTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/endpoint/partialimport/PartialImportTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/LegacyImportTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java 104(+58 -46)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java 66(+66 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java 53(+53 -0)
Details
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java
index 6d0d4ed..1f4724d 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java
@@ -44,6 +44,11 @@ public class AssertEventsServletFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
+ if ("/clear-event-queue".equals(req.getRequestURI().substring(req.getContextPath().length()))) {
+ EventsListenerProvider.getInstance().clear();
+ return;
+ }
+
if ("/event-queue".equals(req.getRequestURI().substring(req.getContextPath().length()))) {
BlockingQueue<Event> events = EventsListenerProvider.getInstance();
HttpServletResponse resp = (HttpServletResponse) servletResponse;
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java
index 0b04ee3..e18be4b 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java
@@ -69,6 +69,7 @@ public class EventsServer {
FilterInfo filter = Servlets.filter("EventsFilter", AssertEventsServletFilter.class);
di.addFilter(filter);
di.addFilterUrlMapping("EventsFilter", "/event-queue", DispatcherType.REQUEST);
+ di.addFilterUrlMapping("EventsFilter", "/clear-event-queue", DispatcherType.REQUEST);
DeploymentManager manager = container.addDeployment(di);
manager.deploy();
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java
new file mode 100644
index 0000000..52e5858
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java
@@ -0,0 +1,74 @@
+/*
+ * 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.rest;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resource.RealmResourceProvider;
+import org.keycloak.services.resources.RealmsResource;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class TestApplicationResourceProvider implements RealmResourceProvider {
+
+ private KeycloakSession session;
+
+ public TestApplicationResourceProvider(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ @Path("/{action}")
+ public String get(@PathParam("action") String action) {
+ //String requestUri = session.getContext().getUri().getRequestUri().toString();
+
+ String title = "APP_REQUEST";
+ if (action.equals("auth")) {
+ title = "AUTH_RESPONSE";
+ } else if (action.equals("logout")) {
+ title = "LOGOUT_REQUEST";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("<html><head><title>" + title + "</title></head><body>");
+ UriBuilder base = UriBuilder.fromUri("http://localhost:8180/auth");
+ sb.append("<a href=\"" + RealmsResource.accountUrl(base).build("test").toString() + "\" id=\"account\">account</a>");
+
+ sb.append("</body></html>");
+ return sb.toString();
+ }
+
+ @Override
+ public Object getResource() {
+ return this;
+ }
+
+ @Override
+ public void close() {
+
+ }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProviderFactory.java
new file mode 100644
index 0000000..e795420
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProviderFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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.rest;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.services.resource.RealmResourceProvider;
+import org.keycloak.services.resource.RealmResourceProviderFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class TestApplicationResourceProviderFactory implements RealmResourceProviderFactory {
+
+ @Override
+ public RealmResourceProvider create(KeycloakSession session) {
+ return new TestApplicationResourceProvider(session);
+ }
+
+ @Override
+ public void init(Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return "app";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
index 57d5390..9a97746 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
@@ -15,4 +15,5 @@
# limitations under the License.
#
-org.keycloak.testsuite.rest.TimeOffsetResourceProviderFactory
\ No newline at end of file
+org.keycloak.testsuite.rest.TimeOffsetResourceProviderFactory
+org.keycloak.testsuite.rest.TestApplicationResourceProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/OAuthClientProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/OAuthClientProvider.java
index b51a3bd..ae07842 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/OAuthClientProvider.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/OAuthClientProvider.java
@@ -21,7 +21,7 @@ import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
-import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.DeleteMeOAuthClient;
import java.lang.annotation.Annotation;
@@ -31,11 +31,11 @@ import java.lang.annotation.Annotation;
public class OAuthClientProvider implements ResourceProvider {
@Inject
- Instance<OAuthClient> oauthClient;
+ Instance<DeleteMeOAuthClient> oauthClient;
@Override
public boolean canProvide(Class<?> type) {
- return OAuthClient.class.isAssignableFrom(type);
+ return DeleteMeOAuthClient.class.isAssignableFrom(type);
}
@Override
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index 3e42a58..11cda10 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -60,19 +60,23 @@ import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.arquillian.SuiteContext;
import org.keycloak.testsuite.auth.page.WelcomePage;
-import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.DeleteMeOAuthClient;
import org.keycloak.util.JsonSerialization;
import org.openqa.selenium.WebDriver;
import org.keycloak.testsuite.auth.page.AuthServer;
import org.keycloak.testsuite.auth.page.AuthServerContextRoot;
import org.keycloak.testsuite.auth.page.AuthRealm;
+
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+
import org.keycloak.testsuite.auth.page.account.Account;
import org.keycloak.testsuite.auth.page.login.OIDCLogin;
import org.keycloak.testsuite.auth.page.login.UpdatePassword;
import org.keycloak.testsuite.util.WaitUtils;
+
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
import org.keycloak.testsuite.util.TestEventsLogger;
/**
@@ -93,7 +97,7 @@ public abstract class AbstractKeycloakTest {
protected Keycloak adminClient;
- protected OAuthClient oauthClient;
+ protected DeleteMeOAuthClient oauthClient;
protected List<RealmRepresentation> testRealmReps;
@@ -128,7 +132,7 @@ public abstract class AbstractKeycloakTest {
public void beforeAbstractKeycloakTest() {
adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
- oauthClient = new OAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");
+ oauthClient = new DeleteMeOAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");
adminUser = createAdminUserRepresentation();
@@ -155,7 +159,7 @@ public abstract class AbstractKeycloakTest {
}
// removeTestRealms(); // keeping test realms after test to be able to inspect failures, instead deleting existing realms before import
-// keycloak.close(); // keeping admin connection open
+// adminClient.close(); // keeping admin connection open
}
private void updateMasterAdminPassword() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java
new file mode 100644
index 0000000..b02c21f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.After;
+import org.junit.Before;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.util.JsonSerialization;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * This class adapts the functionality from the old testsuite to make tests
+ * easier to port.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public abstract class AbstractAdminTest extends TestRealmKeycloakTest {
+ protected static final String REALM_NAME = "admin-client-test";
+
+ protected RealmResource realm;
+
+ @Override
+ public void configureTestRealm(RealmRepresentation testRealm) {
+ findTestApp(testRealm).setDirectAccessGrantsEnabled(true);
+ }
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ super.addTestRealms(testRealms);
+
+ RealmRepresentation adminRealmRep = new RealmRepresentation();
+ adminRealmRep.setRealm(REALM_NAME);
+ adminRealmRep.setEnabled(true);
+ Map<String, String> config = new HashMap<>();
+ config.put("from", "auto@keycloak.org");
+ config.put("host", "localhost");
+ config.put("port", "3025");
+ adminRealmRep.setSmtpServer(config);
+ testRealms.add(adminRealmRep);
+ }
+
+ @Before
+ public void setRealm() {
+ realm = adminClient.realm(REALM_NAME);
+ }
+
+ // old testsuite expects this realm to be removed at the end of the test
+ // not sure if it really matters
+ @After
+ public void after() {
+ for (RealmRepresentation r : adminClient.realms().findAll()) {
+ if (r.getRealm().equals(REALM_NAME)) {
+ removeRealm(r);
+ }
+ }
+ }
+
+ // Taken from Keycloak class in old testsuite.
+ // So, code in old testsuite calling this looks like Keycloak.loadJson(.....)
+ public static <T> T loadJson(InputStream is, Class<T> type) {
+ try {
+ return JsonSerialization.readValue(is, type);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to parse json", e);
+ }
+ }
+
+ public static <T> void assertNames(List<T> actual, String... expected) {
+ Arrays.sort(expected);
+ String[] actualNames = names(actual);
+ assertArrayEquals("Expected: " + Arrays.toString(expected) + ", was: " + Arrays.toString(actualNames), expected, actualNames);
+ }
+
+ public static <T> List<T> sort(List<T> list) {
+ Collections.sort(list, new Comparator<Object>() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ return name(o1).compareTo(name(o2));
+ }
+ });
+ return list;
+ }
+
+ public static <T> String[] names(List<T> list) {
+ String[] names = new String[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ names[i] = name(list.get(i));
+ }
+ Arrays.sort(names);
+ return names;
+ }
+
+ public static String name(Object o1) {
+ if (o1 instanceof RealmRepresentation) {
+ return ((RealmRepresentation) o1).getRealm();
+ } else if (o1 instanceof ClientRepresentation) {
+ return ((ClientRepresentation) o1).getClientId();
+ } else if (o1 instanceof IdentityProviderRepresentation) {
+ return ((IdentityProviderRepresentation) o1).getAlias();
+ }
+ throw new IllegalArgumentException();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
new file mode 100644
index 0000000..0f8ee1f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+
+import org.jboss.logging.Logger;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.Response.StatusType;
+
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+
+import org.keycloak.representations.idm.GroupRepresentation;
+
+/**
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class ApiUtil {
+
+ private static final Logger log = Logger.getLogger(ApiUtil.class);
+
+ public static String getCreatedId(Response response) {
+ URI location = response.getLocation();
+ if (!response.getStatusInfo().equals(Status.CREATED)) {
+ StatusType statusInfo = response.getStatusInfo();
+ throw new RuntimeException("Create method returned status " +
+ statusInfo.getReasonPhrase() + " (Code: " + statusInfo.getStatusCode() + "); expected status: Created (201)");
+ }
+ if (location == null) {
+ return null;
+ }
+ String path = location.getPath();
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+
+ public static ClientResource findClientResourceByClientId(RealmResource realm, String clientId) {
+ for (ClientRepresentation c : realm.clients().findAll()) {
+ if (c.getClientId().equals(clientId)) {
+ return realm.clients().get(c.getId());
+ }
+ }
+ return null;
+ }
+
+ public static ClientResource findClientResourceByName(RealmResource realm, String name) {
+ for (ClientRepresentation c : realm.clients().findAll()) {
+ if (c.getName().equals(name)) {
+ return realm.clients().get(c.getId());
+ }
+ }
+ return null;
+ }
+
+ public static ClientResource findClientByClientId(RealmResource realm, String clientId) {
+ for (ClientRepresentation c : realm.clients().findAll()) {
+ if (c.getClientId().equals(clientId)) {
+ return realm.clients().get(c.getId());
+ }
+ }
+ return null;
+ }
+
+ public static UserRepresentation findUserByUsername(RealmResource realm, String username) {
+ UserRepresentation user = null;
+ List<UserRepresentation> ur = realm.users().search(username, null, null);
+ if (ur.size() == 1) {
+ user = ur.get(0);
+ }
+ return user;
+ }
+
+ public static String createUserWithAdminClient(RealmResource realm, UserRepresentation user) {
+ Response response = realm.users().create(user);
+ String createdId = getCreatedId(response);
+ response.close();
+ return createdId;
+ }
+
+ public static String createUserAndResetPasswordWithAdminClient(RealmResource realm, UserRepresentation user, String password) {
+ String id = createUserWithAdminClient(realm, user);
+ resetUserPassword(realm.users().get(id), password, false);
+ return id;
+ }
+
+ public static void resetUserPassword(UserResource userResource, String newPassword, boolean temporary) {
+ CredentialRepresentation newCredential = new CredentialRepresentation();
+ newCredential.setType(PASSWORD);
+ newCredential.setValue(newPassword);
+ newCredential.setTemporary(temporary);
+ userResource.resetPassword(newCredential);
+ }
+
+ public static void assignClientRoles(RealmResource realm, String userId, String clientName, String... roles) {
+ String realmName = realm.toRepresentation().getRealm();
+ String clientId = "";
+ for (ClientRepresentation clientRepresentation : realm.clients().findAll()) {
+ if (clientRepresentation.getClientId().equals(clientName)) {
+ clientId = clientRepresentation.getId();
+ }
+ }
+
+ if (!clientId.isEmpty()) {
+ ClientResource clientResource = realm.clients().get(clientId);
+
+ List<RoleRepresentation> roleRepresentations = new ArrayList<>();
+ for (String roleName : roles) {
+ RoleRepresentation role = clientResource.roles().get(roleName).toRepresentation();
+ roleRepresentations.add(role);
+ }
+
+ UserResource userResource = realm.users().get(userId);
+ log.debug("assigning roles: " + Arrays.toString(roles) + " to user: \""
+ + userResource.toRepresentation().getUsername() + "\" of client: \""
+ + clientName + "\" in realm: \"" + realmName + "\"");
+ userResource.roles().clientLevel(clientId).add(roleRepresentations);
+ } else {
+ log.warn("client with name " + clientName + "doesn't exist in realm " + realmName);
+ }
+ }
+
+ public static boolean groupContainsSubgroup(GroupRepresentation group, GroupRepresentation subgroup) {
+ boolean contains = false;
+ for (GroupRepresentation sg : group.getSubGroups()) {
+ if (subgroup.getId().equals(sg.getId())) {
+ contains = true;
+ break;
+ }
+ }
+ return contains;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
index 8e4c92a..f66fdf8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -57,7 +57,7 @@ public class AssertEvents {
static final String DEFAULT_REALM = "test";
static final String DEFAULT_USERNAME = "test-user@localhost";
- String defaultRedirectUri = "http://localhost:8081/app/auth";
+ String defaultRedirectUri = "http://localhost:8180/auth/realms/master/app/auth";
String defaultEventsQueueUri = "http://localhost:8092";
private RealmResource realmResource;
@@ -96,7 +96,23 @@ public class AssertEvents {
}
public void clear() {
- realmResource.clearEvents();
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ try {
+ HttpPost post = new HttpPost(defaultEventsQueueUri + "/clear-event-queue");
+ CloseableHttpResponse response = httpclient.execute(post);
+ if (response.getStatusLine().getStatusCode() != 200) {
+ throw new RuntimeException("Failed to clear events from " + post.getURI() + ": " + response.getStatusLine().toString());
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ try {
+ httpclient.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
public ExpectedEvent expectRequiredAction(EventType event) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/LegacyImportTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/LegacyImportTest.java
index 7fbbc95..b0b4c12 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/LegacyImportTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/LegacyImportTest.java
@@ -41,7 +41,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
/**
- * Test importing JSON files exported from previous keycloak versions
+ * Test importing JSON files exported from previous adminClient versions
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
new file mode 100644
index 0000000..00a2cf9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.keycloak.testsuite.util.OAuthClient;
+import java.util.List;
+import org.junit.Before;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ * This class provides loading of the testRealm called "test". It also
+ * provides an OAuthClient for the testRealm.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public abstract class TestRealmKeycloakTest extends AbstractKeycloakTest {
+
+ protected OAuthClient oauth;
+
+ protected ClientRepresentation findTestApp(RealmRepresentation testRealm) {
+ for (ClientRepresentation client : testRealm.getClients()) {
+ if (client.getClientId().equals("test-app")) return client;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ RealmRepresentation testRealm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+
+ oauth = new OAuthClient(driver, testRealm.getPublicKey());
+
+ testRealms.add(testRealm);
+
+ configureTestRealm(testRealm);
+ }
+
+ /**
+ * This allows a subclass to change the configuration of the testRealm before
+ * it is imported. This method will be called prior to any @Before methods
+ * in the subclass.
+ *
+ * @param testRealm The realm read from /testrealm.json.
+ */
+ public abstract void configureTestRealm(RealmRepresentation testRealm);
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java
new file mode 100644
index 0000000..eda966d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.util;
+
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import static org.keycloak.models.utils.KeycloakModelUtils.getDefaultClientAuthenticatorType;
+
+/**
+ * This is a client-side version of KeycloakModelUtils that uses the adminClient to
+ * manipulate the model.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class KeycloakModelUtils {
+
+ public static ClientRepresentation createClient(RealmRepresentation realm, String name) {
+ ClientRepresentation app = new ClientRepresentation();
+ app.setName(name);
+ app.setClientId(name);
+ realm.getClients().add(app);
+ app.setClientAuthenticatorType(getDefaultClientAuthenticatorType());
+ generateSecret(app);
+ app.setFullScopeAllowed(true);
+
+ return app;
+ }
+
+ public static CredentialRepresentation generateSecret(ClientRepresentation client) {
+ UserCredentialModel secret = UserCredentialModel.generateSecret();
+ client.setSecret(secret.getValue());
+ return ModelToRepresentation.toRepresentation(secret);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/OAuthClient.java
new file mode 100644
index 0000000..b213dae
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/OAuthClient.java
@@ -0,0 +1,645 @@
+/*
+ * 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.util;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.junit.Assert;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.common.VerificationException;
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.constants.AdapterConstants;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.RefreshToken;
+import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
+import org.keycloak.util.BasicAuthHelper;
+import org.keycloak.util.JsonSerialization;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class OAuthClient {
+ public static final String SERVER_ROOT = AuthServerTestEnricher.getAuthServerContextRoot();
+ public static final String AUTH_SERVER_ROOT = SERVER_ROOT + "/auth";
+ public static final String APP_ROOT = AUTH_SERVER_ROOT + "/realms/master/app";
+
+ private WebDriver driver;
+
+ private String baseUrl = AUTH_SERVER_ROOT;
+
+ private String realm = "test";
+
+ private String clientId = "test-app";
+
+ private String redirectUri = APP_ROOT + "/auth";
+
+ private String state = "mystate";
+
+ private String scope;
+
+ private String uiLocales = null;
+
+ private PublicKey realmPublicKey;
+
+ private String clientSessionState;
+
+ private String clientSessionHost;
+
+ public OAuthClient(WebDriver driver, String publicKey) {
+ this.driver = driver;
+
+ try {
+ realmPublicKey = PemUtils.decodePublicKey(publicKey);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to retrieve realm public key", e);
+ }
+ }
+
+ public AuthorizationCodeResponse doLogin(String username, String password) {
+ openLoginForm();
+ String src = driver.getPageSource();
+ driver.findElement(By.id("username")).sendKeys(username);
+ driver.findElement(By.id("password")).sendKeys(password);
+ driver.findElement(By.name("login")).click();
+
+ return new AuthorizationCodeResponse(this);
+ }
+
+ public void doLoginGrant(String username, String password) {
+ openLoginForm();
+
+ driver.findElement(By.id("username")).sendKeys(username);
+ driver.findElement(By.id("password")).sendKeys(password);
+ driver.findElement(By.name("login")).click();
+ }
+
+ public AccessTokenResponse doAccessTokenRequest(String code, String password) {
+ CloseableHttpClient client = new DefaultHttpClient();
+ try {
+ HttpPost post = new HttpPost(getAccessTokenUrl());
+
+ List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
+
+ if (code != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
+ }
+ if (redirectUri != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
+ }
+ if (clientId != null && password != null) {
+ String authorization = BasicAuthHelper.createHeader(clientId, password);
+ post.setHeader("Authorization", authorization);
+ } else if (clientId != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
+ }
+
+ if (clientSessionState != null) {
+ parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
+ }
+
+ if (clientSessionHost != null) {
+ parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
+ }
+
+ UrlEncodedFormEntity formEntity = null;
+ try {
+ formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ post.setEntity(formEntity);
+
+ try {
+ return new AccessTokenResponse(client.execute(post));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to retrieve access token", e);
+ }
+ } finally {
+ closeClient(client);
+ }
+ }
+
+ public String introspectAccessTokenWithClientCredential(String clientId, String clientSecret, String tokenToIntrospect) {
+ return introspectTokenWithClientCredential(clientId, clientSecret, "access_token", tokenToIntrospect);
+ }
+
+ public String introspectRefreshTokenWithClientCredential(String clientId, String clientSecret, String tokenToIntrospect) {
+ return introspectTokenWithClientCredential(clientId, clientSecret, "refresh_token", tokenToIntrospect);
+ }
+
+ public String introspectTokenWithClientCredential(String clientId, String clientSecret, String tokenType, String tokenToIntrospect) {
+ CloseableHttpClient client = new DefaultHttpClient();
+ try {
+ HttpPost post = new HttpPost(getTokenIntrospectionUrl());
+
+ String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
+ post.setHeader("Authorization", authorization);
+
+ List<NameValuePair> parameters = new LinkedList<>();
+
+ parameters.add(new BasicNameValuePair("token", tokenToIntrospect));
+ parameters.add(new BasicNameValuePair("token_type_hint", tokenType));
+
+ UrlEncodedFormEntity formEntity;
+
+ try {
+ formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+
+ post.setEntity(formEntity);
+
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ client.execute(post).getEntity().writeTo(out);
+
+ return new String(out.toByteArray());
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to retrieve access token", e);
+ }
+ } finally {
+ closeClient(client);
+ }
+ }
+
+ public AccessTokenResponse doGrantAccessTokenRequest(String clientSecret, String username, String password) throws Exception {
+ return doGrantAccessTokenRequest(realm, username, password, null, clientId, clientSecret);
+ }
+
+ public AccessTokenResponse doGrantAccessTokenRequest(String clientSecret, String username, String password, String otp) throws Exception {
+ return doGrantAccessTokenRequest(realm, username, password, otp, clientId, clientSecret);
+ }
+
+ public AccessTokenResponse doGrantAccessTokenRequest(String realm, String username, String password, String totp,
+ String clientId, String clientSecret) throws Exception {
+ CloseableHttpClient client = new DefaultHttpClient();
+ try {
+ HttpPost post = new HttpPost(getResourceOwnerPasswordCredentialGrantUrl(realm));
+
+ List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
+ parameters.add(new BasicNameValuePair("username", username));
+ parameters.add(new BasicNameValuePair("password", password));
+ if (totp != null) {
+ parameters.add(new BasicNameValuePair("totp", totp));
+
+ }
+ if (clientSecret != null) {
+ String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
+ post.setHeader("Authorization", authorization);
+ } else {
+ parameters.add(new BasicNameValuePair("client_id", clientId));
+
+ }
+
+ if (clientSessionState != null) {
+ parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
+ }
+ if (clientSessionHost != null) {
+ parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
+ }
+ if (scope != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
+ }
+
+ UrlEncodedFormEntity formEntity;
+ try {
+ formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ post.setEntity(formEntity);
+
+ return new AccessTokenResponse(client.execute(post));
+ } finally {
+ closeClient(client);
+ }
+ }
+
+ public AccessTokenResponse doClientCredentialsGrantAccessTokenRequest(String clientSecret) throws Exception {
+ CloseableHttpClient client = new DefaultHttpClient();
+ try {
+ HttpPost post = new HttpPost(getServiceAccountUrl());
+
+ String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
+ post.setHeader("Authorization", authorization);
+
+ List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
+
+ if (scope != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
+ }
+
+ UrlEncodedFormEntity formEntity;
+ try {
+ formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ post.setEntity(formEntity);
+
+ return new AccessTokenResponse(client.execute(post));
+ } finally {
+ closeClient(client);
+ }
+ }
+
+
+ public HttpResponse doLogout(String refreshToken, String clientSecret) throws IOException {
+ CloseableHttpClient client = new DefaultHttpClient();
+ try {
+ HttpPost post = new HttpPost(getLogoutUrl(null, null));
+
+ List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+ if (refreshToken != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
+ }
+ if (clientId != null && clientSecret != null) {
+ String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
+ post.setHeader("Authorization", authorization);
+ } else if (clientId != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
+ }
+
+ UrlEncodedFormEntity formEntity;
+ try {
+ formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ post.setEntity(formEntity);
+
+ return client.execute(post);
+ } finally {
+ closeClient(client);
+ }
+ }
+
+ public AccessTokenResponse doRefreshTokenRequest(String refreshToken, String password) {
+ CloseableHttpClient client = new DefaultHttpClient();
+ try {
+ HttpPost post = new HttpPost(getRefreshTokenUrl());
+
+ List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
+
+ if (refreshToken != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
+ }
+ if (clientId != null && password != null) {
+ String authorization = BasicAuthHelper.createHeader(clientId, password);
+ post.setHeader("Authorization", authorization);
+ } else if (clientId != null) {
+ parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
+ }
+
+ if (clientSessionState != null) {
+ parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
+ }
+ if (clientSessionHost != null) {
+ parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
+ }
+
+ UrlEncodedFormEntity formEntity;
+ try {
+ formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ post.setEntity(formEntity);
+
+ try {
+ return new AccessTokenResponse(client.execute(post));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to retrieve access token", e);
+ }
+ } finally {
+ closeClient(client);
+ }
+ }
+
+ public void closeClient(CloseableHttpClient client) {
+ try {
+ client.close();
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ public AccessToken verifyToken(String token) {
+ try {
+ return RSATokenVerifier.verifyToken(token, realmPublicKey, baseUrl + "/realms/" + realm);
+ } catch (VerificationException e) {
+ throw new RuntimeException("Failed to verify token", e);
+ }
+ }
+
+ public RefreshToken verifyRefreshToken(String refreshToken) {
+ try {
+ JWSInput jws = new JWSInput(refreshToken);
+ if (!RSAProvider.verify(jws, realmPublicKey)) {
+ throw new RuntimeException("Invalid refresh token");
+ }
+ return jws.readJsonContent(RefreshToken.class);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid refresh token", e);
+ }
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public String getCurrentRequest() {
+ return driver.getCurrentUrl().substring(0, driver.getCurrentUrl().indexOf('?'));
+ }
+
+ public URI getCurrentUri() {
+ try {
+ return new URI(driver.getCurrentUrl());
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Map<String, String> getCurrentQuery() {
+ Map<String, String> m = new HashMap<String, String>();
+ List<NameValuePair> pairs = URLEncodedUtils.parse(getCurrentUri(), "UTF-8");
+ for (NameValuePair p : pairs) {
+ m.put(p.getName(), p.getValue());
+ }
+ return m;
+ }
+
+ public void openLoginForm() {
+ driver.navigate().to(getLoginFormUrl());
+ }
+
+ public void openLogout() {
+ UriBuilder b = OIDCLoginProtocolService.logoutUrl(UriBuilder.fromUri(baseUrl));
+ if (redirectUri != null) {
+ b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
+ }
+ driver.navigate().to(b.build(realm).toString());
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public String getLoginFormUrl() {
+ UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(SERVER_ROOT + "/auth"));
+ b.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE);
+ if (clientId != null) {
+ b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
+ }
+ if (redirectUri != null) {
+ b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
+ }
+ if (state != null) {
+ b.queryParam(OAuth2Constants.STATE, state);
+ }
+ if(uiLocales != null){
+ b.queryParam(OAuth2Constants.UI_LOCALES_PARAM, uiLocales);
+ }
+ if (scope != null) {
+ b.queryParam(OAuth2Constants.SCOPE, scope);
+ }
+ return b.build(realm).toString();
+ }
+
+ public String getAccessTokenUrl() {
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
+ return b.build(realm).toString();
+ }
+
+ public String getTokenIntrospectionUrl() {
+ UriBuilder b = OIDCLoginProtocolService.tokenIntrospectionUrl(UriBuilder.fromUri(baseUrl));
+ return b.build(realm).toString();
+ }
+
+ public String getLogoutUrl(String redirectUri, String sessionState) {
+ UriBuilder b = OIDCLoginProtocolService.logoutUrl(UriBuilder.fromUri(baseUrl));
+ if (redirectUri != null) {
+ b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
+ }
+ if (sessionState != null) {
+ b.queryParam("session_state", sessionState);
+ }
+ return b.build(realm).toString();
+ }
+
+ public String getResourceOwnerPasswordCredentialGrantUrl() {
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
+ return b.build(realm).toString();
+ }
+
+ public String getResourceOwnerPasswordCredentialGrantUrl(String realm) {
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
+ return b.build(realm).toString();
+ }
+
+ public String getServiceAccountUrl() {
+ return getResourceOwnerPasswordCredentialGrantUrl();
+ }
+
+ public String getRefreshTokenUrl() {
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
+ return b.build(realm).toString();
+ }
+
+ public OAuthClient realm(String realm) {
+ this.realm = realm;
+ return this;
+ }
+ public OAuthClient realmPublicKey(PublicKey key) {
+ this.realmPublicKey = key;
+ return this;
+ }
+
+ public OAuthClient clientId(String clientId) {
+ this.clientId = clientId;
+ return this;
+ }
+
+ public OAuthClient redirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ return this;
+ }
+
+ public OAuthClient state(String state) {
+ this.state = state;
+ return this;
+ }
+
+ public OAuthClient scope(String scope) {
+ this.scope = scope;
+ return this;
+ }
+
+ public OAuthClient uiLocales(String uiLocales){
+ this.uiLocales = uiLocales;
+ return this;
+ }
+
+ public OAuthClient clientSessionState(String client_session_state) {
+ this.clientSessionState = client_session_state;
+ return this;
+ }
+
+ public OAuthClient clientSessionHost(String client_session_host) {
+ this.clientSessionHost = client_session_host;
+ return this;
+ }
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public static class AuthorizationCodeResponse {
+
+ private boolean isRedirected;
+ private String code;
+ private String state;
+ private String error;
+
+ public AuthorizationCodeResponse(OAuthClient client) {
+ isRedirected = client.getCurrentRequest().equals(client.getRedirectUri());
+ code = client.getCurrentQuery().get(OAuth2Constants.CODE);
+ state = client.getCurrentQuery().get(OAuth2Constants.STATE);
+ error = client.getCurrentQuery().get(OAuth2Constants.ERROR);
+ }
+
+ public boolean isRedirected() {
+ return isRedirected;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ }
+
+ public static class AccessTokenResponse {
+ private int statusCode;
+
+ private String accessToken;
+ private String tokenType;
+ private int expiresIn;
+ private int refreshExpiresIn;
+ private String refreshToken;
+
+ private String error;
+ private String errorDescription;
+
+ public AccessTokenResponse(HttpResponse response) throws Exception {
+ statusCode = response.getStatusLine().getStatusCode();
+ if (!"application/json".equals(response.getHeaders("Content-Type")[0].getValue())) {
+ Assert.fail("Invalid content type");
+ }
+
+ String s = IOUtils.toString(response.getEntity().getContent());
+ Map responseJson = JsonSerialization.readValue(s, Map.class);
+
+ if (statusCode == 200) {
+ accessToken = (String)responseJson.get("access_token");
+ tokenType = (String)responseJson.get("token_type");
+ expiresIn = (Integer)responseJson.get("expires_in");
+ refreshExpiresIn = (Integer)responseJson.get("refresh_expires_in");
+
+ if (responseJson.containsKey(OAuth2Constants.REFRESH_TOKEN)) {
+ refreshToken = (String)responseJson.get(OAuth2Constants.REFRESH_TOKEN);
+ }
+ } else {
+ error = (String)responseJson.get(OAuth2Constants.ERROR);
+ errorDescription = responseJson.containsKey(OAuth2Constants.ERROR_DESCRIPTION) ? (String)responseJson.get(OAuth2Constants.ERROR_DESCRIPTION) : null;
+ }
+ }
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public String getErrorDescription() {
+ return errorDescription;
+ }
+
+ public int getExpiresIn() {
+ return expiresIn;
+ }
+
+ public int getRefreshExpiresIn() {
+ return refreshExpiresIn;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public String getTokenType() {
+ return tokenType;
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
index 845adda..beb1d85 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
@@ -101,11 +101,11 @@
{
"clientId": "test-app",
"enabled": true,
- "baseUrl": "http://localhost:8081/app",
+ "baseUrl": "http://localhost:8180/auth/realms/master/app",
"redirectUris": [
- "http://localhost:8081/app/*"
+ "http://localhost:8180/auth/realms/master/app/*"
],
- "adminUrl": "http://localhost:8081/app/logout",
+ "adminUrl": "http://localhost:8180/auth/realms/master/app/logout",
"secret": "password"
},
{
@@ -114,7 +114,7 @@
"consentRequired": true,
"redirectUris": [
- "http://localhost:8081/app/*"
+ "http://localhost:8180/app/*"
],
"secret": "password"
}