broker token exchange refactor
This commit is contained in:
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);
|
||||
|
||||
-35
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user