Skip to content

Commit

Permalink
Feature/Vas-12560: Multi-domain authentication - External Idp support…
Browse files Browse the repository at this point in the history
… (experimental)
  • Loading branch information
lgheribi committed Mar 22, 2024
1 parent 2b32ebf commit 7d4ad70
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.jee.context.JEEContext;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.webflow.execution.RequestContextHolder;

import java.security.cert.CertificateParsingException;
Expand Down Expand Up @@ -126,7 +128,8 @@
@RequiredArgsConstructor
public class UserPrincipalResolver implements PrincipalResolver {

public static final String EMAIL_VALID_REGEXP = "^[_a-z0-9]+(((\\.|-)[_a-z0-9]+))*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$";
public static final String EMAIL_VALID_REGEXP =
"^[_a-z0-9]+(((\\.|-)[_a-z0-9]+))*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$";
public static final String SUPER_USER_ID_ATTRIBUTE = "superUserId";
public static final String COMPUTED_OTP = "computedOtp";

Expand All @@ -151,7 +154,8 @@ public class UserPrincipalResolver implements PrincipalResolver {
private final String x509DefaultDomain;

@Override
public Principal resolve(final Credential credential, final Optional<Principal> optPrincipal, final Optional<AuthenticationHandler> handler) {
public Principal resolve(final Credential credential, final Optional<Principal> optPrincipal,
final Optional<AuthenticationHandler> handler) {

// OAuth 2 authorization code flow (client credentials authentication)
if (optPrincipal.isEmpty()) {
Expand All @@ -169,7 +173,6 @@ public Principal resolve(final Credential credential, final Optional<Principal>
String superUserCustomerId;

String username;
final String superUsername;
String userProviderId;
final Optional<String> technicalUserId;
// x509 certificate
Expand All @@ -182,7 +185,6 @@ public Principal resolve(final Credential credential, final Optional<Principal>
} catch (final CertificateParsingException e) {
throw new RuntimeException(e.getMessage());
}
superUsername = null;
userProviderId = null;
surrogationCall = false;

Expand All @@ -205,10 +207,6 @@ public Principal resolve(final Credential credential, final Optional<Principal>
userProviderId = userProvider.get().getId();
}
} else if (credential instanceof SurrogateUsernamePasswordCredential) {
// login/password + surrogation
val surrogationCredential = (SurrogateUsernamePasswordCredential) credential;
username = surrogationCredential.getSurrogateUsername();
superUsername = surrogationCredential.getUsername();
userProviderId = null;
technicalUserId = Optional.empty();

Expand All @@ -220,8 +218,6 @@ public Principal resolve(final Credential credential, final Optional<Principal>

} else if (credential instanceof UsernamePasswordCredential) {
// login/password
username = principalId;
superUsername = null;
userProviderId = null;
technicalUserId = Optional.empty();

Expand All @@ -233,12 +229,6 @@ public Principal resolve(final Credential credential, final Optional<Principal>

} else {

// FIXME:
loginEmail = null;
loginCustomerId = null;
superUserEmail = null;
superUserCustomerId = null;

// authentication delegation (+ surrogation)
val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext);
val response = WebUtils.getHttpServletResponseFromExternalWebflowContext(requestContext);
Expand All @@ -251,7 +241,7 @@ public Principal resolve(final Credential credential, final Optional<Principal>
String email = principalId;
if (CommonHelper.isNotBlank(mailAttribute)) {
val mails = principal.getAttributes().get(mailAttribute);
if (mails == null || mails.size() == 0 || CommonHelper.isBlank((String) mails.get(0))) {
if (CollectionUtils.isEmpty(mails) || CommonHelper.isBlank((String) mails.get(0))) {
LOGGER.error(
"Provider: '{}' requested specific mail attribute: '{}' for id, but attribute does not exist or has no value",
providerName, mailAttribute);
Expand All @@ -268,7 +258,7 @@ public Principal resolve(final Credential credential, final Optional<Principal>
String identifier = principalId;
if (CommonHelper.isNotBlank(identifierAttribute)) {
val identifiers = principal.getAttributes().get(identifierAttribute);
if (identifiers == null || identifiers.size() == 0 ||
if (CollectionUtils.isEmpty(identifiers) ||
CommonHelper.isBlank((String) identifiers.get(0))) {
LOGGER.error(
"Provider: '{}' requested specific identifier attribute: '{}' for id, but attribute does not exist or has no value",
Expand All @@ -282,20 +272,38 @@ public Principal resolve(final Credential credential, final Optional<Principal>
identifier = identifierAttr;
}
}
// FIXME
val surrogateInSession = sessionStore.get(webContext, Constants.SURROGATE).orElse(null);
if (surrogateInSession != null) {
username = (String) surrogateInSession;
superUsername = email;

String surrogateEmailFromSession =
(String) sessionStore.get(webContext, Constants.FLOW_SURROGATE_EMAIL).orElse(null);
String surrogateCustomerIdFromSession =
(String) sessionStore.get(webContext, Constants.FLOW_SURROGATE_CUSTOMER_ID).orElse(null);
String loginEmailFromSession =
(String) sessionStore.get(webContext, Constants.FLOW_LOGIN_EMAIL).orElseThrow();
String loginCustomerIdFromSession =
(String) sessionStore.get(webContext, Constants.FLOW_LOGIN_CUSTOMER_ID).orElseThrow();

Assert.isTrue(email.equals(loginEmailFromSession),
String.format("Invalid user from Idp : Expected: '%s', actual: '%s'", loginEmailFromSession, email));

if (surrogateEmailFromSession != null) {
userProviderId = null;
technicalUserId = Optional.empty();
surrogationCall = true;

loginEmail = surrogateEmailFromSession;
loginCustomerId = surrogateCustomerIdFromSession;
superUserEmail = loginEmailFromSession;
superUserCustomerId = loginCustomerIdFromSession;

} else {
username = email;
superUsername = null;
userProviderId = provider.getId();
technicalUserId = Optional.of(identifier);
surrogationCall = false;

loginEmail = loginEmailFromSession;
loginCustomerId = loginCustomerIdFromSession;
superUserEmail = null;
superUserCustomerId = null;
}
}

Expand Down Expand Up @@ -382,7 +390,7 @@ public Principal resolve(final Credential credential, final Optional<Principal>
final Set<String> roles = new HashSet<>();
final List<ProfileDto> profiles = authUser.getProfileGroup().getProfiles();
profiles.forEach(profile -> profile.getRoles().forEach(role -> roles.add(role.getName())));
attributes.put(ROLES_ATTRIBUTE, new ArrayList(roles));
attributes.put(ROLES_ATTRIBUTE, new ArrayList<>(roles));
}
val createdPrincipal = principalFactory.createPrincipal(user.getId(), attributes);
if (surrogationCall) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.iam.common.dto.IdentityProviderDto;
import fr.gouv.vitamui.iam.common.utils.IdentityProviderHelper;
import fr.gouv.vitamui.iam.external.client.CasExternalRestClient;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.apereo.cas.web.support.WebUtils;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.jee.context.JEEContext;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.Event;
Expand Down Expand Up @@ -109,7 +110,7 @@ private Event processSubrogationRequest(RequestContext requestContext, MutableAt
ParameterChecker.checkParameter("Missing subrogation params",
surrogateEmail, surrogateCustomerId, superUserEmail, superUserCustomerId);

return dispatchUser(requestContext, superUserEmail, superUserCustomerId);
return dispatchUser(requestContext, superUserEmail, superUserCustomerId, surrogateEmail, surrogateCustomerId);
}

private Event processLoginRequest(RequestContext requestContext, MutableAttributeMap<Object> flowScope)
Expand All @@ -122,35 +123,43 @@ private Event processLoginRequest(RequestContext requestContext, MutableAttribut

ParameterChecker.checkParameter("Missing authn params", userEmail, customerId);

return dispatchUser(requestContext, userEmail, customerId);
return dispatchUser(requestContext, userEmail, customerId, null, null);
}

private Event dispatchUser(RequestContext requestContext, String username,
String customerId) throws IOException {
private Event dispatchUser(RequestContext requestContext, String loginEmail,
String loginCustomerId, String surrogateEmail, String surrogateCustomerId) throws IOException {

Optional<IdentityProviderDto> providerOpt =
identityProviderHelper.findByCustomerId(providersService.getProviders(), customerId);
identityProviderHelper.findByCustomerId(providersService.getProviders(), loginCustomerId);
if (providerOpt.isEmpty()) {
LOGGER.error("No provider found for superUserCustomerId: {}", customerId);
LOGGER.error("No provider found for superUserCustomerId: {}", loginCustomerId);
return new Event(this, BAD_CONFIGURATION);
}
var identityProviderDto = providerOpt.get();

val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext);
val response = WebUtils.getHttpServletResponseFromExternalWebflowContext(requestContext);
val webContext = new JEEContext(request, response);

if (identityProviderDto.getInternal()) {

// FIXME :
// sessionStore.set(webContext, Constants.SURROGATE, null);
sessionStore.set(webContext, Constants.FLOW_LOGIN_EMAIL, null);
sessionStore.set(webContext, Constants.FLOW_LOGIN_CUSTOMER_ID, null);
sessionStore.set(webContext, Constants.FLOW_SURROGATE_EMAIL, null);
sessionStore.set(webContext, Constants.FLOW_SURROGATE_CUSTOMER_ID, null);

LOGGER.debug("Redirect the user to the password page...");
return success();

} else {

// FIXME :
// // save the surrogate in the session to be retrieved by the UserPrincipalResolver and DelegatedSurrogateAuthenticationPostProcessor
// if (surrogate != null) {
// LOGGER.debug("Saving surrogate for after authentication delegation: {}", surrogate);
// sessionStore.set(webContext, Constants.SURROGATE, surrogate);
// }
LOGGER.debug("Saving surrogate for after authentication delegation: loginEmail : {}, " +
"loginCustomerId : {}, surrogateEmail : {}, surrogateCustomerId : {}",
loginEmail, loginCustomerId, surrogateEmail, surrogateCustomerId);
sessionStore.set(webContext, Constants.FLOW_LOGIN_EMAIL, loginEmail);
sessionStore.set(webContext, Constants.FLOW_LOGIN_CUSTOMER_ID, loginCustomerId);
sessionStore.set(webContext, Constants.FLOW_SURROGATE_EMAIL, surrogateEmail);
sessionStore.set(webContext, Constants.FLOW_SURROGATE_CUSTOMER_ID, surrogateCustomerId);

return utils.performClientRedirection(this,
((Pac4jClientIdentityProviderDto) identityProviderDto).getClient(), requestContext);
Expand Down

0 comments on commit 7d4ad70

Please sign in to comment.