自定义登录验证器

重写ldap认证方式,方便增加账号安全检测

1.首先配置pom.xml文件

     <dependency><groupId>org.apereo.cas</groupId><artifactId>cas-server-support-ldap-core</artifactId><version>${cas.version}</version></dependency>

2.配置application.properties文件(这里只是部分内容)

#########################ldap authentication#######################################
#认证方式
#cas.authn.ldap[0].type=AD|DIRECT|ANONYMOUS|AUTHENTICATED
cas.authn.ldap[0].type=AUTHENTICATED
#LDAP服务地址,如果支持SSL,地址为 ldaps://127.0.0.1:689
cas.authn.ldap[0].ldapUrl=ldap://127.0.0.1:389
#是否使用SSL
cas.authn.ldap[0].useSsl=false
cas.authn.ldap[0].useStartTls=false
cas.authn.ldap[0].connectTimeout=5000
#LDAP中基础DN
cas.authn.ldap[0].baseDn=ou=people,dc=xxx,dc=cn
#用户名匹配规则,简单的可以只写成uid={user}
cas.authn.ldap[0].searchFilter=(&(|(cn={user})(uid={user})(xjtuIDNumber={user})(mobile={user})(mail={user}))(xjtuAccountlocked=FALSE))
cas.authn.ldap[0].subtreeSearch=true
#cas.authn.ldap[0].usePasswordPolicy=false
#LDAP的DN
cas.authn.ldap[0].bindDn=cn=xxxadmin,dc=xxx,dc=cn
#LDAP的密码
cas.authn.ldap[0].bindCredential=111cas.authn.ldap[0].principalAttributeId=uid
cas.authn.ldap[0].principalAttributePassword=userPassword##默认加密策略,通过encodingAlgorithm来指定算法,默认NONE不加密
#原来这里是在密码验证之前对密码再做一次encode,如果配置为NONE,则什么都不做,
#直接使用默认的SHA加密方式(AbstractCompareAuthenticationHandler里面配置)加密密码后与LDAP里面的密码比对,
#如果配置为DEFAULT则先用配置的#encodingAlgorithm加密一次,再使用默认的SHA加密方式加密后与LDAP里面的密码比对
cas.authn.ldap[0].passwordEncoder.type=NONE
cas.authn.ldap[0].passwordEncoder.characterEncoding=UTF-8
cas.authn.ldap[0].passwordEncoder.encodingAlgorithm=SHA#登入成功后可以查看到的信息
cas.authn.ldap[0].principalAttributeList=uid:accountID,sn:userNo,cn:userAccount,displayName:userName,description,departmentNumber:depNO,mail:email
cas.authn.ldap[0].allowMultiplePrincipalAttributeValues=true
cas.authn.ldap[0].allowMissingPrincipalAttributeValue=true

3.自定义登录验证器

