1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.spring.boot.autoconfigure.security.authentication;
18
19 import static java.util.Objects.nonNull;
20 import static org.springframework.util.ObjectUtils.isEmpty;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.bremersee.ldaptive.LdaptiveTemplate;
25 import org.bremersee.spring.boot.autoconfigure.ldaptive.LdaptiveAutoConfiguration;
26 import org.bremersee.spring.security.core.EmailToUsernameResolver;
27 import org.bremersee.spring.security.core.mapping.authority.NormalizedGrantedAuthoritiesMapper;
28 import org.bremersee.spring.security.ldaptive.authentication.AccountControlEvaluator;
29 import org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthentication;
30 import org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthenticationManager;
31 import org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthenticationProperties;
32 import org.bremersee.spring.security.ldaptive.authentication.ReactiveLdaptiveAuthenticationManager;
33 import org.bremersee.spring.security.ldaptive.userdetails.LdaptiveEvaluatedRememberMeTokenProvider;
34 import org.bremersee.spring.security.ldaptive.userdetails.LdaptivePwdLastSetRememberMeTokenProvider;
35 import org.bremersee.spring.security.ldaptive.userdetails.LdaptiveRememberMeTokenProvider;
36 import org.bremersee.spring.security.ldaptive.userdetails.LdaptiveUserDetails;
37 import org.ldaptive.ConnectionConfig;
38 import org.ldaptive.ConnectionFactory;
39 import org.ldaptive.DefaultConnectionFactory;
40 import org.mapstruct.Mapper;
41 import org.mapstruct.NullValueCheckStrategy;
42 import org.mapstruct.factory.Mappers;
43 import org.springframework.beans.factory.ObjectProvider;
44 import org.springframework.boot.autoconfigure.AutoConfiguration;
45 import org.springframework.boot.autoconfigure.AutoConfigureAfter;
46 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
47 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
48 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
49 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
50 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
51 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
52 import org.springframework.boot.context.event.ApplicationReadyEvent;
53 import org.springframework.boot.context.properties.EnableConfigurationProperties;
54 import org.springframework.context.annotation.Bean;
55 import org.springframework.context.event.EventListener;
56 import org.springframework.core.convert.converter.Converter;
57 import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
58 import org.springframework.util.ClassUtils;
59
60
61
62
63
64
65 @AutoConfiguration
66 @ConditionalOnClass(name = {
67 "org.ldaptive.ConnectionFactory",
68 "org.bremersee.ldaptive.LdaptiveTemplate",
69 "org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthenticationManager"
70 })
71 @ConditionalOnBean({ConnectionConfig.class})
72 @ConditionalOnProperty(prefix = "bremersee.authentication.ldaptive", name = "user-base-dn")
73 @AutoConfigureAfter({LdaptiveAutoConfiguration.class})
74 @EnableConfigurationProperties(AuthenticationProperties.class)
75 public class LdaptiveAuthenticationAutoConfiguration {
76
77 private static final Log log = LogFactory.getLog(LdaptiveAuthenticationAutoConfiguration.class);
78
79 private final LdaptiveAuthenticationProperties properties;
80
81 private final String rememberMeKey;
82
83
84
85
86
87
88 public LdaptiveAuthenticationAutoConfiguration(AuthenticationProperties properties) {
89 this.properties = LdaptivePropertiesMapper.map(properties);
90 this.rememberMeKey = properties.getRememberMe().getKey();
91 }
92
93
94
95
96 @EventListener(ApplicationReadyEvent.class)
97 public void init() {
98 log.info(String.format("""
99
100 *********************************************************************************
101 * %s
102 * properties = %s
103 *********************************************************************************""",
104 ClassUtils.getUserClass(getClass()).getSimpleName(),
105 properties));
106 }
107
108
109
110
111
112
113 @ConditionalOnMissingBean
114 @Bean
115 public LdaptivePasswordEncoderProvider ldaptivePasswordEncoderProvider() {
116 return LdaptivePasswordEncoderProvider.defaultProvider();
117 }
118
119
120
121
122
123
124
125 @ConditionalOnMissingBean
126 @Bean
127 public LdaptiveRememberMeTokenProvider ldaptiveRememberMeTokenProvider(
128 ObjectProvider<AccountControlEvaluator> accountControlEvaluator) {
129
130 AccountControlEvaluator evaluator = accountControlEvaluator
131 .getIfAvailable(() -> properties.getAccountControlEvaluator().get());
132 if (!isEmpty(properties.getPasswordLastSetAttribute())) {
133 return new LdaptivePwdLastSetRememberMeTokenProvider(
134 evaluator, properties.getPasswordLastSetAttribute());
135 }
136 return new LdaptiveEvaluatedRememberMeTokenProvider(evaluator);
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 @ConditionalOnWebApplication(type = Type.SERVLET)
154 @Bean(initMethod = "init")
155 public LdaptiveAuthenticationManager ldaptiveAuthenticationManager(
156 ConnectionConfig connectionConfig,
157 ObjectProvider<ConnectionFactory> connectionFactoryProvider,
158 ObjectProvider<LdaptiveTemplate> ldaptiveTemplateProvider,
159 LdaptivePasswordEncoderProvider ldaptivePasswordEncoderProvider,
160 LdaptiveRememberMeTokenProvider ldaptiveRememberMeTokenProvider,
161 ObjectProvider<EmailToUsernameResolver> emailToUsernameResolver,
162 ObjectProvider<AccountControlEvaluator> accountControlEvaluator,
163 ObjectProvider<GrantedAuthoritiesMapper> grantedAuthoritiesMapper,
164 ObjectProvider<Converter<LdaptiveUserDetails, LdaptiveAuthentication>> tokenConverter) {
165
166 LdaptiveAuthenticationManager manager = new LdaptiveAuthenticationManager(
167 getLdaptiveTemplate(connectionConfig, connectionFactoryProvider, ldaptiveTemplateProvider),
168 properties,
169 rememberMeKey);
170 manager.setPasswordEncoder(ldaptivePasswordEncoderProvider.get());
171 manager.setPasswordProvider(ldaptiveRememberMeTokenProvider);
172 emailToUsernameResolver.ifAvailable(manager::setEmailToUsernameResolver);
173 accountControlEvaluator.ifAvailable(manager::setAccountControlEvaluator);
174 manager.setGrantedAuthoritiesMapper(getGrantedAuthoritiesMapper(grantedAuthoritiesMapper));
175 tokenConverter.ifAvailable(manager::setTokenConverter);
176 return manager;
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 @ConditionalOnWebApplication(type = Type.REACTIVE)
194 @Bean
195 public ReactiveLdaptiveAuthenticationManager reactiveLdaptiveAuthenticationManager(
196 ConnectionConfig connectionConfig,
197 ObjectProvider<ConnectionFactory> connectionFactoryProvider,
198 ObjectProvider<LdaptiveTemplate> ldaptiveTemplateProvider,
199 LdaptivePasswordEncoderProvider ldaptivePasswordEncoderProvider,
200 LdaptiveRememberMeTokenProvider ldaptiveRememberMeTokenProvider,
201 ObjectProvider<EmailToUsernameResolver> emailToUsernameResolver,
202 ObjectProvider<AccountControlEvaluator> accountControlEvaluator,
203 ObjectProvider<GrantedAuthoritiesMapper> grantedAuthoritiesMapper,
204 ObjectProvider<Converter<LdaptiveUserDetails, LdaptiveAuthentication>> tokenConverter) {
205 return new ReactiveLdaptiveAuthenticationManager(
206 ldaptiveAuthenticationManager(
207 connectionConfig,
208 connectionFactoryProvider,
209 ldaptiveTemplateProvider,
210 ldaptivePasswordEncoderProvider,
211 ldaptiveRememberMeTokenProvider,
212 emailToUsernameResolver,
213 accountControlEvaluator,
214 grantedAuthoritiesMapper,
215 tokenConverter));
216 }
217
218 private LdaptiveTemplate getLdaptiveTemplate(
219 ConnectionConfig connectionConfig,
220 ObjectProvider<ConnectionFactory> connectionFactoryProvider,
221 ObjectProvider<LdaptiveTemplate> ldaptiveTemplateProvider) {
222
223 LdaptiveTemplate ldaptiveTemplate = ldaptiveTemplateProvider.getIfAvailable();
224 if (nonNull(ldaptiveTemplate)) {
225 return ldaptiveTemplate;
226 }
227 ConnectionFactory connectionFactory = connectionFactoryProvider.getIfAvailable();
228 if (nonNull(connectionFactory)) {
229 return new LdaptiveTemplate(connectionFactory);
230 }
231 return new LdaptiveTemplate(new DefaultConnectionFactory(connectionConfig));
232 }
233
234 private GrantedAuthoritiesMapper getGrantedAuthoritiesMapper(
235 ObjectProvider<GrantedAuthoritiesMapper> grantedAuthoritiesMapper) {
236 return grantedAuthoritiesMapper.getIfAvailable(() -> new NormalizedGrantedAuthoritiesMapper(
237 properties.getDefaultRoles(),
238 properties.toRoleMappings(),
239 properties.getRolePrefix(),
240 properties.getRoleCaseTransformation(),
241 properties.toRoleStringReplacements()));
242 }
243
244
245
246
247 @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
248 interface PropertiesMapper {
249
250
251
252
253 PropertiesMapper INSTANCE = Mappers.getMapper(PropertiesMapper.class);
254
255
256
257
258
259
260
261 LdaptiveAuthenticationProperties map(AuthenticationProperties.LdaptiveProperties source);
262
263 }
264
265 }