diff --git a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index 26bcdf6..e7661cd 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -33,6 +33,7 @@ public class UserRepresentation {
protected String self; // link
protected String id;
+ protected String origin;
protected Long createdTimestamp;
protected String username;
protected Boolean enabled;
@@ -240,4 +241,17 @@ public class UserRepresentation {
public void setGroups(List<String> groups) {
this.groups = groups;
}
+
+ /**
+ * Returns id of UserStorageProvider that loaded this user
+ *
+ * @return NULL if user stored locally
+ */
+ public String getOrigin() {
+ return origin;
+ }
+
+ public void setOrigin(String origin) {
+ this.origin = origin;
+ }
}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index ef8828c..5a18a6e 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -87,6 +87,7 @@ import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentatio
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.storage.StorageId;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
@@ -178,6 +179,8 @@ public class ModelToRepresentation {
public static UserRepresentation toRepresentation(KeycloakSession session, RealmModel realm, UserModel user) {
UserRepresentation rep = new UserRepresentation();
rep.setId(user.getId());
+ String providerId = StorageId.resolveProviderId(user);
+ rep.setOrigin(providerId);
rep.setUsername(user.getUsername());
rep.setCreatedTimestamp(user.getCreatedTimestamp());
rep.setLastName(user.getLastName());
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 313db82..27cb790 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -1204,5 +1204,6 @@ userStorage.cachePolicy.evictionMinute=Eviction Minute
userStorage.cachePolicy.evictionMinute.tooltip=Minute of day the entry will become invalid on.
userStorage.cachePolicy.maxLifespan=Max Lifespan
userStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of a user cache entry in milliseconds.
+user-origin-link=Storage Origin
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index 9ffe627..1e7eb29 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -335,6 +335,7 @@ module.controller('UserTabCtrl', function($scope, $location, Dialog, Notificatio
});
module.controller('UserDetailCtrl', function($scope, realm, user, BruteForceUser, User,
+ Components,
UserFederationInstances, UserImpersonation, RequiredActions,
$location, Dialog, Notifications) {
$scope.realm = realm;
@@ -362,13 +363,29 @@ module.controller('UserDetailCtrl', function($scope, realm, user, BruteForceUser
};
if(user.federationLink) {
console.log("federationLink is not null");
- UserFederationInstances.get({realm : realm.realm, instance: user.federationLink}, function(link) {
- $scope.federationLinkName = link.displayName;
- $scope.federationLink = "#/realms/" + realm.realm + "/user-federation/providers/" + link.providerName + "/" + link.id;
- })
+ if (user.federationLink.startsWith('f:')) {
+ Components.get({realm: realm.realm, componentId: user.federationLink}, function (link) {
+ $scope.federationLinkName = link.name;
+ $scope.federationLink = "#/realms/" + realm.realm + "/user-storage/providers/" + link.providerId + "/" + link.id;
+ });
+ } else {
+ UserFederationInstances.get({realm: realm.realm, instance: user.federationLink}, function (link) {
+ $scope.federationLinkName = link.displayName;
+ $scope.federationLink = "#/realms/" + realm.realm + "/user-federation/providers/" + link.providerName + "/" + link.id;
+ });
+ }
+
} else {
console.log("federationLink is null");
}
+ if(user.origin) {
+ Components.get({realm: realm.realm, componentId: user.origin}, function (link) {
+ $scope.originName = link.name;
+ $scope.originLink = "#/realms/" + realm.realm + "/user-storage/providers/" + link.providerId + "/" + link.id;
+ })
+ } else {
+ console.log("origin is null");
+ }
console.log('realm brute force? ' + realm.bruteForceProtected)
$scope.temporarilyDisabled = false;
var isDisabled = function () {
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
index c06e5b5..17eb4f9 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
@@ -82,6 +82,12 @@
<a href="{{federationLink}}">{{federationLinkName}}</a>
</div>
</div>
+ <div class="form-group clearfix block" data-ng-show="!create && user.origin">
+ <label class="col-md-2 control-label">{{:: 'user-origin-link' | translate}}</label>
+ <div class="col-md-6">
+ <a href="{{originLink}}">{{originName}}</a>
+ </div>
+ </div>
<div class="form-group clearfix block">
<label class="col-md-2 control-label" for="emailVerified">{{:: 'email-verified' | translate}}</label>
<div class="col-md-6">