Merge pull request #1057 from mposolda/master
KEYCLOAK-1108 Remove option for enable/disable login per app. Few other minor fixes
This commit is contained in:
commit
b8d5109744
18 changed files with 218 additions and 288 deletions
|
@ -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.
|
||||
|
@ -961,44 +988,6 @@ Authorization: Bearer {keycloak_access_token}]]></programlisting>
|
|||
</note>
|
||||
</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>
|
||||
|
|
|
@ -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 currentProvider = {};
|
||||
currentProvider.identityProvider = identityProvider;
|
||||
currentProvider.retrieveToken = "false";
|
||||
$scope.identityProviders.push(currentProvider);
|
||||
|
||||
var currentAppProvider = {};
|
||||
currentAppProvider.id = identityProvider.id;
|
||||
currentAppProvider.retrieveToken = "false";
|
||||
$scope.application.identityProviders.push(currentAppProvider);
|
||||
}
|
||||
|
||||
var oldCopy = angular.copy($scope.application);
|
||||
|
||||
$scope.save = function() {
|
||||
var selectedProviders = [];
|
||||
|
||||
for (i = 0; i < $scope.application.identityProviders.length; i++) {
|
||||
var appProvider = $scope.application.identityProviders[i];
|
||||
|
||||
if (appProvider.id != null && appProvider.id != false) {
|
||||
selectedProviders[selectedProviders.length] = appProvider;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.application.identityProviders = selectedProviders;
|
||||
|
||||
Application.update({
|
||||
realm : realm.realm,
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
@ -416,19 +416,6 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
return models;
|
||||
}
|
||||
|
||||
@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()) {
|
||||
|
|
|
@ -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
|
||||
|
@ -275,12 +275,6 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
return cachedClient.getIdentityProviders();
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
@ -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>();
|
||||
|
@ -377,17 +377,6 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
return models;
|
||||
}
|
||||
|
||||
@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()) {
|
||||
|
|
|
@ -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) {
|
||||
|
@ -442,19 +442,6 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
|
|||
return models;
|
||||
}
|
||||
|
||||
@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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue