-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Upgrade the forked Home IdP extension to latest commit (#121)
* Upgrade the fork of sventorben/keycloak-home-idp-discovery to the latest commit 04b9becfb37df63784559c936f0b49609686439e * Apply custom p2-inc patches to home-idp-discovery needed for keycloak-orgs functionality * Reinstate AutoService annotation to HomeIdpDiscoveryAuthenticatorFactory
- Loading branch information
Showing
21 changed files
with
1,051 additions
and
513 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
src/main/java/io/phasetwo/service/auth/idp/AlwaysSelectableIdentityProviderModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//package de.sventorben.keycloak.authentication.hidpd; | ||
package io.phasetwo.service.auth.idp; | ||
|
||
import org.keycloak.models.IdentityProviderModel; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
final class AlwaysSelectableIdentityProviderModel extends IdentityProviderModel { | ||
|
||
AlwaysSelectableIdentityProviderModel(IdentityProviderModel delegate) { | ||
super(delegate); | ||
} | ||
|
||
@Override | ||
public boolean isHideOnLogin() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public Map<String, String> getConfig() { | ||
Map<String, String> superConfig = new HashMap<>(super.getConfig()); | ||
superConfig.put("hideOnLoginPage", Boolean.FALSE.toString()); | ||
return superConfig; | ||
} | ||
|
||
} |
49 changes: 49 additions & 0 deletions
49
src/main/java/io/phasetwo/service/auth/idp/AuthenticationChallenge.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
//package de.sventorben.keycloak.authentication.hidpd; | ||
package io.phasetwo.service.auth.idp; | ||
|
||
import jakarta.ws.rs.core.MultivaluedMap; | ||
import jakarta.ws.rs.core.Response; | ||
import org.jboss.resteasy.specimpl.MultivaluedMapImpl; | ||
import org.keycloak.authentication.AuthenticationFlowContext; | ||
import org.keycloak.models.IdentityProviderModel; | ||
import org.keycloak.services.managers.AuthenticationManager; | ||
|
||
import java.util.List; | ||
|
||
final class AuthenticationChallenge { | ||
|
||
private final AuthenticationFlowContext context; | ||
private final RememberMe rememberMe; | ||
private final LoginHint loginHint; | ||
private final LoginForm loginForm; | ||
|
||
AuthenticationChallenge(AuthenticationFlowContext context, RememberMe rememberMe, LoginHint loginHint, LoginForm loginForm) { | ||
this.context = context; | ||
this.rememberMe = rememberMe; | ||
this.loginHint = loginHint; | ||
this.loginForm = loginForm; | ||
} | ||
|
||
void forceChallenge() { | ||
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>(); | ||
String loginHintUsername = loginHint.getFromSession(); | ||
|
||
String rememberMeUsername = rememberMe.getUserName(); | ||
|
||
if (loginHintUsername != null || rememberMeUsername != null) { | ||
if (loginHintUsername != null) { | ||
formData.add(AuthenticationManager.FORM_USERNAME, loginHintUsername); | ||
} else { | ||
formData.add(AuthenticationManager.FORM_USERNAME, rememberMeUsername); | ||
formData.add("rememberMe", "on"); | ||
} | ||
} | ||
Response challengeResponse = loginForm.create(formData); | ||
context.challenge(challengeResponse); | ||
} | ||
|
||
void forceChallenge(List<IdentityProviderModel> homeIdps) { | ||
context.forceChallenge(loginForm.create(homeIdps)); | ||
} | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/io/phasetwo/service/auth/idp/BaseUriLoginFormsProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// package de.sventorben.keycloak.authentication.hidpd; | ||
package io.phasetwo.service.auth.idp; | ||
|
||
import jakarta.ws.rs.core.UriBuilder; | ||
import org.keycloak.authentication.AuthenticationFlowContext; | ||
import org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider; | ||
import org.keycloak.services.resources.LoginActionsService; | ||
|
||
import java.net.URI; | ||
|
||
/** | ||
* Workaround to reuse the logic in FreeMarkerLoginFormsProvider.prepareBaseUriBuilder, so no need to reimplement it. | ||
*/ | ||
final class BaseUriLoginFormsProvider extends FreeMarkerLoginFormsProvider { | ||
|
||
public BaseUriLoginFormsProvider(AuthenticationFlowContext context) { | ||
super(context.getSession()); | ||
super.setAuthenticationSession(context.getAuthenticationSession()); | ||
super.setClientSessionCode(context.generateAccessCode()); | ||
} | ||
|
||
public URI getBaseUriWithCodeAndClientId() { | ||
UriBuilder baseUriBuilder = super.prepareBaseUriBuilder(false); | ||
if (accessCode != null) { | ||
baseUriBuilder.queryParam(LoginActionsService.SESSION_CODE, accessCode); | ||
} | ||
return baseUriBuilder.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
//package de.sventorben.keycloak.authentication.hidpd; | ||
package io.phasetwo.service.auth.idp; | ||
|
||
import java.util.Objects; | ||
|
||
class Domain { | ||
|
||
private final String value; | ||
|
||
Domain(String value) { | ||
Objects.requireNonNull(value); | ||
this.value = value.toLowerCase(); | ||
} | ||
|
||
boolean isSubDomainOf(Domain domain) { | ||
return this.value.endsWith("." + domain.value); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (obj == null) | ||
return false; | ||
if (!(obj instanceof Domain)) | ||
return false; | ||
if (this == obj) | ||
return true; | ||
return this.value.equalsIgnoreCase(((Domain) obj).value); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return this.value.hashCode(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return this.value; | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/main/java/io/phasetwo/service/auth/idp/DomainExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
//package de.sventorben.keycloak.authentication.hidpd; | ||
package io.phasetwo.service.auth.idp; | ||
|
||
import org.jboss.logging.Logger; | ||
import org.keycloak.models.UserModel; | ||
|
||
import java.util.Optional; | ||
|
||
final class DomainExtractor { | ||
|
||
private static final Logger LOG = Logger.getLogger(DomainExtractor.class); | ||
private static final String EMAIL_ATTRIBUTE = "email"; | ||
|
||
private final HomeIdpDiscoveryConfig config; | ||
|
||
DomainExtractor(HomeIdpDiscoveryConfig config) { | ||
this.config = config; | ||
} | ||
|
||
Optional<Domain> extractFrom(UserModel user) { | ||
if (!user.isEnabled()) { | ||
LOG.warnf("User '%s' not enabled", user.getId()); | ||
return Optional.empty(); | ||
} | ||
String userAttribute = user.getFirstAttribute(config.userAttribute()); | ||
if (userAttribute == null) { | ||
LOG.warnf("Could not find user attribute '%s' for user '%s'", config.userAttribute(), user.getId()); | ||
return Optional.empty(); | ||
} | ||
if (EMAIL_ATTRIBUTE.equalsIgnoreCase(config.userAttribute()) && !user.isEmailVerified()) { | ||
LOG.warnf("Email address of user '%s' is not verified", user.getId()); | ||
return Optional.empty(); | ||
} | ||
return extractFrom(userAttribute); | ||
} | ||
|
||
Optional<Domain> extractFrom(String usernameOrEmail) { | ||
Domain domain = null; | ||
if (usernameOrEmail != null) { | ||
int atIndex = usernameOrEmail.trim().lastIndexOf("@"); | ||
if (atIndex >= 0) { | ||
String strDomain = usernameOrEmail.trim().substring(atIndex + 1); | ||
if (strDomain.length() > 0) { | ||
domain = new Domain(strDomain); | ||
} | ||
} | ||
} | ||
return Optional.ofNullable(domain); | ||
} | ||
|
||
} |
85 changes: 85 additions & 0 deletions
85
src/main/java/io/phasetwo/service/auth/idp/HomeIdpAuthenticationFlowContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
//package de.sventorben.keycloak.authentication.hidpd; | ||
package io.phasetwo.service.auth.idp; | ||
|
||
import org.keycloak.authentication.AuthenticationFlowContext; | ||
|
||
final class HomeIdpAuthenticationFlowContext { | ||
|
||
private final AuthenticationFlowContext context; | ||
private HomeIdpDiscoveryConfig config; | ||
private LoginPage loginPage; | ||
private LoginHint loginHint; | ||
private HomeIdpDiscoverer discoverer; | ||
private RememberMe rememberMe; | ||
private AuthenticationChallenge authenticationChallenge; | ||
private Redirector redirector; | ||
private BaseUriLoginFormsProvider loginFormsProvider; | ||
private LoginForm loginForm; | ||
|
||
HomeIdpAuthenticationFlowContext(AuthenticationFlowContext context) { | ||
this.context = context; | ||
} | ||
|
||
HomeIdpDiscoveryConfig config() { | ||
if (config == null) { | ||
config = new HomeIdpDiscoveryConfig(context.getAuthenticatorConfig()); | ||
} | ||
return config; | ||
} | ||
|
||
LoginPage loginPage() { | ||
if (loginPage == null) { | ||
loginPage = new LoginPage(context, config()); | ||
} | ||
return loginPage; | ||
} | ||
|
||
LoginHint loginHint() { | ||
if (loginHint == null) { | ||
loginHint = new LoginHint(context); | ||
} | ||
return loginHint; | ||
} | ||
|
||
HomeIdpDiscoverer discoverer() { | ||
if (discoverer == null) { | ||
discoverer = new HomeIdpDiscoverer(context); | ||
} | ||
return discoverer; | ||
} | ||
|
||
RememberMe rememberMe() { | ||
if (rememberMe == null) { | ||
rememberMe = new RememberMe(context); | ||
} | ||
return rememberMe; | ||
} | ||
|
||
AuthenticationChallenge authenticationChallenge() { | ||
if (authenticationChallenge == null) { | ||
authenticationChallenge = new AuthenticationChallenge(context, rememberMe(), loginHint(), loginForm()); | ||
} | ||
return authenticationChallenge; | ||
} | ||
|
||
Redirector redirector() { | ||
if (redirector == null) { | ||
redirector = new Redirector(context); | ||
} | ||
return redirector; | ||
} | ||
|
||
LoginForm loginForm() { | ||
if (loginForm == null) { | ||
loginForm = new LoginForm(context, loginFormsProvider()); | ||
} | ||
return loginForm; | ||
} | ||
|
||
BaseUriLoginFormsProvider loginFormsProvider() { | ||
if (loginFormsProvider == null) { | ||
loginFormsProvider = new BaseUriLoginFormsProvider(context); | ||
} | ||
return loginFormsProvider; | ||
} | ||
} |
Oops, something went wrong.