keycloak-aplcache
Changes
testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java 213(+0 -213)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java 5(+5 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java 206(+206 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java 36(+29 -7)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientBuilder.java 66(+66 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/CredentialBuilder.java 51(+51 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java 83(+83 -0)
Details
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 84bd64c..3fd7712 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
@@ -129,7 +129,7 @@ public abstract class AbstractKeycloakTest {
private boolean resetTimeOffset;
@Before
- public void beforeAbstractKeycloakTest() {
+ public void beforeAbstractKeycloakTest() throws Exception {
adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
deleteMeOAuthClient = new DeleteMeOAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");
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
index 0f8ee1f..a60926e 100644
--- 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
@@ -19,6 +19,7 @@ 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.RoleResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -85,6 +86,10 @@ public class ApiUtil {
return null;
}
+ public static RoleResource findClientRoleByName(ClientResource client, String role) {
+ return client.roles().get(role);
+ }
+
public static UserRepresentation findUserByUsername(RealmResource realm, String username) {
UserRepresentation user = null;
List<UserRepresentation> ur = realm.users().search(username, null, null);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
new file mode 100755
index 0000000..afe11a3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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.junit.Assert;
+import org.junit.Test;
+import org.keycloak.Config;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventType;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.Constants;
+import org.keycloak.models.ImpersonationConstants;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.resources.admin.AdminRoot;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.CredentialBuilder;
+import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests Undertow Adapter
+ *
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+public class ImpersonationTest extends AbstractKeycloakTest {
+
+ private AssertEvents events;
+
+ private String impersonatedUserId;
+
+ @Override
+ public void beforeAbstractKeycloakTest() throws Exception {
+ super.beforeAbstractKeycloakTest();
+ events = new AssertEvents(this);
+ }
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ RealmBuilder realm = RealmBuilder.create().name("test").testEventListener();
+
+ realm.client(ClientBuilder.create().clientId("myclient").publicClient().directAccessGrants());
+
+ impersonatedUserId = KeycloakModelUtils.generateId();
+
+ realm.user(UserBuilder.create().id(impersonatedUserId).username("test-user@localhost"));
+ realm.user(UserBuilder.create().username("realm-admin").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
+ realm.user(UserBuilder.create().username("impersonator").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, ImpersonationConstants.IMPERSONATION_ROLE).role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.VIEW_USERS));
+ realm.user(UserBuilder.create().username("bad-impersonator").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.MANAGE_USERS));
+
+ testRealms.add(realm.build());
+ }
+
+ private String createAdminToken(String username, String realm) {
+ try {
+ String password = username.equals("admin") ? "admin" : "password";
+ String clientId = realm.equals("master") ? Constants.ADMIN_CLI_CLIENT_ID : "myclient";
+ AccessTokenResponse tokenResponse = oauthClient.doGrantAccessTokenRequest(realm, username, password, null, clientId, null);
+ if (tokenResponse.getStatusCode() != 200) {
+ throw new RuntimeException("Failed to get token: " + tokenResponse.getErrorDescription());
+ }
+ events.clear();
+ return tokenResponse.getAccessToken();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void testImpersonateByMasterAdmin() {
+ // test that composite is set up right for impersonation role
+ testSuccessfulImpersonation("admin", Config.getAdminRealm());
+ }
+
+ @Test
+ public void testImpersonateByMasterImpersonator() {
+ Response response = adminClient.realm("master").users().create(UserBuilder.create().username("master-impersonator").build());
+ String userId = ApiUtil.getCreatedId(response);
+ response.close();
+
+ UserResource user = adminClient.realm("master").users().get(userId);
+ user.resetPassword(CredentialBuilder.create().password("password").build());
+
+ ClientResource testRealmClient = ApiUtil.findClientResourceByClientId(adminClient.realm("master"), "test-realm");
+
+ List<RoleRepresentation> roles = new LinkedList<>();
+ roles.add(ApiUtil.findClientRoleByName(testRealmClient, AdminRoles.VIEW_USERS).toRepresentation());
+ roles.add(ApiUtil.findClientRoleByName(testRealmClient, ImpersonationConstants.IMPERSONATION_ROLE).toRepresentation());
+
+ user.roles().clientLevel(testRealmClient.toRepresentation().getId()).add(roles);
+
+ testSuccessfulImpersonation("master-impersonator", Config.getAdminRealm());
+
+ adminClient.realm("master").users().get(userId).remove();
+ }
+
+ @Test
+ public void testImpersonateByTestImpersonator() {
+ testSuccessfulImpersonation("impersonator", "test");
+ }
+
+ @Test
+ public void testImpersonateByTestAdmin() {
+ // test that composite is set up right for impersonation role
+ testSuccessfulImpersonation("realm-admin", "test");
+ }
+
+ @Test
+ public void testImpersonateByTestBadImpersonator() {
+ testForbiddenImpersonation("bad-impersonator", "test");
+ }
+
+ @Test
+ public void testImpersonateByMastertBadImpersonator() {
+ Response response = adminClient.realm("master").users().create(UserBuilder.create().username("master-bad-impersonator").build());
+ String userId = ApiUtil.getCreatedId(response);
+ response.close();
+ adminClient.realm("master").users().get(userId).resetPassword(CredentialBuilder.create().password("password").build());
+
+ testForbiddenImpersonation("master-bad-impersonator", Config.getAdminRealm());
+
+ adminClient.realm("master").users().get(userId).remove();
+ }
+
+
+
+ protected void testSuccessfulImpersonation(String admin, String adminRealm) {
+ Client client = createClient(admin, adminRealm);
+ WebTarget impersonate = createImpersonateTarget(client);
+ Map data = impersonate.request().post(null, Map.class);
+ Assert.assertNotNull(data);
+ Assert.assertNotNull(data.get("redirect"));
+
+ // TODO Events not working
+ events.expect(EventType.IMPERSONATE)
+ .session(AssertEvents.isUUID())
+ .user(impersonatedUserId)
+ .detail(Details.IMPERSONATOR, admin)
+ .detail(Details.IMPERSONATOR_REALM, adminRealm)
+ .client((String) null).assertEvent();
+
+ client.close();
+ }
+
+ protected void testForbiddenImpersonation(String admin, String adminRealm) {
+ Client client = createClient(admin, adminRealm);
+ WebTarget impersonate = createImpersonateTarget(client);
+ Response response = impersonate.request().post(null);
+ response.close();
+ client.close();
+ }
+
+
+ protected WebTarget createImpersonateTarget(Client client) {
+ UriBuilder authBase = UriBuilder.fromUri(getAuthServerRoot());
+ WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
+ WebTarget realmTarget = adminRealms.path("test");
+ return realmTarget.path("users").path(impersonatedUserId).path("impersonation");
+ }
+
+ protected Client createClient(String admin, String adminRealm) {
+ String token = createAdminToken(admin, adminRealm);
+ final String authHeader = "Bearer " + token;
+ ClientRequestFilter authFilter = new ClientRequestFilter() {
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
+ }
+ };
+ return javax.ws.rs.client.ClientBuilder.newBuilder().register(authFilter).build();
+ }
+
+}
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 6df6511..6a4a554 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
@@ -64,7 +64,6 @@ public class AssertEvents {
private RealmRepresentation realmRep;
private AbstractKeycloakTest context;
private PublicKey realmPublicKey;
- private UserRepresentation defaultUser;
public AssertEvents(AbstractKeycloakTest ctx) throws Exception {
context = ctx;
@@ -74,11 +73,6 @@ public class AssertEvents {
String pubKeyString = realmRep.getPublicKey();
realmPublicKey = PemUtils.decodePublicKey(pubKeyString);
- defaultUser = getUser(DEFAULT_USERNAME);
- if (defaultUser == null) {
- throw new RuntimeException("Default user does not exist: " + DEFAULT_USERNAME + ". Make sure to add it to your test realm.");
- }
-
defaultEventsQueueUri = getAuthServerEventsQueueUri();
}
@@ -192,7 +186,7 @@ public class AssertEvents {
return new ExpectedEvent()
.realm(realmRep.getId())
.client(DEFAULT_CLIENT_ID)
- .user(defaultUser.getId())
+ .user(defaultUserId())
.ipAddress(DEFAULT_IP_ADDRESS)
.session((String) null)
.event(event);
@@ -357,6 +351,34 @@ public class AssertEvents {
};
}
+ public Matcher<String> defaultUserId() {
+ return new TypeSafeMatcher<String>() {
+ private String userId;
+
+ @Override
+ protected boolean matchesSafely(String item) {
+ return item.equals(getUserId());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(getUserId());
+ }
+
+ private String getUserId() {
+ if (userId == null) {
+ UserRepresentation user = getUser(DEFAULT_USERNAME);
+ if (user == null) {
+ throw new RuntimeException("Default user does not exist: " + DEFAULT_USERNAME + ". Make sure to add it to your test realm.");
+ }
+ userId = user.getId();
+ }
+ return userId;
+ }
+
+ };
+ }
+
private EventRepresentation fetchNextEvent() {
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientBuilder.java
new file mode 100644
index 0000000..a0b3bf7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientBuilder.java
@@ -0,0 +1,66 @@
+/*
+ * 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.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ClientBuilder {
+
+ private ClientRepresentation rep = new ClientRepresentation();
+
+ public static ClientBuilder create() {
+ return new ClientBuilder();
+ }
+
+ private ClientBuilder() {
+ rep.setEnabled(true);
+ }
+
+ public ClientBuilder id(String id) {
+ rep.setId(id);
+ return this;
+ }
+
+ public ClientBuilder clientId(String clientId) {
+ rep.setClientId(clientId);
+ return this;
+ }
+
+ public ClientBuilder publicClient() {
+ rep.setPublicClient(true);
+ return this;
+ }
+
+ public ClientBuilder directAccessGrants() {
+ rep.setDirectAccessGrantsEnabled(true);
+ return this;
+ }
+
+ public ClientRepresentation build() {
+ return rep;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/CredentialBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/CredentialBuilder.java
new file mode 100644
index 0000000..038f4fb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/CredentialBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class CredentialBuilder {
+
+ private CredentialRepresentation rep = new CredentialRepresentation();
+
+ public static CredentialBuilder create() {
+ return new CredentialBuilder();
+ }
+
+ private CredentialBuilder() {
+ }
+
+ public CredentialBuilder password(String password) {
+ rep.setType(CredentialRepresentation.PASSWORD);
+ rep.setValue(password);
+ return this;
+ }
+
+ public CredentialRepresentation build() {
+ return rep;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java
new file mode 100644
index 0000000..8859f03
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java
@@ -0,0 +1,83 @@
+/*
+ * 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.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import java.util.LinkedList;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RealmBuilder {
+
+ private RealmRepresentation rep = new RealmRepresentation();
+
+ public static RealmBuilder create() {
+ return new RealmBuilder();
+ }
+
+ private RealmBuilder() {
+ rep.setEnabled(true);
+ }
+
+ public RealmBuilder name(String name) {
+ rep.setRealm(name);
+ return this;
+ }
+
+ public RealmBuilder testEventListener() {
+ if (rep.getEventsListeners() == null) {
+ rep.setEventsListeners(new LinkedList<String>());
+ }
+
+ rep.getEventsListeners().add("event-queue");
+ return this;
+ }
+
+ public RealmBuilder client(ClientBuilder client) {
+ return client(client.build());
+ }
+
+ public RealmBuilder client(ClientRepresentation client) {
+ if (rep.getClients() == null) {
+ rep.setClients(new LinkedList<ClientRepresentation>());
+ }
+ rep.getClients().add(client);
+ return this;
+ }
+
+ public RealmBuilder user(UserBuilder user) {
+ return user(user.build());
+ }
+
+ public RealmBuilder user(UserRepresentation user) {
+ if (rep.getUsers() == null) {
+ rep.setUsers(new LinkedList<UserRepresentation>());
+ }
+ rep.getUsers().add(user);
+ return this;
+ }
+
+ public RealmRepresentation build() {
+ return rep;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RoleBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RoleBuilder.java
new file mode 100644
index 0000000..d46d160
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RoleBuilder.java
@@ -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.util;
+
+import org.keycloak.representations.idm.RoleRepresentation;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RoleBuilder {
+
+ private RoleRepresentation rep = new RoleRepresentation();
+
+ public static RoleBuilder create() {
+ return new RoleBuilder();
+ }
+
+ private RoleBuilder() {
+ }
+
+ public RoleBuilder id(String id) {
+ rep.setId(id);
+ return this;
+ }
+
+ public RoleBuilder name(String name) {
+ rep.setName(name);
+ return this;
+ }
+
+ public RoleRepresentation build() {
+ return rep;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/UserBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/UserBuilder.java
new file mode 100644
index 0000000..e976a45
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/UserBuilder.java
@@ -0,0 +1,87 @@
+/*
+ * 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.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserBuilder {
+
+ private UserRepresentation rep = new UserRepresentation();
+
+ public static UserBuilder create() {
+ return new UserBuilder();
+ }
+
+ private UserBuilder() {
+ rep.setEnabled(true);
+ }
+
+ public UserBuilder id(String id) {
+ rep.setId(id);
+ return this;
+ }
+
+ public UserBuilder username(String username) {
+ rep.setUsername(username);
+ return this;
+ }
+
+ public UserBuilder password(String password) {
+ if (rep.getCredentials() == null) {
+ rep.setCredentials(new LinkedList<CredentialRepresentation>());
+ }
+
+ CredentialRepresentation credential = new CredentialRepresentation();
+ credential.setType(CredentialRepresentation.PASSWORD);
+ credential.setValue(password);
+
+ rep.getCredentials().add(credential);
+ return this;
+ }
+
+ public UserBuilder role(String role) {
+ if (rep.getRealmRoles() == null) {
+ rep.setRealmRoles(new LinkedList<String>());
+ }
+ return this;
+ }
+
+ public UserBuilder role(String client, String role) {
+ if (rep.getClientRoles() == null) {
+ rep.setClientRoles(new HashMap<String, List<String>>());
+ }
+ if (rep.getClientRoles().get(client) == null) {
+ rep.getClientRoles().put(client, new LinkedList<String>());
+ }
+ rep.getClientRoles().get(client).add(role);
+ return this;
+ }
+
+ public UserRepresentation build() {
+ return rep;
+ }
+
+}