1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.security.authentication;
18
19 import lombok.extern.slf4j.Slf4j;
20 import org.bremersee.data.ldaptive.LdaptiveAutoConfiguration;
21 import org.bremersee.data.ldaptive.LdaptiveOperations;
22 import org.bremersee.data.ldaptive.LdaptiveProperties;
23 import org.bremersee.data.ldaptive.LdaptiveProperties.UserDetailsProperties;
24 import org.bremersee.data.ldaptive.reactive.ReactiveLdaptiveOperations;
25 import org.bremersee.security.core.userdetails.LdaptivePasswordEncoder;
26 import org.bremersee.security.core.userdetails.LdaptivePasswordMatcher;
27 import org.bremersee.security.core.userdetails.LdaptiveUserDetailsService;
28 import org.bremersee.security.core.userdetails.ReactiveLdaptiveUserDetailsService;
29 import org.ldaptive.ConnectionFactory;
30 import org.springframework.beans.factory.ObjectProvider;
31 import org.springframework.boot.autoconfigure.AutoConfigureAfter;
32 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
33 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
34 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
35 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
36 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
37 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
38 import org.springframework.boot.context.event.ApplicationReadyEvent;
39 import org.springframework.boot.context.properties.EnableConfigurationProperties;
40 import org.springframework.context.annotation.Bean;
41 import org.springframework.context.annotation.Configuration;
42 import org.springframework.context.event.EventListener;
43 import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
44 import org.springframework.security.core.userdetails.UserDetailsService;
45 import org.springframework.security.crypto.password.PasswordEncoder;
46 import org.springframework.util.Assert;
47 import org.springframework.util.ClassUtils;
48
49
50
51
52
53
54 @Configuration
55 @ConditionalOnWebApplication(type = Type.ANY)
56 @AutoConfigureBefore(InMemoryUserDetailsAutoConfiguration.class)
57 @AutoConfigureAfter(LdaptiveAutoConfiguration.class)
58 @ConditionalOnClass({
59 ConnectionFactory.class,
60 LdaptiveOperations.class
61 })
62 @ConditionalOnProperty(
63 prefix = "bremersee.ldaptive",
64 name = {"enabled", "authentication-enabled"},
65 havingValue = "true")
66 @EnableConfigurationProperties(LdaptiveProperties.class)
67 @Slf4j
68 public class LdaptiveUserDetailsAutoConfiguration {
69
70 private final UserDetailsProperties properties;
71
72 private final LdaptiveOperations ldaptiveOperations;
73
74
75
76
77
78
79
80 public LdaptiveUserDetailsAutoConfiguration(
81 LdaptiveProperties properties,
82 ObjectProvider<LdaptiveOperations> ldaptiveOperationsProvider) {
83 this.properties = properties.getUserDetails();
84 this.ldaptiveOperations = ldaptiveOperationsProvider.getIfAvailable();
85 Assert.notNull(this.ldaptiveOperations, "Ldap operations must not be present.");
86 }
87
88
89
90
91 @EventListener(ApplicationReadyEvent.class)
92 public void init() {
93 log.info("\n"
94 + "*********************************************************************************\n"
95 + "* {}\n"
96 + "*********************************************************************************\n"
97 + "* properties = {}\n"
98 + "*********************************************************************************",
99 ClassUtils.getUserClass(getClass()).getSimpleName(),
100 properties);
101 Assert.hasText(properties.getUserBaseDn(), "User base dn must be present.");
102 Assert.hasText(properties.getUserFindOneFilter(), "User find one filter must be present.");
103 }
104
105
106
107
108
109
110 @ConditionalOnWebApplication(type = Type.SERVLET)
111 @ConditionalOnMissingBean(value = {UserDetailsService.class})
112 @Bean
113 public LdaptiveUserDetailsService ldaptiveUserDetailsService() {
114 return new LdaptiveUserDetailsService(
115 ldaptiveOperations,
116 properties.getUserBaseDn(),
117 properties.getUserFindOneFilter(),
118 properties.getUserFindOneSearchScope(),
119 properties.getUserAccountControlAttributeName(),
120 properties.getAuthorities(),
121 properties.getAuthorityAttributeName(),
122 properties.isAuthorityDn(),
123 properties.getAuthorityMap(),
124 properties.getAuthorityPrefix());
125 }
126
127
128
129
130
131
132
133 @ConditionalOnWebApplication(type = Type.REACTIVE)
134 @ConditionalOnMissingBean(value = {ReactiveUserDetailsService.class})
135 @Bean
136 public ReactiveLdaptiveUserDetailsService reactiveLdaptiveUserDetailsService(
137 ObjectProvider<ReactiveLdaptiveOperations> reactiveLdaptiveOperationsProvider) {
138 ReactiveLdaptiveOperations reactiveLdaptiveOperations = reactiveLdaptiveOperationsProvider.getIfAvailable();
139 Assert.notNull(reactiveLdaptiveOperations, "Reactive ldap operations must not be present.");
140 return new ReactiveLdaptiveUserDetailsService(
141 reactiveLdaptiveOperations,
142 properties.getUserBaseDn(),
143 properties.getUserFindOneFilter(),
144 properties.getUserFindOneSearchScope(),
145 properties.getUserAccountControlAttributeName(),
146 properties.getAuthorities(),
147 properties.getAuthorityAttributeName(),
148 properties.isAuthorityDn(),
149 properties.getAuthorityMap(),
150 properties.getAuthorityPrefix());
151 }
152
153
154
155
156
157
158 @ConditionalOnMissingBean(value = {PasswordEncoder.class})
159 @Bean
160 public LdaptivePasswordMatcher passwordEncoder() {
161 LdaptivePasswordMatcher matcher = new LdaptivePasswordMatcher(
162 ldaptiveOperations,
163 properties.getUserBaseDn(),
164 properties.getUserFindOneFilter());
165 matcher.setUserPasswordAttributeName(properties.getUserAccountControlAttributeName());
166 matcher.setUserFindOneSearchScope(properties.getUserFindOneSearchScope());
167 matcher.setUserPasswordAttributeName(properties.getUserPasswordAttributeName());
168 matcher.setDelegate(new LdaptivePasswordEncoder(
169 properties.getUserPasswordLabel(),
170 properties.getUserPasswordAlgorithm()));
171 return matcher;
172 }
173
174 }