diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java index ac118e47ae..0ffb980922 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java @@ -144,7 +144,7 @@ public class ClientRepresentation { this.consentRequired = consentRequired; } - public Boolean getDirectGrantsOnly() { + public Boolean isDirectGrantsOnly() { return directGrantsOnly; } diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js index e75628d79b..37a744343f 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js @@ -792,7 +792,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, serverInfo $scope.client.attributes['saml.signature.algorithm'] = $scope.signatureAlgorithm; $scope.client.attributes['saml_name_id_format'] = $scope.nameIdFormat; - if ($scope.client.protocol != 'saml' && !$scope.client.bearerOnly && (!$scope.client.redirectUris || $scope.client.redirectUris.length == 0)) { + if ($scope.client.protocol != 'saml' && !$scope.client.bearerOnly && !$scope.client.directGrantsOnly && (!$scope.client.redirectUris || $scope.client.redirectUris.length == 0)) { Notifications.error("You must specify at least one redirect uri"); } else { if ($scope.create) { 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 54b3eef8c8..c30a68e892 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 @@ -871,7 +871,11 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload }; $scope.cancel = function() { - $route.reload(); + if ($scope.newIdentityProvider) { + $location.url("/realms/" + realm.realm + "/identity-provider-settings"); + } else { + $route.reload(); + } }; 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 efc33b8556..29ef06908c 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 @@ -384,7 +384,7 @@ module.controller('UserFederationCtrl', function($scope, $location, realm, UserF }); -module.controller('GenericUserFederationCtrl', function($scope, $location, Notifications, Dialog, realm, instance, providerFactory, UserFederationInstances, UserFederationSync) { +module.controller('GenericUserFederationCtrl', function($scope, $location, Notifications, $route, Dialog, realm, instance, providerFactory, UserFederationInstances, UserFederationSync) { console.log('GenericUserFederationCtrl'); $scope.create = !instance.providerName; @@ -453,9 +453,13 @@ module.controller('GenericUserFederationCtrl', function($scope, $location, Notif $scope.save = function() { $scope.changed = false; if ($scope.create) { - UserFederationInstances.save({realm: realm.realm}, $scope.instance, function () { + UserFederationInstances.save({realm: realm.realm}, $scope.instance, function (data, headers) { $scope.changed = false; - $location.url("/realms/" + realm.realm + "/user-federation"); + + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/user-federation/providers/" + $scope.instance.providerName + "/" + id); Notifications.success("The provider has been created."); }); } else { @@ -463,11 +467,9 @@ module.controller('GenericUserFederationCtrl', function($scope, $location, Notif instance: instance.id }, $scope.instance, function () { - $scope.changed = false; - $location.url("/realms/" + realm.realm + "/user-federation"); + $route.reload(); Notifications.success("The provider has been updated."); }); - } }; diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html index a246ba3748..f3b4739272 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html @@ -158,7 +158,7 @@ The name ID format to use for the subject. -
+
@@ -204,7 +204,7 @@ If configured, this URL will be used for every binding to both the SP's Assertion Consumer and Single Logout Services. This can be individually overiden for each binding and service in the Fine Grain SAML Endpoint Configuration.
- +
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-list.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-list.html index b5d3cfd370..782c782732 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-list.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-list.html @@ -19,8 +19,8 @@
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html index df581742c8..59b5b889f2 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html @@ -92,9 +92,12 @@
-
- - +
+
+ + + +
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html index 584d4d4998..9314e7abd8 100644 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html @@ -4,5 +4,5 @@
  • Role Mappings
  • Consents
  • Sessions
  • -
  • Federated Identities
  • +
  • Identity Provider Links
  • \ No newline at end of file diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 1da1fcf9b9..32f4e8942b 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -238,6 +238,7 @@ public class ModelToRepresentation { rep.setFullScopeAllowed(clientModel.isFullScopeAllowed()); rep.setBearerOnly(clientModel.isBearerOnly()); rep.setConsentRequired(clientModel.isConsentRequired()); + rep.setDirectGrantsOnly(clientModel.isDirectGrantsOnly()); rep.setSurrogateAuthRequired(clientModel.isSurrogateAuthRequired()); rep.setBaseUrl(clientModel.getBaseUrl()); rep.setNotBefore(clientModel.getNotBefore()); diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index d39356d844..a80e582d9c 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -531,6 +531,7 @@ public class RepresentationToModel { if (resourceRep.getBaseUrl() != null) client.setBaseUrl(resourceRep.getBaseUrl()); if (resourceRep.isBearerOnly() != null) client.setBearerOnly(resourceRep.isBearerOnly()); if (resourceRep.isConsentRequired() != null) client.setConsentRequired(resourceRep.isConsentRequired()); + if (resourceRep.isDirectGrantsOnly() != null) client.setDirectGrantsOnly(resourceRep.isDirectGrantsOnly()); if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient()); if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout()); if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol()); @@ -619,6 +620,7 @@ public class RepresentationToModel { if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled()); if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly()); if (rep.isConsentRequired() != null) resource.setConsentRequired(rep.isConsentRequired()); + if (rep.isDirectGrantsOnly() != null) resource.setDirectGrantsOnly(rep.isDirectGrantsOnly()); if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient()); if (rep.isFullScopeAllowed() != null) resource.setFullScopeAllowed(rep.isFullScopeAllowed()); if (rep.isFrontchannelLogout() != null) resource.setFrontchannelLogout(rep.isFrontchannelLogout()); 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 666c1daca6..ee9dc90dc0 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 @@ -59,6 +59,7 @@ import javax.ws.rs.core.UriInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -217,7 +218,20 @@ public class UsersResource { throw new NotFoundException("User not found"); } - return ModelToRepresentation.toRepresentation(user); + UserRepresentation rep = ModelToRepresentation.toRepresentation(user); + + if (realm.isIdentityFederationEnabled()) { + Set identities = session.users().getFederatedIdentities(user, realm); + if (!identities.isEmpty()) { + List reps = new LinkedList<>(); + for (FederatedIdentityModel m : identities) { + reps.add(ModelToRepresentation.toRepresentation(m)); + } + rep.setFederatedIdentities(reps); + } + } + + return rep; } /** diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json index a3f508a86a..277a708e5b 100755 --- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json +++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json @@ -43,7 +43,7 @@ "theme": { "default": "keycloak", - "staticMaxAge": 2592000, + "staticMaxAge": "${keycloak.theme.staticMaxAge:2592000}", "cacheTemplates": "${keycloak.theme.cacheTemplates:true}", "cacheThemes": "${keycloak.theme.cacheThemes:true}", "folder": {