keycloak-aplcache
Changes
forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js 56(+26 -30)
forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html 4(+0 -4)
forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java 27(+7 -20)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java 10(+2 -8)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java 22(+4 -18)
services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java 84(+74 -10)
services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java 16(+0 -16)
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java 93(+47 -46)
Details
diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml
index 673f00a..0ab53f0 100755
--- a/docbook/reference/en/en-US/modules/identity-broker.xml
+++ b/docbook/reference/en/en-US/modules/identity-broker.xml
@@ -954,6 +954,33 @@ Authorization: Bearer {keycloak_access_token}]]></programlisting>
In this case, given that you are accessing an protected service in Keycloak, you need to send the access token
issued by Keycloak during the user authentication.
</para>
+ <para>
+ By default, the Keycloak access token issued for the application can't be automatically used for retrieve thirdparty token. You will
+ need to enable this in admin console first:
+ <orderedlist>
+ <listitem>
+ <para>
+ Click 'Applications' on the left side menu.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Select an application from the list.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Click the 'Identity Provider' tab.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ From this page you can configure if an application is allowed to retrieve tokens from an specific identity provider. For that,
+ just click on the <emphasis>Can Retrieve Token</emphasis> button.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
<note>
<para>
If your application is not at the same origin as the authentication server, make sure you have properly configured CORS.
@@ -962,44 +989,6 @@ Authorization: Bearer {keycloak_access_token}]]></programlisting>
</section>
<section>
- <title>Configuring Identity Providers for Applications</title>
- <para>
- By default, all identity providers enabled for a particular realm are also available to all its applications.
- However, you can also specify which identity providers should be available when
- authenticating users for a particular application.
- </para>
- <para>
- For that, please follow these steps:
- </para>
- <orderedlist>
- <listitem>
- <para>
- Click 'Applications' on the left side menu.
- </para>
- </listitem>
- <listitem>
- <para>
- Select an application from the list.
- </para>
- </listitem>
- <listitem>
- <para>
- Click the 'Identity Provider' tab.
- </para>
- </listitem>
- <listitem>
- <para>
- Now you should be able to enable or disabled identity providers to the application by clicking on the Enable/Disable button.
- </para>
- </listitem>
- </orderedlist>
- <para>
- From this page you can also configure if an application is allowed to retrieve tokens from an specific identity provider. For that,
- just click on the <emphasis>Can Retrieve Token</emphasis> button.
- </para>
- </section>
-
- <section>
<title>Automatically Select and Identity Provider</title>
<para>
Applications can automatically select an identity provider in order to authenticate an user. In this case, the user will not be presented to the login page but automatically redirected to the identity provider.
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
index 5552bfa..2334c9b 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
@@ -56,35 +56,34 @@ module.controller('ApplicationIdentityProviderCtrl', function($scope, $location,
if ($scope.application.identityProviders) {
length = $scope.application.identityProviders.length;
- } else {
- $scope.application.identityProviders = new Array(realm.identityProviders.length);
- }
- for (j = length; j < realm.identityProviders.length; j++) {
- $scope.application.identityProviders[j] = {};
+ for (i = 0; i < $scope.application.identityProviders.length; i++) {
+ var applicationProvider = $scope.application.identityProviders[i];
+ if (applicationProvider.retrieveToken) {
+ applicationProvider.retrieveToken = applicationProvider.retrieveToken.toString();
+ }
+ }
+
+ } else {
+ $scope.application.identityProviders = [];
}
$scope.identityProviders = [];
+ var providersMissingInApp = [];
for (j = 0; j < realm.identityProviders.length; j++) {
var identityProvider = realm.identityProviders[j];
- var match = false;
- var applicationProvider;
+ var applicationProvider = null;
for (i = 0; i < $scope.application.identityProviders.length; i++) {
applicationProvider = $scope.application.identityProviders[i];
if (applicationProvider) {
- if (applicationProvider.retrieveToken) {
- applicationProvider.retrieveToken = applicationProvider.retrieveToken.toString();
- } else {
- applicationProvider.retrieveToken = false.toString();
- }
if (applicationProvider.id == identityProvider.id) {
$scope.identityProviders[i] = {};
$scope.identityProviders[i].identityProvider = identityProvider;
- $scope.identityProviders[i].retrieveToken = applicationProvider.retrieveToken.toString();
+ $scope.identityProviders[i].retrieveToken = applicationProvider.retrieveToken;
break;
}
@@ -93,30 +92,27 @@ module.controller('ApplicationIdentityProviderCtrl', function($scope, $location,
}
if (applicationProvider == null) {
- var length = $scope.identityProviders.length + $scope.application.identityProviders.length;
-
- $scope.identityProviders[length] = {};
- $scope.identityProviders[length].identityProvider = identityProvider;
- $scope.identityProviders[length].retrieveToken = false.toString();
+ providersMissingInApp.push(identityProvider);
}
}
- $scope.identityProviders = $scope.identityProviders.filter(function(n){ return n != undefined });
+ for (j = 0; j < providersMissingInApp.length; j++) {
+ var identityProvider = providersMissingInApp[j];
- var oldCopy = angular.copy($scope.application);
-
- $scope.save = function() {
- var selectedProviders = [];
+ var currentProvider = {};
+ currentProvider.identityProvider = identityProvider;
+ currentProvider.retrieveToken = "false";
+ $scope.identityProviders.push(currentProvider);
- for (i = 0; i < $scope.application.identityProviders.length; i++) {
- var appProvider = $scope.application.identityProviders[i];
+ var currentAppProvider = {};
+ currentAppProvider.id = identityProvider.id;
+ currentAppProvider.retrieveToken = "false";
+ $scope.application.identityProviders.push(currentAppProvider);
+ }
- if (appProvider.id != null && appProvider.id != false) {
- selectedProviders[selectedProviders.length] = appProvider;
- }
- }
+ var oldCopy = angular.copy($scope.application);
- $scope.application.identityProviders = selectedProviders;
+ $scope.save = function() {
Application.update({
realm : realm.realm,
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html
index aeb3b8d..f4473bf 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html
@@ -11,10 +11,6 @@
<form class="form-horizontal" name="identityProviderForm" novalidate>
<div class="form-group" ng-repeat="identityProvider in identityProviders">
<legend><span class="text">{{identityProvider.identityProvider.name}}</span></legend>
- <label class="col-sm-2 control-label" for="{{identityProvider.identityProvider.id}}">Enable <span tooltip-placement="right" tooltip="If disabled, users can not login to the application using this identity provider." class="fa fa-info-circle"></span></label>
- <div class="col-sm-4">
- <input ng-model="application.identityProviders[$index].id" name="identityProvider.identityProvider.id" id="identityProvider.identityProvider.id" value="identityProvider.identityProvider.id" onoffswitchmodel />
- </div>
<div data-ng-show="application.identityProviders[$index].id">
<label class="col-sm-2 control-label" for="{{identityProvider.identityProvider.id}}retrieveToken">Can Retrieve Token <span tooltip-placement="right" tooltip="If disabled, the application can not retrieve tokens from the identity provider." class="fa fa-info-circle"></span></label>
<div class="col-sm-4">
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login.ftl b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
index e514b9e..0dea114 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
@@ -63,14 +63,6 @@
</div>
</div>
</form>
- <#elseif realm.social>
- <div id="kc-social-providers">
- <ul>
- <#list social.providers as p>
- <li><a href="${p.loginUrl}" class="zocial ${p.id}"> <span class="text">${p.name}</span></a></li>
- </#list>
- </ul>
- </div>
</#if>
<#elseif section = "info" >
<#if realm.password && realm.registrationAllowed>
@@ -83,7 +75,7 @@
<div id="kc-social-providers">
<ul>
<#list social.providers as p>
- <li><a href="${p.loginUrl}" class="zocial ${p.id}"> <span class="text">${p.name}</span></a></li>
+ <li><a href="${p.loginUrl}" id="zocial-${p.id}" class="zocial ${p.providerId}"> <span class="text">${p.name}</span></a></li>
</#list>
</ul>
</div>
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
index 12a73ee..9cbf469 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
@@ -53,24 +53,6 @@ public class IdentityProviderBean {
for (IdentityProviderModel identityProvider : identityProviders) {
if (identityProvider.isEnabled()) {
- String clientId = uriInfo.getQueryParameters().getFirst(OAuth2Constants.CLIENT_ID);
-
- if (clientId != null) {
- ClientModel clientModel = realm.findClient(clientId);
-
- if (clientModel != null && !clientModel.hasIdentityProvider(identityProvider.getId())) {
- if (ApplicationModel.class.isInstance(clientModel)) {
- ApplicationModel applicationModel = (ApplicationModel) clientModel;
-
- if (applicationModel.getName().equals(Constants.ACCOUNT_MANAGEMENT_APP)) {
- addIdentityProvider(realm, baseURI, identityProvider);
- }
- }
-
- continue;
- }
- }
-
addIdentityProvider(realm, baseURI, identityProvider);
}
}
@@ -83,7 +65,7 @@ public class IdentityProviderBean {
private void addIdentityProvider(RealmModel realm, URI baseURI, IdentityProviderModel identityProvider) {
String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getId(), realm.getName()).toString();
- providers.add(new IdentityProvider(identityProvider.getId(), identityProvider.getName(), loginUrl));
+ providers.add(new IdentityProvider(identityProvider.getId(), identityProvider.getProviderId(), identityProvider.getName(), loginUrl));
}
public List<IdentityProvider> getProviders() {
@@ -97,11 +79,13 @@ public class IdentityProviderBean {
public static class IdentityProvider {
private final String id;
+ private final String providerId; // This refer to providerType (facebook, google, etc.)
private final String name;
private final String loginUrl;
- public IdentityProvider(String id, String name, String loginUrl) {
+ public IdentityProvider(String id, String providerId, String name, String loginUrl) {
this.id = id;
+ this.providerId = providerId;
if (name == null) {
name = id;
@@ -123,5 +107,8 @@ public class IdentityProviderBean {
return loginUrl;
}
+ public String getProviderId() {
+ return providerId;
+ }
}
}
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 5f66b7d..39e4d17 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -98,9 +98,8 @@ public interface ClientModel {
void setNotBefore(int notBefore);
- void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders);
+ void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders);
List<ClientIdentityProviderMappingModel> getIdentityProviders();
- boolean hasIdentityProvider(String providerId);
boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId);
Set<ProtocolMapperModel> getProtocolMappers();
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 c2090d3..afdd6aa 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
@@ -489,7 +489,7 @@ public class RepresentationToModel {
}
}
- applicationModel.updateAllowedIdentityProviders(toModel(resourceRep.getIdentityProviders(), realm));
+ applicationModel.updateIdentityProviders(toModel(resourceRep.getIdentityProviders(), realm));
return applicationModel;
}
@@ -538,7 +538,7 @@ public class RepresentationToModel {
}
}
- updateClientIdentityProvides(rep.getIdentityProviders(), resource);
+ updateClientIdentityProviders(rep.getIdentityProviders(), resource);
}
public static void setClaims(ClientModel model, ClaimRepresentation rep) {
@@ -613,7 +613,7 @@ public class RepresentationToModel {
public static OAuthClientModel createOAuthClient(OAuthClientRepresentation rep, RealmModel realm) {
OAuthClientModel model = createOAuthClient(rep.getId(), rep.getName(), realm);
- model.updateAllowedIdentityProviders(toModel(rep.getIdentityProviders(), realm));
+ model.updateIdentityProviders(toModel(rep.getIdentityProviders(), realm));
updateOAuthClient(rep, model);
return model;
@@ -653,7 +653,7 @@ public class RepresentationToModel {
}
}
- updateClientIdentityProvides(rep.getIdentityProviders(), model);
+ updateClientIdentityProviders(rep.getIdentityProviders(), model);
if (rep.getProtocolMappers() != null) {
// first, remove all default/built in mappers
@@ -818,35 +818,25 @@ public class RepresentationToModel {
}
private static List<ClientIdentityProviderMappingModel> toModel(List<ClientIdentityProviderMappingRepresentation> repIdentityProviders, RealmModel realm) {
- List<ClientIdentityProviderMappingModel> allowedIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
+ List<ClientIdentityProviderMappingModel> result = new ArrayList<ClientIdentityProviderMappingModel>();
- if (repIdentityProviders == null || repIdentityProviders.isEmpty()) {
- allowedIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
-
- for (IdentityProviderModel identityProvider : realm.getIdentityProviders()) {
- ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
-
- identityProviderMapping.setIdentityProvider(identityProvider.getId());
-
- allowedIdentityProviders.add(identityProviderMapping);
- }
- } else {
+ if (repIdentityProviders != null) {
for (ClientIdentityProviderMappingRepresentation rep : repIdentityProviders) {
ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
identityProviderMapping.setIdentityProvider(rep.getId());
identityProviderMapping.setRetrieveToken(rep.isRetrieveToken());
- allowedIdentityProviders.add(identityProviderMapping);
+ result.add(identityProviderMapping);
}
}
- return allowedIdentityProviders;
+ return result;
}
- private static void updateClientIdentityProvides(List<ClientIdentityProviderMappingRepresentation> identityProviders, ClientModel resource) {
+ private static void updateClientIdentityProviders(List<ClientIdentityProviderMappingRepresentation> identityProviders, ClientModel resource) {
if (identityProviders != null) {
- List<ClientIdentityProviderMappingModel> allowedIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
+ List<ClientIdentityProviderMappingModel> result = new ArrayList<ClientIdentityProviderMappingModel>();
for (ClientIdentityProviderMappingRepresentation mappingRepresentation : identityProviders) {
ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
@@ -854,10 +844,10 @@ public class RepresentationToModel {
identityProviderMapping.setIdentityProvider(mappingRepresentation.getId());
identityProviderMapping.setRetrieveToken(mappingRepresentation.isRetrieveToken());
- allowedIdentityProviders.add(identityProviderMapping);
+ result.add(identityProviderMapping);
}
- resource.updateAllowedIdentityProviders(allowedIdentityProviders);
+ resource.updateIdentityProviders(result);
}
}
}
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
index d5eda8e..c7ef8ad 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
@@ -386,7 +386,7 @@ public abstract class ClientAdapter implements ClientModel {
}
@Override
- public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
+ public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
List<ClientIdentityProviderMappingEntity> stored = new ArrayList<ClientIdentityProviderMappingEntity>();
for (ClientIdentityProviderMappingModel model : identityProviders) {
@@ -417,19 +417,6 @@ public abstract class ClientAdapter implements ClientModel {
}
@Override
- public boolean hasIdentityProvider(String providerId) {
- for (ClientIdentityProviderMappingEntity identityProviderMappingModel : clientEntity.getIdentityProviders()) {
- String identityProvider = identityProviderMappingModel.getId();
-
- if (identityProvider.equals(providerId)) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
for (ClientIdentityProviderMappingEntity identityProviderMappingModel : clientEntity.getIdentityProviders()) {
if (identityProviderMappingModel.getId().equals(providerId)) {
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
index c15059e..202be7b 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -264,9 +264,9 @@ public abstract class ClientAdapter implements ClientModel {
}
@Override
- public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
+ public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
getDelegateForUpdate();
- updatedClient.updateAllowedIdentityProviders(identityProviders);
+ updatedClient.updateIdentityProviders(identityProviders);
}
@Override
@@ -276,12 +276,6 @@ public abstract class ClientAdapter implements ClientModel {
}
@Override
- public boolean hasIdentityProvider(String providerId) {
- if (updatedClient != null) return updatedClient.hasIdentityProvider(providerId);
- return cachedClient.hasIdentityProvider(providerId);
- }
-
- @Override
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
if (updatedClient != null) return updatedClient.isAllowedRetrieveTokenFromIdentityProvider(providerId);
return cachedClient.isAllowedRetrieveTokenFromIdentityProvider(providerId);
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 52fe965..1d2cb05 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -307,7 +307,7 @@ public abstract class ClientAdapter implements ClientModel {
}
@Override
- public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
+ public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
Collection<ClientIdentityProviderMappingEntity> entities = entity.getIdentityProviders();
Set<String> already = new HashSet<String>();
List<ClientIdentityProviderMappingEntity> remove = new ArrayList<ClientIdentityProviderMappingEntity>();
@@ -378,17 +378,6 @@ public abstract class ClientAdapter implements ClientModel {
}
@Override
- public boolean hasIdentityProvider(String providerId) {
- for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
- if (model.getIdentityProvider().equals(providerId)) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
if (model.getIdentityProvider().equals(providerId)) {
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index f52e9ef..ea97d65 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -411,7 +411,7 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
@Override
- public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
+ public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
List<ClientIdentityProviderMappingEntity> stored = new ArrayList<ClientIdentityProviderMappingEntity>();
for (ClientIdentityProviderMappingModel model : identityProviders) {
@@ -443,19 +443,6 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
}
@Override
- public boolean hasIdentityProvider(String providerId) {
- for (ClientIdentityProviderMappingEntity identityProviderMappingModel : getMongoEntityAsClient().getIdentityProviders()) {
- String identityProvider = identityProviderMappingModel.getId();
-
- if (identityProvider.equals(providerId)) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
for (ClientIdentityProviderMappingEntity identityProviderMappingModel : getMongoEntityAsClient().getIdentityProviders()) {
if (identityProviderMappingModel.getId().equals(providerId)) {
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
index bd41eff..bcae24d 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
@@ -230,26 +230,12 @@ public class MongoUserProvider implements UserProvider {
return result;
}
- private FederatedIdentityEntity findSocialLink(UserModel userModel, String socialProvider, RealmModel realm) {
- UserModel user = getUserById(userModel.getId(), realm);
- MongoUserEntity userEntity = ((UserAdapter) user).getUser();
- List<FederatedIdentityEntity> linkEntities = userEntity.getFederatedIdentities();
- if (linkEntities == null) {
- return null;
- }
-
- for (FederatedIdentityEntity federatedIdentityEntity : linkEntities) {
- if (federatedIdentityEntity.getIdentityProvider().equals(socialProvider)) {
- return federatedIdentityEntity;
- }
- }
- return null;
- }
-
-
@Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
- FederatedIdentityEntity federatedIdentityEntity = findSocialLink(user, socialProvider, realm);
+ user = getUserById(user.getId(), realm);
+ MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+ FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, socialProvider);
+
return federatedIdentityEntity != null ? new FederatedIdentityModel(federatedIdentityEntity.getIdentityProvider(), federatedIdentityEntity.getUserId(),
federatedIdentityEntity.getUserName(), federatedIdentityEntity.getToken()) : null;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index e8ec27e..400fba4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -1,15 +1,17 @@
package org.keycloak.services.resources.admin;
+import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
-import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.models.ClientIdentityProviderMappingModel;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.provider.ProviderFactory;
@@ -22,22 +24,21 @@ import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* @author Pedro Igor
*/
public class IdentityProviderResource {
+ private static Logger logger = Logger.getLogger(IdentityProviderResource.class);
+
private final RealmAuth auth;
private final RealmModel realm;
private final KeycloakSession session;
@@ -62,23 +63,86 @@ public class IdentityProviderResource {
public Response delete() {
this.auth.requireManage();
removeClientIdentityProviders(this.realm.getApplications(), this.identityProviderModel);
- removeClientIdentityProviders(this.realm.getApplications(), this.identityProviderModel);
+ removeClientIdentityProviders(this.realm.getOAuthClients(), this.identityProviderModel);
this.realm.removeIdentityProviderById(this.identityProviderModel.getId());
return Response.noContent().build();
}
@PUT
@Consumes("application/json")
- public Response update(IdentityProviderRepresentation model) {
+ public Response update(IdentityProviderRepresentation providerRep) {
try {
this.auth.requireManage();
- this.realm.updateIdentityProvider(RepresentationToModel.toModel(model));
+
+ String internalId = providerRep.getInternalId();
+ String newProviderId = providerRep.getId();
+ String oldProviderId = getProviderIdByInternalId(this.realm, internalId);
+
+ this.realm.updateIdentityProvider(RepresentationToModel.toModel(providerRep));
+
+ if (oldProviderId != null && !oldProviderId.equals(newProviderId)) {
+
+ // Admin changed the ID (alias) of identity provider. We must update all clients and users
+ logger.debug("Changing providerId in all clients and linked users. oldProviderId=" + oldProviderId + ", newProviderId=" + newProviderId);
+
+ updateClientsAfterProviderAliasChange(this.realm.getApplications(), oldProviderId, newProviderId);
+ updateClientsAfterProviderAliasChange(this.realm.getOAuthClients(), oldProviderId, newProviderId);
+ updateUsersAfterProviderAliasChange(this.session.users().getUsers(this.realm), oldProviderId, newProviderId);
+ }
+
return Response.noContent().build();
} catch (ModelDuplicateException e) {
- return Flows.errors().exists("Identity Provider " + model.getId() + " already exists");
+ return Flows.errors().exists("Identity Provider " + providerRep.getId() + " already exists");
}
}
+ // return ID of IdentityProvider from realm based on internalId of this provider
+ private String getProviderIdByInternalId(RealmModel realm, String providerInternalId) {
+ List<IdentityProviderModel> providerModels = realm.getIdentityProviders();
+ for (IdentityProviderModel providerModel : providerModels) {
+ if (providerModel.getInternalId().equals(providerInternalId)) {
+ return providerModel.getId();
+ }
+ }
+
+ return null;
+ }
+
+ private void updateClientsAfterProviderAliasChange(List<? extends ClientModel> clients, String oldProviderId, String newProviderId) {
+ for (ClientModel client : clients) {
+ List<ClientIdentityProviderMappingModel> clientIdentityProviders = client.getIdentityProviders();
+ boolean found = true;
+
+ for (ClientIdentityProviderMappingModel mappingModel : clientIdentityProviders) {
+ if (mappingModel.getIdentityProvider().equals(oldProviderId)) {
+ mappingModel.setIdentityProvider(newProviderId);
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ client.updateIdentityProviders(clientIdentityProviders);
+ }
+ }
+ }
+
+ private void updateUsersAfterProviderAliasChange(List<UserModel> users, String oldProviderId, String newProviderId) {
+ for (UserModel user : users) {
+ FederatedIdentityModel federatedIdentity = this.session.users().getFederatedIdentity(user, oldProviderId, this.realm);
+ if (federatedIdentity != null) {
+ // Remove old link first
+ this.session.users().removeFederatedIdentity(this.realm, user, oldProviderId);
+
+ // And create new
+ FederatedIdentityModel newFederatedIdentity = new FederatedIdentityModel(newProviderId, federatedIdentity.getUserId(), federatedIdentity.getUserName(),
+ federatedIdentity.getToken());
+ this.session.users().addFederatedIdentity(this.realm, user, newFederatedIdentity);
+ }
+ }
+ }
+
+
private IdentityProviderFactory getIdentityProviderFactory() {
List<ProviderFactory> allProviders = new ArrayList<ProviderFactory>();
@@ -113,10 +177,10 @@ public class IdentityProviderResource {
for (ClientIdentityProviderMappingModel providerMappingModel : new ArrayList<ClientIdentityProviderMappingModel>(identityProviders)) {
if (providerMappingModel.getIdentityProvider().equals(identityProvider.getId())) {
identityProviders.remove(providerMappingModel);
+ clientModel.updateIdentityProviders(identityProviders);
+ break;
}
}
-
- clientModel.updateAllowedIdentityProviders(identityProviders);
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index b59ea60..b2d4ebf 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -94,9 +94,6 @@ public class IdentityProvidersResource {
try {
this.realm.addIdentityProvider(RepresentationToModel.toModel(representation));
- updateClientIdentityProviders(this.realm.getApplications(), representation);
- updateClientIdentityProviders(this.realm.getOAuthClients(), representation);
-
return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("Identity Provider " + representation.getId() + " already exists");
@@ -220,17 +217,4 @@ public class IdentityProvidersResource {
return allProviders;
}
-
- private void updateClientIdentityProviders(List<? extends ClientModel> clients, IdentityProviderRepresentation identityProvider) {
- for (ClientModel clientModel : clients) {
- List<ClientIdentityProviderMappingModel> allowedIdentityProviders = clientModel.getIdentityProviders();
- ClientIdentityProviderMappingModel providerMappingModel = new ClientIdentityProviderMappingModel();
-
- providerMappingModel.setIdentityProvider(identityProvider.getId());
-
- allowedIdentityProviders.add(providerMappingModel);
-
- clientModel.updateAllowedIdentityProviders(allowedIdentityProviders);
- }
- }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 4666ff4..2b3402b 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -182,10 +182,6 @@ public class IdentityBrokerService {
return badRequest("Invalid client.");
}
- if (!clientModel.hasIdentityProvider(providerId)) {
- return corsResponse(badRequest("Client [" + audience + "] not authorized."), clientModel);
- }
-
if (!clientModel.isAllowedRetrieveTokenFromIdentityProvider(providerId)) {
return corsResponse(badRequest("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
}
@@ -399,16 +395,16 @@ public class IdentityBrokerService {
if (clientSession != null) {
ClientModel client = clientSession.getClient();
- if (client != null) {
- LOGGER.debugf("Got authorization code from client [%s].", client.getClientId());
- this.event.client(client);
+ if (client == null) {
+ throw new IdentityBrokerException("Invalid client");
}
+ LOGGER.debugf("Got authorization code from client [%s].", client.getClientId());
+ this.event.client(client);
+
if (clientSession.getUserSession() != null) {
this.event.session(clientSession.getUserSession());
}
- } else {
- validateClientPermissions(clientCode, providerId);
}
if (isDebugEnabled()) {
@@ -509,19 +505,6 @@ public class IdentityBrokerService {
throw new IdentityBrokerException("Configuration for identity provider [" + providerId + "] not found.");
}
- private void validateClientPermissions(ClientSessionCode clientSessionCode, String providerId) {
- ClientSessionModel clientSession = clientSessionCode.getClientSession();
- ClientModel clientModel = clientSession.getClient();
-
- if (clientModel == null) {
- throw new IdentityBrokerException("Invalid client.");
- }
-
- if (!clientModel.hasIdentityProvider(providerId)) {
- throw new IdentityBrokerException("Client [" + clientModel.getClientId() + "] not authorized to authenticate with identity provider [" + providerId + "].");
- }
- }
-
private UserModel createUser(FederatedIdentity updatedIdentity) {
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(updatedIdentity.getIdentityProviderId(), updatedIdentity.getId(),
updatedIdentity.getUsername(), updatedIdentity.getToken());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index 5b66f7f..d20309a 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -62,6 +62,7 @@ import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URI;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -226,41 +227,31 @@ public abstract class AbstractIdentityProviderTest {
}
@Test
- public void testDisabledForApplication() {
+ public void testProviderOnLoginPage() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
RealmModel realm = getRealm();
ApplicationModel applicationModel = realm.getApplicationByName("test-app");
- List<ClientIdentityProviderMappingModel> allowedIdentityProviders = applicationModel.getIdentityProviders();
- ClientIdentityProviderMappingModel mapping = null;
- for (ClientIdentityProviderMappingModel model : allowedIdentityProviders) {
- if (model.getIdentityProvider().equals(identityProviderModel.getId())) {
- mapping = model;
- }
- }
-
- assertNotNull(mapping);
-
- allowedIdentityProviders.remove(mapping);
+ // This client doesn't have any specific identity providers settings
+ ClientModel client2 = realm.findClient("test-app");
+ assertEquals(0, client2.getIdentityProviders().size());
+ // Provider button is available on login page
this.driver.navigate().to("http://localhost:8081/test-app/");
-
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
+ loginPage.findSocialButton(getProviderId());
- try {
- this.driver.findElement(By.className(getProviderId()));
- fail("Provider [" + getProviderId() + "] not disabled.");
- } catch (NoSuchElementException nsee) {
-
- }
-
- allowedIdentityProviders.add(mapping);
-
- applicationModel.updateAllowedIdentityProviders(allowedIdentityProviders);
+ // Add identityProvider to client model
+ List<ClientIdentityProviderMappingModel> appIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
+ ClientIdentityProviderMappingModel mapping = new ClientIdentityProviderMappingModel();
+ mapping.setIdentityProvider(getProviderId());
+ mapping.setRetrieveToken(true);
+ appIdentityProviders.add(mapping);
+ applicationModel.updateIdentityProviders(appIdentityProviders);
+ // Provider button still available on login page
this.driver.navigate().to("http://localhost:8081/test-app/");
-
- this.driver.findElement(By.className(getProviderId()));
+ loginPage.findSocialButton(getProviderId());
}
@Test
@@ -398,17 +389,7 @@ public abstract class AbstractIdentityProviderTest {
assertNotNull(identityModel.getToken());
- ClientModel clientModel = realm.findClient("test-app");
- ClientIdentityProviderMappingModel providerMappingModel = null;
-
- for (ClientIdentityProviderMappingModel identityProviderMappingModel : clientModel.getIdentityProviders()) {
- if (identityProviderMappingModel.getIdentityProvider().equals(getProviderId())) {
- providerMappingModel = identityProviderMappingModel;
- break;
- }
- }
-
- providerMappingModel.setRetrieveToken(false);
+ configureRetrieveToken(realm.findClient("test-app"), getProviderId(), false);
UserSessionStatus userSessionStatus = retrieveSessionStatus();
String accessToken = userSessionStatus.getAccessTokenString();
@@ -426,7 +407,7 @@ public abstract class AbstractIdentityProviderTest {
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- providerMappingModel.setRetrieveToken(true);
+ configureRetrieveToken(getRealm().findClient("test-app"), getProviderId(), true);
client = ClientBuilder.newBuilder().register(authFilter).build();
tokenEndpoint = client.target(tokenEndpointUrl);
@@ -477,16 +458,9 @@ public abstract class AbstractIdentityProviderTest {
assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.CODE));
ClientModel clientModel = getRealm().findClient("third-party");
- ClientIdentityProviderMappingModel providerMappingModel = null;
+ assertEquals(0, clientModel.getIdentityProviders().size());
- for (ClientIdentityProviderMappingModel identityProviderMappingModel : clientModel.getIdentityProviders()) {
- if (identityProviderMappingModel.getIdentityProvider().equals(getProviderId())) {
- providerMappingModel = identityProviderMappingModel;
- break;
- }
- }
-
- providerMappingModel.setRetrieveToken(true);
+ configureRetrieveToken(clientModel, getProviderId(), true);
AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get(OAuth2Constants.CODE), "password");
URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), getRealm().getName());
@@ -505,6 +479,33 @@ public abstract class AbstractIdentityProviderTest {
doAssertTokenRetrieval(driver.getPageSource());
}
+ private void configureRetrieveToken(ClientModel clientModel, String providerId, boolean retrieveToken) {
+ List<ClientIdentityProviderMappingModel> providerMappingModels = clientModel.getIdentityProviders();
+ ClientIdentityProviderMappingModel providerMappingModel = null;
+
+ // Check if provider is already linked with this client
+ for (ClientIdentityProviderMappingModel current : providerMappingModels) {
+ if (current.getIdentityProvider().equals(providerId)) {
+ providerMappingModel = current;
+ break;
+ }
+ }
+
+ // Link provider with client if not linked yet
+ if (providerMappingModel == null) {
+ providerMappingModel = new ClientIdentityProviderMappingModel();
+ providerMappingModel.setIdentityProvider(providerId);
+ providerMappingModels.add(providerMappingModel);
+ }
+
+ providerMappingModel.setRetrieveToken(retrieveToken);
+
+ clientModel.updateIdentityProviders(providerMappingModels);
+
+ brokerServerRule.stopSession(session, true);
+ session = brokerServerRule.startSession();
+ }
+
protected abstract void doAssertTokenRetrieval(String pageSource);
private void assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
index fe4febd..3906666 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
@@ -133,7 +133,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
identityProviders.remove(identityProviderMappingModel);
- client.updateAllowedIdentityProviders(identityProviders);
+ client.updateIdentityProviders(identityProviders);
client = realm.findClientById(client.getId());
identityProviders = client.getIdentityProviders();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
index fc83347..7d83b0c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
@@ -110,8 +110,14 @@ public class LoginPage extends AbstractPage {
registerLink.click();
}
- public void clickSocial(String id) {
- driver.findElement(By.className(id)).click();
+ public void clickSocial(String providerId) {
+ WebElement socialButton = findSocialButton(providerId);
+ socialButton.click();
+ }
+
+ public WebElement findSocialButton(String providerId) {
+ String id = "zocial-" + providerId;
+ return this.driver.findElement(By.id(id));
}
public void resetPassword() {