Merge pull request #2908 from mstruk/KEYCLOAK-2879-a
KEYCLOAK-2879 UserResource
This commit is contained in:
commit
fba78f3e2a
6 changed files with 518 additions and 59 deletions
|
@ -146,4 +146,8 @@ public interface UserResource {
|
|||
@Path("consents/{client}")
|
||||
public void revokeConsent(@PathParam("client") String clientId);
|
||||
|
||||
@POST
|
||||
@Path("impersonation")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Map<String, Object> impersonate();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.pages;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
public class ConsentPage extends AbstractPage {
|
||||
|
||||
@FindBy(id = "kc-login")
|
||||
private WebElement submitButton;
|
||||
|
||||
public void confirm() {
|
||||
submitButton.click();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return driver.getTitle().equalsIgnoreCase("grant access");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
|
||||
}
|
||||
}
|
|
@ -294,6 +294,9 @@ public class ClientTest extends AbstractAdminTest {
|
|||
Map<String, Long> offlineSessionCount = realm.clients().get(id).getOfflineSessionCount();
|
||||
assertEquals(new Long(0), offlineSessionCount.get("count"));
|
||||
|
||||
List<UserSessionRepresentation> userSessions = realm.users().get(userId).getOfflineSessions(id);
|
||||
assertEquals("There should be no offline sessions", 0, userSessions.size());
|
||||
|
||||
oauth.realm(REALM_NAME);
|
||||
oauth.redirectUri(client.getRedirectUris().get(0));
|
||||
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||
|
@ -307,6 +310,17 @@ public class ClientTest extends AbstractAdminTest {
|
|||
List<UserSessionRepresentation> offlineUserSessions = realm.clients().get(id).getOfflineUserSessions(0, 100);
|
||||
assertEquals(1, offlineUserSessions.size());
|
||||
assertEquals("testuser", offlineUserSessions.get(0).getUsername());
|
||||
|
||||
userSessions = realm.users().get(userId).getOfflineSessions(id);
|
||||
assertEquals("There should be one offline session", 1, userSessions.size());
|
||||
assertOfflineSession(offlineUserSessions.get(0), userSessions.get(0));
|
||||
}
|
||||
|
||||
private void assertOfflineSession(UserSessionRepresentation expected, UserSessionRepresentation actual) {
|
||||
assertEquals("id", expected.getId(), actual.getId());
|
||||
assertEquals("userId", expected.getUserId(), actual.getUserId());
|
||||
assertEquals("userName", expected.getUsername(), actual.getUsername());
|
||||
assertEquals("clients", expected.getClients(), actual.getClients());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* 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.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.pages.ConsentPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
public class ConsentsTest extends AbstractKeycloakTest {
|
||||
|
||||
final static String REALM_PROV_NAME = "provider";
|
||||
final static String REALM_CONS_NAME = "consumer";
|
||||
|
||||
final static String IDP_OIDC_ALIAS = "kc-oidc-idp";
|
||||
final static String IDP_OIDC_PROVIDER_ID = "keycloak-oidc";
|
||||
|
||||
final static String CLIENT_ID = "brokerapp";
|
||||
final static String CLIENT_SECRET = "secret";
|
||||
|
||||
final static String USER_LOGIN = "testuser";
|
||||
final static String USER_EMAIL = "user@localhost.com";
|
||||
final static String USER_PASSWORD = "password";
|
||||
final static String USER_FIRSTNAME = "User";
|
||||
final static String USER_LASTNAME = "Tester";
|
||||
|
||||
protected RealmRepresentation createProviderRealm() {
|
||||
RealmRepresentation realm = new RealmRepresentation();
|
||||
realm.setRealm(REALM_PROV_NAME);
|
||||
realm.setEnabled(true);
|
||||
|
||||
return realm;
|
||||
}
|
||||
|
||||
protected RealmRepresentation createConsumerRealm() {
|
||||
RealmRepresentation realm = new RealmRepresentation();
|
||||
realm.setRealm(REALM_CONS_NAME);
|
||||
realm.setEnabled(true);
|
||||
|
||||
return realm;
|
||||
}
|
||||
|
||||
protected List<ClientRepresentation> createProviderClients() {
|
||||
ClientRepresentation client = new ClientRepresentation();
|
||||
client.setId(CLIENT_ID);
|
||||
client.setName(CLIENT_ID);
|
||||
client.setSecret(CLIENT_SECRET);
|
||||
client.setEnabled(true);
|
||||
client.setConsentRequired(true);
|
||||
|
||||
client.setRedirectUris(Collections.singletonList(getAuthRoot() +
|
||||
"/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint/*"));
|
||||
|
||||
client.setAdminUrl(getAuthRoot() +
|
||||
"/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint");
|
||||
|
||||
return Collections.singletonList(client);
|
||||
}
|
||||
|
||||
protected IdentityProviderRepresentation setUpIdentityProvider() {
|
||||
IdentityProviderRepresentation idp = createIdentityProvider(IDP_OIDC_ALIAS, IDP_OIDC_PROVIDER_ID);
|
||||
|
||||
Map<String, String> config = idp.getConfig();
|
||||
|
||||
config.put("clientId", CLIENT_ID);
|
||||
config.put("clientSecret", CLIENT_SECRET);
|
||||
config.put("prompt", "login");
|
||||
config.put("authorizationUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/auth");
|
||||
config.put("tokenUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/token");
|
||||
config.put("logoutUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/logout");
|
||||
config.put("userInfoUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/userinfo");
|
||||
config.put("defaultScope", "email profile");
|
||||
config.put("backchannelSupported", "true");
|
||||
|
||||
return idp;
|
||||
}
|
||||
|
||||
protected String getUserLogin() {
|
||||
return USER_LOGIN;
|
||||
}
|
||||
|
||||
protected String getUserPassword() {
|
||||
return USER_PASSWORD;
|
||||
}
|
||||
|
||||
protected String getUserEmail() {
|
||||
return USER_EMAIL;
|
||||
}
|
||||
|
||||
protected String getUserFirstName() {
|
||||
return USER_FIRSTNAME;
|
||||
}
|
||||
|
||||
protected String getUserLastName() {
|
||||
return USER_LASTNAME;
|
||||
}
|
||||
protected String providerRealmName() {
|
||||
return REALM_PROV_NAME;
|
||||
}
|
||||
|
||||
protected String consumerRealmName() {
|
||||
return REALM_CONS_NAME;
|
||||
}
|
||||
|
||||
protected String getIDPAlias() {
|
||||
return IDP_OIDC_ALIAS;
|
||||
}
|
||||
|
||||
|
||||
@Page
|
||||
protected LoginPage accountLoginPage;
|
||||
|
||||
@Page
|
||||
protected ConsentPage consentPage;
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation providerRealm = createProviderRealm();
|
||||
RealmRepresentation consumerRealm = createConsumerRealm();
|
||||
|
||||
testRealms.add(providerRealm);
|
||||
testRealms.add(consumerRealm);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createUser() {
|
||||
log.debug("creating user for realm " + providerRealmName());
|
||||
|
||||
UserRepresentation user = new UserRepresentation();
|
||||
user.setUsername(getUserLogin());
|
||||
user.setEmail(getUserEmail());
|
||||
user.setFirstName(getUserFirstName());
|
||||
user.setLastName(getUserLastName());
|
||||
user.setEmailVerified(true);
|
||||
user.setEnabled(true);
|
||||
|
||||
RealmResource realmResource = adminClient.realm(providerRealmName());
|
||||
String userId = createUserWithAdminClient(realmResource, user);
|
||||
|
||||
resetUserPassword(realmResource.users().get(userId), getUserPassword(), false);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void addIdentityProviderToProviderRealm() {
|
||||
log.debug("adding identity provider to realm " + consumerRealmName());
|
||||
|
||||
RealmResource realm = adminClient.realm(consumerRealmName());
|
||||
realm.identityProviders().create(setUpIdentityProvider());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void addClients() {
|
||||
List<ClientRepresentation> clients = createProviderClients();
|
||||
if (clients != null) {
|
||||
RealmResource providerRealm = adminClient.realm(providerRealmName());
|
||||
for (ClientRepresentation client : clients) {
|
||||
log.debug("adding client " + client.getName() + " to realm " + providerRealmName());
|
||||
|
||||
providerRealm.clients().create(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String getAuthRoot() {
|
||||
return suiteContext.getAuthServerInfo().getContextRoot().toString();
|
||||
}
|
||||
|
||||
protected IdentityProviderRepresentation createIdentityProvider(String alias, String providerId) {
|
||||
IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
|
||||
|
||||
identityProviderRepresentation.setAlias(alias);
|
||||
identityProviderRepresentation.setProviderId(providerId);
|
||||
identityProviderRepresentation.setEnabled(true);
|
||||
|
||||
return identityProviderRepresentation;
|
||||
}
|
||||
|
||||
private void waitForPage(String title) {
|
||||
long startAt = System.currentTimeMillis();
|
||||
|
||||
while (!driver.getTitle().toLowerCase().contains(title)
|
||||
&& System.currentTimeMillis() - startAt < 200) {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConsents() {
|
||||
driver.navigate().to(getAccountUrl(consumerRealmName()));
|
||||
|
||||
log.debug("Clicking social " + getIDPAlias());
|
||||
accountLoginPage.clickSocial(getIDPAlias());
|
||||
|
||||
if (!driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/")) {
|
||||
log.debug("Not on provider realm page, url: " + driver.getCurrentUrl());
|
||||
}
|
||||
|
||||
Assert.assertTrue("Driver should be on the provider realm page right now",
|
||||
driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
|
||||
|
||||
log.debug("Logging in");
|
||||
accountLoginPage.login(getUserLogin(), getUserPassword());
|
||||
|
||||
waitForPage("grant access");
|
||||
|
||||
Assert.assertTrue(consentPage.isCurrent());
|
||||
consentPage.confirm();
|
||||
|
||||
Assert.assertTrue("We must be on correct realm right now",
|
||||
driver.getCurrentUrl().contains("/auth/realms/" + consumerRealmName() + "/"));
|
||||
|
||||
UsersResource consumerUsers = adminClient.realm(consumerRealmName()).users();
|
||||
Assert.assertTrue("There must be at least one user", consumerUsers.count() > 0);
|
||||
|
||||
List<UserRepresentation> users = consumerUsers.search("", 0, 5);
|
||||
|
||||
UserRepresentation foundUser = null;
|
||||
for (UserRepresentation user : users) {
|
||||
if (user.getUsername().equals(getUserLogin()) && user.getEmail().equals(getUserEmail())) {
|
||||
foundUser = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertNotNull("There must be user " + getUserLogin() + " in realm " + consumerRealmName(),
|
||||
foundUser);
|
||||
|
||||
// get user with the same username from provider realm
|
||||
RealmResource providerRealm = adminClient.realm(providerRealmName());
|
||||
users = providerRealm.users().search(null, foundUser.getFirstName(), foundUser.getLastName(), null, 0, 1);
|
||||
Assert.assertEquals("Same user should be in provider realm", 1, users.size());
|
||||
|
||||
String userId = users.get(0).getId();
|
||||
UserResource userResource = providerRealm.users().get(userId);
|
||||
|
||||
// list consents
|
||||
List<Map<String, Object>> consents = userResource.getConsents();
|
||||
Assert.assertEquals("There should be one consent", 1, consents.size());
|
||||
|
||||
Map<String, Object> consent = consents.get(0);
|
||||
Assert.assertEquals("Consent should be given to " + CLIENT_ID, CLIENT_ID, consent.get("clientId"));
|
||||
|
||||
// list sessions
|
||||
List<UserSessionRepresentation> sessions = userResource.getUserSessions();
|
||||
Assert.assertEquals("There should be one active session", 1, sessions.size());
|
||||
|
||||
// revoke consent
|
||||
userResource.revokeConsent(CLIENT_ID);
|
||||
|
||||
// list consents
|
||||
consents = userResource.getConsents();
|
||||
Assert.assertEquals("There should be no consents", 0, consents.size());
|
||||
|
||||
// list sessions
|
||||
sessions = userResource.getUserSessions();
|
||||
Assert.assertEquals("There should be no active session", 0, sessions.size());
|
||||
}
|
||||
|
||||
private String getAccountUrl(String realmName) {
|
||||
return getAuthRoot() + "/auth/realms/" + realmName + "/account";
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import org.junit.Assert;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.events.Details;
|
||||
|
@ -29,25 +30,20 @@ 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.EventRepresentation;
|
||||
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.arquillian.AuthServerTestEnricher;
|
||||
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||
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.ClientErrorException;
|
||||
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;
|
||||
|
@ -85,21 +81,6 @@ public class ImpersonationTest extends AbstractKeycloakTest {
|
|||
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 = oauth.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
|
||||
|
@ -157,51 +138,65 @@ public class ImpersonationTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
|
||||
|
||||
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();
|
||||
Keycloak client = login(admin, adminRealm);
|
||||
try {
|
||||
Map data = client.realms().realm("test").users().get(impersonatedUserId).impersonate();
|
||||
Assert.assertNotNull(data);
|
||||
Assert.assertNotNull(data.get("redirect"));
|
||||
|
||||
client.close();
|
||||
events.expect(EventType.IMPERSONATE)
|
||||
.session(AssertEvents.isUUID())
|
||||
.user(impersonatedUserId)
|
||||
.detail(Details.IMPERSONATOR, admin)
|
||||
.detail(Details.IMPERSONATOR_REALM, adminRealm)
|
||||
.client((String) null).assertEvent();
|
||||
} finally {
|
||||
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();
|
||||
Keycloak client = createAdminClient(adminRealm, establishClientId(adminRealm), admin);
|
||||
try {
|
||||
client.realms().realm("test").users().get(impersonatedUserId).impersonate();
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertTrue(e.getMessage().indexOf("403 Forbidden") != -1);
|
||||
} finally {
|
||||
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");
|
||||
Keycloak createAdminClient(String realm, String clientId, String username) {
|
||||
return createAdminClient(realm, clientId, username, null);
|
||||
}
|
||||
|
||||
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();
|
||||
String establishClientId(String realm) {
|
||||
return realm.equals("master") ? Constants.ADMIN_CLI_CLIENT_ID : "myclient";
|
||||
}
|
||||
|
||||
Keycloak createAdminClient(String realm, String clientId, String username, String password) {
|
||||
if (password == null) {
|
||||
password = username.equals("admin") ? "admin" : "password";
|
||||
}
|
||||
return Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
|
||||
realm, username, password, clientId);
|
||||
}
|
||||
|
||||
private Keycloak login(String username, String realm) {
|
||||
String clientId = establishClientId(realm);
|
||||
Keycloak client = createAdminClient(realm, clientId, username);
|
||||
|
||||
client.tokenManager().grantToken();
|
||||
// only poll for LOGIN event if realm is not master
|
||||
// - since for master testing event listener is not installed
|
||||
if (!AuthRealm.MASTER.equals(realm)) {
|
||||
EventRepresentation e = events.poll();
|
||||
Assert.assertEquals("Event type", EventType.LOGIN.toString(), e.getType());
|
||||
Assert.assertEquals("Client ID", clientId, e.getClientId());
|
||||
Assert.assertEquals("Username", username, e.getDetails().get("username"));
|
||||
}
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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.arquillian.graphene.page.Page;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.idm.AdminEventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.services.resources.AccountService;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.TestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.pages.AccountTotpPage;
|
||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
public class UserTotpTest extends TestRealmKeycloakTest {
|
||||
|
||||
private static final UriBuilder BASE = UriBuilder.fromUri("http://localhost:8180/auth");
|
||||
public static String ACCOUNT_REDIRECT = AccountService.loginRedirectUrl(BASE.clone()).build("test").toString();
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
@Page
|
||||
protected AccountTotpPage totpPage;
|
||||
|
||||
@Page
|
||||
protected AccountUpdateProfilePage profilePage;
|
||||
|
||||
@Page
|
||||
protected LoginPage loginPage;
|
||||
|
||||
private TimeBasedOTP totp = new TimeBasedOTP();
|
||||
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupTotp() {
|
||||
totpPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=totp").assertEvent();
|
||||
|
||||
Assert.assertTrue(totpPage.isCurrent());
|
||||
|
||||
Assert.assertFalse(driver.getPageSource().contains("Remove Google"));
|
||||
|
||||
totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()));
|
||||
|
||||
Assert.assertEquals("Mobile authenticator configured.", profilePage.getSuccess());
|
||||
|
||||
events.expectAccount(EventType.UPDATE_TOTP).assertEvent();
|
||||
|
||||
Assert.assertTrue(driver.getPageSource().contains("pficon-delete"));
|
||||
|
||||
List<UserRepresentation> users = adminClient.realms().realm("test").users().search("test-user@localhost", null, null, null, 0, 1);
|
||||
String userId = users.get(0).getId();
|
||||
|
||||
adminClient.realms().realm("test").users().get(userId).removeTotp();
|
||||
|
||||
totpPage.open();
|
||||
Assert.assertFalse(driver.getPageSource().contains("pficon-delete"));
|
||||
|
||||
AdminEventRepresentation event = testingClient.testing().pollAdminEvent();
|
||||
Assert.assertNotNull(event);
|
||||
Assert.assertEquals(OperationType.ACTION.name(), event.getOperationType());
|
||||
Assert.assertEquals("users/" + userId + "/remove-totp", event.getResourcePath());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue