diff --git a/authenticator/src/main/java/cz/cesnet/keycloak/CustomAuthenticator.java b/authenticator/src/main/java/cz/cesnet/keycloak/CustomAuthenticator.java index 3b39d4152fc2604d2b0b5eb152139c594752be07..0b79a3789c77c245c7c1ff5dc37e7c2d9adb1bbf 100644 --- a/authenticator/src/main/java/cz/cesnet/keycloak/CustomAuthenticator.java +++ b/authenticator/src/main/java/cz/cesnet/keycloak/CustomAuthenticator.java @@ -1,10 +1,13 @@ package cz.cesnet.keycloak; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.keycloak.authentication.AuthenticationFlowContext; +import org.keycloak.authentication.AuthenticationFlowError; +import org.keycloak.authentication.AuthenticationFlowException; import org.keycloak.authentication.Authenticator; -import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator; -import org.keycloak.broker.provider.IdentityBrokerException; +import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -14,19 +17,20 @@ import org.slf4j.LoggerFactory; import jakarta.ws.rs.core.Response; -import java.util.Locale; +import java.util.List; import java.util.Map; +import static org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE; +import static org.keycloak.broker.oidc.OIDCIdentityProvider.USER_INFO; + public class CustomAuthenticator implements Authenticator { private final Logger log = LoggerFactory.getLogger(CustomAuthenticator.class); private final static String EDU_PERSON_ENTITLEMENT = "eduperson_entitlement"; - private final static String REQUIRED_ENTITLEMENT = "urn:mace:egi:eu:group:eval.c-scale.eu:role=member#aai.egi.eu"; + private final static String REQUIRED_ENTITLEMENT = "urn:mace:egi.eu:group:eval.c-scale.eu:role=member#aai.egi.eu"; private final static String REDIRECT_URL = "https://perun.egi.eu/egi/registrar/?vo=eval.c-scale.eu"; - private ObjectMapper objectMapper = new ObjectMapper(); - private final KeycloakSession session; public CustomAuthenticator(KeycloakSession session) { @@ -40,29 +44,41 @@ public class CustomAuthenticator implements Authenticator { */ @Override public void authenticate(AuthenticationFlowContext context) { - log.warn("Custom EGI authenticator"); + log.debug("Custom EGI authenticator initiated"); AuthenticationSessionModel authSession = context.getAuthenticationSession(); - Map<String, String> userSessionNotes = authSession.getUserSessionNotes(); - for (Map.Entry<String, String> entry : userSessionNotes.entrySet()) { - log.warn("User Session Note - Key: " + entry.getKey() + ", Value: " + entry.getValue()); - - if (entry.getKey().equals(EDU_PERSON_ENTITLEMENT)) { - log.warn("Got the entitlement!"); + SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, BROKERED_CONTEXT_NOTE); + if (serializedCtx == null) { + throw new AuthenticationFlowException("Not found serialized context in clientSession", AuthenticationFlowError.IDENTITY_PROVIDER_ERROR); + } + + BrokeredIdentityContext brokerContext = serializedCtx.deserialize(context.getSession(), authSession); + Map<String, Object> contextData = brokerContext.getContextData(); + if (contextData != null && contextData.containsKey(USER_INFO) && contextData.get(USER_INFO) != null) { + Object userInfo = contextData.get(USER_INFO); + + if (userInfo instanceof ObjectNode userInfoNode) { + JsonNode entitlementsNode = userInfoNode.get(EDU_PERSON_ENTITLEMENT); + if (entitlementsNode != null && entitlementsNode.isArray()) { + for (JsonNode entitlement : entitlementsNode) { + if (entitlement.asText().equals(REQUIRED_ENTITLEMENT)) { + log.debug("EGI custom authenticator - entitlement found, user authenticated."); + context.success(); + return; + } + } + } + } else { + throw new IllegalStateException("Unexpected type for USER_INFO: " + userInfo.getClass()); } } -// -// if (entitlement == null || !entitlement.contains(REQUIRED_ENTITLEMENT)) { + + log.debug("EGI custom authenticator - entitlement not found, redirecting user."); Response response = Response.status(Response.Status.FOUND) .location(java.net.URI.create(REDIRECT_URL)) .build(); context.forceChallenge(response); - return; -// } - - // If the user has the required entitlement or didn't log in via the EGI Check-in IdP -// context.success(); } @Override