Avoid adding organization flows if they are already exist
Closes #31182 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
25da859d18
commit
de1de06354
3 changed files with 113 additions and 132 deletions
|
@ -17,20 +17,12 @@
|
|||
|
||||
package org.keycloak.organization.jpa;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.GroupModel.GroupEvent;
|
||||
import org.keycloak.models.ModelValidationException;
|
||||
import org.keycloak.organization.authentication.authenticators.broker.IdpOrganizationAuthenticatorFactory;
|
||||
import org.keycloak.organization.authentication.authenticators.browser.OrganizationAuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmModel.RealmPostCreateEvent;
|
||||
import org.keycloak.models.RealmModel.RealmRemovedEvent;
|
||||
import org.keycloak.organization.OrganizationProvider;
|
||||
import org.keycloak.organization.OrganizationProviderFactory;
|
||||
import org.keycloak.organization.utils.Organizations;
|
||||
|
@ -65,133 +57,13 @@ public class JpaOrganizationProviderFactory implements OrganizationProviderFacto
|
|||
return ID;
|
||||
}
|
||||
|
||||
private void handleEvents(ProviderEvent event) {
|
||||
if (event instanceof RealmPostCreateEvent) {
|
||||
RealmModel realm = ((RealmPostCreateEvent) event).getCreatedRealm();
|
||||
configureAuthenticationFlows(realm);
|
||||
}
|
||||
if (event instanceof GroupEvent) {
|
||||
GroupEvent groupEvent = (GroupEvent) event;
|
||||
KeycloakSession session = groupEvent.getKeycloakSession();
|
||||
GroupModel group = groupEvent.getGroup();
|
||||
private void handleEvents(ProviderEvent e) {
|
||||
if (e instanceof GroupEvent event) {
|
||||
KeycloakSession session = event.getKeycloakSession();
|
||||
GroupModel group = event.getGroup();
|
||||
if (!Organizations.canManageOrganizationGroup(session, group)) {
|
||||
throw new ModelValidationException("Can not update organization group");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void configureAuthenticationFlows(RealmModel realm) {
|
||||
addOrganizationFirstBrokerFlowStep(realm);
|
||||
addOrganizationBrowserFlowStep(realm);
|
||||
}
|
||||
|
||||
private void addOrganizationFirstBrokerFlowStep(RealmModel realm) {
|
||||
|
||||
AuthenticationFlowModel firstBrokerLoginFlow = realm.getFirstBrokerLoginFlow();
|
||||
if (firstBrokerLoginFlow == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (realm.getAuthenticationExecutionsStream(firstBrokerLoginFlow.getId())
|
||||
.map(AuthenticationExecutionModel::getAuthenticator)
|
||||
.anyMatch(IdpOrganizationAuthenticatorFactory.ID::equals)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config.getAdminRealm().equals(realm.getName())) {
|
||||
// do not add the org flows to the master realm for now.
|
||||
AuthenticationFlowModel conditionalOrg = new AuthenticationFlowModel();
|
||||
conditionalOrg.setTopLevel(false);
|
||||
conditionalOrg.setBuiltIn(true);
|
||||
conditionalOrg.setAlias("First Broker Login - Conditional Organization");
|
||||
conditionalOrg.setDescription("Flow to determine if the authenticator that adds organization members is to be used");
|
||||
conditionalOrg.setProviderId("basic-flow");
|
||||
conditionalOrg = realm.addAuthenticationFlow(conditionalOrg);
|
||||
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(firstBrokerLoginFlow.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.CONDITIONAL);
|
||||
execution.setFlowId(conditionalOrg.getId());
|
||||
execution.setPriority(50);
|
||||
execution.setAuthenticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator("conditional-user-configured");
|
||||
execution.setPriority(10);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator(IdpOrganizationAuthenticatorFactory.ID);
|
||||
execution.setPriority(20);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
}
|
||||
}
|
||||
|
||||
public void addOrganizationBrowserFlowStep(RealmModel realm) {
|
||||
|
||||
AuthenticationFlowModel browserFlow = realm.getBrowserFlow();
|
||||
if (browserFlow == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (realm.getAuthenticationExecutionsStream(browserFlow.getId())
|
||||
.map(AuthenticationExecutionModel::getAuthenticator)
|
||||
.anyMatch(OrganizationAuthenticatorFactory.ID::equals)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config.getAdminRealm().equals(realm.getName())) {
|
||||
// do not add the org flows to the master realm for now.
|
||||
AuthenticationFlowModel organizations = new AuthenticationFlowModel();
|
||||
organizations.setTopLevel(false);
|
||||
organizations.setBuiltIn(true);
|
||||
organizations.setAlias("Organization");
|
||||
organizations.setProviderId("basic-flow");
|
||||
organizations = realm.addAuthenticationFlow(organizations);
|
||||
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(browserFlow.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setFlowId(organizations.getId());
|
||||
execution.setPriority(26);
|
||||
execution.setAuthenticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
AuthenticationFlowModel conditionalOrg = new AuthenticationFlowModel();
|
||||
conditionalOrg.setTopLevel(false);
|
||||
conditionalOrg.setBuiltIn(true);
|
||||
conditionalOrg.setAlias("Browser - Conditional Organization");
|
||||
conditionalOrg.setDescription("Flow to determine if the organization identity-first login is to be used");
|
||||
conditionalOrg.setProviderId("basic-flow");
|
||||
conditionalOrg = realm.addAuthenticationFlow(conditionalOrg);
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(organizations.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.CONDITIONAL);
|
||||
execution.setFlowId(conditionalOrg.getId());
|
||||
execution.setPriority(10);
|
||||
execution.setAuthenticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator("conditional-user-configured");
|
||||
execution.setPriority(10);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setAuthenticator(OrganizationAuthenticatorFactory.ID);
|
||||
execution.setPriority(20);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
package org.keycloak.models.utils;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.Profile.Feature;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
|
@ -379,6 +382,8 @@ public class DefaultAuthenticationFlows {
|
|||
execution.setPriority(20);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
addOrganizationBrowserFlowStep(realm, browser);
|
||||
}
|
||||
|
||||
public static void addIdentityProviderAuthenticator(RealmModel realm, String defaultProvider) {
|
||||
|
@ -638,6 +643,8 @@ public class DefaultAuthenticationFlows {
|
|||
execution.setPriority(20);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
addOrganizationFirstBrokerFlowStep(realm, firstBrokerLogin);
|
||||
}
|
||||
|
||||
public static void samlEcpProfile(RealmModel realm) {
|
||||
|
@ -682,4 +689,96 @@ public class DefaultAuthenticationFlows {
|
|||
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
}
|
||||
|
||||
private static void addOrganizationFirstBrokerFlowStep(RealmModel realm, AuthenticationFlowModel flow) {
|
||||
if (!Profile.isFeatureEnabled(Feature.ORGANIZATION)) {
|
||||
return;
|
||||
}
|
||||
if (!Config.getAdminRealm().equals(realm.getName())) {
|
||||
// do not add the org flows to the master realm for now.
|
||||
AuthenticationFlowModel conditionalOrg = new AuthenticationFlowModel();
|
||||
conditionalOrg.setTopLevel(false);
|
||||
conditionalOrg.setBuiltIn(true);
|
||||
conditionalOrg.setAlias("First Broker Login - Conditional Organization");
|
||||
conditionalOrg.setDescription("Flow to determine if the authenticator that adds organization members is to be used");
|
||||
conditionalOrg.setProviderId("basic-flow");
|
||||
conditionalOrg = realm.addAuthenticationFlow(conditionalOrg);
|
||||
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(flow.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.CONDITIONAL);
|
||||
execution.setFlowId(conditionalOrg.getId());
|
||||
execution.setPriority(50);
|
||||
execution.setAuthenticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator("conditional-user-configured");
|
||||
execution.setPriority(10);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator("idp-add-organization-member");
|
||||
execution.setPriority(20);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addOrganizationBrowserFlowStep(RealmModel realm, AuthenticationFlowModel flow) {
|
||||
if (!Profile.isFeatureEnabled(Feature.ORGANIZATION)) {
|
||||
return;
|
||||
}
|
||||
if (!Config.getAdminRealm().equals(realm.getName())) {
|
||||
// do not add the org flows to the master realm for now.
|
||||
AuthenticationFlowModel organizations = new AuthenticationFlowModel();
|
||||
organizations.setTopLevel(false);
|
||||
organizations.setBuiltIn(true);
|
||||
organizations.setAlias("Organization");
|
||||
organizations.setProviderId("basic-flow");
|
||||
organizations = realm.addAuthenticationFlow(organizations);
|
||||
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(flow.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setFlowId(organizations.getId());
|
||||
execution.setPriority(26);
|
||||
execution.setAuthenticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
AuthenticationFlowModel conditionalOrg = new AuthenticationFlowModel();
|
||||
conditionalOrg.setTopLevel(false);
|
||||
conditionalOrg.setBuiltIn(true);
|
||||
conditionalOrg.setAlias("Browser - Conditional Organization");
|
||||
conditionalOrg.setDescription("Flow to determine if the organization identity-first login is to be used");
|
||||
conditionalOrg.setProviderId("basic-flow");
|
||||
conditionalOrg = realm.addAuthenticationFlow(conditionalOrg);
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(organizations.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.CONDITIONAL);
|
||||
execution.setFlowId(conditionalOrg.getId());
|
||||
execution.setPriority(10);
|
||||
execution.setAuthenticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator("conditional-user-configured");
|
||||
execution.setPriority(10);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(conditionalOrg.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setAuthenticator("organization");
|
||||
execution.setPriority(20);
|
||||
execution.setAuthenticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,12 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
|
@ -40,6 +42,8 @@ import org.keycloak.exportimport.ExportImportConfig;
|
|||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||
import org.keycloak.exportimport.singlefile.SingleFileImportProviderFactory;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.OrganizationRepresentation;
|
||||
import org.keycloak.representations.idm.PartialImportRepresentation;
|
||||
|
@ -125,6 +129,12 @@ public class OrganizationExportTest extends AbstractOrganizationTest {
|
|||
// login to the organization identity provider and run the configured first broker login flow
|
||||
loginPage.login(email, bc.getUserPassword());
|
||||
assertThat(appPage.getRequestType(),is(AppPage.RequestType.AUTH_RESPONSE));
|
||||
|
||||
AuthenticationManagementResource flows = testRealm().flows();
|
||||
List<AuthenticationExecutionInfoRepresentation> executions = flows.getExecutions(DefaultAuthenticationFlows.BROWSER_FLOW);
|
||||
assertThat(executions.stream().filter(e -> "Organization".equals(e.getDisplayName())).count(), is(1L));
|
||||
executions = flows.getExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW);
|
||||
assertThat(executions.stream().filter(e -> "First Broker Login - Conditional Organization".equals(e.getDisplayName())).count(), is(1L));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in a new issue