提交 7f8506ce 编写于 作者: X xm.lin 提交者: nobodyiam

集成ldap,注,因各个公司ldap中定义的属性不同,需对LdapUserInfo做相应调整

上级 4ea75826
......@@ -14,6 +14,18 @@
<github.path>${project.artifactId}</github.path>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-common</artifactId>
......
package com.ctrip.framework.apollo.portal.entity.bo;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import javax.naming.Name;
/**
* @author xm.lin xm.lin@anxincloud.com
* @Description
* @date 18-8-9 下午4:43
*/
@Entry(base = "cn=Manager",objectClasses = {"inetOrgPerson"})
public class LdapUserInfo {
@Id
private Name id;
@Attribute(name = "cn")
private String username;
@Attribute(name = "sn")
private String realName;
@Attribute(name = "userPassword")
private String userPassword;
@Attribute(name = "mail")
private String mail;
public Name getId() {
return id;
}
public void setId(Name id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
}
package com.ctrip.framework.apollo.portal.spi.configuration;
import com.google.common.collect.Maps;
import com.ctrip.framework.apollo.common.condition.ConditionalOnMissingProfile;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.ctrip.framework.apollo.portal.spi.LogoutHandler;
......@@ -16,11 +14,13 @@ import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultLogoutHandler;
import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultSsoHeartbeatHandler;
import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultUserInfoHolder;
import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultUserService;
import com.ctrip.framework.apollo.portal.spi.ldap.LdapUserService;
import com.ctrip.framework.apollo.portal.spi.springsecurity.SpringSecurityUserInfoHolder;
import com.ctrip.framework.apollo.portal.spi.springsecurity.SpringSecurityUserService;
import com.google.common.collect.Maps;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
......@@ -28,6 +28,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
......@@ -58,7 +60,8 @@ public class AuthConfiguration {
@Bean
public ServletListenerRegistrationBean redisAppSettingListner() {
ServletListenerRegistrationBean redisAppSettingListener = new ServletListenerRegistrationBean();
redisAppSettingListener.setListener(listener("org.jasig.cas.client.credis.CRedisAppSettingListner"));
redisAppSettingListener
.setListener(listener("org.jasig.cas.client.credis.CRedisAppSettingListner"));
return redisAppSettingListener;
}
......@@ -92,7 +95,8 @@ public class AuthConfiguration {
filterInitParam.put("/openapi.*", "exclude");
casFilter.setInitParameters(filterInitParam);
casFilter.setFilter(filter("com.ctrip.framework.apollo.sso.filter.ApolloAuthenticationFilter"));
casFilter
.setFilter(filter("com.ctrip.framework.apollo.sso.filter.ApolloAuthenticationFilter"));
casFilter.addUrlPatterns("/*");
casFilter.setOrder(2);
......@@ -112,7 +116,8 @@ public class AuthConfiguration {
filterInitParam.put("redisClusterName", "casClientPrincipal");
casValidationFilter
.setFilter(filter("org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"));
.setFilter(
filter("org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"));
casValidationFilter.setInitParameters(filterInitParam);
casValidationFilter.addUrlPatterns("/*");
casValidationFilter.setOrder(3);
......@@ -131,7 +136,8 @@ public class AuthConfiguration {
assertionHolderFilter.setInitParameters(filterInitParam);
assertionHolderFilter.setFilter(filter("com.ctrip.framework.apollo.sso.filter.ApolloAssertionThreadLocalFilter"));
assertionHolderFilter.setFilter(
filter("com.ctrip.framework.apollo.sso.filter.ApolloAssertionThreadLocalFilter"));
assertionHolderFilter.addUrlPatterns("/*");
assertionHolderFilter.setOrder(4);
......@@ -210,19 +216,27 @@ public class AuthConfiguration {
}
@Bean
public JdbcUserDetailsManager jdbcUserDetailsManager(AuthenticationManagerBuilder auth, DataSource datasource) throws Exception {
JdbcUserDetailsManager jdbcUserDetailsManager = auth.jdbcAuthentication().passwordEncoder(new BCryptPasswordEncoder()).dataSource(datasource)
public JdbcUserDetailsManager jdbcUserDetailsManager(AuthenticationManagerBuilder auth,
DataSource datasource) throws Exception {
JdbcUserDetailsManager jdbcUserDetailsManager = auth.jdbcAuthentication()
.passwordEncoder(new BCryptPasswordEncoder()).dataSource(datasource)
.usersByUsernameQuery("select Username,Password,Enabled from `Users` where Username = ?")
.authoritiesByUsernameQuery("select Username,Authority from `Authorities` where Username = ?")
.authoritiesByUsernameQuery(
"select Username,Authority from `Authorities` where Username = ?")
.getUserDetailsService();
jdbcUserDetailsManager.setUserExistsSql("select Username from `Users` where Username = ?");
jdbcUserDetailsManager.setCreateUserSql("insert into `Users` (Username, Password, Enabled) values (?,?,?)");
jdbcUserDetailsManager.setUpdateUserSql("update `Users` set Password = ?, Enabled = ? where Username = ?");
jdbcUserDetailsManager
.setCreateUserSql("insert into `Users` (Username, Password, Enabled) values (?,?,?)");
jdbcUserDetailsManager
.setUpdateUserSql("update `Users` set Password = ?, Enabled = ? where Username = ?");
jdbcUserDetailsManager.setDeleteUserSql("delete from `Users` where Username = ?");
jdbcUserDetailsManager.setCreateAuthoritySql("insert into `Authorities` (Username, Authority) values (?,?)");
jdbcUserDetailsManager.setDeleteUserAuthoritiesSql("delete from `Authorities` where Username = ?");
jdbcUserDetailsManager.setChangePasswordSql("update `Users` set Password = ? where Username = ?");
jdbcUserDetailsManager
.setCreateAuthoritySql("insert into `Authorities` (Username, Authority) values (?,?)");
jdbcUserDetailsManager
.setDeleteUserAuthoritiesSql("delete from `Authorities` where Username = ?");
jdbcUserDetailsManager
.setChangePasswordSql("update `Users` set Password = ? where Username = ?");
return jdbcUserDetailsManager;
}
......@@ -257,11 +271,84 @@ public class AuthConfiguration {
}
/**
* spring.profiles.active = ldap
*/
@Configuration
@Profile("ldap")
static class SpringSecurityLDAPAuthAutoConfiguration {
@Bean
@ConditionalOnMissingBean(SsoHeartbeatHandler.class)
public SsoHeartbeatHandler defaultSsoHeartbeatHandler() {
return new DefaultSsoHeartbeatHandler();
}
@Bean
@ConditionalOnMissingBean(UserInfoHolder.class)
public UserInfoHolder springSecurityUserInfoHolder() {
return new SpringSecurityUserInfoHolder();
}
@Bean
@ConditionalOnMissingBean(LogoutHandler.class)
public LogoutHandler logoutHandler() {
return new DefaultLogoutHandler();
}
@Bean
@ConditionalOnMissingBean(UserService.class)
public UserService springSecurityUserService() {
return new LdapUserService();
}
}
@Order(99)
@Profile("ldap")
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@AutoConfigureAfter(LdapAutoConfiguration.class)
static class SpringSecurityLDAPConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private LdapProperties ldapProperties;
@Autowired
private LdapContextSource ldapContextSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
http.authorizeRequests()
.antMatchers("/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**",
"/img/**").permitAll()
.antMatchers("/**").authenticated();
http.formLogin().loginPage("/signin").permitAll().failureUrl("/signin?#/error").and()
.httpBasic();
http.logout().invalidateHttpSession(true).clearAuthentication(true)
.logoutSuccessUrl("/signin?#/logout");
http.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/signin"));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userDnPatterns(ldapProperties.getUserDnPatterns())
.contextSource(ldapContextSource)
.passwordCompare()
.passwordEncoder(new LdapShaPasswordEncoder())
.passwordAttribute("userPassword");
}
}
/**
* default profile
*/
@Configuration
@ConditionalOnMissingProfile({"ctrip", "auth"})
@ConditionalOnMissingProfile({"ctrip", "auth", "ldap"})
static class DefaultAuthAutoConfiguration {
@Bean
......
package com.ctrip.framework.apollo.portal.spi.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.env.Environment;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import java.util.Collections;
/**
* @author xm.lin xm.lin@anxincloud.com
* @Description
* @date 18-8-9 下午4:37
*/
@Configuration
@ConditionalOnClass(ContextSource.class)
@EnableConfigurationProperties(LdapProperties.class)
public class LdapAutoConfiguration {
@Autowired
private LdapProperties properties;
@Autowired
private Environment environment;
@Bean
@ConditionalOnMissingBean
public ContextSource ldapContextSource() {
LdapContextSource source = new LdapContextSource();
source.setUserDn(this.properties.getUsername());
source.setPassword(this.properties.getPassword());
source.setAnonymousReadOnly(this.properties.getAnonymousReadOnly());
source.setBase(this.properties.getBase());
source.setUrls(this.properties.determineUrls(this.environment));
source.setBaseEnvironmentProperties(
Collections.unmodifiableMap(this.properties.getBaseEnvironment()));
return source;
}
@Bean
@ConditionalOnMissingBean(LdapOperations.class)
public LdapTemplate ldapTemplate(ContextSource contextSource) {
return new LdapTemplate(contextSource);
}
}
package com.ctrip.framework.apollo.portal.spi.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author xm.lin xm.lin@anxincloud.com
* @Description
* @date 18-8-9 下午4:36
*/
@ConfigurationProperties(prefix = "spring.ldap")
public class LdapProperties {
private static final int DEFAULT_PORT = 389;
/**
* LDAP URLs of the server.
*/
private String[] urls;
/**
* Base suffix from which all operations should originate.
*/
private String base;
/**
* Login username of the server.
*/
private String username;
/**
* Login password of the server.
*/
private String password;
/**
* Whether read-only operations should use an anonymous environment.
*/
private boolean anonymousReadOnly;
/**
* LDAP specification settings.
*/
private final Map<String, String> baseEnvironment = new HashMap<>();
private String userDnPatterns;
public String[] getUrls() {
return this.urls;
}
public void setUrls(String[] urls) {
this.urls = urls;
}
public String getBase() {
return this.base;
}
public void setBase(String base) {
this.base = base;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean getAnonymousReadOnly() {
return this.anonymousReadOnly;
}
public void setAnonymousReadOnly(boolean anonymousReadOnly) {
this.anonymousReadOnly = anonymousReadOnly;
}
public String getUserDnPatterns() {
return userDnPatterns;
}
public void setUserDnPatterns(String userDnPatterns) {
this.userDnPatterns = userDnPatterns;
}
public Map<String, String> getBaseEnvironment() {
return this.baseEnvironment;
}
public String[] determineUrls(Environment environment) {
if (ObjectUtils.isEmpty(this.urls)) {
return new String[]{"ldap://localhost:" + determinePort(environment)};
}
return this.urls;
}
private int determinePort(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
String localPort = environment.getProperty("local.ldap.port");
if (localPort != null) {
return Integer.valueOf(localPort);
}
return DEFAULT_PORT;
}
}
package com.ctrip.framework.apollo.portal.spi.ldap;
import com.ctrip.framework.apollo.portal.entity.bo.LdapUserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserService;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.query.ContainerCriteria;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.ldap.query.SearchScope;
import org.springframework.util.CollectionUtils;
/**
* @author xm.lin xm.lin@anxincloud.com
* @Description
* @date 18-8-9 下午4:42
*/
public class LdapUserService implements UserService {
@Autowired
private LdapTemplate ldapTemplate;
@Override
public List<UserInfo> searchUsers(String keyword, int offset, int limit) {
List<LdapUserInfo> ldapUserInfoList = null;
if (Strings.isNullOrEmpty(keyword)) {
ldapUserInfoList = ldapTemplate.findAll(LdapUserInfo.class);
} else {
ContainerCriteria criteria = LdapQueryBuilder
.query().searchScope(SearchScope.SUBTREE)
.where("cn").like(keyword + "*")
.or("sn").like(keyword + "*");
ldapUserInfoList = ldapTemplate.find(criteria, LdapUserInfo.class);
}
return convertLdapUserToUserInfo(ldapUserInfoList);
}
@Override
public UserInfo findByUserId(String userId) {
ContainerCriteria criteria = LdapQueryBuilder.query().where("cn").is(userId);
LdapUserInfo ldapUser = ldapTemplate.findOne(criteria, LdapUserInfo.class);
UserInfo userInfo = new UserInfo();
userInfo.setUserId(ldapUser.getUsername());
userInfo.setName(ldapUser.getRealName());
userInfo.setEmail(ldapUser.getMail());
return userInfo;
}
@Override
public List<UserInfo> findByUserIds(List<String> userIds) {
if (!CollectionUtils.isEmpty(userIds)) {
LdapQueryBuilder ldapQueryBuilder = LdapQueryBuilder.query()
.searchScope(SearchScope.SUBTREE);
ContainerCriteria criteria = ldapQueryBuilder.where("cn").is(userIds.get(0));
userIds.stream().skip(1).forEach(userId -> {
criteria.or("cn").is(userId);
});
List<LdapUserInfo> ldapUserInfoList = ldapTemplate.find(criteria, LdapUserInfo.class);
return convertLdapUserToUserInfo(ldapUserInfoList);
}
return null;
}
private List<UserInfo> convertLdapUserToUserInfo(List<LdapUserInfo> ldapUserInfoList) {
List<UserInfo> userInfoList = Lists.newArrayList();
if (!CollectionUtils.isEmpty(ldapUserInfoList)) {
ldapUserInfoList.stream().map(p -> {
UserInfo userInfo = new UserInfo();
userInfo.setUserId(p.getUsername());
userInfo.setName(p.getRealName());
userInfo.setEmail(p.getMail());
return userInfo;
}).forEach(userInfoList::add);
}
return userInfoList;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册