Add organizations enabled/disabled capability
Closes #28804 Signed-off-by: vramik <vramik@redhat.com>
This commit is contained in:
parent
80de3a0a71
commit
278341aff9
34 changed files with 331 additions and 64 deletions
|
@ -214,6 +214,8 @@ public class RealmRepresentation {
|
|||
|
||||
protected Boolean userManagedAccessAllowed;
|
||||
|
||||
protected Boolean organizationsEnabled;
|
||||
|
||||
@Deprecated
|
||||
protected Boolean social;
|
||||
@Deprecated
|
||||
|
@ -1420,6 +1422,14 @@ public class RealmRepresentation {
|
|||
return userManagedAccessAllowed;
|
||||
}
|
||||
|
||||
public Boolean isOrganizationsEnabled() {
|
||||
return organizationsEnabled;
|
||||
}
|
||||
|
||||
public void setOrganizationsEnabled(Boolean organizationsEnabled) {
|
||||
this.organizationsEnabled = organizationsEnabled;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Map<String, String> getAttributesOrEmpty() {
|
||||
return (Map<String, String>) (attributes == null ? Collections.emptyMap() : attributes);
|
||||
|
|
|
@ -3132,3 +3132,5 @@ searchClientRegistration=Search for policy
|
|||
importFileHelp=File to import a key
|
||||
logo=Logo
|
||||
avatarImage=Avatar image
|
||||
organizationsEnabled=Organizations
|
||||
organizationsEnabledHelp=If enabled, allows managing organizations. Otherwise, existing organizations are still kept but you will not be able to manage them anymore or authenticate their members.
|
||||
|
|
|
@ -36,6 +36,8 @@ import {
|
|||
import { useFetch } from "../utils/useFetch";
|
||||
import { UIRealmRepresentation } from "./RealmSettingsTabs";
|
||||
|
||||
import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled";
|
||||
|
||||
type RealmSettingsGeneralTabProps = {
|
||||
realm: UIRealmRepresentation;
|
||||
save: (realm: UIRealmRepresentation) => void;
|
||||
|
@ -105,6 +107,8 @@ function RealmSettingsGeneralTabForm({
|
|||
setValue,
|
||||
formState: { isDirty, errors },
|
||||
} = form;
|
||||
const isFeatureEnabled = useIsFeatureEnabled();
|
||||
const isOrganizationsEnabled = isFeatureEnabled(Feature.Organizations);
|
||||
|
||||
const setupForm = () => {
|
||||
convertToFormValues(realm, setValue);
|
||||
|
@ -212,6 +216,13 @@ function RealmSettingsGeneralTabForm({
|
|||
label={t("userManagedAccess")}
|
||||
labelIcon={t("userManagedAccessHelp")}
|
||||
/>
|
||||
{isOrganizationsEnabled && (
|
||||
<DefaultSwitchControl
|
||||
name="organizationsEnabled"
|
||||
label={t("organizationsEnabled")}
|
||||
labelIcon={t("organizationsEnabledHelp")}
|
||||
/>
|
||||
)}
|
||||
<SelectControl
|
||||
name="unmanagedAttributePolicy"
|
||||
label={t("unmanagedAttributes")}
|
||||
|
|
|
@ -10,6 +10,7 @@ export enum Feature {
|
|||
TransientUsers = "TRANSIENT_USERS",
|
||||
ClientTypes = "CLIENT_TYPES",
|
||||
DeclarativeUI = "DECLARATIVE_UI",
|
||||
Organizations = "ORGANIZATION",
|
||||
}
|
||||
|
||||
export default function useIsFeatureEnabled() {
|
||||
|
|
|
@ -81,6 +81,7 @@ export default interface RealmRepresentation {
|
|||
offlineSessionIdleTimeout?: number;
|
||||
offlineSessionMaxLifespan?: number;
|
||||
offlineSessionMaxLifespanEnabled?: boolean;
|
||||
organizationsEnabled?: boolean;
|
||||
otpPolicyAlgorithm?: string;
|
||||
otpPolicyDigits?: number;
|
||||
otpPolicyInitialCounter?: number;
|
||||
|
|
|
@ -32,6 +32,8 @@ import java.util.*;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.organization.OrganizationProvider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -860,19 +862,34 @@ public class RealmAdapter implements CachedRealmModel {
|
|||
|
||||
@Override
|
||||
public Stream<IdentityProviderModel> getIdentityProvidersStream() {
|
||||
if (isUpdated()) return updated.getIdentityProvidersStream();
|
||||
return cached.getIdentityProviders().stream();
|
||||
if (isUpdated()) return updated.getIdentityProvidersStream().map(this::createOrganizationAwareIdentityProviderModel);
|
||||
return cached.getIdentityProviders().stream().map(this::createOrganizationAwareIdentityProviderModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityProviderModel getIdentityProviderByAlias(String alias) {
|
||||
if (isUpdated()) return updated.getIdentityProviderByAlias(alias);
|
||||
if (isUpdated()) return createOrganizationAwareIdentityProviderModel(updated.getIdentityProviderByAlias(alias));
|
||||
return getIdentityProvidersStream()
|
||||
.filter(model -> Objects.equals(model.getAlias(), alias))
|
||||
.findFirst()
|
||||
.map(this::createOrganizationAwareIdentityProviderModel)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private IdentityProviderModel createOrganizationAwareIdentityProviderModel(IdentityProviderModel idp) {
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.ORGANIZATION)) return idp;
|
||||
return new IdentityProviderModel(idp) {
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
// if IdP is bound to an org
|
||||
if (getOrganizationId() != null) {
|
||||
return session.getProvider(OrganizationProvider.class).isEnabled() && super.isEnabled();
|
||||
}
|
||||
return super.isEnabled();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIdentityProvider(IdentityProviderModel identityProvider) {
|
||||
getDelegateForUpdate();
|
||||
|
@ -1748,4 +1765,21 @@ public class RealmAdapter implements CachedRealmModel {
|
|||
public String toString() {
|
||||
return String.format("%s@%08x", getId(), hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrganizationsEnabled() {
|
||||
if (isUpdated()) return featureAwareIsOrganizationsEnabled(updated.isOrganizationsEnabled());
|
||||
return featureAwareIsOrganizationsEnabled(cached.isOrganizationsEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrganizationsEnabled(boolean organizationsEnabled) {
|
||||
getDelegateForUpdate();
|
||||
updated.setOrganizationsEnabled(organizationsEnabled);
|
||||
}
|
||||
|
||||
private boolean featureAwareIsOrganizationsEnabled(boolean isOrganizationsEnabled) {
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.ORGANIZATION)) return false;
|
||||
return isOrganizationsEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -340,10 +340,12 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
|
|||
int notBefore = getDelegate().getNotBeforeOfUser(realm, delegate);
|
||||
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.ORGANIZATION)) {
|
||||
// check if user is member of a disabled organization.
|
||||
// check if provider is enabled and user is managed member of a disabled organization OR provider is disabled and user is managed member
|
||||
OrganizationProvider organizationProvider = session.getProvider(OrganizationProvider.class);
|
||||
OrganizationModel organization = organizationProvider.getByMember(delegate);
|
||||
if (organization != null && organization.isManaged(delegate) && !organization.isEnabled()) {
|
||||
|
||||
if ((organizationProvider.isEnabled() && organization != null && organization.isManaged(delegate) && !organization.isEnabled()) ||
|
||||
(!organizationProvider.isEnabled() && organization != null && organization.isManaged(delegate))) {
|
||||
return new ReadOnlyUserModelDelegate(delegate) {
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
|
|
|
@ -70,6 +70,7 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
|||
protected boolean resetPasswordAllowed;
|
||||
protected boolean identityFederationEnabled;
|
||||
protected boolean editUsernameAllowed;
|
||||
protected boolean organizationsEnabled;
|
||||
//--- brute force settings
|
||||
protected boolean bruteForceProtected;
|
||||
protected boolean permanentLockout;
|
||||
|
@ -191,6 +192,7 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
|||
resetPasswordAllowed = model.isResetPasswordAllowed();
|
||||
identityFederationEnabled = model.isIdentityFederationEnabled();
|
||||
editUsernameAllowed = model.isEditUsernameAllowed();
|
||||
organizationsEnabled = model.isOrganizationsEnabled();
|
||||
//--- brute force settings
|
||||
bruteForceProtected = model.isBruteForceProtected();
|
||||
permanentLockout = model.isPermanentLockout();
|
||||
|
@ -423,6 +425,10 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
|||
return editUsernameAllowed;
|
||||
}
|
||||
|
||||
public boolean isOrganizationsEnabled() {
|
||||
return organizationsEnabled;
|
||||
}
|
||||
|
||||
public String getDefaultSignatureAlgorithm() {
|
||||
return defaultSignatureAlgorithm;
|
||||
}
|
||||
|
|
|
@ -1173,6 +1173,16 @@ public class RealmAdapter implements StorageProviderRealmModel, JpaModel<RealmEn
|
|||
em.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrganizationsEnabled() {
|
||||
return getAttribute(RealmAttributes.ORGANIZATIONS_ENABLED, Boolean.FALSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrganizationsEnabled(boolean organizationsEnabled) {
|
||||
setAttribute(RealmAttributes.ORGANIZATIONS_ENABLED, organizationsEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientModel getMasterAdminClient() {
|
||||
String masterAdminClientId = realm.getMasterAdminClient();
|
||||
|
|
|
@ -56,4 +56,5 @@ public interface RealmAttributes {
|
|||
|
||||
String FIRST_BROKER_LOGIN_FLOW_ID = "firstBrokerLoginFlowId";
|
||||
|
||||
String ORGANIZATIONS_ENABLED = "organizationsEnabled";
|
||||
}
|
||||
|
|
|
@ -398,7 +398,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
|||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return getAllStream().findAny().isPresent();
|
||||
return realm.isOrganizationsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -91,7 +91,7 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
|||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return entity.isEnabled();
|
||||
return provider.isEnabled() && entity.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,8 +136,6 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
|||
throw new ModelValidationException("You must provide at least one domain");
|
||||
}
|
||||
|
||||
List<IdentityProviderModel> idps = this.getIdentityProviders().toList();
|
||||
|
||||
Map<String, OrganizationDomainModel> modelMap = domains.stream()
|
||||
.map(this::validateDomain)
|
||||
.collect(Collectors.toMap(OrganizationDomainModel::getName, Function.identity()));
|
||||
|
@ -147,17 +145,16 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
|||
if (modelMap.containsKey(domainEntity.getName())) {
|
||||
domainEntity.setVerified(modelMap.get(domainEntity.getName()).getVerified());
|
||||
modelMap.remove(domainEntity.getName());
|
||||
}
|
||||
// remove domain that is not found in the new set.
|
||||
else {
|
||||
} else {
|
||||
// remove domain that is not found in the new set.
|
||||
this.entity.removeDomain(domainEntity);
|
||||
// check if any idp is assigned to the removed domain, and unset the domain if that's the case.
|
||||
idps.forEach(idp -> {
|
||||
if (Objects.equals(domainEntity.getName(), idp.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE))) {
|
||||
idp.getConfig().remove(ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||
realm.updateIdentityProvider(idp);
|
||||
}
|
||||
});
|
||||
getIdentityProviders()
|
||||
.filter(idp -> Objects.equals(domainEntity.getName(), idp.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE)))
|
||||
.forEach(idp -> {
|
||||
idp.getConfig().remove(ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||
realm.updateIdentityProvider(idp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@ import org.keycloak.organization.OrganizationProvider;
|
|||
import org.keycloak.storage.client.ClientStorageProvider;
|
||||
import org.keycloak.storage.datastore.DefaultDatastoreProvider;
|
||||
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
||||
import org.keycloak.storage.federated.UserGroupMembershipFederatedStorage;
|
||||
import org.keycloak.storage.managers.UserStorageSyncManager;
|
||||
import org.keycloak.storage.user.ImportedUserValidation;
|
||||
import org.keycloak.storage.user.UserBulkUpdateProvider;
|
||||
|
@ -116,10 +115,12 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
|
|||
protected UserModel importValidation(RealmModel realm, UserModel user) {
|
||||
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.ORGANIZATION) && user != null) {
|
||||
// check if user belongs to a disabled organization
|
||||
// check if provider is enabled and user is managed member of a disabled organization OR provider is disabled and user is managed member
|
||||
OrganizationProvider organizationProvider = session.getProvider(OrganizationProvider.class);
|
||||
OrganizationModel organization = organizationProvider.getByMember(user);
|
||||
if (organization != null && organization.isManaged(user) && !organization.isEnabled()) {
|
||||
|
||||
if ((organizationProvider.isEnabled() && organization != null && organization.isManaged(user) && !organization.isEnabled()) ||
|
||||
(!organizationProvider.isEnabled() && organization != null && organization.isManaged(user))) {
|
||||
return new ReadOnlyUserModelDelegate(user) {
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
|
@ -128,6 +129,7 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (user == null || user.getFederationLink() == null) return user;
|
||||
|
||||
UserStorageProviderModel model = getStorageProviderModel(realm, user.getFederationLink());
|
||||
|
|
|
@ -275,6 +275,7 @@ public class DefaultExportImportManager implements ExportImportManager {
|
|||
if (rep.isDuplicateEmailsAllowed() != null) newRealm.setDuplicateEmailsAllowed(rep.isDuplicateEmailsAllowed());
|
||||
if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
|
||||
if (rep.isEditUsernameAllowed() != null) newRealm.setEditUsernameAllowed(rep.isEditUsernameAllowed());
|
||||
if (rep.isOrganizationsEnabled() != null) newRealm.setOrganizationsEnabled(rep.isOrganizationsEnabled());
|
||||
if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
|
||||
if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
|
||||
if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAdminTheme());
|
||||
|
@ -754,6 +755,7 @@ public class DefaultExportImportManager implements ExportImportManager {
|
|||
if (rep.isDuplicateEmailsAllowed() != null) realm.setDuplicateEmailsAllowed(rep.isDuplicateEmailsAllowed());
|
||||
if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
|
||||
if (rep.isEditUsernameAllowed() != null) realm.setEditUsernameAllowed(rep.isEditUsernameAllowed());
|
||||
if (rep.isOrganizationsEnabled() != null) realm.setOrganizationsEnabled(rep.isOrganizationsEnabled());
|
||||
if (rep.getSslRequired() != null) realm.setSslRequired(SslRequired.valueOf(rep.getSslRequired().toUpperCase()));
|
||||
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||
if (rep.getAccessCodeLifespanUserAction() != null)
|
||||
|
|
|
@ -387,6 +387,7 @@ public class ModelToRepresentation {
|
|||
rep.setDuplicateEmailsAllowed(realm.isDuplicateEmailsAllowed());
|
||||
rep.setResetPasswordAllowed(realm.isResetPasswordAllowed());
|
||||
rep.setEditUsernameAllowed(realm.isEditUsernameAllowed());
|
||||
rep.setOrganizationsEnabled(realm.isOrganizationsEnabled());
|
||||
rep.setDefaultSignatureAlgorithm(realm.getDefaultSignatureAlgorithm());
|
||||
rep.setRevokeRefreshToken(realm.isRevokeRefreshToken());
|
||||
rep.setRefreshTokenMaxReuse(realm.getRefreshTokenMaxReuse());
|
||||
|
|
|
@ -1120,4 +1120,13 @@ public class RealmModelDelegate implements RealmModel {
|
|||
return delegate.searchForRolesStream(search, first, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrganizationsEnabled() {
|
||||
return delegate.isOrganizationsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrganizationsEnabled(boolean organizationsEnabled) {
|
||||
delegate.setOrganizationsEnabled(organizationsEnabled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.keycloak.organization;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
|
|
@ -1773,6 +1773,14 @@ public class IdentityBrokerStateTestHelpers {
|
|||
public void decreaseRemainingCount(ClientInitialAccessModel clientInitialAccess) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrganizationsEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrganizationsEnabled(boolean organizationsEnabled) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.common.Profile.Feature;
|
|||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>A model type representing the configuration for identity providers. It provides some common properties and also a {@link org.keycloak.models.IdentityProviderModel#config}
|
||||
|
@ -319,4 +320,20 @@ public class IdentityProviderModel implements Serializable {
|
|||
public void setMetadataDescriptorUrl(String metadataDescriptorUrl) {
|
||||
getConfig().put(METADATA_DESCRIPTOR_URL, metadataDescriptorUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 61 * hash + Objects.hashCode(this.internalId);
|
||||
hash = 61 * hash + Objects.hashCode(this.alias);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof IdentityProviderModel)) return false;
|
||||
return Objects.equals(getInternalId(), ((IdentityProviderModel) obj).getInternalId()) &&
|
||||
Objects.equals(getAlias(), ((IdentityProviderModel) obj).getAlias());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,10 @@ public interface RealmModel extends RoleContainerModel {
|
|||
|
||||
void setUserManagedAccessAllowed(boolean userManagedAccessAllowed);
|
||||
|
||||
boolean isOrganizationsEnabled();
|
||||
|
||||
void setOrganizationsEnabled(boolean organizationsEnabled);
|
||||
|
||||
void setAttribute(String name, String value);
|
||||
default void setAttribute(String name, Boolean value) {
|
||||
setAttribute(name, value.toString());
|
||||
|
|
|
@ -89,6 +89,7 @@ public class OrganizationResource {
|
|||
@Operation( summary = "Creates a new organization")
|
||||
public Response create(OrganizationRepresentation organization) {
|
||||
auth.realm().requireManageRealm();
|
||||
checkOrganizationsEnabled();
|
||||
if (organization == null) {
|
||||
throw ErrorResponse.error("Organization cannot be null.", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
@ -126,6 +127,7 @@ public class OrganizationResource {
|
|||
@Parameter(description = "The maximum number of results to be returned - defaults to 10") @QueryParam("max") @DefaultValue("10") Integer max
|
||||
) {
|
||||
auth.realm().requireManageRealm();
|
||||
checkOrganizationsEnabled();
|
||||
|
||||
// check if are searching orgs by attribute.
|
||||
if(StringUtil.isNotBlank(searchQuery)) {
|
||||
|
@ -150,6 +152,7 @@ public class OrganizationResource {
|
|||
@Operation(summary = "Returns the organization associated with the specified id, or null if no organization is found")
|
||||
public OrganizationRepresentation get(@PathParam("id") String id) {
|
||||
auth.realm().requireManageRealm();
|
||||
checkOrganizationsEnabled();
|
||||
if (StringUtil.isBlank(id)) {
|
||||
throw ErrorResponse.error("Id cannot be null.", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
@ -163,6 +166,7 @@ public class OrganizationResource {
|
|||
@Operation(summary = "Deletes the organization with the specified id")
|
||||
public Response delete(@PathParam("id") String id) {
|
||||
auth.realm().requireManageRealm();
|
||||
checkOrganizationsEnabled();
|
||||
if (StringUtil.isBlank(id)) {
|
||||
throw ErrorResponse.error("Id cannot be null.", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
@ -179,6 +183,7 @@ public class OrganizationResource {
|
|||
@Operation(summary = "Updates the organization with the specified id")
|
||||
public Response update(@PathParam("id") String id, OrganizationRepresentation organization) {
|
||||
auth.realm().requireManageRealm();
|
||||
checkOrganizationsEnabled();
|
||||
OrganizationModel model = getOrganization(id);
|
||||
toModel(organization, model);
|
||||
|
||||
|
@ -187,11 +192,13 @@ public class OrganizationResource {
|
|||
|
||||
@Path("{id}/members")
|
||||
public OrganizationMemberResource members(@PathParam("id") String id) {
|
||||
checkOrganizationsEnabled();
|
||||
return new OrganizationMemberResource(session, getOrganization(id), auth, adminEvent);
|
||||
}
|
||||
|
||||
@Path("{id}/identity-providers")
|
||||
public OrganizationIdentityProvidersResource identityProvider(@PathParam("id") String id) {
|
||||
checkOrganizationsEnabled();
|
||||
return new OrganizationIdentityProvidersResource(session, getOrganization(id), auth, adminEvent);
|
||||
}
|
||||
|
||||
|
@ -259,4 +266,10 @@ public class OrganizationResource {
|
|||
private OrganizationDomainModel toModel(OrganizationDomainRepresentation domainRepresentation) {
|
||||
return new OrganizationDomainModel(domainRepresentation.getName(), domainRepresentation.isVerified());
|
||||
}
|
||||
|
||||
private void checkOrganizationsEnabled() {
|
||||
if (provider != null && !provider.isEnabled()) {
|
||||
throw ErrorResponse.error("Organizations not enabled for this realm.", Response.Status.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.keycloak.organization.authentication.authenticators.broker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
|
@ -32,6 +31,8 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.organization.OrganizationProvider;
|
||||
|
||||
import static org.keycloak.organization.utils.Organizations.isEnabledAndOrganizationsPresent;
|
||||
|
||||
public class IdpAddOrganizationMemberAuthenticator extends AbstractIdpAuthenticator {
|
||||
|
||||
@Override
|
||||
|
@ -70,13 +71,13 @@ public class IdpAddOrganizationMemberAuthenticator extends AbstractIdpAuthentica
|
|||
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
|
||||
|
||||
if (!provider.isEnabled()) {
|
||||
if (!isEnabledAndOrganizationsPresent(provider)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OrganizationModel organization = (OrganizationModel) session.getAttribute(OrganizationModel.class.getName());
|
||||
|
||||
if (organization == null) {
|
||||
if (organization == null || !organization.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,10 @@
|
|||
|
||||
package org.keycloak.organization.authentication.authenticators.browser;
|
||||
|
||||
import static org.keycloak.organization.utils.Organizations.isEnabledAndOrganizationsPresent;
|
||||
import static org.keycloak.organization.utils.Organizations.resolveBroker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jakarta.ws.rs.core.MultivaluedMap;
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.AuthenticationFlowError;
|
||||
|
@ -30,7 +29,6 @@ import org.keycloak.forms.login.LoginFormsProvider;
|
|||
import org.keycloak.forms.login.freemarker.model.AuthenticationContextBean;
|
||||
import org.keycloak.forms.login.freemarker.model.IdentityProviderBean;
|
||||
import org.keycloak.http.HttpRequest;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
|
@ -56,7 +54,7 @@ public class OrganizationAuthenticator extends IdentityProviderAuthenticator {
|
|||
public void authenticate(AuthenticationFlowContext context) {
|
||||
OrganizationProvider provider = getOrganizationProvider();
|
||||
|
||||
if (!provider.isEnabled()) {
|
||||
if (!isEnabledAndOrganizationsPresent(provider)) {
|
||||
context.attempted();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
|||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import static org.keycloak.organization.utils.Organizations.isEnabledAndOrganizationsPresent;
|
||||
|
||||
public class OrganizationMembershipMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-organization-membership-mapper";
|
||||
|
@ -77,7 +79,7 @@ public class OrganizationMembershipMapper extends AbstractOIDCProtocolMapper imp
|
|||
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
|
||||
OrganizationProvider provider = keycloakSession.getProvider(OrganizationProvider.class);
|
||||
|
||||
if (!provider.isEnabled()) {
|
||||
if (!isEnabledAndOrganizationsPresent(provider)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package org.keycloak.organization.protocol.mappers.saml;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.Profile.Feature;
|
||||
|
@ -39,6 +38,8 @@ import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
|||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
|
||||
import static org.keycloak.organization.utils.Organizations.isEnabledAndOrganizationsPresent;
|
||||
|
||||
public class OrganizationMembershipMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String ID = "saml-organization-membership-mapper";
|
||||
|
@ -59,7 +60,7 @@ public class OrganizationMembershipMapper extends AbstractSAMLProtocolMapper imp
|
|||
public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
|
||||
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
|
||||
|
||||
if (!provider.isEnabled()) {
|
||||
if (!isEnabledAndOrganizationsPresent(provider)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -114,4 +114,9 @@ public class Organizations {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isEnabledAndOrganizationsPresent(OrganizationProvider organizationProvider) {
|
||||
// todo replace getAllStream().findAny().isPresent() with count query
|
||||
return organizationProvider != null && organizationProvider.isEnabled() && organizationProvider.getAllStream().findAny().isPresent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ import org.keycloak.provider.ProviderConfigProperty;
|
|||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* OpenShift 4 Identity Provider configuration class.
|
||||
|
|
|
@ -179,4 +179,9 @@ public class RealmAttributeUpdater extends ServerResourceUpdater<RealmAttributeU
|
|||
rep.getBrowserSecurityHeaders().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RealmAttributeUpdater setOrganizationEnabled(Boolean organizationsEnabled) {
|
||||
rep.setOrganizationsEnabled(organizationsEnabled);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.keycloak.testsuite.organization.admin;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
@ -24,7 +26,6 @@ import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
|
@ -48,6 +49,7 @@ import org.keycloak.testsuite.pages.AppPage;
|
|||
import org.keycloak.testsuite.pages.IdpConfirmLinkPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
|
||||
import org.keycloak.testsuite.util.TestCleanup;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
|
@ -78,6 +80,7 @@ public abstract class AbstractOrganizationTest extends AbstractAdminTest {
|
|||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
testRealm.getClients().addAll(bc.createConsumerClients());
|
||||
testRealm.setSmtpServer(null);
|
||||
testRealm.setOrganizationsEnabled(Boolean.TRUE);
|
||||
super.configureTestRealm(testRealm);
|
||||
}
|
||||
|
||||
|
@ -96,25 +99,28 @@ public abstract class AbstractOrganizationTest extends AbstractAdminTest {
|
|||
}
|
||||
|
||||
protected OrganizationRepresentation createOrganization(String name, String... orgDomain) {
|
||||
return createOrganization(testRealm(), getCleanup(), name, brokerConfigFunction.apply(name).setUpIdentityProvider(), orgDomain);
|
||||
}
|
||||
|
||||
protected static OrganizationRepresentation createOrganization(RealmResource testRealm, TestCleanup testCleanup, String name, IdentityProviderRepresentation broker, String... orgDomain) {
|
||||
OrganizationRepresentation org = createRepresentation(name, orgDomain);
|
||||
String id;
|
||||
|
||||
try (Response response = testRealm().organizations().create(org)) {
|
||||
try (Response response = testRealm.organizations().create(org)) {
|
||||
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
||||
id = ApiUtil.getCreatedId(response);
|
||||
}
|
||||
IdentityProviderRepresentation broker = brokerConfigFunction.apply(name).setUpIdentityProvider();
|
||||
broker.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, org.getDomains().iterator().next().getName());
|
||||
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();
|
||||
getCleanup().addCleanup(() -> testRealm().organizations().get(id).delete().close());
|
||||
testRealm.identityProviders().create(broker).close();
|
||||
testCleanup.addCleanup(testRealm.identityProviders().get(broker.getAlias())::remove);
|
||||
testRealm.organizations().get(id).identityProviders().addIdentityProvider(broker.getAlias()).close();
|
||||
org = testRealm.organizations().get(id).toRepresentation();
|
||||
testCleanup.addCleanup(() -> testRealm.organizations().get(id).delete().close());
|
||||
|
||||
return org;
|
||||
}
|
||||
|
||||
protected OrganizationRepresentation createRepresentation(String name, String... orgDomains) {
|
||||
protected static OrganizationRepresentation createRepresentation(String name, String... orgDomains) {
|
||||
OrganizationRepresentation org = new OrganizationRepresentation();
|
||||
org.setName(name);
|
||||
|
||||
|
@ -188,6 +194,7 @@ public abstract class AbstractOrganizationTest extends AbstractAdminTest {
|
|||
log.debug("Updating info on updateAccount page");
|
||||
assertFalse(driver.getPageSource().contains("kc.org"));
|
||||
updateAccountInformationPage.updateAccountInformation(bc.getUserLogin(), email, "Firstname", "Lastname");
|
||||
assertThat(appPage.getRequestType(),is(AppPage.RequestType.AUTH_RESPONSE));
|
||||
|
||||
assertIsMember(email, organization);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ public class OrganizationAdminPermissionsTest extends AbstractOrganizationTest {
|
|||
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.MANAGE_IDENTITY_PROVIDERS)
|
||||
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.MANAGE_USERS)
|
||||
.build());
|
||||
super.configureTestRealm(testRealm);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -17,14 +17,18 @@
|
|||
|
||||
package org.keycloak.testsuite.organization.admin;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||
import org.keycloak.common.Profile.Feature;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
|
||||
@EnableFeature(Feature.ORGANIZATION)
|
||||
public class OrganizationMemberAuthenticationTest extends AbstractOrganizationTest {
|
||||
|
@ -86,4 +90,36 @@ public class OrganizationMemberAuthenticationTest extends AbstractOrganizationTe
|
|||
Assert.assertTrue(loginPage.isUsernameInputPresent());
|
||||
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateUnmanagedMemberWehnProviderDisabled() throws IOException {
|
||||
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||
UserRepresentation member = addMember(organization, "contractor@contractor.org");
|
||||
|
||||
// first try to access login page
|
||||
oauth.clientId("broker-app");
|
||||
loginPage.open(bc.consumerRealmName());
|
||||
Assert.assertFalse(loginPage.isPasswordInputPresent());
|
||||
Assert.assertFalse(loginPage.isSocialButtonPresent(bc.getIDPAlias()));
|
||||
|
||||
// disable the organization provider
|
||||
try (RealmAttributeUpdater rau = new RealmAttributeUpdater(testRealm())
|
||||
.setOrganizationEnabled(Boolean.FALSE)
|
||||
.update()) {
|
||||
|
||||
// access the page again, now it should be present username and password fields
|
||||
loginPage.open(bc.consumerRealmName());
|
||||
|
||||
waitForPage(driver, "sign in to", true);
|
||||
assertThat("Driver should be on the consumer realm page right now",
|
||||
driver.getCurrentUrl(), Matchers.containsString("/auth/realms/" + bc.consumerRealmName() + "/"));
|
||||
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
||||
// no idp should be shown because there is only a single idp that is bound to an organization
|
||||
Assert.assertFalse(loginPage.isSocialButtonPresent(bc.getIDPAlias()));
|
||||
|
||||
// the member should be able to log in using the credentials
|
||||
loginPage.login(member.getEmail(), memberPassword);
|
||||
appPage.assertCurrent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@ import jakarta.ws.rs.BadRequestException;
|
|||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import java.io.IOException;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.OrganizationMemberResource;
|
||||
|
@ -57,6 +58,7 @@ import org.keycloak.representations.userprofile.config.UPConfig;
|
|||
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
|
||||
@EnableFeature(Feature.ORGANIZATION)
|
||||
public class OrganizationMemberTest extends AbstractOrganizationTest {
|
||||
|
@ -194,7 +196,7 @@ public class OrganizationMemberTest extends AbstractOrganizationTest {
|
|||
assertThat(existingOrg.isEnabled(), is(false));
|
||||
|
||||
// now fetch all users from the org - unmanaged users should still be enabled, but managed ones should not.
|
||||
List<UserRepresentation> existing = organization.members().getAll();;
|
||||
List<UserRepresentation> existing = organization.members().getAll();
|
||||
assertThat(existing, not(empty()));
|
||||
assertThat(existing, hasSize(6));
|
||||
for (UserRepresentation user : existing) {
|
||||
|
@ -229,6 +231,48 @@ public class OrganizationMemberTest extends AbstractOrganizationTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllDisabledOrganizationProvider() throws IOException {
|
||||
OrganizationRepresentation orgRep = createOrganization();
|
||||
OrganizationResource organization = testRealm().organizations().get(orgRep.getId());
|
||||
|
||||
// add some unmanaged members to the organization.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
addMember(organization, "member-" + i + "@neworg.org");
|
||||
}
|
||||
|
||||
// onboard a test user by authenticating using the organization's provider.
|
||||
super.assertBrokerRegistration(organization, bc.getUserEmail());
|
||||
|
||||
// now fetch all users from the realm
|
||||
List<UserRepresentation> members = testRealm().users().search("*neworg*", null, null);
|
||||
members.stream().forEach(user -> assertThat(user.isEnabled(), is(Boolean.TRUE)));
|
||||
|
||||
// disable the organization provider
|
||||
try (RealmAttributeUpdater rau = new RealmAttributeUpdater(testRealm())
|
||||
.setOrganizationEnabled(Boolean.FALSE)
|
||||
.update()) {
|
||||
|
||||
// now fetch all members from the realm - unmanaged users should still be enabled, but managed ones should not.
|
||||
List<UserRepresentation> existing = testRealm().users().search("*neworg*", null, null);
|
||||
assertThat(existing, hasSize(members.size()));
|
||||
for (UserRepresentation user : existing) {
|
||||
if (user.getEmail().equals(bc.getUserEmail())) {
|
||||
assertThat(user.isEnabled(), is(Boolean.FALSE));
|
||||
|
||||
// try to update the disabled user (for example, try to re-enable the user) - should not be possible.
|
||||
user.setEnabled(Boolean.TRUE);
|
||||
try {
|
||||
testRealm().users().get(user.getId()).update(user);
|
||||
fail("Should not be possible to update disabled org user");
|
||||
} catch(BadRequestException expected) {}
|
||||
} else {
|
||||
assertThat("User " + user.getUsername(), user.isEnabled(), is(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteUnmanagedMember() {
|
||||
UPConfig upConfig = testRealm().users().userProfile().getConfiguration();
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.util.stream.Collectors;
|
|||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
|
@ -51,6 +52,7 @@ import org.keycloak.representations.idm.OrganizationDomainRepresentation;
|
|||
import org.keycloak.representations.idm.OrganizationRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
import org.keycloak.testsuite.util.RealmBuilder;
|
||||
|
||||
@EnableFeature(Feature.ORGANIZATION)
|
||||
|
@ -373,35 +375,67 @@ public class OrganizationTest extends AbstractOrganizationTest {
|
|||
assertNotNull(existing.getDomain("acme.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledOrganizationProvider() throws IOException {
|
||||
OrganizationRepresentation existing = createOrganization("acme", "acme.org", "acme.net");
|
||||
// disable the organization provider and try to access REST endpoints
|
||||
try (RealmAttributeUpdater rau = new RealmAttributeUpdater(testRealm())
|
||||
.setOrganizationEnabled(Boolean.FALSE)
|
||||
.update()) {
|
||||
OrganizationRepresentation org = createRepresentation("some", "some.com");
|
||||
|
||||
try (Response response = testRealm().organizations().create(org)) {
|
||||
assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
|
||||
}
|
||||
try {
|
||||
testRealm().organizations().getAll();
|
||||
fail("Expected NotFoundException");
|
||||
} catch (NotFoundException expected) {}
|
||||
try {
|
||||
testRealm().organizations().search("*");
|
||||
fail("Expected NotFoundException");
|
||||
} catch (NotFoundException expected) {}
|
||||
try {
|
||||
testRealm().organizations().get(existing.getId()).toRepresentation();
|
||||
fail("Expected NotFoundException");
|
||||
} catch (NotFoundException expected) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteRealm() {
|
||||
RealmRepresentation realmRep = RealmBuilder.create().name(KeycloakModelUtils.generateId()).build();
|
||||
RealmResource realm = realmsResouce().realm(realmRep.getRealm());
|
||||
RealmRepresentation realmRep = RealmBuilder.create()
|
||||
.name(KeycloakModelUtils.generateId())
|
||||
.organizationEnabled(true)
|
||||
.build();
|
||||
RealmResource realmRes = realmsResouce().realm(realmRep.getRealm());
|
||||
|
||||
try {
|
||||
realmRep.setEnabled(true);
|
||||
realmsResouce().create(realmRep);
|
||||
realm = realmsResouce().realm(realmRep.getRealm());
|
||||
realm.toRepresentation();
|
||||
realmRes = realmsResouce().realm(realmRep.getRealm());
|
||||
realmRes.toRepresentation();
|
||||
OrganizationRepresentation org = new OrganizationRepresentation();
|
||||
org.setName("test-org");
|
||||
org.addDomain(new OrganizationDomainRepresentation("test.org"));
|
||||
org.setEnabled(true);
|
||||
Response response = realm.organizations().create(org);
|
||||
response.close();
|
||||
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
||||
List<OrganizationRepresentation> orgs = realm.organizations().getAll();
|
||||
assertEquals(1, orgs.size());
|
||||
try (Response response = realmRes.organizations().create(org)) {
|
||||
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
||||
}
|
||||
|
||||
List<OrganizationRepresentation> orgs = realmRes.organizations().getAll();
|
||||
assertThat(orgs, hasSize(1));
|
||||
|
||||
IdentityProviderRepresentation broker = bc.setUpIdentityProvider();
|
||||
broker.setAlias(KeycloakModelUtils.generateId());
|
||||
response = realm.identityProviders().create(broker);
|
||||
response.close();
|
||||
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
||||
response = realm.organizations().get(orgs.get(0).getId()).identityProviders().addIdentityProvider(broker.getAlias());
|
||||
response.close();
|
||||
assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
|
||||
try (Response response = realmRes.identityProviders().create(broker)) {
|
||||
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
|
||||
}
|
||||
try (Response response = realmRes.organizations().get(orgs.get(0).getId()).identityProviders().addIdentityProvider(broker.getAlias())) {
|
||||
assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
|
||||
}
|
||||
} finally {
|
||||
realm.remove();
|
||||
realmRes.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -326,4 +326,9 @@ public class RealmBuilder {
|
|||
rep.setDefaultLocale(defaultLocale);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RealmBuilder organizationEnabled(boolean enabled) {
|
||||
rep.setOrganizationsEnabled(enabled);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue