spring security LdapAuthenticationProviderConfigurer 源码
spring security LdapAuthenticationProviderConfigurer 代码
文件路径:/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configurers.ldap;
import java.io.IOException;
import java.net.ServerSocket;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.AbstractLdapAuthenticator;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.LdapAuthenticator;
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.security.ldap.search.LdapUserSearch;
import org.springframework.security.ldap.server.ApacheDSContainer;
import org.springframework.security.ldap.server.UnboundIdContainer;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
*
* @param <B> the {@link ProviderManagerBuilder} type that this is configuring.
* @author Rob Winch
* @author Eddú Meléndez
* @author Tony Dalbrekt
* @since 3.2
*/
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
private String groupRoleAttribute = "cn";
private String groupSearchBase = "";
private boolean groupSearchSubtree = false;
private String groupSearchFilter = "(uniqueMember={0})";
private String rolePrefix = "ROLE_";
private String userSearchBase = ""; // only for search
private String userSearchFilter = null; // "uid={0}"; // only for search
private String[] userDnPatterns;
private BaseLdapPathContextSource contextSource;
private ContextSourceBuilder contextSourceBuilder = new ContextSourceBuilder();
private UserDetailsContextMapper userDetailsContextMapper;
private PasswordEncoder passwordEncoder;
private String passwordAttribute;
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
private GrantedAuthoritiesMapper authoritiesMapper;
private LdapAuthenticationProvider build() throws Exception {
BaseLdapPathContextSource contextSource = getContextSource();
LdapAuthenticator ldapAuthenticator = createLdapAuthenticator(contextSource);
LdapAuthoritiesPopulator authoritiesPopulator = getLdapAuthoritiesPopulator();
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(ldapAuthenticator,
authoritiesPopulator);
ldapAuthenticationProvider.setAuthoritiesMapper(getAuthoritiesMapper());
if (this.userDetailsContextMapper != null) {
ldapAuthenticationProvider.setUserDetailsContextMapper(this.userDetailsContextMapper);
}
return ldapAuthenticationProvider;
}
/**
* Specifies the {@link LdapAuthoritiesPopulator}.
* @param ldapAuthoritiesPopulator the {@link LdapAuthoritiesPopulator} the default is
* {@link DefaultLdapAuthoritiesPopulator}
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> ldapAuthoritiesPopulator(
LdapAuthoritiesPopulator ldapAuthoritiesPopulator) {
this.ldapAuthoritiesPopulator = ldapAuthoritiesPopulator;
return this;
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
* @param objectPostProcessor
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
/**
* Gets the {@link LdapAuthoritiesPopulator} and defaults to
* {@link DefaultLdapAuthoritiesPopulator}
* @return the {@link LdapAuthoritiesPopulator}
*/
private LdapAuthoritiesPopulator getLdapAuthoritiesPopulator() {
if (this.ldapAuthoritiesPopulator != null) {
return this.ldapAuthoritiesPopulator;
}
DefaultLdapAuthoritiesPopulator defaultAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(
this.contextSource, this.groupSearchBase);
defaultAuthoritiesPopulator.setGroupRoleAttribute(this.groupRoleAttribute);
defaultAuthoritiesPopulator.setGroupSearchFilter(this.groupSearchFilter);
defaultAuthoritiesPopulator.setSearchSubtree(this.groupSearchSubtree);
defaultAuthoritiesPopulator.setRolePrefix(this.rolePrefix);
this.ldapAuthoritiesPopulator = postProcess(defaultAuthoritiesPopulator);
return defaultAuthoritiesPopulator;
}
/**
* Specifies the {@link GrantedAuthoritiesMapper}.
* @param grantedAuthoritiesMapper the {@link GrantedAuthoritiesMapper} the default is
* {@link SimpleAuthorityMapper}
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*
* @since 4.1.1
*/
public LdapAuthenticationProviderConfigurer<B> authoritiesMapper(
GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
this.authoritiesMapper = grantedAuthoritiesMapper;
return this;
}
/**
* Gets the {@link GrantedAuthoritiesMapper} and defaults to
* {@link SimpleAuthorityMapper}.
* @return the {@link GrantedAuthoritiesMapper}
* @throws Exception if errors in {@link SimpleAuthorityMapper#afterPropertiesSet()}
*/
protected GrantedAuthoritiesMapper getAuthoritiesMapper() throws Exception {
if (this.authoritiesMapper != null) {
return this.authoritiesMapper;
}
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
simpleAuthorityMapper.setPrefix(this.rolePrefix);
simpleAuthorityMapper.afterPropertiesSet();
this.authoritiesMapper = simpleAuthorityMapper;
return simpleAuthorityMapper;
}
/**
* Creates the {@link LdapAuthenticator} to use
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return the {@link LdapAuthenticator} to use
*/
private LdapAuthenticator createLdapAuthenticator(BaseLdapPathContextSource contextSource) {
AbstractLdapAuthenticator ldapAuthenticator = (this.passwordEncoder != null)
? createPasswordCompareAuthenticator(contextSource) : createBindAuthenticator(contextSource);
LdapUserSearch userSearch = createUserSearch();
if (userSearch != null) {
ldapAuthenticator.setUserSearch(userSearch);
}
if (this.userDnPatterns != null && this.userDnPatterns.length > 0) {
ldapAuthenticator.setUserDnPatterns(this.userDnPatterns);
}
return postProcess(ldapAuthenticator);
}
/**
* Creates {@link PasswordComparisonAuthenticator}
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return
*/
private PasswordComparisonAuthenticator createPasswordCompareAuthenticator(
BaseLdapPathContextSource contextSource) {
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(contextSource);
if (this.passwordAttribute != null) {
ldapAuthenticator.setPasswordAttributeName(this.passwordAttribute);
}
ldapAuthenticator.setPasswordEncoder(this.passwordEncoder);
return ldapAuthenticator;
}
/**
* Creates a {@link BindAuthenticator}
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return the {@link BindAuthenticator} to use
*/
private BindAuthenticator createBindAuthenticator(BaseLdapPathContextSource contextSource) {
return new BindAuthenticator(contextSource);
}
private LdapUserSearch createUserSearch() {
if (this.userSearchFilter == null) {
return null;
}
return new FilterBasedLdapUserSearch(this.userSearchBase, this.userSearchFilter, this.contextSource);
}
/**
* Specifies the {@link BaseLdapPathContextSource} to be used. If not specified, an
* embedded LDAP server will be created using {@link #contextSource()}.
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
* @see #contextSource()
*/
public LdapAuthenticationProviderConfigurer<B> contextSource(BaseLdapPathContextSource contextSource) {
this.contextSource = contextSource;
return this;
}
/**
* Allows easily configuring of a {@link BaseLdapPathContextSource} with defaults
* pointing to an embedded LDAP server that is created.
* @return the {@link ContextSourceBuilder} for further customizations
*/
public ContextSourceBuilder contextSource() {
return this.contextSourceBuilder;
}
/**
* Specifies the {@link org.springframework.security.crypto.password.PasswordEncoder}
* to be used when authenticating with password comparison.
* @param passwordEncoder the
* {@link org.springframework.security.crypto.password.PasswordEncoder} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
*/
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(
final org.springframework.security.crypto.password.PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder must not be null.");
this.passwordEncoder = passwordEncoder;
return this;
}
/**
* If your users are at a fixed location in the directory (i.e. you can work out the
* DN directly from the username without doing a directory search), you can use this
* attribute to map directly to the DN. It maps directly to the userDnPatterns
* property of AbstractLdapAuthenticator. The value is a specific pattern used to
* build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present
* and will be substituted with the username.
* @param userDnPatterns the LDAP patterns for finding the usernames
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> userDnPatterns(String... userDnPatterns) {
this.userDnPatterns = userDnPatterns;
return this;
}
/**
* Allows explicit customization of the loaded user object by specifying a
* UserDetailsContextMapper bean which will be called with the context information
* from the user's directory entry.
* @param userDetailsContextMapper the {@link UserDetailsContextMapper} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*
* @see PersonContextMapper
* @see InetOrgPersonContextMapper
* @see LdapUserDetailsMapper
*/
public LdapAuthenticationProviderConfigurer<B> userDetailsContextMapper(
UserDetailsContextMapper userDetailsContextMapper) {
this.userDetailsContextMapper = userDetailsContextMapper;
return this;
}
/**
* Specifies the attribute name which contains the role name. Default is "cn".
* @param groupRoleAttribute the attribute name that maps a group to a role.
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupRoleAttribute(String groupRoleAttribute) {
this.groupRoleAttribute = groupRoleAttribute;
return this;
}
/**
* The search base for group membership searches. Defaults to "".
* @param groupSearchBase
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupSearchBase(String groupSearchBase) {
this.groupSearchBase = groupSearchBase;
return this;
}
/**
* If set to true, a subtree scope search will be performed for group membership. If
* false a single-level search is used.
* @param groupSearchSubtree set to true to enable searching of the entire tree below
* the <tt>groupSearchBase</tt>.
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupSearchSubtree(boolean groupSearchSubtree) {
this.groupSearchSubtree = groupSearchSubtree;
return this;
}
/**
* The LDAP filter to search for groups. Defaults to "(uniqueMember={0})". The
* substituted parameter is the DN of the user.
* @param groupSearchFilter the LDAP filter to search for groups
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupSearchFilter(String groupSearchFilter) {
this.groupSearchFilter = groupSearchFilter;
return this;
}
/**
* A non-empty string prefix that will be added as a prefix to the existing roles. The
* default is "ROLE_".
* @param rolePrefix the prefix to be added to the roles that are loaded.
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
* @see SimpleAuthorityMapper#setPrefix(String)
*/
public LdapAuthenticationProviderConfigurer<B> rolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
return this;
}
/**
* Search base for user searches. Defaults to "". Only used with
* {@link #userSearchFilter(String)}.
* @param userSearchBase search base for user searches
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> userSearchBase(String userSearchBase) {
this.userSearchBase = userSearchBase;
return this;
}
/**
* The LDAP filter used to search for users (optional). For example "(uid={0})". The
* substituted parameter is the user's login name.
* @param userSearchFilter the LDAP filter used to search for users
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> userSearchFilter(String userSearchFilter) {
this.userSearchFilter = userSearchFilter;
return this;
}
@Override
public void configure(B builder) throws Exception {
LdapAuthenticationProvider provider = postProcess(build());
builder.authenticationProvider(provider);
}
private BaseLdapPathContextSource getContextSource() throws Exception {
if (this.contextSource == null) {
this.contextSource = this.contextSourceBuilder.build();
}
return this.contextSource;
}
/**
* @return the {@link PasswordCompareConfigurer} for further customizations
*/
public PasswordCompareConfigurer passwordCompare() {
return new PasswordCompareConfigurer().passwordAttribute("password")
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
/**
* Sets up Password based comparison
*
* @author Rob Winch
*/
public final class PasswordCompareConfigurer {
/**
* Allows specifying the {@link PasswordEncoder} to use. The default is
* {@link org.springframework.security.crypto.password.NoOpPasswordEncoder}.
* @param passwordEncoder the {@link PasswordEncoder} to use
* @return the {@link PasswordCompareConfigurer} for further customizations
*/
public PasswordCompareConfigurer passwordEncoder(PasswordEncoder passwordEncoder) {
LdapAuthenticationProviderConfigurer.this.passwordEncoder = passwordEncoder;
return this;
}
/**
* The attribute in the directory which contains the user password. Defaults to
* "userPassword".
* @param passwordAttribute the attribute in the directory which contains the user
* password
* @return the {@link PasswordCompareConfigurer} for further customizations
*/
public PasswordCompareConfigurer passwordAttribute(String passwordAttribute) {
LdapAuthenticationProviderConfigurer.this.passwordAttribute = passwordAttribute;
return this;
}
/**
* Allows obtaining a reference to the
* {@link LdapAuthenticationProviderConfigurer} for further customizations
* @return attribute in the directory which contains the user password
*/
public LdapAuthenticationProviderConfigurer<B> and() {
return LdapAuthenticationProviderConfigurer.this;
}
private PasswordCompareConfigurer() {
}
}
/**
* Allows building a {@link BaseLdapPathContextSource} and optionally creating an
* embedded LDAP instance.
*
* @author Rob Winch
* @author Evgeniy Cheban
* @since 3.2
*/
public final class ContextSourceBuilder {
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
private static final int DEFAULT_PORT = 33389;
private static final int RANDOM_PORT = 0;
private String ldif = "classpath*:*.ldif";
private String managerPassword;
private String managerDn;
private Integer port;
private String root = "dc=springframework,dc=org";
private String url;
/**
* Specifies an ldif to load at startup for an embedded LDAP server. This only
* loads if using an embedded instance. The default is "classpath*:*.ldif".
* @param ldif the ldif to load at startup for an embedded LDAP server.
* @return the {@link ContextSourceBuilder} for further customization
*/
public ContextSourceBuilder ldif(String ldif) {
this.ldif = ldif;
return this;
}
/**
* Username (DN) of the "manager" user identity (i.e. "uid=admin,ou=system") which
* will be used to authenticate to a (non-embedded) LDAP server. If omitted,
* anonymous access will be used.
* @param managerDn the username (DN) of the "manager" user identity used to
* authenticate to a LDAP server.
* @return the {@link ContextSourceBuilder} for further customization
*/
public ContextSourceBuilder managerDn(String managerDn) {
this.managerDn = managerDn;
return this;
}
/**
* The password for the manager DN. This is required if the manager-dn is
* specified.
* @param managerPassword password for the manager DN
* @return the {@link ContextSourceBuilder} for further customization
*/
public ContextSourceBuilder managerPassword(String managerPassword) {
this.managerPassword = managerPassword;
return this;
}
/**
* The port to connect to LDAP to (the default is 33389 or random available port
* if unavailable).
*
* Supplying 0 as the port indicates that a random available port should be
* selected.
* @param port the port to connect to
* @return the {@link ContextSourceBuilder} for further customization
*/
public ContextSourceBuilder port(int port) {
this.port = port;
return this;
}
/**
* Optional root suffix for the embedded LDAP server. Default is
* "dc=springframework,dc=org"
* @param root root suffix for the embedded LDAP server
* @return the {@link ContextSourceBuilder} for further customization
*/
public ContextSourceBuilder root(String root) {
this.root = root;
return this;
}
/**
* Specifies the ldap server URL when not using the embedded LDAP server. For
* example, "ldaps://ldap.example.com:33389/dc=myco,dc=org".
* @param url the ldap server URL
* @return the {@link ContextSourceBuilder} for further customization
*/
public ContextSourceBuilder url(String url) {
this.url = url;
return this;
}
/**
* Gets the {@link LdapAuthenticationProviderConfigurer} for further
* customizations
* @return the {@link LdapAuthenticationProviderConfigurer} for further
* customizations
*/
public LdapAuthenticationProviderConfigurer<B> and() {
return LdapAuthenticationProviderConfigurer.this;
}
private DefaultSpringSecurityContextSource build() throws Exception {
if (this.url == null) {
startEmbeddedLdapServer();
}
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(getProviderUrl());
if (this.managerDn != null) {
contextSource.setUserDn(this.managerDn);
if (this.managerPassword == null) {
throw new IllegalStateException("managerPassword is required if managerDn is supplied");
}
contextSource.setPassword(this.managerPassword);
}
contextSource = postProcess(contextSource);
return contextSource;
}
private void startEmbeddedLdapServer() throws Exception {
if (ClassUtils.isPresent(APACHEDS_CLASSNAME, getClass().getClassLoader())) {
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(this.root, this.ldif);
apacheDsContainer.setPort(getPort());
postProcess(apacheDsContainer);
this.port = apacheDsContainer.getLocalPort();
}
else if (ClassUtils.isPresent(UNBOUNDID_CLASSNAME, getClass().getClassLoader())) {
UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
unboundIdContainer.setPort(getPort());
postProcess(unboundIdContainer);
this.port = unboundIdContainer.getPort();
}
else {
throw new IllegalStateException("Embedded LDAP server is not provided");
}
}
private int getPort() {
if (this.port == null) {
this.port = getDefaultPort();
}
return this.port;
}
private int getDefaultPort() {
try (ServerSocket serverSocket = new ServerSocket(DEFAULT_PORT)) {
return serverSocket.getLocalPort();
}
catch (IOException ex) {
return RANDOM_PORT;
}
}
private String getProviderUrl() {
if (this.url == null) {
return "ldap://127.0.0.1:" + getPort() + "/" + this.root;
}
return this.url;
}
private ContextSourceBuilder() {
}
}
}
相关信息
相关文章
spring security AclEntryVoter 源码
spring security AclPermissionCacheOptimizer 源码
spring security AclPermissionEvaluator 源码
spring security AbstractAclProvider 源码
spring security AclEntryAfterInvocationCollectionFilteringProvider 源码
spring security AclEntryAfterInvocationProvider 源码
spring security ArrayFilterer 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