CAS5.3自定义密码(LADP)认证(三)
自定义登录验证器
重写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)认证(三)相关推荐
- [信息安全] 4.一次性密码 amp;amp;amp;amp; 身份认证三要素
在信息安全领域,一般把Cryptography称为密码,而把Password称为口令.日常用户的认知中,以及我们开发人员沟通过程中,绝大多数被称作密码的东西其实都是Password(口令),而不是真正 ...
- Shrio 自定义算法登录认证
1.实现shrio SimpleCredentialsMatcher的doCredentialsMatch算法 package cn.steven.manager.security;import cn ...
- spring security——学习笔记(day05)-实现自定义 AuthenticationProvider身份认证-手机号码认证登录
目录 5.2 自定义 Provider 身份认证 5.2.1 编码思路和疑问 5.2.2 创建用户信息配置类 PhonePasswordAuthenticationToken 5.2.2 修改自定义的 ...
- 项目1在线交流平台-7.构建安全高效的企业服务-2.使用Security自定义社区网页认证与授权
文章目录 功能需求 一. 废弃登录检查的拦截器 二.授权配置 1. 导包 2. Security配置 2.1 `WebSecurity` 2.2`HttpSecurity` ` http.author ...
- Spring全家桶-Spring Security之自定义数据库表认证和鉴权
Spring全家桶-Spring Security之自定义数据库表认证和鉴权 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供 ...
- 自定义Realm实现认证
自定义Realm实现认证 Shiro默认使用自带的 IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm. 1,R ...
- 集成OpenLDAP与Kerberos实现统一认证(三):基于SASL/GSSAPI深度集成
文章目录 1. 写作背景 2. 既定目标 3. 重要概念 3.1 SASL 3.2 GSSAPI 3.3 SASL与GSSAPI的关系 3.4 saslauthd 3.5 Kerberos化 4. 核 ...
- kafka SASL认证介绍及自定义SASL PLAIN认证功能
文章目录 kafka 2.x用户认证方式小结 SASL/PLAIN实例(配置及客户端) broker配置 客户端配置 自定义SASL/PLAIN认证(二次开发) kafka2新的callback接口介 ...
- Word控件Spire.Doc 【加密解密】教程(一):在 C#、VB.NET 中使用自定义密码加密、解密、保护 Word
Word 加密是保护 Word 文档的一种方法,它要求用户为文档提供密码.没有密码,加密文件无法打开.本指南中的解决方案演示了如何通过 Spire.Doc for .NET 在 C# 和 VB.NET ...
最新文章
- linux中mkswap命令使用方法,mkswap命令_Linux mkswap 命令用法详解:建立和设置SWAP交换分区...
- 对时域连续信号用matlab离散,数字信号处理上机实验一 离散时间信号的时域分析...
- iOS RunLoop 初识
- 使用powershell 执行脚本,windows默认不允许任何脚本运行
- Ubuntu 下安装JDK
- 【SpringBoot】自动装配原理
- 元宵节电商促销活动首页PSD分层模板
- LeetCode 260. Single Number III
- Ubuntu下安装Adobe Reader的中文语言包
- Failed to register native method nativeSetStatusCallback in base.apk
- mysql 开启用户远程登录
- 知名互联网公司网站架构图
- Nexus私服下载及安装
- App测试如何进行?手机app测试要点
- java实现给图片添加水印
- 黑森林理论,猜疑链思考
- 由零开始学习小程序架构
- python 3 过滤股票
- 国内几款接口管理平台,使用体验分析对比:总有一款是你想要的!
- PHP+Mysql 实现最简单的注册登录