Do not manage brokers through the Organization API
Closes #29268 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
2172741eb6
commit
c0325c9fdb
10 changed files with 323 additions and 149 deletions
|
@ -17,10 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
import jakarta.ws.rs.Consumes;
|
|
||||||
import jakarta.ws.rs.DELETE;
|
import jakarta.ws.rs.DELETE;
|
||||||
import jakarta.ws.rs.GET;
|
import jakarta.ws.rs.GET;
|
||||||
import jakarta.ws.rs.PUT;
|
|
||||||
import jakarta.ws.rs.Produces;
|
import jakarta.ws.rs.Produces;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
@ -32,10 +30,6 @@ public interface OrganizationIdentityProviderResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
IdentityProviderRepresentation toRepresentation();
|
IdentityProviderRepresentation toRepresentation();
|
||||||
|
|
||||||
@PUT
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
Response update(IdentityProviderRepresentation idpRepresentation);
|
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
Response delete();
|
Response delete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public interface OrganizationIdentityProvidersResource {
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
Response create(IdentityProviderRepresentation idpRepresentation);
|
Response addIdentityProvider(String id);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
|
|
@ -100,7 +100,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
||||||
//TODO: won't scale, requires a better mechanism for bulk deleting users
|
//TODO: won't scale, requires a better mechanism for bulk deleting users
|
||||||
userProvider.getGroupMembersStream(realm, group).forEach(userModel -> removeMember(organization, userModel));
|
userProvider.getGroupMembersStream(realm, group).forEach(userModel -> removeMember(organization, userModel));
|
||||||
groupProvider.removeGroup(realm, group);
|
groupProvider.removeGroup(realm, group);
|
||||||
organization.getIdentityProviders().forEach((model) -> realm.removeIdentityProviderByAlias(model.getAlias()));
|
organization.getIdentityProviders().forEach((model) -> removeIdentityProvider(organization, model));
|
||||||
|
|
||||||
em.remove(entity);
|
em.remove(entity);
|
||||||
|
|
||||||
|
@ -216,6 +216,13 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
||||||
throwExceptionIfObjectIsNull(identityProvider, "Identity provider");
|
throwExceptionIfObjectIsNull(identityProvider, "Identity provider");
|
||||||
|
|
||||||
OrganizationEntity organizationEntity = getEntity(organization.getId());
|
OrganizationEntity organizationEntity = getEntity(organization.getId());
|
||||||
|
String orgId = identityProvider.getOrganizationId();
|
||||||
|
|
||||||
|
if (organizationEntity.getId().equals(orgId)) {
|
||||||
|
return false;
|
||||||
|
} else if (orgId != null) {
|
||||||
|
throw new ModelValidationException("Identity provider already associated with a different organization");
|
||||||
|
}
|
||||||
|
|
||||||
identityProvider.setOrganizationId(organizationEntity.getId());
|
identityProvider.setOrganizationId(organizationEntity.getId());
|
||||||
realm.updateIdentityProvider(identityProvider);
|
realm.updateIdentityProvider(identityProvider);
|
||||||
|
@ -243,7 +250,8 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
realm.removeIdentityProviderByAlias(identityProvider.getAlias());
|
identityProvider.setOrganizationId(null);
|
||||||
|
realm.updateIdentityProvider(identityProvider);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ import org.keycloak.client.clienttype.ClientType;
|
||||||
import org.keycloak.client.clienttype.ClientTypeException;
|
import org.keycloak.client.clienttype.ClientTypeException;
|
||||||
import org.keycloak.client.clienttype.ClientTypeManager;
|
import org.keycloak.client.clienttype.ClientTypeManager;
|
||||||
import org.keycloak.common.Profile;
|
import org.keycloak.common.Profile;
|
||||||
|
import org.keycloak.common.Profile.Feature;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.common.util.ObjectUtil;
|
import org.keycloak.common.util.ObjectUtil;
|
||||||
import org.keycloak.common.util.UriUtils;
|
import org.keycloak.common.util.UriUtils;
|
||||||
|
@ -80,6 +81,8 @@ import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakContext;
|
import org.keycloak.models.KeycloakContext;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
|
import org.keycloak.models.OrganizationDomainModel;
|
||||||
|
import org.keycloak.models.OrganizationModel;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
@ -92,6 +95,7 @@ import org.keycloak.models.credential.PasswordCredentialModel;
|
||||||
import org.keycloak.models.credential.dto.OTPCredentialData;
|
import org.keycloak.models.credential.dto.OTPCredentialData;
|
||||||
import org.keycloak.models.credential.dto.OTPSecretData;
|
import org.keycloak.models.credential.dto.OTPSecretData;
|
||||||
import org.keycloak.models.credential.dto.PasswordCredentialData;
|
import org.keycloak.models.credential.dto.PasswordCredentialData;
|
||||||
|
import org.keycloak.organization.OrganizationProvider;
|
||||||
import org.keycloak.policy.PasswordPolicyNotMetException;
|
import org.keycloak.policy.PasswordPolicyNotMetException;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
|
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
|
||||||
|
@ -875,6 +879,7 @@ public class RepresentationToModel {
|
||||||
identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
|
identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
|
||||||
identityProviderModel.setStoreToken(representation.isStoreToken());
|
identityProviderModel.setStoreToken(representation.isStoreToken());
|
||||||
identityProviderModel.setAddReadTokenRoleOnCreate(representation.isAddReadTokenRoleOnCreate());
|
identityProviderModel.setAddReadTokenRoleOnCreate(representation.isAddReadTokenRoleOnCreate());
|
||||||
|
updateOrganizationBroker(realm, representation, session);
|
||||||
identityProviderModel.setConfig(removeEmptyString(representation.getConfig()));
|
identityProviderModel.setConfig(removeEmptyString(representation.getConfig()));
|
||||||
|
|
||||||
String flowAlias = representation.getFirstBrokerLoginFlowAlias();
|
String flowAlias = representation.getFirstBrokerLoginFlowAlias();
|
||||||
|
@ -898,7 +903,7 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
identityProviderModel.setPostBrokerLoginFlowId(flowModel.getId());
|
identityProviderModel.setPostBrokerLoginFlowId(flowModel.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
identityProviderModel.validate(realm);
|
identityProviderModel.validate(realm);
|
||||||
|
|
||||||
return identityProviderModel;
|
return identityProviderModel;
|
||||||
|
@ -1121,11 +1126,11 @@ public class RepresentationToModel {
|
||||||
resourceServer.setAllowRemoteResourceManagement(rep.isAllowRemoteResourceManagement());
|
resourceServer.setAllowRemoteResourceManagement(rep.isAllowRemoteResourceManagement());
|
||||||
|
|
||||||
DecisionStrategy decisionStrategy = rep.getDecisionStrategy();
|
DecisionStrategy decisionStrategy = rep.getDecisionStrategy();
|
||||||
|
|
||||||
if (decisionStrategy == null) {
|
if (decisionStrategy == null) {
|
||||||
decisionStrategy = DecisionStrategy.UNANIMOUS;
|
decisionStrategy = DecisionStrategy.UNANIMOUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceServer.setDecisionStrategy(decisionStrategy);
|
resourceServer.setDecisionStrategy(decisionStrategy);
|
||||||
|
|
||||||
for (ScopeRepresentation scope : rep.getScopes()) {
|
for (ScopeRepresentation scope : rep.getScopes()) {
|
||||||
|
@ -1548,7 +1553,7 @@ public class RepresentationToModel {
|
||||||
public static Scope toModel(ScopeRepresentation scope, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
public static Scope toModel(ScopeRepresentation scope, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||||
return toModel(scope, resourceServer, authorization, true);
|
return toModel(scope, resourceServer, authorization, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scope toModel(ScopeRepresentation scope, ResourceServer resourceServer, AuthorizationProvider authorization, boolean updateIfExists) {
|
public static Scope toModel(ScopeRepresentation scope, ResourceServer resourceServer, AuthorizationProvider authorization, boolean updateIfExists) {
|
||||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||||
ScopeStore scopeStore = storeFactory.getScopeStore();
|
ScopeStore scopeStore = storeFactory.getScopeStore();
|
||||||
|
@ -1645,4 +1650,34 @@ public class RepresentationToModel {
|
||||||
.map(HashSet::new)
|
.map(HashSet::new)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void updateOrganizationBroker(RealmModel realm, IdentityProviderRepresentation representation, KeycloakSession session) {
|
||||||
|
if (!Profile.isFeatureEnabled(Feature.ORGANIZATION)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentityProviderModel existing = realm.getIdentityProvidersStream()
|
||||||
|
.filter(p -> Objects.equals(p.getAlias(), representation.getAlias()) || Objects.equals(p.getInternalId(), representation.getInternalId()))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
String orgId = existing == null ? representation.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE) : existing.getOrganizationId();
|
||||||
|
|
||||||
|
if (orgId != null) {
|
||||||
|
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
|
||||||
|
OrganizationModel org = provider.getById(orgId);
|
||||||
|
String newOrgId = representation.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE);
|
||||||
|
|
||||||
|
if (org == null || (newOrgId != null && provider.getById(newOrgId) == null)) {
|
||||||
|
throw new IllegalArgumentException("Organization associated with broker does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
String domain = representation.getConfig().get(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||||
|
|
||||||
|
if (domain != null && org.getDomains().map(OrganizationDomainModel::getName).noneMatch(domain::equals)) {
|
||||||
|
throw new IllegalArgumentException("Domain does not match any domain from the organization");
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the link to an organization does not change
|
||||||
|
representation.getConfig().put(OrganizationModel.ORGANIZATION_ATTRIBUTE, orgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.keycloak.organization.admin.resource;
|
package org.keycloak.organization.admin.resource;
|
||||||
|
|
||||||
import jakarta.ws.rs.Consumes;
|
import jakarta.ws.rs.Consumes;
|
||||||
|
import jakarta.ws.rs.DELETE;
|
||||||
import jakarta.ws.rs.GET;
|
import jakarta.ws.rs.GET;
|
||||||
import jakarta.ws.rs.POST;
|
import jakarta.ws.rs.POST;
|
||||||
import jakarta.ws.rs.Path;
|
import jakarta.ws.rs.Path;
|
||||||
|
@ -28,13 +29,12 @@ import jakarta.ws.rs.core.Response;
|
||||||
import jakarta.ws.rs.core.Response.Status;
|
import jakarta.ws.rs.core.Response.Status;
|
||||||
import jakarta.ws.rs.ext.Provider;
|
import jakarta.ws.rs.ext.Provider;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Objects;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
import org.keycloak.models.OrganizationDomainModel;
|
|
||||||
import org.keycloak.models.OrganizationModel;
|
import org.keycloak.models.OrganizationModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
@ -42,19 +42,15 @@ import org.keycloak.organization.OrganizationProvider;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.services.ErrorResponse;
|
import org.keycloak.services.ErrorResponse;
|
||||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||||
import org.keycloak.services.resources.admin.IdentityProviderResource;
|
|
||||||
import org.keycloak.services.resources.admin.IdentityProvidersResource;
|
|
||||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||||
|
|
||||||
@Provider
|
@Provider
|
||||||
public class OrganizationIdentityProvidersResource {
|
public class OrganizationIdentityProvidersResource {
|
||||||
|
|
||||||
private final KeycloakSession session;
|
|
||||||
private final RealmModel realm;
|
private final RealmModel realm;
|
||||||
private final OrganizationProvider organizationProvider;
|
private final OrganizationProvider organizationProvider;
|
||||||
private final OrganizationModel organization;
|
private final OrganizationModel organization;
|
||||||
private final AdminPermissionEvaluator auth;
|
private final AdminPermissionEvaluator auth;
|
||||||
private final AdminEventBuilder adminEvent;
|
|
||||||
|
|
||||||
public OrganizationIdentityProvidersResource() {
|
public OrganizationIdentityProvidersResource() {
|
||||||
// needed for registering to the JAX-RS stack
|
// needed for registering to the JAX-RS stack
|
||||||
|
@ -62,36 +58,34 @@ public class OrganizationIdentityProvidersResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrganizationIdentityProvidersResource(KeycloakSession session, OrganizationModel organization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
public OrganizationIdentityProvidersResource(KeycloakSession session, OrganizationModel organization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||||
this.session = session;
|
|
||||||
this.realm = session == null ? null : session.getContext().getRealm();
|
this.realm = session == null ? null : session.getContext().getRealm();
|
||||||
this.organizationProvider = session == null ? null : session.getProvider(OrganizationProvider.class);
|
this.organizationProvider = session == null ? null : session.getProvider(OrganizationProvider.class);
|
||||||
this.organization = organization;
|
this.organization = organization;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.adminEvent = adminEvent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public Response addIdentityProvider(IdentityProviderRepresentation providerRep) {
|
public Response addIdentityProvider(String id) {
|
||||||
auth.realm().requireManageRealm();
|
auth.realm().requireManageRealm();
|
||||||
|
|
||||||
Response response = new IdentityProvidersResource(realm, session, auth, adminEvent).create(providerRep);
|
try {
|
||||||
|
IdentityProviderModel identityProvider = this.realm.getIdentityProvidersStream()
|
||||||
|
.filter(p -> Objects.equals(p.getAlias(), id) || Objects.equals(p.getInternalId(), id))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
|
||||||
if (Status.CREATED.getStatusCode() == response.getStatus()) {
|
if (identityProvider == null) {
|
||||||
try {
|
throw ErrorResponse.error("Identity provider not found with the given alias", Status.BAD_REQUEST);
|
||||||
IdentityProviderModel identityProvider = realm.getIdentityProviderByAlias(providerRep.getAlias());
|
|
||||||
|
|
||||||
if (organizationProvider.addIdentityProvider(organization, identityProvider)) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw ErrorResponse.error("Identity provider already associated to the organization", Status.BAD_REQUEST);
|
|
||||||
} catch (ModelException me) {
|
|
||||||
throw ErrorResponse.error(me.getMessage(), Status.BAD_REQUEST);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
if (organizationProvider.addIdentityProvider(organization, identityProvider)) {
|
||||||
|
return Response.noContent().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ErrorResponse.error("Identity provider already associated to the organization", Status.CONFLICT);
|
||||||
|
} catch (ModelException me) {
|
||||||
|
throw ErrorResponse.error(me.getMessage(), Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
@ -102,37 +96,40 @@ public class OrganizationIdentityProvidersResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("{alias}")
|
@Path("{alias}")
|
||||||
public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public IdentityProviderRepresentation getIdentityProvider(@PathParam("alias") String alias) {
|
||||||
IdentityProviderModel broker = realm.getIdentityProviderByAlias(alias);
|
IdentityProviderModel broker = realm.getIdentityProviderByAlias(alias);
|
||||||
return new IdentityProviderResource(auth, realm, session, broker, adminEvent) {
|
|
||||||
@Override
|
|
||||||
public Response delete() {
|
|
||||||
Response response = super.delete();
|
|
||||||
|
|
||||||
if (organizationProvider.removeIdentityProvider(organization, broker)) {
|
if (!isOrganizationBroker(broker)) {
|
||||||
return response;
|
throw ErrorResponse.error("Identity provider not associated with the organization", Status.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw ErrorResponse.error("Identity provider not associated with the organization", Status.BAD_REQUEST);
|
return ModelToRepresentation.toRepresentation(realm, broker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Path("{alias}")
|
||||||
public Response update(IdentityProviderRepresentation providerRep) {
|
@DELETE
|
||||||
if (organization.getIdentityProviders().noneMatch(model -> model.getInternalId().equals(providerRep.getInternalId()) || model.getAlias().equals(providerRep.getAlias()))) {
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
return Response.status(Status.NOT_FOUND).build();
|
public Response delete(@PathParam("alias") String alias) {
|
||||||
}
|
IdentityProviderModel broker = realm.getIdentityProviderByAlias(alias);
|
||||||
String domain = providerRep.getConfig().get(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
|
||||||
|
|
||||||
if (domain != null && organization.getDomains().map(OrganizationDomainModel::getName).noneMatch(domain::equals)) {
|
if (!isOrganizationBroker(broker)) {
|
||||||
return Response.status(Status.BAD_REQUEST).build();
|
throw ErrorResponse.error("Identity provider not found with the given alias", Status.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.update(providerRep);
|
if (organizationProvider.removeIdentityProvider(organization, broker)) {
|
||||||
}
|
return Response.noContent().build();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
throw ErrorResponse.error("Identity provider not associated with the organization", Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IdentityProviderRepresentation toRepresentation(IdentityProviderModel idp) {
|
private IdentityProviderRepresentation toRepresentation(IdentityProviderModel idp) {
|
||||||
return ModelToRepresentation.toRepresentation(realm, idp);
|
return ModelToRepresentation.toRepresentation(realm, idp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOrganizationBroker(IdentityProviderModel broker) {
|
||||||
|
return broker != null && organization.getId().equals(broker.getOrganizationId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.admin.client.resource.UsersResource;
|
import org.keycloak.admin.client.resource.UsersResource;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.representations.idm.OrganizationDomainRepresentation;
|
import org.keycloak.representations.idm.OrganizationDomainRepresentation;
|
||||||
import org.keycloak.representations.idm.OrganizationRepresentation;
|
import org.keycloak.representations.idm.OrganizationRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
@ -144,8 +145,10 @@ public abstract class AbstractOrganizationTest extends AbstractAdminTest {
|
||||||
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
||||||
id = ApiUtil.getCreatedId(response);
|
id = ApiUtil.getCreatedId(response);
|
||||||
}
|
}
|
||||||
|
IdentityProviderRepresentation broker = brokerConfigFunction.apply(name).setUpIdentityProvider();
|
||||||
testRealm().organizations().get(id).identityProviders().create(brokerConfigFunction.apply(name).setUpIdentityProvider()).close();
|
testRealm().identityProviders().create(broker).close();
|
||||||
|
getCleanup().addCleanup(testRealm().identityProviders().get(broker.getAlias())::remove);
|
||||||
|
testRealm().organizations().get(id).identityProviders().addIdentityProvider(broker.getAlias()).close();
|
||||||
org = testRealm().organizations().get(id).toRepresentation();
|
org = testRealm().organizations().get(id).toRepresentation();
|
||||||
getCleanup().addCleanup(() -> testRealm().organizations().get(id).delete().close());
|
getCleanup().addCleanup(() -> testRealm().organizations().get(id).delete().close());
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.organization.admin;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.AbstractTestRealmKeycloakTest.TEST_REALM_NAME;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.keycloak.models.IdentityProviderSyncMode;
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.testsuite.broker.BrokerConfiguration;
|
||||||
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
|
|
||||||
|
public class BrokerConfigurationWrapper implements BrokerConfiguration {
|
||||||
|
|
||||||
|
private final String orgName;
|
||||||
|
private final BrokerConfiguration delegate;
|
||||||
|
|
||||||
|
public BrokerConfigurationWrapper(String orgName, BrokerConfiguration delegate) {
|
||||||
|
this.orgName = orgName;
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String consumerRealmName() {
|
||||||
|
return TEST_REALM_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RealmRepresentation createProviderRealm() {
|
||||||
|
RealmRepresentation providerRealm = delegate.createProviderRealm();
|
||||||
|
|
||||||
|
providerRealm.setClients(createProviderClients());
|
||||||
|
providerRealm.setUsers(List.of(
|
||||||
|
UserBuilder.create()
|
||||||
|
.username(getUserLogin())
|
||||||
|
.email(getUserEmail())
|
||||||
|
.password(getUserPassword())
|
||||||
|
.enabled(true)
|
||||||
|
.build(),
|
||||||
|
UserBuilder.create()
|
||||||
|
.username("external")
|
||||||
|
.email("external@user.org")
|
||||||
|
.password("password")
|
||||||
|
.enabled(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return providerRealm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserEmail() {
|
||||||
|
return getUserLogin() + "@" + orgName + ".org";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIDPAlias() {
|
||||||
|
return orgName + "-identity-provider";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdentityProviderRepresentation setUpIdentityProvider() {
|
||||||
|
IdentityProviderRepresentation broker = delegate.setUpIdentityProvider();
|
||||||
|
broker.setAlias(getIDPAlias());
|
||||||
|
return broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ClientRepresentation> createProviderClients() {
|
||||||
|
List<ClientRepresentation> clients = delegate.createProviderClients();
|
||||||
|
clients.get(0).setRedirectUris(List.of("*"));
|
||||||
|
return clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RealmRepresentation createConsumerRealm() {
|
||||||
|
return delegate.createConsumerRealm();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ClientRepresentation> createConsumerClients() {
|
||||||
|
return delegate.createConsumerClients();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdentityProviderRepresentation setUpIdentityProvider(IdentityProviderSyncMode force) {
|
||||||
|
IdentityProviderRepresentation broker = delegate.setUpIdentityProvider(force);
|
||||||
|
broker.setAlias(getIDPAlias());
|
||||||
|
return broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String providerRealmName() {
|
||||||
|
return delegate.providerRealmName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIDPClientIdInProviderRealm() {
|
||||||
|
return delegate.getIDPClientIdInProviderRealm();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserLogin() {
|
||||||
|
return delegate.getUserLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserPassword() {
|
||||||
|
return delegate.getUserPassword();
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,13 +105,15 @@ public class OrganizationAdminPermissionsTest extends AbstractOrganizationTest {
|
||||||
IdentityProviderRepresentation idpRep = new IdentityProviderRepresentation();
|
IdentityProviderRepresentation idpRep = new IdentityProviderRepresentation();
|
||||||
idpRep.setAlias("dummy");
|
idpRep.setAlias("dummy");
|
||||||
idpRep.setProviderId("oidc");
|
idpRep.setProviderId("oidc");
|
||||||
|
realmAdminResource.identityProviders().create(idpRep).close();
|
||||||
|
|
||||||
//create IdP
|
//create IdP
|
||||||
try (
|
try (
|
||||||
Response userResponse = realmUserResource.organizations().get(orgId).identityProviders().create(idpRep);
|
Response userResponse = realmUserResource.organizations().get(orgId).identityProviders().addIdentityProvider(idpRep.getAlias());
|
||||||
Response adminResponse = realmAdminResource.organizations().get(orgId).identityProviders().create(idpRep)
|
Response adminResponse = realmAdminResource.organizations().get(orgId).identityProviders().addIdentityProvider(idpRep.getAlias())
|
||||||
) {
|
) {
|
||||||
assertThat(userResponse.getStatus(), equalTo(Status.FORBIDDEN.getStatusCode()));
|
assertThat(userResponse.getStatus(), equalTo(Status.FORBIDDEN.getStatusCode()));
|
||||||
assertThat(adminResponse.getStatus(), equalTo(Status.CREATED.getStatusCode()));
|
assertThat(adminResponse.getStatus(), equalTo(Status.NO_CONTENT.getStatusCode()));
|
||||||
getCleanup().addCleanup(() -> testRealm().organizations().get(orgId).identityProviders().get(idpRep.getAlias()).delete().close());
|
getCleanup().addCleanup(() -> testRealm().organizations().get(orgId).identityProviders().get(idpRep.getAlias()).delete().close());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,11 +129,6 @@ public class OrganizationAdminPermissionsTest extends AbstractOrganizationTest {
|
||||||
} catch (ForbiddenException expected) {}
|
} catch (ForbiddenException expected) {}
|
||||||
assertThat(realmAdminResource.organizations().get(orgId).identityProviders().get(idpRep.getAlias()).toRepresentation(), Matchers.notNullValue());
|
assertThat(realmAdminResource.organizations().get(orgId).identityProviders().get(idpRep.getAlias()).toRepresentation(), Matchers.notNullValue());
|
||||||
|
|
||||||
//update IdP
|
|
||||||
try (Response userResponse = realmUserResource.organizations().get(orgId).identityProviders().get(idpRep.getAlias()).update(idpRep)) {
|
|
||||||
assertThat(userResponse.getStatus(), equalTo(Status.FORBIDDEN.getStatusCode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete IdP
|
//delete IdP
|
||||||
try (Response userResponse = realmUserResource.organizations().get(orgId).identityProviders().get(idpRep.getAlias()).delete()) {
|
try (Response userResponse = realmUserResource.organizations().get(orgId).identityProviders().get(idpRep.getAlias()).delete()) {
|
||||||
assertThat(userResponse.getStatus(), equalTo(Status.FORBIDDEN.getStatusCode()));
|
assertThat(userResponse.getStatus(), equalTo(Status.FORBIDDEN.getStatusCode()));
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||||
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
idp.getConfig().put(IdentityProviderModel.LOGIN_HINT, "true");
|
idp.getConfig().put(IdentityProviderModel.LOGIN_HINT, "true");
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).update(idp).close();
|
testRealm().identityProviders().get(bc.getIDPAlias()).update(idp);
|
||||||
|
|
||||||
oauth.clientId("broker-app");
|
oauth.clientId("broker-app");
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
@ -127,10 +127,10 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
// create a realm user in the consumer realm
|
// create a realm user in the consumer realm
|
||||||
realmsResouce().realm(bc.consumerRealmName()).users()
|
realmsResouce().realm(bc.consumerRealmName()).users()
|
||||||
.create(UserBuilder.create()
|
.create(UserBuilder.create()
|
||||||
.username(bc.getUserLogin())
|
.username(bc.getUserLogin())
|
||||||
.email(bc.getUserEmail())
|
.email(bc.getUserEmail())
|
||||||
.password(bc.getUserPassword())
|
.password(bc.getUserPassword())
|
||||||
.enabled(true).build()
|
.enabled(true).build()
|
||||||
).close();
|
).close();
|
||||||
|
|
||||||
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||||
|
@ -174,6 +174,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
// logout to force the user to authenticate again
|
// logout to force the user to authenticate again
|
||||||
UserRepresentation account = getUserRepresentation(bc.getUserEmail());
|
UserRepresentation account = getUserRepresentation(bc.getUserEmail());
|
||||||
realmsResouce().realm(bc.consumerRealmName()).users().get(account.getId()).logout();
|
realmsResouce().realm(bc.consumerRealmName()).users().get(account.getId()).logout();
|
||||||
|
realmsResouce().realm(bc.providerRealmName()).logoutAll();
|
||||||
|
|
||||||
// login with email only
|
// login with email only
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
@ -197,7 +198,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
OrganizationIdentityProviderResource idp = organization.identityProviders().get(bc.getIDPAlias());
|
OrganizationIdentityProviderResource idp = organization.identityProviders().get(bc.getIDPAlias());
|
||||||
IdentityProviderRepresentation idpRep = idp.toRepresentation();
|
IdentityProviderRepresentation idpRep = idp.toRepresentation();
|
||||||
idpRep.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
idpRep.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
||||||
idp.update(idpRep).close();
|
testRealm().identityProviders().get(idpRep.getAlias()).update(idpRep);
|
||||||
|
|
||||||
// add the member for the first time
|
// add the member for the first time
|
||||||
assertBrokerRegistration(organization, bc.getUserEmail());
|
assertBrokerRegistration(organization, bc.getUserEmail());
|
||||||
|
@ -248,11 +249,13 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||||
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).update(idp).close();
|
testRealm().identityProviders().get(bc.getIDPAlias()).update(idp);
|
||||||
idp.setAlias("second-idp");
|
idp.setAlias("second-idp");
|
||||||
idp.setInternalId(null);
|
idp.setInternalId(null);
|
||||||
idp.getConfig().remove(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
idp.getConfig().remove(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||||
organization.identityProviders().create(idp).close();
|
testRealm().identityProviders().create(idp).close();
|
||||||
|
getCleanup().addCleanup(testRealm().identityProviders().get("second-idp")::remove);
|
||||||
|
organization.identityProviders().addIdentityProvider(idp.getAlias()).close();
|
||||||
|
|
||||||
oauth.clientId("broker-app");
|
oauth.clientId("broker-app");
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
@ -290,7 +293,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
||||||
// set a domain to the existing broker
|
// set a domain to the existing broker
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).update(idp).close();
|
testRealm().identityProviders().get(bc.getIDPAlias()).update(idp);
|
||||||
|
|
||||||
idp = bc.setUpIdentityProvider();
|
idp = bc.setUpIdentityProvider();
|
||||||
idp.setAlias("second-idp");
|
idp.setAlias("second-idp");
|
||||||
|
@ -298,7 +301,9 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
idp.getConfig().remove(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
idp.getConfig().remove(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||||
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
||||||
// create a second broker without a domain set
|
// create a second broker without a domain set
|
||||||
organization.identityProviders().create(idp).close();
|
testRealm().identityProviders().create(idp).close();
|
||||||
|
getCleanup().addCleanup(testRealm().identityProviders().get("second-idp")::remove);
|
||||||
|
organization.identityProviders().addIdentityProvider(idp.getAlias()).close();
|
||||||
idp = organization.identityProviders().get(idp.getAlias()).toRepresentation();
|
idp = organization.identityProviders().get(idp.getAlias()).toRepresentation();
|
||||||
|
|
||||||
oauth.clientId("broker-app");
|
oauth.clientId("broker-app");
|
||||||
|
@ -313,7 +318,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
Assert.assertTrue(loginPage.isSocialButtonPresent(idp.getAlias()));
|
Assert.assertTrue(loginPage.isSocialButtonPresent(idp.getAlias()));
|
||||||
|
|
||||||
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.FALSE.toString());
|
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.FALSE.toString());
|
||||||
organization.identityProviders().get(idp.getAlias()).update(idp).close();
|
testRealm().identityProviders().get(idp.getAlias()).update(idp);
|
||||||
driver.navigate().refresh();
|
driver.navigate().refresh();
|
||||||
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
||||||
Assert.assertFalse(loginPage.isSocialButtonPresent(bc.getIDPAlias()));
|
Assert.assertFalse(loginPage.isSocialButtonPresent(bc.getIDPAlias()));
|
||||||
|
@ -326,7 +331,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
||||||
// set a domain to the existing broker
|
// set a domain to the existing broker
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).update(idp).close();
|
testRealm().identityProviders().get(bc.getIDPAlias()).update(idp);
|
||||||
|
|
||||||
idp = bc.setUpIdentityProvider();
|
idp = bc.setUpIdentityProvider();
|
||||||
idp.setAlias("second-idp");
|
idp.setAlias("second-idp");
|
||||||
|
@ -334,7 +339,9 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
idp.getConfig().remove(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
idp.getConfig().remove(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||||
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
||||||
// create a second broker without a domain set
|
// create a second broker without a domain set
|
||||||
organization.identityProviders().create(idp).close();
|
testRealm().identityProviders().create(idp).close();
|
||||||
|
getCleanup().addCleanup(testRealm().identityProviders().get("second-idp")::remove);
|
||||||
|
organization.identityProviders().addIdentityProvider(idp.getAlias()).close();
|
||||||
|
|
||||||
oauth.clientId("broker-app");
|
oauth.clientId("broker-app");
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
@ -375,7 +382,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
||||||
// set a domain to the existing broker
|
// set a domain to the existing broker
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).update(idp).close();
|
testRealm().identityProviders().get(bc.getIDPAlias()).update(idp);
|
||||||
|
|
||||||
idp = bc.setUpIdentityProvider();
|
idp = bc.setUpIdentityProvider();
|
||||||
idp.setAlias("second-idp");
|
idp.setAlias("second-idp");
|
||||||
|
@ -383,7 +390,9 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "other.org");
|
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "other.org");
|
||||||
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
||||||
// create a second broker without a domain set
|
// create a second broker without a domain set
|
||||||
organization.identityProviders().create(idp).close();
|
testRealm().identityProviders().create(idp).close();
|
||||||
|
getCleanup().addCleanup(testRealm().identityProviders().get("second-idp")::remove);
|
||||||
|
organization.identityProviders().addIdentityProvider(idp.getAlias()).close();
|
||||||
|
|
||||||
oauth.clientId("broker-app");
|
oauth.clientId("broker-app");
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
@ -421,14 +430,16 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org");
|
||||||
// set a domain to the existing broker
|
// set a domain to the existing broker
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).update(idp).close();
|
testRealm().identityProviders().get(bc.getIDPAlias()).update(idp);
|
||||||
|
|
||||||
idp = bc.setUpIdentityProvider();
|
idp = bc.setUpIdentityProvider();
|
||||||
idp.setAlias("second-idp");
|
idp.setAlias("second-idp");
|
||||||
idp.setInternalId(null);
|
idp.setInternalId(null);
|
||||||
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
idp.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
||||||
// create a second broker without a domain set
|
// create a second broker without a domain set
|
||||||
organization.identityProviders().create(idp).close();
|
testRealm().identityProviders().create(idp).close();
|
||||||
|
getCleanup().addCleanup(testRealm().identityProviders().get("second-idp")::remove);
|
||||||
|
organization.identityProviders().addIdentityProvider(idp.getAlias()).close();
|
||||||
|
|
||||||
oauth.clientId("broker-app");
|
oauth.clientId("broker-app");
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
@ -498,7 +509,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
|
|
||||||
// make sure the user can select this idp from the organization when authenticating
|
// make sure the user can select this idp from the organization when authenticating
|
||||||
idpRep.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
idpRep.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
||||||
organization.identityProviders().get(idpRep.getAlias()).update(idpRep).close();
|
testRealm().identityProviders().get(idpRep.getAlias()).update(idpRep);
|
||||||
|
|
||||||
// create a user to the provider realm using a email that does not share the same domain as the org
|
// create a user to the provider realm using a email that does not share the same domain as the org
|
||||||
UserRepresentation user = UserBuilder.create()
|
UserRepresentation user = UserBuilder.create()
|
||||||
|
@ -536,7 +547,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
|
|
||||||
// make sure the user can select this idp from the organization when authenticating
|
// make sure the user can select this idp from the organization when authenticating
|
||||||
idpRep.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
idpRep.getConfig().put(OrganizationModel.BROKER_PUBLIC, Boolean.TRUE.toString());
|
||||||
organization.identityProviders().get(idpRep.getAlias()).update(idpRep).close();
|
testRealm().identityProviders().get(idpRep.getAlias()).update(idpRep);
|
||||||
|
|
||||||
// create a user to the provider realm using a email that does not share the same domain as the org
|
// create a user to the provider realm using a email that does not share the same domain as the org
|
||||||
UserRepresentation user = UserBuilder.create()
|
UserRepresentation user = UserBuilder.create()
|
||||||
|
@ -571,6 +582,7 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
updateAccountInformationPage.updateAccountInformation(user.getUsername(), user.getEmail(), "Firstname", "Lastname");
|
updateAccountInformationPage.updateAccountInformation(user.getUsername(), user.getEmail(), "Firstname", "Lastname");
|
||||||
UserRepresentation account = getUserRepresentation(user.getEmail());
|
UserRepresentation account = getUserRepresentation(user.getEmail());
|
||||||
realmsResouce().realm(bc.consumerRealmName()).users().get(account.getId()).logout();
|
realmsResouce().realm(bc.consumerRealmName()).users().get(account.getId()).logout();
|
||||||
|
realmsResouce().realm(bc.providerRealmName()).logoutAll();
|
||||||
|
|
||||||
// the flow now changed and the user should be automatically redirected to the origin broker
|
// the flow now changed and the user should be automatically redirected to the origin broker
|
||||||
loginPage.open(bc.consumerRealmName());
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
|
|
@ -20,11 +20,13 @@ package org.keycloak.testsuite.organization.admin;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.BadRequestException;
|
||||||
import jakarta.ws.rs.NotFoundException;
|
import jakarta.ws.rs.NotFoundException;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import jakarta.ws.rs.core.Response.Status;
|
import jakarta.ws.rs.core.Response.Status;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||||
import org.keycloak.admin.client.resource.OrganizationIdentityProviderResource;
|
import org.keycloak.admin.client.resource.OrganizationIdentityProviderResource;
|
||||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||||
import org.keycloak.common.Profile.Feature;
|
import org.keycloak.common.Profile.Feature;
|
||||||
|
@ -41,28 +43,35 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
OrganizationRepresentation organization = createOrganization();
|
OrganizationRepresentation organization = createOrganization();
|
||||||
OrganizationIdentityProviderResource orgIdPResource = testRealm().organizations().get(organization.getId())
|
OrganizationIdentityProviderResource orgIdPResource = testRealm().organizations().get(organization.getId())
|
||||||
.identityProviders().get(bc.getIDPAlias());
|
.identityProviders().get(bc.getIDPAlias());
|
||||||
IdentityProviderRepresentation actual = orgIdPResource.toRepresentation();
|
IdentityProviderRepresentation expected = orgIdPResource.toRepresentation();
|
||||||
IdentityProviderRepresentation expected = actual;
|
|
||||||
assertThat(expected.getAlias(), equalTo(bc.getIDPAlias()));
|
|
||||||
|
|
||||||
//update
|
// organization link set
|
||||||
expected.setAlias("changed-alias");
|
Assert.assertEquals(expected.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE), organization.getId());
|
||||||
expected.setDisplayName("My Org Broker");
|
|
||||||
expected.getConfig().put("test", "value");
|
IdentityProviderResource idpResource = testRealm().identityProviders().get(expected.getAlias());
|
||||||
try (Response response = orgIdPResource.update(expected)) {
|
IdentityProviderRepresentation actual = idpResource.toRepresentation();
|
||||||
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
Assert.assertEquals(actual.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE), organization.getId());
|
||||||
}
|
actual.getConfig().put(OrganizationModel.ORGANIZATION_ATTRIBUTE, "somethingelse");
|
||||||
try {
|
try {
|
||||||
orgIdPResource.toRepresentation();
|
idpResource.update(actual);
|
||||||
Assert.fail("should fail because the alias changed");
|
Assert.fail("Should fail because it maps to an invalid org");
|
||||||
} catch (NotFoundException ignore) {
|
} catch (BadRequestException ignore) {
|
||||||
|
|
||||||
}
|
}
|
||||||
orgIdPResource = testRealm().organizations().get(organization.getId()).identityProviders().get(expected.getAlias());
|
|
||||||
actual = orgIdPResource.toRepresentation();
|
OrganizationRepresentation secondOrg = createOrganization("secondorg");
|
||||||
assertThat(expected.getAlias(), equalTo(actual.getAlias()));
|
actual.getConfig().put(OrganizationModel.ORGANIZATION_ATTRIBUTE, secondOrg.getId());
|
||||||
assertThat(expected.getDisplayName(), equalTo(actual.getDisplayName()));
|
idpResource.update(actual);
|
||||||
Assert.assertEquals(expected.getConfig().get("test"), actual.getConfig().get("test"));
|
actual = idpResource.toRepresentation();
|
||||||
|
Assert.assertEquals(actual.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE), organization.getId());
|
||||||
|
|
||||||
|
actual = idpResource.toRepresentation();
|
||||||
|
// the link to the organization should not change
|
||||||
|
Assert.assertEquals(actual.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE), organization.getId());
|
||||||
|
actual.getConfig().remove(OrganizationModel.ORGANIZATION_ATTRIBUTE);
|
||||||
|
idpResource.update(actual);
|
||||||
|
actual = idpResource.toRepresentation();
|
||||||
|
// the link to the organization should not change
|
||||||
|
Assert.assertEquals(actual.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE), organization.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -74,13 +83,15 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
idpTemplate.setAlias("idp-" + i);
|
idpTemplate.setAlias("idp-" + i);
|
||||||
idpTemplate.setInternalId(null);
|
idpTemplate.setInternalId(null);
|
||||||
organization.identityProviders().create(idpTemplate).close();
|
testRealm().identityProviders().create(idpTemplate).close();
|
||||||
|
organization.identityProviders().addIdentityProvider(idpTemplate.getAlias()).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.assertEquals(6, organization.identityProviders().getIdentityProviders().size());
|
Assert.assertEquals(6, organization.identityProviders().getIdentityProviders().size());
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
OrganizationIdentityProviderResource idpResource = organization.identityProviders().get("idp-" + i);
|
String alias = "idp-" + i;
|
||||||
|
OrganizationIdentityProviderResource idpResource = organization.identityProviders().get(alias);
|
||||||
|
|
||||||
try (Response response = idpResource.delete()) {
|
try (Response response = idpResource.delete()) {
|
||||||
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
||||||
|
@ -91,11 +102,13 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
Assert.fail("should be removed");
|
Assert.fail("should be removed");
|
||||||
} catch (NotFoundException expected) {
|
} catch (NotFoundException expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not removed from the realm
|
||||||
|
testRealm().identityProviders().get(alias).toRepresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
organization.identityProviders().get(bc.getIDPAlias()).delete().close();
|
organization.identityProviders().get(bc.getIDPAlias()).delete().close();
|
||||||
|
Assert.assertFalse(testRealm().identityProviders().findAll().isEmpty());
|
||||||
Assert.assertTrue(testRealm().identityProviders().findAll().isEmpty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -108,20 +121,25 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
|
|
||||||
String alias = idpRepresentation.getAlias();
|
String alias = idpRepresentation.getAlias();
|
||||||
idpRepresentation.setAlias("another-idp");
|
idpRepresentation.setAlias("another-idp");
|
||||||
|
testRealm().identityProviders().create(idpRepresentation).close();
|
||||||
|
|
||||||
try (Response response = organization.identityProviders().create(idpRepresentation)) {
|
try (Response response = organization.identityProviders().addIdentityProvider(alias)) {
|
||||||
|
// already associated with the org
|
||||||
assertThat(response.getStatus(), equalTo(Status.CONFLICT.getStatusCode()));
|
assertThat(response.getStatus(), equalTo(Status.CONFLICT.getStatusCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
idpRepresentation.setAlias(alias);
|
idpRepresentation.setAlias(alias);
|
||||||
idpRepresentation.setInternalId(null);
|
idpRepresentation.setInternalId(null);
|
||||||
|
|
||||||
try (Response response = organization.identityProviders().create(idpRepresentation)) {
|
OrganizationResource secondOrg = testRealm().organizations().get(createOrganization("secondorg").getId());
|
||||||
assertThat(response.getStatus(), equalTo(Status.CONFLICT.getStatusCode()));
|
|
||||||
|
try (Response response = secondOrg.identityProviders().addIdentityProvider(alias)) {
|
||||||
|
// associated with another org
|
||||||
|
assertThat(response.getStatus(), equalTo(Status.BAD_REQUEST.getStatusCode()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = jakarta.ws.rs.NotFoundException.class)
|
@Test
|
||||||
public void testRemovingOrgShouldRemoveIdP() {
|
public void testRemovingOrgShouldRemoveIdP() {
|
||||||
OrganizationRepresentation orgRep = createOrganization();
|
OrganizationRepresentation orgRep = createOrganization();
|
||||||
OrganizationResource orgResource = testRealm().organizations().get(orgRep.getId());
|
OrganizationResource orgResource = testRealm().organizations().get(orgRep.getId());
|
||||||
|
@ -130,8 +148,10 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
testRealm().identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
// broker not removed from realm
|
||||||
Assert.assertTrue(testRealm().identityProviders().findAll().isEmpty());
|
IdentityProviderRepresentation idpRep = testRealm().identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
|
// broker no longer linked to the org
|
||||||
|
Assert.assertNull(idpRep.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -144,10 +164,6 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
//create IdP in realm not bound to Org
|
//create IdP in realm not bound to Org
|
||||||
testRealm().identityProviders().create(idpRepresentation).close();
|
testRealm().identityProviders().create(idpRepresentation).close();
|
||||||
|
|
||||||
try (Response response = orgIdPResource.update(idpRepresentation)) {
|
|
||||||
assertThat(response.getStatus(), equalTo(Response.Status.NOT_FOUND.getStatusCode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Response response = orgIdPResource.delete()) {
|
try (Response response = orgIdPResource.delete()) {
|
||||||
assertThat(response.getStatus(), equalTo(Status.NO_CONTENT.getStatusCode()));
|
assertThat(response.getStatus(), equalTo(Status.NO_CONTENT.getStatusCode()));
|
||||||
}
|
}
|
||||||
|
@ -157,33 +173,6 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void tryUpdateIdPWithValidAliasInvalidInternalId() {
|
|
||||||
OrganizationRepresentation orgRep = createOrganization();
|
|
||||||
OrganizationResource orgResource = testRealm().organizations().get(orgRep.getId());
|
|
||||||
|
|
||||||
OrganizationIdentityProviderResource orgIdPResource = orgResource.identityProviders().get(bc.getIDPAlias());
|
|
||||||
|
|
||||||
IdentityProviderRepresentation idpRepresentation = createRep("some-broker", "oidc");
|
|
||||||
//create IdP in realm not bound to Org and get created internalId
|
|
||||||
testRealm().identityProviders().create(idpRepresentation).close();
|
|
||||||
getCleanup().addCleanup(() -> testRealm().identityProviders().get(idpRepresentation.getAlias()).remove());
|
|
||||||
String internalId = testRealm().identityProviders().get("some-broker").toRepresentation().getInternalId();
|
|
||||||
|
|
||||||
IdentityProviderRepresentation orgIdPRep = orgIdPResource.toRepresentation();
|
|
||||||
orgIdPRep.setInternalId(internalId);
|
|
||||||
|
|
||||||
try (Response response = orgIdPResource.update(orgIdPRep)) {
|
|
||||||
assertThat(response.getStatus(), equalTo(Status.CONFLICT.getStatusCode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
orgIdPRep.setAlias("some-broker-alias");
|
|
||||||
|
|
||||||
try (Response response = orgIdPResource.update(orgIdPRep)) {
|
|
||||||
assertThat(response.getStatus(), equalTo(Response.Status.NOT_FOUND.getStatusCode()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignDomainNotBoundToOrganization() {
|
public void testAssignDomainNotBoundToOrganization() {
|
||||||
OrganizationRepresentation orgRep = createOrganization();
|
OrganizationRepresentation orgRep = createOrganization();
|
||||||
|
@ -192,8 +181,17 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
IdentityProviderRepresentation idpRep = orgIdPResource.toRepresentation();
|
IdentityProviderRepresentation idpRep = orgIdPResource.toRepresentation();
|
||||||
idpRep.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "unknown.org");
|
idpRep.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "unknown.org");
|
||||||
|
|
||||||
try (Response response = orgIdPResource.update(idpRep)) {
|
try {
|
||||||
assertThat(response.getStatus(), equalTo(Status.BAD_REQUEST.getStatusCode()));
|
testRealm().identityProviders().get(idpRep.getAlias()).update(idpRep);
|
||||||
|
Assert.fail("Domain set to broker is invalid");
|
||||||
|
} catch (BadRequestException ignore) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
idpRep.setAlias("newbroker");
|
||||||
|
idpRep.setInternalId(null);
|
||||||
|
try (Response response = testRealm().identityProviders().create(idpRep)) {
|
||||||
|
Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue