Skip to content

Commit e418a71

Browse files
committed
Add LDAP factory beans
Issue gh-10138
1 parent 3855ac8 commit e418a71

File tree

8 files changed

+1216
-0
lines changed

8 files changed

+1216
-0
lines changed

config/spring-security-config.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ dependencies {
7474
testImplementation "org.apache.directory.server:apacheds-protocol-ldap"
7575
testImplementation "org.apache.directory.server:apacheds-server-jndi"
7676
testImplementation 'org.apache.directory.shared:shared-ldap'
77+
testImplementation "com.unboundid:unboundid-ldapsdk"
7778
testImplementation 'org.eclipse.persistence:javax.persistence'
7879
testImplementation 'org.hibernate:hibernate-entitymanager'
7980
testImplementation 'org.hsqldb:hsqldb'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.ldap;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
22+
import org.springframework.beans.factory.UnsatisfiedDependencyException;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.ldap.core.support.LdapContextSource;
26+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
27+
import org.springframework.security.config.test.SpringTestContext;
28+
import org.springframework.security.config.test.SpringTestContextExtension;
29+
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
30+
import org.springframework.test.web.servlet.MockMvc;
31+
32+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
33+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
34+
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
35+
36+
@ExtendWith(SpringTestContextExtension.class)
37+
public class EmbeddedLdapServerContextSourceFactoryBeanITests {
38+
39+
public final SpringTestContext spring = new SpringTestContext(this);
40+
41+
@Autowired
42+
private MockMvc mockMvc;
43+
44+
@Test
45+
public void contextSourceFactoryBeanWhenEmbeddedServerThenAuthenticates() throws Exception {
46+
this.spring.register(FromEmbeddedLdapServerConfig.class).autowire();
47+
48+
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
49+
.andExpect(authenticated().withUsername("bob"));
50+
}
51+
52+
@Test
53+
public void contextSourceFactoryBeanWhenPortZeroThenAuthenticates() throws Exception {
54+
this.spring.register(PortZeroConfig.class).autowire();
55+
56+
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
57+
.andExpect(authenticated().withUsername("bob"));
58+
}
59+
60+
@Test
61+
public void contextSourceFactoryBeanWhenCustomLdifAndRootThenAuthenticates() throws Exception {
62+
this.spring.register(CustomLdifAndRootConfig.class).autowire();
63+
64+
this.mockMvc.perform(formLogin().user("pg").password("password")).andExpect(authenticated().withUsername("pg"));
65+
}
66+
67+
@Test
68+
public void contextSourceFactoryBeanWhenCustomManagerDnThenAuthenticates() throws Exception {
69+
this.spring.register(CustomManagerDnConfig.class).autowire();
70+
71+
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
72+
.andExpect(authenticated().withUsername("bob"));
73+
}
74+
75+
@Test
76+
public void contextSourceFactoryBeanWhenManagerDnAndNoPasswordThenException() {
77+
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
78+
.isThrownBy(() -> this.spring.register(CustomManagerDnNoPasswordConfig.class).autowire())
79+
.withRootCauseInstanceOf(IllegalStateException.class)
80+
.withMessageContaining("managerPassword is required if managerDn is supplied");
81+
}
82+
83+
@EnableWebSecurity
84+
static class FromEmbeddedLdapServerConfig {
85+
86+
@Bean
87+
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
88+
return EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer();
89+
}
90+
91+
@Bean
92+
LdapAuthenticationManagerFactoryBean authenticationManagerFactoryBean(LdapContextSource contextSource) {
93+
LdapAuthenticationManagerFactoryBean factoryBean = LdapAuthenticationManagerFactoryBean
94+
.fromContextSource(contextSource);
95+
factoryBean.setUserDnPatterns("uid={0},ou=people");
96+
return factoryBean;
97+
}
98+
99+
}
100+
101+
@EnableWebSecurity
102+
static class PortZeroConfig {
103+
104+
@Bean
105+
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
106+
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
107+
.fromEmbeddedLdapServer();
108+
factoryBean.setPort(0);
109+
return factoryBean;
110+
}
111+
112+
@Bean
113+
LdapAuthenticationManagerFactoryBean authenticationManagerFactoryBean(LdapContextSource contextSource) {
114+
LdapAuthenticationManagerFactoryBean factoryBean = LdapAuthenticationManagerFactoryBean
115+
.fromContextSource(contextSource);
116+
factoryBean.setUserDnPatterns("uid={0},ou=people");
117+
return factoryBean;
118+
}
119+
120+
}
121+
122+
@EnableWebSecurity
123+
static class CustomLdifAndRootConfig {
124+
125+
@Bean
126+
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
127+
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
128+
.fromEmbeddedLdapServer();
129+
factoryBean.setLdif("classpath*:test-server2.xldif");
130+
factoryBean.setRoot("dc=monkeymachine,dc=co,dc=uk");
131+
return factoryBean;
132+
}
133+
134+
@Bean
135+
LdapAuthenticationManagerFactoryBean authenticationManagerFactoryBean(LdapContextSource contextSource) {
136+
LdapAuthenticationManagerFactoryBean factoryBean = LdapAuthenticationManagerFactoryBean
137+
.fromContextSource(contextSource);
138+
factoryBean.setUserDnPatterns("uid={0},ou=gorillas");
139+
return factoryBean;
140+
}
141+
142+
}
143+
144+
@EnableWebSecurity
145+
static class CustomManagerDnConfig {
146+
147+
@Bean
148+
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
149+
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
150+
.fromEmbeddedLdapServer();
151+
factoryBean.setManagerDn("uid=admin,ou=system");
152+
factoryBean.setManagerPassword("secret");
153+
return factoryBean;
154+
}
155+
156+
@Bean
157+
LdapAuthenticationManagerFactoryBean authenticationManagerFactoryBean(LdapContextSource contextSource) {
158+
LdapAuthenticationManagerFactoryBean factoryBean = LdapAuthenticationManagerFactoryBean
159+
.fromContextSource(contextSource);
160+
factoryBean.setUserDnPatterns("uid={0},ou=people");
161+
factoryBean.setPasswordEncoder(NoOpPasswordEncoder.getInstance());
162+
return factoryBean;
163+
}
164+
165+
}
166+
167+
@EnableWebSecurity
168+
static class CustomManagerDnNoPasswordConfig {
169+
170+
@Bean
171+
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
172+
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
173+
.fromEmbeddedLdapServer();
174+
factoryBean.setManagerDn("uid=admin,ou=system");
175+
return factoryBean;
176+
}
177+
178+
@Bean
179+
LdapAuthenticationManagerFactoryBean authenticationManagerFactoryBean(LdapContextSource contextSource) {
180+
LdapAuthenticationManagerFactoryBean factoryBean = LdapAuthenticationManagerFactoryBean
181+
.fromContextSource(contextSource);
182+
factoryBean.setUserDnPatterns("uid={0},ou=people");
183+
factoryBean.setPasswordEncoder(NoOpPasswordEncoder.getInstance());
184+
return factoryBean;
185+
}
186+
187+
}
188+
189+
}

0 commit comments

Comments
 (0)