package gds.application.cas.config.principal;import com.google.common.collect.Multimap;
import gds.application.cas.authentication.adaptors.CustomLdapAuthenticationHandler;
import gds.application.cas.model.usercenter.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.CoreAuthenticationUtils;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.authentication.principal.PrincipalFactoryUtils;
import org.apereo.cas.authentication.principal.PrincipalNameTransformerUtils;
import org.apereo.cas.authentication.principal.PrincipalResolver;
import org.apereo.cas.authentication.support.DefaultLdapAccountStateHandler;
import org.apereo.cas.authentication.support.password.DefaultPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.password.GroovyPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.OptionalWarningLdapAccountStateHandler;
import org.apereo.cas.authentication.support.RejectResultCodeLdapPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.password.PasswordEncoderUtils;
import org.apereo.cas.authentication.support.password.PasswordPolicyConfiguration;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.model.support.ldap.LdapAuthenticationProperties;
import org.apereo.cas.configuration.model.support.ldap.LdapPasswordPolicyProperties;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.LdapUtils;
import org.ldaptive.auth.AuthenticationResponse;
import org.ldaptive.auth.AuthenticationResponseHandler;
import org.ldaptive.auth.Authenticator;
import org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler;
import org.ldaptive.auth.ext.EDirectoryAuthenticationResponseHandler;
import org.ldaptive.auth.ext.FreeIPAAuthenticationResponseHandler;
import org.ldaptive.auth.ext.PasswordExpirationAuthenticationResponseHandler;
import org.ldaptive.auth.ext.PasswordPolicyAuthenticationResponseHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;import java.time.Period;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;@Configuration("customldapAuthenticationConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Slf4j
public class CustomLdapAuthenticationConfiguration {private static final Logger LOGGER = LoggerFactory.getLogger(CustomLdapAuthenticationConfiguration.class);@Autowiredprivate CasConfigurationProperties casProperties;@Autowired@Qualifier("personDirectoryPrincipalResolver")private PrincipalResolver personDirectoryPrincipalResolver;@Autowired@Qualifier("servicesManager")private ServicesManager servicesManager;@Autowiredprivate UserService userService;@ConditionalOnMissingBean(name = "ldapPrincipalFactory")@Beanpublic PrincipalFactory ldapPrincipalFactory() {return PrincipalFactoryUtils.newPrincipalFactory();}@Beanpublic Collection<AuthenticationHandler> ldapAuthenticationHandlers() {final Collection<AuthenticationHandler> handlers = new HashSet<>();casProperties.getAuthn().getLdap().stream().filter(ldapInstanceConfigurationPredicate()).forEach(l -> {final Multimap<String, Object> multiMapAttributes =CoreAuthenticationUtils.transformPrincipalAttributesListIntoMultiMap(l.getPrincipalAttributeList());LOGGER.debug("Created and mapped principal attributes [{}] for [{}]...", multiMapAttributes, l.getLdapUrl());LOGGER.debug("Creating LDAP authenticator for [{}] and baseDn [{}]", l.getLdapUrl(), l.getBaseDn());final Authenticator authenticator = LdapUtils.newLdaptiveAuthenticator(l);LOGGER.debug("Ldap authenticator configured with return attributes [{}] for [{}] and baseDn [{}]",multiMapAttributes.keySet(), l.getLdapUrl(), l.getBaseDn());LOGGER.debug("Creating LDAP password policy handling strategy for [{}]", l.getLdapUrl());final AuthenticationPasswordPolicyHandlingStrategy strategy = createLdapPasswordPolicyHandlingStrategy(l);LOGGER.debug("Creating LDAP authentication handler for [{}]", l.getLdapUrl());final CustomLdapAuthenticationHandler handler = new CustomLdapAuthenticationHandler(l.getName(),servicesManager, userService, ldapPrincipalFactory(), casProperties.getCustom(), l.getOrder(), authenticator, strategy);handler.setCollectDnAttribute(l.isCollectDnAttribute());final List<String> additionalAttributes = l.getAdditionalAttributes();if (StringUtils.isNotBlank(l.getPrincipalAttributeId())) {additionalAttributes.add(l.getPrincipalAttributeId());}if (StringUtils.isNotBlank(l.getPrincipalDnAttributeName())) {handler.setPrincipalDnAttributeName(l.getPrincipalDnAttributeName());}handler.setAllowMultiplePrincipalAttributeValues(l.isAllowMultiplePrincipalAttributeValues());handler.setAllowMissingPrincipalAttributeValue(l.isAllowMissingPrincipalAttributeValue());handler.setPasswordEncoder(PasswordEncoderUtils.newPasswordEncoder(l.getPasswordEncoder()));handler.setPrincipalNameTransformer(PrincipalNameTransformerUtils.newPrincipalNameTransformer(l.getPrincipalTransformation()));if (StringUtils.isNotBlank(l.getCredentialCriteria())) {LOGGER.debug("Ldap authentication for [{}] is filtering credentials by [{}]",l.getLdapUrl(), l.getCredentialCriteria());handler.setCredentialSelectionPredicate(CoreAuthenticationUtils.newCredentialSelectionPredicate(l.getCredentialCriteria()));}if (StringUtils.isBlank(l.getPrincipalAttributeId())) {LOGGER.debug("No principal id attribute is found for LDAP authentication via [{}]", l.getLdapUrl());} else {handler.setPrincipalIdAttribute(l.getPrincipalAttributeId());LOGGER.debug("Using principal id attribute [{}] for LDAP authentication via [{}]", l.getPrincipalAttributeId(), l.getLdapUrl());}final LdapPasswordPolicyProperties passwordPolicy = l.getPasswordPolicy();if (passwordPolicy.isEnabled()) {LOGGER.debug("Password policy is enabled for [{}]. Constructing password policy configuration", l.getLdapUrl());final PasswordPolicyConfiguration cfg = createLdapPasswordPolicyConfiguration(passwordPolicy, authenticator, multiMapAttributes);handler.setPasswordPolicyConfiguration(cfg);}final Map<String, Object> attributes = CollectionUtils.wrap(multiMapAttributes);handler.setPrincipalAttributeMap(attributes);LOGGER.debug("Initializing LDAP authentication handler for [{}]", l.getLdapUrl());handler.initialize();handlers.add(handler);});return handlers;}private static Predicate<LdapAuthenticationProperties> ldapInstanceConfigurationPredicate() {return l -> {if (l.getType() == null) {LOGGER.warn("Skipping LDAP authentication entry since no type is defined");return false;}if (StringUtils.isBlank(l.getLdapUrl())) {LOGGER.warn("Skipping LDAP authentication entry since no LDAP url is defined");return false;}return true;};}private AuthenticationPasswordPolicyHandlingStrategy<AuthenticationResponse, PasswordPolicyConfiguration>createLdapPasswordPolicyHandlingStrategy(final LdapAuthenticationProperties l) {if (l.getPasswordPolicy().getStrategy() == LdapPasswordPolicyProperties.PasswordPolicyHandlingOptions.REJECT_RESULT_CODE) {LOGGER.debug("Created LDAP password policy handling strategy based on blacklisted authentication result codes");return new RejectResultCodeLdapPasswordPolicyHandlingStrategy();}final Resource location = l.getPasswordPolicy().getGroovy().getLocation();if (l.getPasswordPolicy().getStrategy() == LdapPasswordPolicyProperties.PasswordPolicyHandlingOptions.GROOVY && location != null) {LOGGER.debug("Created LDAP password policy handling strategy based on Groovy script [{}]", location);return new GroovyPasswordPolicyHandlingStrategy(location);}LOGGER.debug("Created default LDAP password policy handling strategy");return new DefaultPasswordPolicyHandlingStrategy();}private PasswordPolicyConfiguration createLdapPasswordPolicyConfiguration(final LdapPasswordPolicyProperties passwordPolicy,final Authenticator authenticator,final Multimap<String, Object> attributes) {final PasswordPolicyConfiguration cfg = new PasswordPolicyConfiguration(passwordPolicy);final Set<AuthenticationResponseHandler> handlers = new HashSet<>();final String customPolicyClass = passwordPolicy.getCustomPolicyClass();if (StringUtils.isNotBlank(customPolicyClass)) {try {LOGGER.debug("Configuration indicates use of a custom password policy handler [{}]", customPolicyClass);final Class<AuthenticationResponseHandler> clazz = (Class<AuthenticationResponseHandler>) Class.forName(customPolicyClass);handlers.add(clazz.getDeclaredConstructor().newInstance());} catch (final Exception e) {LOGGER.warn("Unable to construct an instance of the password policy handler", e);}}LOGGER.debug("Password policy authentication response handler is set to accommodate directory type: [{}]", passwordPolicy.getType());switch (passwordPolicy.getType()) {case AD:handlers.add(new ActiveDirectoryAuthenticationResponseHandler(Period.ofDays(cfg.getPasswordWarningNumberOfDays())));Arrays.stream(ActiveDirectoryAuthenticationResponseHandler.ATTRIBUTES).forEach(a -> {LOGGER.debug("Configuring authentication to retrieve password policy attribute [{}]", a);attributes.put(a, a);});break;case FreeIPA:Arrays.stream(FreeIPAAuthenticationResponseHandler.ATTRIBUTES).forEach(a -> {LOGGER.debug("Configuring authentication to retrieve password policy attribute [{}]", a);attributes.put(a, a);});handlers.add(new FreeIPAAuthenticationResponseHandler(Period.ofDays(cfg.getPasswordWarningNumberOfDays()), cfg.getLoginFailures()));break;case EDirectory:Arrays.stream(EDirectoryAuthenticationResponseHandler.ATTRIBUTES).forEach(a -> {LOGGER.debug("Configuring authentication to retrieve password policy attribute [{}]", a);attributes.put(a, a);});handlers.add(new EDirectoryAuthenticationResponseHandler(Period.ofDays(cfg.getPasswordWarningNumberOfDays())));break;default:handlers.add(new PasswordPolicyAuthenticationResponseHandler());handlers.add(new PasswordExpirationAuthenticationResponseHandler());break;}authenticator.setAuthenticationResponseHandlers((AuthenticationResponseHandler[]) handlers.toArray(new AuthenticationResponseHandler[0]));LOGGER.debug("LDAP authentication response handlers configured are: [{}]", handlers);if (!passwordPolicy.isAccountStateHandlingEnabled()) {cfg.setAccountStateHandler((response, configuration) -> new ArrayList<>(0));LOGGER.debug("Handling LDAP account states is disabled via CAS configuration");} else if (StringUtils.isNotBlank(passwordPolicy.getWarningAttributeName()) && StringUtils.isNotBlank(passwordPolicy.getWarningAttributeValue())) {final OptionalWarningLdapAccountStateHandler accountHandler = new OptionalWarningLdapAccountStateHandler();accountHandler.setDisplayWarningOnMatch(passwordPolicy.isDisplayWarningOnMatch());accountHandler.setWarnAttributeName(passwordPolicy.getWarningAttributeName());accountHandler.setWarningAttributeValue(passwordPolicy.getWarningAttributeValue());accountHandler.setAttributesToErrorMap(passwordPolicy.getPolicyAttributes());cfg.setAccountStateHandler(accountHandler);LOGGER.debug("Configuring an warning account state handler for LDAP authentication for warning attribute [{}] and value [{}]",passwordPolicy.getWarningAttributeName(), passwordPolicy.getWarningAttributeValue());} else {final DefaultLdapAccountStateHandler accountHandler = new DefaultLdapAccountStateHandler();accountHandler.setAttributesToErrorMap(passwordPolicy.getPolicyAttributes());cfg.setAccountStateHandler(accountHandler);LOGGER.debug("Configuring the default account state handler for LDAP authentication");}return cfg;}/*** 注册验证器* @param plan*/@ConditionalOnMissingBean(name = "ldapAuthenticationEventExecutionPlanConfigurer")@Beanpublic AuthenticationEventExecutionPlanConfigurer ldapAuthenticationEventExecutionPlanConfigurer() {return plan -> ldapAuthenticationHandlers().forEach(handler -> {LOGGER.info("Registering LDAP authentication for [{}]", handler.getName());plan.registerAuthenticationHandlerWithPrincipalResolver(handler, personDirectoryPrincipalResolver);});}
}

(2)编写抽象身份验证处理程序,方便后续集成其它认证方式,将公共的代码写在一个地方。可自定义数据库认证等等

package gds.application.cas.authentication.adaptors;import gds.application.cas.common.constants.CustomWebConstants;
import gds.application.cas.exception.AccountUnusedLockedException;
import gds.application.cas.exception.WeakPasswordWarnException;
import gds.application.cas.model.usercenter.service.UserService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.UsernamePasswordCredential;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.configuration.model.support.custom.CasCustomProperties;
import org.apereo.cas.services.ServicesManager;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.security.auth.login.AccountNotFoundException;
import javax.servlet.http.HttpServletRequest;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;@Slf4j
@Setter
@Getter
public abstract class AbstractCustomAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {/*** Mapping of LDAP attribute name to principal attribute name.*/protected Map<String, Object> principalAttributeMap = new HashMap<>();public final UserService userService;public final CasCustomProperties casCustomProperties;public AbstractCustomAuthenticationHandler(String name, ServicesManager servicesManager, UserService userService, PrincipalFactory principalFactory, CasCustomProperties casCustomProperties, Integer order) {super(name, servicesManager, principalFactory, order);this.userService = userService;this.casCustomProperties = casCustomProperties;}@Overrideprotected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {final UsernamePasswordCredential originalUserPass = (UsernamePasswordCredential) credential;final UsernamePasswordCredential userPass = new UsernamePasswordCredential(originalUserPass.getUsername(), originalUserPass.getPassword());HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//这里可以自定义在检验密码之前做一些操作return beforeAuthenticationUsernamePasswordInternal(userPass, originalUserPass.getPassword());}protected abstract AuthenticationHandlerExecutionResult beforeAuthenticationUsernamePasswordInternal(UsernamePasswordCredential credential,String originalPassword) throws GeneralSecurityException, PreventedException;
}

(3)编写身份验证处理程序

package gds.application.cas.authentication.adaptors;import gds.application.cas.common.constants.CustomWebConstants;
import gds.application.cas.model.usercenter.service.UserService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.*;
import org.apereo.cas.authentication.principal.Principal;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.configuration.model.support.custom.CasCustomProperties;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.CollectionUtils;
import org.ldaptive.LdapAttribute;
import org.ldaptive.LdapEntry;
import org.ldaptive.LdapException;
import org.ldaptive.ReturnAttributes;
import org.ldaptive.auth.AuthenticationRequest;
import org.ldaptive.auth.AuthenticationResponse;
import org.ldaptive.auth.AuthenticationResultCode;
import org.ldaptive.auth.Authenticator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** LDAP authentication handler that uses the ldaptive {@code Authenticator} component underneath.* This handler provides simple attribute resolution machinery by reading attributes from the entry* corresponding to the DN of the bound user (in the bound security context) upon successful authentication.** @author Marvin S. Addison* @since 4.0.0*/
@Slf4j
@Setter
public class CustomLdapAuthenticationHandler extends AbstractCustomAuthenticationHandler {private static final Logger LOGGER = LoggerFactory.getLogger(CustomLdapAuthenticationHandler.class);/*** Performs LDAP authentication given username/password.**/private final Authenticator authenticator;/*** Name of attribute to be used for resolved principal.*/private String principalIdAttribute;/*** Flag indicating whether multiple values are allowed fo principalIdAttribute.*/private boolean allowMultiplePrincipalAttributeValues;/*** Flag to indicate whether CAS should block authentication* if a specific/configured principal id attribute is not found.*/private boolean allowMissingPrincipalAttributeValue = true;/*** Set of LDAP attributes fetch from an entry as part of the authentication process.*/private String[] authenticatedEntryAttributes = ReturnAttributes.NONE.value();private boolean collectDnAttribute;/*** Name of attribute to be used for principal's DN.*/private String principalDnAttributeName = "principalLdapDn";/*** Creates a new authentication handler that delegates to the given authenticator.** @param name             the name* @param servicesManager  the services manager* @param principalFactory the principal factory* @param order            the order* @param authenticator    Ldaptive authenticator component.* @param strategy         the strategy*/public CustomLdapAuthenticationHandler(final String name, final ServicesManager servicesManager, UserService userService, final PrincipalFactory principalFactory, CasCustomProperties casCustomProperties, final Integer order, final Authenticator authenticator,final AuthenticationPasswordPolicyHandlingStrategy strategy) {super(name, servicesManager, userService, principalFactory, casCustomProperties, order);this.authenticator = authenticator;this.passwordPolicyHandlingStrategy = strategy;}@Overrideprotected AuthenticationHandlerExecutionResult beforeAuthenticationUsernamePasswordInternal(final UsernamePasswordCredential upc,final String originalPassword) throws GeneralSecurityException, PreventedException {final AuthenticationResponse response;HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();final String username = upc.getUsername();final String password = upc.getPassword();try {final AuthenticationRequest request = new AuthenticationRequest(username,new org.ldaptive.Credential(password), authenticatedEntryAttributes);response = authenticator.authenticate(request);} catch (final LdapException e) {LOGGER.trace(e.getMessage(), e);throw new PreventedException("Unexpected LDAP error", e);}if (AuthenticationResultCode.DN_RESOLUTION_FAILURE == response.getAuthenticationResultCode()) {throw new AccountNotFoundException(username + " not found.");}try {if (!passwordPolicyHandlingStrategy.supports(response)) {throw new FailedLoginException("用户名或密码错误!");}final List<MessageDescriptor> messageList = passwordPolicyHandlingStrategy.handle(response, getPasswordPolicyConfiguration());if (response.getResult()) {// 在此可增加账号安全检测流程final Principal principal = createPrincipal(username, response.getLdapEntry());return createHandlerResult(upc, principal, messageList);}throw new FailedLoginException("用户名或密码错误!");} catch (FailedLoginException e){LOGGER.error("登录失败[{}]",e.getMessage());throw e;}}/*** Creates a CAS principal with attributes if the LDAP entry contains principal attributes.** @param username  Username that was successfully authenticated which is used for principal ID when principal id is not specified.* @param ldapEntry LDAP entry that may contain principal attributes.* @return Principal if the LDAP entry contains at least a principal ID attribute value, null otherwise.* @throws LoginException On security policy errors related to principal creation.*/protected Principal createPrincipal(final String username, final LdapEntry ldapEntry) throws LoginException {LOGGER.debug("Creating LDAP principal for [{}] based on [{}] and attributes [{}]", username, ldapEntry.getDn(),ldapEntry.getAttributeNames());final String id = getLdapPrincipalIdentifier(username, ldapEntry);LOGGER.debug("LDAP principal identifier created is [{}]", id);final Map<String, Object> attributeMap = collectAttributesForLdapEntry(ldapEntry, id);LOGGER.debug("Created LDAP principal for id [{}] and [{}] attributes", id, attributeMap.size());return this.principalFactory.createPrincipal(id, attributeMap);}/*** Collect attributes for ldap entry.** @param ldapEntry the ldap entry* @param username  the username* @return the map*/protected Map<String, Object> collectAttributesForLdapEntry(final LdapEntry ldapEntry, final String username) {final Map<String, Object> attributeMap = new LinkedHashMap<>(this.principalAttributeMap.size());LOGGER.debug("The following attributes are requested to be retrieved and mapped: [{}]", attributeMap.keySet());this.principalAttributeMap.forEach((key, attributeNames) -> {final LdapAttribute attr = ldapEntry.getAttribute(key);if (attr != null) {LOGGER.debug("Found principal attribute: [{}]", attr);final Collection<String> names = (Collection<String>) attributeNames;if (names.isEmpty()) {LOGGER.debug("Principal attribute [{}] is collected as [{}]", attr, key);attributeMap.put(key, CollectionUtils.wrap(attr.getStringValues()));} else {names.forEach(s -> {LOGGER.debug("Principal attribute [{}] is virtually remapped/renamed to [{}]", attr, s);attributeMap.put(s, CollectionUtils.wrap(attr.getStringValues()));});}} else {LOGGER.warn("Requested LDAP attribute [{}] could not be found on the resolved LDAP entry for [{}]", key, ldapEntry.getDn());}});if (this.collectDnAttribute) {LOGGER.debug("Recording principal DN attribute as [{}]", this.principalDnAttributeName);attributeMap.put(this.principalDnAttributeName, ldapEntry.getDn());}return attributeMap;}/*** Gets ldap principal identifier. If the principal id attribute is defined, it's retrieved.* If no attribute value is found, a warning is generated and the provided username is used instead.* If no attribute is defined, username is used instead.** @param username  the username* @param ldapEntry the ldap entry* @return the ldap principal identifier* @throws LoginException in case the principal id cannot be determined.*/protected String getLdapPrincipalIdentifier(final String username, final LdapEntry ldapEntry) throws LoginException {if (StringUtils.isNotBlank(this.principalIdAttribute)) {final LdapAttribute principalAttr = ldapEntry.getAttribute(this.principalIdAttribute);if (principalAttr == null || principalAttr.size() == 0) {if (this.allowMissingPrincipalAttributeValue) {LOGGER.warn("The principal id attribute [{}] is not found. CAS cannot construct the final authenticated principal "+ "if it's unable to locate the attribute that is designated as the principal id. "+ "Attributes available on the LDAP entry are [{}]. Since principal id attribute is not available, CAS will "+ "fall back to construct the principal based on the provided user id: [{}]",this.principalIdAttribute, ldapEntry.getAttributes(), username);return username;}LOGGER.error("The principal id attribute [{}] is not found. CAS is configured to disallow missing principal attributes",this.principalIdAttribute);throw new LoginException("Principal id attribute is not found for " + principalAttr);}final String value = principalAttr.getStringValue();if (principalAttr.size() > 1) {if (!this.allowMultiplePrincipalAttributeValues) {throw new LoginException("Multiple principal values are not allowed: " + principalAttr);}LOGGER.warn("Found multiple values for principal id attribute: [{}]. Using first value=[{}].", principalAttr, value);}LOGGER.debug("Retrieved principal id attribute [{}]", value);return value;}LOGGER.debug("Principal id attribute is not defined. Using the default provided user id [{}]", username);return username;}/*** Initialize the handler, setup the authentication entry attributes.*/public void initialize() {/** Use a set to ensure we ignore duplicates.*/final Set<String> attributes = new HashSet<>();LOGGER.debug("Initializing LDAP attribute configuration...");if (StringUtils.isNotBlank(this.principalIdAttribute)) {LOGGER.debug("Configured to retrieve principal id attribute [{}]", this.principalIdAttribute);attributes.add(this.principalIdAttribute);}if (this.principalAttributeMap != null && !this.principalAttributeMap.isEmpty()) {final Set<String> attrs = this.principalAttributeMap.keySet();attributes.addAll(attrs);LOGGER.debug("Configured to retrieve principal attribute collection of [{}]", attrs);}if (authenticator.getReturnAttributes() != null) {final List<String> authenticatorAttributes = CollectionUtils.wrapList(authenticator.getReturnAttributes());if (!authenticatorAttributes.isEmpty()) {LOGGER.debug("Filtering authentication entry attributes [{}] based on authenticator attributes [{}]", authenticatedEntryAttributes, authenticatorAttributes);attributes.removeIf(authenticatorAttributes::contains);}}this.authenticatedEntryAttributes = attributes.toArray(new String[0]);LOGGER.debug("LDAP authentication entry attributes for the authentication request are [{}]", (Object[]) this.authenticatedEntryAttributes);}
}

(4)spring.factories 中配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\gds.application.cas.config.spring.SpringConfig,\gds.application.cas.config.principal.CustomLdapAuthenticationConfiguration

(5)至此自定义验证器完成。

如果CAS是https协议的话,需要生成证书;
生成证书可参考 https://blog.csdn.net/qq_21359467/article/details/102731032
系统中如果同时存在数据库认证和ldap认证方式,两种将都会被加载,只要有一种认证通过就行

CAS5.3自定义密码(LADP)认证(三)相关推荐

  1. [信息安全] 4.一次性密码 amp;amp;amp;amp; 身份认证三要素

    在信息安全领域,一般把Cryptography称为密码,而把Password称为口令.日常用户的认知中,以及我们开发人员沟通过程中,绝大多数被称作密码的东西其实都是Password(口令),而不是真正 ...

  2. Shrio 自定义算法登录认证

    1.实现shrio SimpleCredentialsMatcher的doCredentialsMatch算法 package cn.steven.manager.security;import cn ...

  3. spring security——学习笔记(day05)-实现自定义 AuthenticationProvider身份认证-手机号码认证登录

    目录 5.2 自定义 Provider 身份认证 5.2.1 编码思路和疑问 5.2.2 创建用户信息配置类 PhonePasswordAuthenticationToken 5.2.2 修改自定义的 ...

  4. 项目1在线交流平台-7.构建安全高效的企业服务-2.使用Security自定义社区网页认证与授权

    文章目录 功能需求 一. 废弃登录检查的拦截器 二.授权配置 1. 导包 2. Security配置 2.1 `WebSecurity` 2.2`HttpSecurity` ` http.author ...

  5. Spring全家桶-Spring Security之自定义数据库表认证和鉴权

    Spring全家桶-Spring Security之自定义数据库表认证和鉴权 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供 ...

  6. 自定义Realm实现认证

    自定义Realm实现认证 Shiro默认使用自带的 IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm. 1,R ...

  7. 集成OpenLDAP与Kerberos实现统一认证(三):基于SASL/GSSAPI深度集成

    文章目录 1. 写作背景 2. 既定目标 3. 重要概念 3.1 SASL 3.2 GSSAPI 3.3 SASL与GSSAPI的关系 3.4 saslauthd 3.5 Kerberos化 4. 核 ...

  8. kafka SASL认证介绍及自定义SASL PLAIN认证功能

    文章目录 kafka 2.x用户认证方式小结 SASL/PLAIN实例(配置及客户端) broker配置 客户端配置 自定义SASL/PLAIN认证(二次开发) kafka2新的callback接口介 ...

  9. Word控件Spire.Doc 【加密解密】教程(一):在 C#、VB.NET 中使用自定义密码加密、解密、保护 Word

    Word 加密是保护 Word 文档的一种方法,它要求用户为文档提供密码.没有密码,加密文件无法打开.本指南中的解决方案演示了如何通过 Spire.Doc for .NET 在 C# 和 VB.NET ...

最新文章

  1. linux中mkswap命令使用方法,mkswap命令_Linux mkswap 命令用法详解:建立和设置SWAP交换分区...
  2. 对时域连续信号用matlab离散,数字信号处理上机实验一 离散时间信号的时域分析...
  3. iOS RunLoop 初识
  4. 使用powershell 执行脚本,windows默认不允许任何脚本运行
  5. Ubuntu 下安装JDK
  6. 【SpringBoot】自动装配原理
  7. 元宵节电商促销活动首页PSD分层模板
  8. LeetCode 260. Single Number III
  9. Ubuntu下安装Adobe Reader的中文语言包
  10. Failed to register native method nativeSetStatusCallback in base.apk
  11. mysql 开启用户远程登录
  12. 知名互联网公司网站架构图
  13. Nexus私服下载及安装
  14. App测试如何进行?手机app测试要点
  15. java实现给图片添加水印
  16. 黑森林理论,猜疑链思考
  17. 由零开始学习小程序架构
  18. python 3 过滤股票
  19. 国内几款接口管理平台,使用体验分析对比:总有一款是你想要的!
  20. PHP+Mysql 实现最简单的注册登录

热门文章

  1. 如何在微信小程序里面退出小程序
  2. 关于SI (系统集成)
  3. 怎么在Mac上修复问题硬盘
  4. 分享视频剪辑技巧,视频尺寸和格式修改为相同
  5. 树莓派 cpolar免费vip穿透局域网异地连接(ssh web均可)
  6. vue文件夹上传组件选哪个好?
  7. 无法打开SQL Server的连接 provider:Named Pipes Provider,error:40
  8. vue仿美团饿了么,实现购物车功能
  9. 50天入门人工智能!
  10. 净化自己的内心,扫除内心的尘埃