diff --git a/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProviderFactory.java b/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProviderFactory.java index a47789d352b..4e24104aec4 100644 --- a/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProviderFactory.java +++ b/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProviderFactory.java @@ -17,6 +17,7 @@ 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; @@ -88,8 +89,8 @@ public class JpaOrganizationProviderFactory implements OrganizationProviderFacto } private void addOrganizationFirstBrokerFlowStep(RealmModel realm) { - AuthenticationFlowModel firstBrokerLoginFlow = realm.getFirstBrokerLoginFlow(); + AuthenticationFlowModel firstBrokerLoginFlow = realm.getFirstBrokerLoginFlow(); if (firstBrokerLoginFlow == null) { return; } @@ -100,18 +101,44 @@ public class JpaOrganizationProviderFactory implements OrganizationProviderFacto return; } - AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); - execution.setParentFlow(firstBrokerLoginFlow.getId()); - execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); - execution.setAuthenticator(IdpOrganizationAuthenticatorFactory.ID); - execution.setPriority(50); - execution.setAuthenticatorFlow(false); - realm.addAuthenticatorExecution(execution); + 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(); + AuthenticationFlowModel browserFlow = realm.getBrowserFlow(); if (browserFlow == null) { return; } @@ -122,14 +149,52 @@ public class JpaOrganizationProviderFactory implements OrganizationProviderFacto return; } - AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); + 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); - execution.setParentFlow(browserFlow.getId()); - execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); - execution.setAuthenticator(OrganizationAuthenticatorFactory.ID); - execution.setPriority(26); - execution.setAuthenticatorFlow(false); + 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); - 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); + } } } diff --git a/services/src/main/java/org/keycloak/organization/authentication/authenticators/broker/IdpOrganizationAuthenticatorFactory.java b/services/src/main/java/org/keycloak/organization/authentication/authenticators/broker/IdpOrganizationAuthenticatorFactory.java index a2ff2baa690..408b4d57ed8 100644 --- a/services/src/main/java/org/keycloak/organization/authentication/authenticators/broker/IdpOrganizationAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/organization/authentication/authenticators/broker/IdpOrganizationAuthenticatorFactory.java @@ -77,7 +77,7 @@ public class IdpOrganizationAuthenticatorFactory implements AuthenticatorFactory @Override public String getDisplayType() { - return "Organization"; + return "Organization Member Onboard"; } @Override diff --git a/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticator.java b/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticator.java index 8ff30c77c97..4045ddacd67 100644 --- a/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticator.java +++ b/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticator.java @@ -190,4 +190,9 @@ public class OrganizationAuthenticator extends IdentityProviderAuthenticator { return email.substring(domainSeparator + 1); } + + @Override + public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { + return realm.isOrganizationsEnabled(); + } } diff --git a/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticatorFactory.java b/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticatorFactory.java index a52a9286899..b3231f798d2 100644 --- a/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/organization/authentication/authenticators/browser/OrganizationAuthenticatorFactory.java @@ -17,6 +17,8 @@ package org.keycloak.organization.authentication.authenticators.browser; +import java.util.List; + import org.keycloak.Config.Scope; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticatorFactory; @@ -24,6 +26,7 @@ import org.keycloak.common.Profile; import org.keycloak.common.Profile.Feature; import org.keycloak.models.KeycloakSession; import org.keycloak.provider.EnvironmentDependentProviderFactory; +import org.keycloak.provider.ProviderConfigProperty; /** * @author Stian Thorgersen @@ -39,7 +42,7 @@ public class OrganizationAuthenticatorFactory extends IdentityProviderAuthentica @Override public String getDisplayType() { - return "Organization Identity Provider Redirector"; + return "Organization Identity-First Login"; } @Override @@ -56,4 +59,9 @@ public class OrganizationAuthenticatorFactory extends IdentityProviderAuthentica public boolean isSupported(Scope config) { return Profile.isFeatureEnabled(Feature.ORGANIZATION); } + + @Override + public List getConfigProperties() { // org identity-first login + return List.of(); + } } \ No newline at end of file