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 }