org.apereo.cas.syncope.authentication.SyncopeAuthenticationHandler Maven / Gradle / Ivy
package org.apereo.cas.syncope.authentication;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.credential.UsernamePasswordCredential;
import org.apereo.cas.authentication.exceptions.AccountDisabledException;
import org.apereo.cas.authentication.exceptions.AccountPasswordMustChangeException;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.HttpUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.syncope.common.lib.to.MembershipTO;
import org.apache.syncope.common.lib.to.RelationshipTO;
import org.apache.syncope.common.lib.to.UserTO;
import javax.security.auth.login.FailedLoginException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* This is {@link SyncopeAuthenticationHandler}.
*
* @author Misagh Moayyed
* @since 5.3.0
*/
@Slf4j
public class SyncopeAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
private final ObjectMapper objectMapper = new IgnoringJaxbModuleJacksonObjectMapper().findAndRegisterModules();
private final String syncopeUrl;
private final String syncopeDomain;
public SyncopeAuthenticationHandler(final String name, final ServicesManager servicesManager,
final PrincipalFactory principalFactory, final String syncopeUrl, final String syncopeDomain) {
super(name, servicesManager, principalFactory, null);
this.syncopeUrl = syncopeUrl;
this.syncopeDomain = syncopeDomain;
}
@Override
@SneakyThrows
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential c,
final String originalPassword) {
HttpResponse response = null;
try {
val syncopeRestUrl = StringUtils.appendIfMissing(this.syncopeUrl, "/rest/users/self");
response = HttpUtils.executeGet(syncopeRestUrl, c.getUsername(), c.getPassword(),
new HashMap<>(), CollectionUtils.wrap("X-Syncope-Domain", this.syncopeDomain));
LOGGER.debug("Received http response status as [{}]", response.getStatusLine());
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
val result = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
LOGGER.debug("Received user object as [{}]", result);
val user = this.objectMapper.readValue(result, UserTO.class);
if (user.isSuspended()) {
throw new AccountDisabledException("Could not authenticate forbidden account for " + c.getUsername());
}
if (user.isMustChangePassword()) {
throw new AccountPasswordMustChangeException("Account password must change for " + c.getUsername());
}
val principal = this.principalFactory.createPrincipal(user.getUsername(), buildSyncopeUserAttributes(user));
return createHandlerResult(c, principal, new ArrayList<>());
}
} finally {
HttpUtils.close(response);
}
throw new FailedLoginException("Could not authenticate account for " + c.getUsername());
}
private static Map> buildSyncopeUserAttributes(final UserTO user) {
val attributes = new HashMap>();
if (user.getRoles() != null) {
attributes.put("syncopeUserRoles", List.of(user.getRoles()));
}
if (user.getSecurityQuestion() != null) {
attributes.put("syncopeUserSecurityQuestion", List.of(user.getSecurityQuestion()));
}
attributes.put("syncopeUserStatus", List.of(StringUtils.defaultIfBlank(user.getStatus(), "OK")));
attributes.put("syncopeUserType", List.of(user.getType()));
if (user.getRealm() != null) {
attributes.put("syncopeUserRealm", List.of(user.getRealm()));
}
attributes.put("syncopeUserCreator", List.of(StringUtils.defaultIfBlank(user.getCreator(), "NA")));
if (user.getCreationDate() != null) {
attributes.put("syncopeUserCreationDate", List.of(user.getCreationDate().toString()));
}
val changePwdDate = user.getChangePwdDate();
if (changePwdDate != null) {
attributes.put("syncopeUserChangePwdDate", List.of(changePwdDate.toString()));
}
val lastLoginDate = user.getLastLoginDate();
if (lastLoginDate != null) {
attributes.put("syncopeUserLastLoginDate", List.of(lastLoginDate));
}
if (user.getDynRoles() != null && !user.getDynRoles().isEmpty()) {
attributes.put("syncopeUserDynRoles", List.of(user.getDynRoles()));
}
if (user.getDynRealms() != null && !user.getDynRealms().isEmpty()) {
attributes.put("syncopeUserDynRealms", List.of(user.getDynRealms()));
}
if (user.getMemberships() != null && !user.getMemberships().isEmpty()) {
attributes.put("syncopeUserMemberships", user.getMemberships()
.stream()
.map(MembershipTO::getGroupName)
.collect(Collectors.toList()));
}
if (user.getMemberships() != null && !user.getMemberships().isEmpty()) {
attributes.put("syncopeUserDynMemberships", user.getDynMemberships()
.stream()
.map(MembershipTO::getGroupName)
.collect(Collectors.toList()));
}
if (user.getRelationships() != null && !user.getRelationships().isEmpty()) {
attributes.put("syncopeUserRelationships", user.getRelationships()
.stream()
.map(RelationshipTO::getType)
.collect(Collectors.toList()));
}
user.getPlainAttrs().forEach(a -> attributes.put("syncopeUserAttr" + a.getSchema(), (List) a.getValues()));
return attributes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy