broker token exchange refactor

This commit is contained in:
Bill Burke committed 2015-04-23 11:26:44 -04:00
1 parent f9b099d49d
commit 1f4df58e6c
43 files changed
+304 -585

No files matched your search

@@ -21,6 +21,7 @@ import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.resources.IdentityBrokerService;
import org.keycloak.timer.TimerProvider;
import java.util.Collections;
@@ -84,6 +85,7 @@ public class RealmManager {
setupMasterAdminManagement(realm);
setupRealmAdminManagement(realm);
setupAccountManagement(realm);
setupBrokerService(realm);
setupAdminConsole(realm);
return realm;
@@ -214,6 +216,19 @@ public class RealmManager {
}
}
public void setupBrokerService(RealmModel realm) {
ClientModel client = realm.getClientNameMap().get(Constants.BROKER_SERVICE_CLIENT_ID);
if (client == null) {
client = new ClientManager(this).createClient(realm, Constants.BROKER_SERVICE_CLIENT_ID);
client.setEnabled(true);
client.setFullScopeAllowed(false);
for (String role : IdentityBrokerService.ROLES) {
client.addRole(role).setDescription("${role_"+role+"}");
}
}
}
public RealmModel importRealm(RealmRepresentation rep) {
String id = rep.getId();
if (id == null) {
@@ -228,6 +243,7 @@ public class RealmManager {
setupMasterAdminManagement(realm);
if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
if (!hasBrokerClient(rep)) setupBrokerService(realm);
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
RepresentationToModel.importRealm(session, rep, realm);
@@ -260,6 +276,15 @@ public class RealmManager {
}
return false;
}
private boolean hasBrokerClient(RealmRepresentation rep) {
if (rep.getClients() == null) return false;
for (ClientRepresentation clientRep : rep.getClients()) {
if (clientRep.getClientId().equals(Constants.BROKER_SERVICE_CLIENT_ID)) {
return true;
}
}
return false;
}
private boolean hasAdminConsoleClient(RealmRepresentation rep) {
if (rep.getClients() == null) return false;
@@ -34,17 +34,20 @@ import org.keycloak.events.EventType;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.ProtocolMapper;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
@@ -92,6 +95,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
private static final Logger LOGGER = Logger.getLogger(IdentityBrokerService.class);
public static final String BROKER_PROVIDER_ID = "BROKER_PROVIDER_ID";
public static final String READ_TOKEN_ROLE = "READ_TOKEN";
public static final String[] ROLES = {READ_TOKEN_ROLE};
private final RealmModel realmModel;
@@ -185,7 +190,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
AuthResult authResult = authManager.authenticateBearerToken(this.session, this.realmModel, this.uriInfo, this.clientConnection, this.request.getHttpHeaders());
if (authResult != null) {
String audience = authResult.getToken().getAudience();
AccessToken token = authResult.getToken();
String audience = token.getAudience();
ClientModel clientModel = this.realmModel.getClientByClientId(audience);
if (clientModel == null) {
@@ -194,16 +200,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
session.getContext().setClient(clientModel);
if (!clientModel.isAllowedRetrieveTokenFromIdentityProvider(providerId)) {
return corsResponse(badRequest("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
ClientModel brokerClient = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID);
if (brokerClient == null) {
return corsResponse(forbidden("Realm has not migrated to support the broker token exchange service"), clientModel);
}
Map<String, AccessToken.Access> resourceAccess = token.getResourceAccess();
AccessToken.Access brokerRoles = resourceAccess == null ? null : resourceAccess.get(Constants.BROKER_SERVICE_CLIENT_ID);
if (brokerRoles == null || !brokerRoles.isUserInRole(READ_TOKEN_ROLE)) {
return corsResponse(forbidden("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
if (clientModel.isConsentRequired()) {
return corsResponse(session.getProvider(LoginFormsProvider.class)
.setClientSessionCode(authManager.extractAuthorizationHeaderToken(this.request.getHttpHeaders()))
.setAccessRequest("Your information from " + providerId + " identity provider.")
.setActionUri(this.uriInfo.getRequestUri())
.createOAuthGrant(null), clientModel);
}
IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
@@ -232,18 +238,6 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
}
@POST
@Path("{provider_id}/token")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response consentTokenRetrieval(@PathParam("provider_id") String providerId,
MultivaluedMap<String, String> formData) {
if (formData.containsKey("cancel")) {
return redirectToErrorPage(Messages.PERMISSION_NOT_APPROVED);
}
return getToken(providerId, true);
}
public Response authenticated(BrokeredIdentityContext context) {
ClientSessionCode clientCode = null;
IdentityProviderModel identityProviderConfig = context.getIdpConfig();
@@ -445,6 +439,11 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return ErrorResponse.error(message, Status.BAD_REQUEST);
}
private Response forbidden(String message) {
fireErrorEvent(message);
return ErrorResponse.error(message, Status.FORBIDDEN);
}
public static IdentityProvider getIdentityProvider(KeycloakSession session, RealmModel realm, String alias) {
IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(alias);
@@ -534,6 +533,13 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
federatedUser.setFirstName(updatedIdentity.getFirstName());
federatedUser.setLastName(updatedIdentity.getLastName());
if (updatedIdentity.getIdpConfig().isStoreToken()) {
RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(READ_TOKEN_ROLE);
federatedUser.grantRole(readTokenRole);
}
this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
updatedIdentity.getIdp().importNewUser(session, realmModel, federatedUser, updatedIdentity);
@@ -84,8 +84,6 @@ public class IdentityProviderResource {
public Response delete() {
this.auth.requireManage();
removeClientIdentityProviders(this.realm.getClients(), this.identityProviderModel);
this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias());
return Response.noContent().build();
@@ -109,7 +107,6 @@ public class IdentityProviderResource {
// 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.getClients(), oldProviderId, newProviderId);
updateUsersAfterProviderAliasChange(this.session.users().getUsers(this.realm), oldProviderId, newProviderId);
}
@@ -131,25 +128,6 @@ public class IdentityProviderResource {
return null;
}
private void updateClientsAfterProviderAliasChange(List<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);
@@ -285,18 +263,5 @@ public class IdentityProviderResource {
realm.removeIdentityProviderMapper(model);
}
private void removeClientIdentityProviders(List<ClientModel> clients, IdentityProviderModel identityProvider) {
for (ClientModel clientModel : clients) {
List<ClientIdentityProviderMappingModel> identityProviders = clientModel.getIdentityProviders();
for (ClientIdentityProviderMappingModel providerMappingModel : new ArrayList<>(identityProviders)) {
if (providerMappingModel.getIdentityProvider().equals(identityProvider.getAlias())) {
identityProviders.remove(providerMappingModel);
clientModel.updateIdentityProviders(identityProviders);
break;
}
}
}
}
}