keycloak-aplcache
Changes
forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js 24(+22 -2)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html 9(+5 -4)
Details
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index e9341b3..335bef3 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -79,6 +79,9 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, WhoAmI, Current, $
get manageEvents() {
return getAccess('manage-events');
+ },
+ get impersonation() {
+ return getAccess('impersonation');
}
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index 93e321b..9d807a9 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -154,7 +154,7 @@ module.controller('UserConsentsCtrl', function($scope, realm, user, userConsents
});
-module.controller('UserListCtrl', function($scope, realm, User) {
+module.controller('UserListCtrl', function($scope, realm, User, UserImpersonation) {
$scope.realm = realm;
$scope.page = 0;
@@ -164,6 +164,16 @@ module.controller('UserListCtrl', function($scope, realm, User) {
first : 0
}
+ $scope.impersonate = function(userId) {
+ UserImpersonation.save({realm : realm.realm, user: userId}, function (data) {
+ if (data.sameRealm) {
+ window.location = data.redirect;
+ } else {
+ window.open(data.redirect, "_blank");
+ }
+ });
+ };
+
$scope.firstPage = function() {
$scope.query.first = 0;
$scope.searchQuery();
@@ -195,7 +205,7 @@ module.controller('UserListCtrl', function($scope, realm, User) {
-module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, RequiredActions, $location, Dialog, Notifications) {
+module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, UserImpersonation, RequiredActions, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.create = !user.id;
$scope.editUsername = $scope.create || $scope.realm.editUsernameAllowed;
@@ -208,7 +218,17 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFede
}
convertAttributeValuesToString(user);
+
$scope.user = angular.copy(user);
+ $scope.impersonate = function() {
+ UserImpersonation.save({realm : realm.realm, user: $scope.user.id}, function (data) {
+ if (data.sameRealm) {
+ window.location = data.redirect;
+ } else {
+ window.open(data.redirect, "_blank");
+ }
+ });
+ };
if(user.federationLink) {
console.log("federationLink is not null");
UserFederationInstances.get({realm : realm.realm, instance: user.federationLink}, function(link) {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
index 3107101..bd1fe98 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -319,6 +319,13 @@ module.factory('UserConsents', function($resource) {
});
});
+module.factory('UserImpersonation', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/users/:user/impersonation', {
+ realm : '@realm',
+ user : '@user'
+ });
+});
+
module.factory('UserCredentials', function($resource) {
var credentials = {};
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
index 6779d42..19f79af 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
@@ -116,13 +116,14 @@
<button kc-cancel data-ng-click="cancel()">Cancel</button>
</div>
- <div class="col-md-10 col-md-offset-2" data-ng-show="!create && access.manageUsers">
- <button kc-save data-ng-show="changed">Save</button>
- <button kc-reset data-ng-show="changed">Cancel</button>
+ <div class="col-md-10 col-md-offset-2" data-ng-show="!create">
+ <button kc-save data-ng-show="access.manageUsers && changed">Save</button>
+ <button kc-reset data-ng-show="access.manageUsers && changed">Cancel</button>
+ <button data-ng-show="access.impersonation" class="btn btn-default" data-ng-click="impersonate()">Impersonate</button>
</div>
</div>
</form>
</div>
-<kc-menu></kc-menu>
+<kc-menu></kc-menu>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-list.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-list.html
index 9a042e3..dc2c4ac 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-list.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-list.html
@@ -5,7 +5,7 @@
<caption data-ng-show="users" class="hidden">Table of realm users</caption>
<thead>
<tr>
- <th colspan="4">
+ <th colspan="{{access.impersonation == true ? '5' : '4'}}">
<div class="form-inline">
<div class="form-group">
<div class="input-group">
@@ -17,7 +17,7 @@
</div>
<button class="btn btn-primary" ng-click="query.search = null; firstPage()">View all users</button>
- <div class="pull-right">
+ <div class="pull-right" data-ng-show="access.manageUsers">
<a class="btn btn-primary" href="#/create/user/{{realm.realm}}">Add User</a>
</div>
</div>
@@ -29,6 +29,7 @@
<th>Last Name</th>
<th>First Name</th>
<th>Email</th>
+ <th data-ng-show="access.impersonation"></th>
</tr>
</tr>
</thead>
@@ -49,6 +50,7 @@
<td>{{user.lastName}}</td>
<td>{{user.firstName}}</td>
<td>{{user.email}}</td>
+ <td data-ng-show="access.impersonation"><button class="btn btn-default" data-ng-click="impersonate(user.id)">Impersonate</button></td>
</tr>
<tr data-ng-show="!users || users.length == 0">
<td class="text-muted" data-ng-show="!users">Please enter a search, or click on view all users</td>
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java
index 734c472..4f49a17 100755
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java
@@ -1,7 +1,7 @@
package org.keycloak.migration.migrators;
import org.keycloak.migration.ModelVersion;
-import org.keycloak.models.ImpersonationServiceConstants;
+import org.keycloak.models.ImpersonationConstants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
@@ -23,7 +23,7 @@ public class MigrateTo1_4_0 {
DefaultAuthenticationFlows.addFlows(realm);
DefaultRequiredActions.addActions(realm);
}
- ImpersonationServiceConstants.setupImpersonationService(session, realm, session.getContext().getContextPath());
+ ImpersonationConstants.setupImpersonationService(session, realm);
}
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index b99c1c8..1aff2ed 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -9,7 +9,7 @@ import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.BrowserSecurityHeaders;
import org.keycloak.models.Constants;
-import org.keycloak.models.ImpersonationServiceConstants;
+import org.keycloak.models.ImpersonationConstants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
@@ -236,7 +236,7 @@ public class RealmManager {
}
public void setupImpersonationService(RealmModel realm) {
- ImpersonationServiceConstants.setupImpersonationService(session, realm, contextPath);
+ ImpersonationConstants.setupImpersonationService(session, realm);
}
public void setupBrokerService(RealmModel realm) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
index 39ef7c3..b0d4c72 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
@@ -56,7 +56,7 @@ public class AuthenticationManagementResource {
this.realm = realm;
this.session = session;
this.auth = auth;
- this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
+ this.auth.init(RealmAuth.Resource.REALM);
this.adminEvent = adminEvent;
}
@@ -140,6 +140,7 @@ public class AuthenticationManagementResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public List<AuthenticationFlowModel> getFlows() {
+ this.auth.requireView();
List<AuthenticationFlowModel> flows = new LinkedList<>();
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
if (flow.isTopLevel()) {
@@ -265,6 +266,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public AuthenticatorConfigModel getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id) {
+ this.auth.requireView();
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
if (config == null) {
throw new NotFoundException("Could not find authenticator config");
@@ -328,6 +330,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public List<RequiredActionProviderRepresentation> getRequiredActions() {
+ this.auth.requireView();
List<RequiredActionProviderRepresentation> list = new LinkedList<>();
for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
RequiredActionProviderRepresentation rep = toRepresentation(model);
@@ -351,6 +354,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) {
+ this.auth.requireView();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
if (model == null) {
throw new NotFoundException("Failed to find required action: " + alias);
@@ -363,6 +367,7 @@ public class AuthenticationManagementResource {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public void updateRequiredAction(@PathParam("alias") String alias, RequiredActionProviderRepresentation rep) {
+ this.auth.requireManage();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
if (model == null) {
throw new NotFoundException("Failed to find required action: " + alias);
@@ -381,6 +386,7 @@ public class AuthenticationManagementResource {
@Path("required-actions/{alias}")
@DELETE
public void updateRequiredAction(@PathParam("alias") String alias) {
+ this.auth.requireManage();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
if (model == null) {
throw new NotFoundException("Failed to find required action: " + alias);
@@ -434,6 +440,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public AuthenticatorConfigDescription getAuthenticatorConfigDescription(@PathParam("providerId") String providerId) {
+ this.auth.requireView();
ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(providerId);
if (factory == null) {
throw new NotFoundException("Could not find authenticator provider");
@@ -460,6 +467,7 @@ public class AuthenticationManagementResource {
@POST
@NoCache
public Response createAuthenticatorConfig(AuthenticatorConfigModel config) {
+ this.auth.requireManage();
config = realm.addAuthenticatorConfig(config);
return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
}
@@ -469,6 +477,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public AuthenticatorConfigModel getAuthenticatorConfig(@PathParam("id") String id) {
+ this.auth.requireView();
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
if (config == null) {
throw new NotFoundException("Could not find authenticator config");
@@ -480,6 +489,7 @@ public class AuthenticationManagementResource {
@DELETE
@NoCache
public void removeAuthenticatorConfig(@PathParam("id") String id) {
+ this.auth.requireManage();
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
if (config == null) {
throw new NotFoundException("Could not find authenticator config");
@@ -502,6 +512,7 @@ public class AuthenticationManagementResource {
@Consumes(MediaType.APPLICATION_JSON)
@NoCache
public void updateAuthenticatorConfig(@PathParam("id") String id, AuthenticatorConfigModel config) {
+ this.auth.requireManage();
AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id);
if (exists == null) {
throw new NotFoundException("Could not find authenticator config");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
index f93e8c7..fc778d0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
@@ -2,6 +2,7 @@ package org.keycloak.services.resources.admin;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.ImpersonationConstants;
import org.keycloak.services.ForbiddenException;
@@ -13,7 +14,7 @@ public class RealmAuth {
private Resource resource;
public enum Resource {
- CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER
+ CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION
}
private AdminAuth auth;
@@ -29,6 +30,10 @@ public class RealmAuth {
return this;
}
+ public AdminAuth getAuth() {
+ return auth;
+ }
+
public void requireAny() {
if (!auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
throw new ForbiddenException();
@@ -84,6 +89,8 @@ public class RealmAuth {
return AdminRoles.MANAGE_EVENTS;
case IDENTITY_PROVIDER:
return AdminRoles.MANAGE_IDENTITY_PROVIDERS;
+ case IMPERSONATION:
+ return ImpersonationConstants.IMPERSONATION_ROLE;
default:
throw new IllegalStateException();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index b6f1fb1..a56534d 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -61,6 +61,7 @@ import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.WebApplicationException;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -72,6 +73,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.services.managers.BruteForceProtector;
+import org.keycloak.services.resources.AccountService;
/**
* Base resource for managing users
@@ -276,6 +278,37 @@ public class UsersResource {
return rep;
}
+ @Path("{id}/impersonation")
+ @POST
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> impersonate(final @PathParam("id") String id) {
+ auth.init(RealmAuth.Resource.IMPERSONATION);
+ auth.requireManage();
+ UserModel user = session.users().getUserById(id, realm);
+ if (user == null) {
+ throw new NotFoundException("User not found");
+ }
+ RealmModel authenticatedRealm = auth.getAuth().getRealm();
+ // if same realm logout before impersonation
+ boolean sameRealm = false;
+ if (authenticatedRealm.getId().equals(realm.getId())) {
+ sameRealm = true;
+ UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.getAuth().getToken().getSessionState());
+ AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
+ AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
+ AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true);
+ }
+ UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
+ AuthenticationManager.createLoginCookie(realm, userSession.getUser(), userSession, uriInfo, clientConnection);
+ URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(realm.getName());
+ Map<String, Object> result = new HashMap<>();
+ result.put("sameRealm", sameRealm);
+ result.put("redirect", redirect.toString());
+ return result;
+ }
+
+
/**
* List set of sessions associated with this user.
*
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index a5fe083..ee91b43 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -148,22 +148,6 @@ public class RealmsResource {
return accountService;
}
- @Path("{realm}/impersonate")
- public ImpersonationService getImpersonationService(final @PathParam("realm") String name) {
- RealmModel realm = init(name);
-
- ClientModel client = realm.getClientNameMap().get(Constants.IMPERSONATION_SERVICE_CLIENT_ID);
- if (client == null || !client.isEnabled()) {
- logger.debug("impersonate service not enabled");
- throw new NotFoundException("impersonate service not enabled");
- }
-
- EventBuilder event = new EventBuilder(realm, session, clientConnection);
- ImpersonationService impersonateService = new ImpersonationService(realm, client, event);
- ResteasyProviderFactory.getInstance().injectProperties(impersonateService);
- return impersonateService;
- }
-
@Path("{realm}")
public PublicRealmResource getRealmResource(final @PathParam("realm") String name) {
RealmModel realm = init(name);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 1ea081f..95434c0 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -167,7 +167,7 @@ public class AccountTest {
});
}
- //@Test
+ @Test
public void ideTesting() throws Exception {
Thread.sleep(100000000);
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index 01a8ed9..c30ee36 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -42,7 +42,7 @@ public class ClientTest extends AbstractClientTest {
@Test
public void getClients() {
- assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "impersonation");
+ assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker");
}
private String createClient() {
@@ -59,7 +59,7 @@ public class ClientTest extends AbstractClientTest {
String id = createClient();
assertNotNull(realm.clients().get(id));
- assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app", "impersonation");
+ assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app");
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 0141166..86ca62e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -86,7 +86,7 @@ public class ImportTest extends AbstractModelTest {
Assert.assertEquals(0, session.users().getFederatedIdentities(user, realm).size());
List<ClientModel> resources = realm.getClients();
- Assert.assertEquals(8, resources.size());
+ Assert.assertEquals(7, resources.size());
// Test applications imported
ClientModel application = realm.getClientByClientId("Application");
@@ -97,7 +97,7 @@ public class ImportTest extends AbstractModelTest {
Assert.assertNotNull(otherApp);
Assert.assertNull(nonExisting);
Map<String, ClientModel> clients = realm.getClientNameMap();
- Assert.assertEquals(8, clients.size());
+ Assert.assertEquals(7, clients.size());
Assert.assertTrue(clients.values().contains(application));
Assert.assertTrue(clients.values().contains(otherApp));
Assert.assertTrue(clients.values().contains(accountApp));