View Javadoc
1   /*
2    * Copyright 2024-2026 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    *      http://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.bremersee.spring.boot.autoconfigure.security.authentication;
18  
19  import static org.springframework.util.ObjectUtils.isEmpty;
20  
21  import java.util.Optional;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.bremersee.spring.boot.autoconfigure.security.authentication.AuthenticationProperties.RememberMeProperties;
25  import org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthenticationManager;
26  import org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthenticationProperties;
27  import org.bremersee.spring.security.ldaptive.authentication.LdaptiveTokenBasedRememberMeServices;
28  import org.springframework.boot.autoconfigure.AutoConfiguration;
29  import org.springframework.boot.autoconfigure.AutoConfigureAfter;
30  import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
31  import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
33  import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
34  import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
35  import org.springframework.boot.context.event.ApplicationReadyEvent;
36  import org.springframework.boot.context.properties.EnableConfigurationProperties;
37  import org.springframework.context.annotation.Bean;
38  import org.springframework.context.event.EventListener;
39  import org.springframework.security.web.authentication.RememberMeServices;
40  import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
41  import org.springframework.util.ClassUtils;
42  
43  /**
44   * The ldaptive remember-me autoconfiguration.
45   *
46   * @author Christian Bremer
47   */
48  @AutoConfiguration
49  @ConditionalOnWebApplication(type = Type.SERVLET)
50  @ConditionalOnProperty(prefix = "bremersee.authentication.remember-me", name = "key")
51  @ConditionalOnBean(
52      type = "org.bremersee.spring.security.ldaptive.authentication.LdaptiveAuthenticationManager")
53  @AutoConfigureAfter({LdaptiveAuthenticationAutoConfiguration.class})
54  @EnableConfigurationProperties(AuthenticationProperties.class)
55  public class LdaptiveRememberMeAutoConfiguration {
56  
57    private static final Log log = LogFactory.getLog(LdaptiveRememberMeAutoConfiguration.class);
58  
59    private final RememberMeProperties rememberMeProperties;
60  
61    private final LdaptiveAuthenticationProperties properties;
62  
63    /**
64     * Instantiates a new ldaptive remember-me autoconfiguration.
65     *
66     * @param properties the properties
67     */
68    public LdaptiveRememberMeAutoConfiguration(AuthenticationProperties properties) {
69      this.rememberMeProperties = properties.getRememberMe();
70      this.properties = LdaptivePropertiesMapper.map(properties);
71    }
72  
73    /**
74     * Init.
75     */
76    @EventListener(ApplicationReadyEvent.class)
77    public void init() {
78      String message;
79      if (isEmpty(properties.getPasswordLastSetAttribute())) {
80        message = """
81            WARNING: There is no password-last-set attribute configured.
82            * Remembered users can login as long as they exist and have been correctly evaluated.
83            * You may provide your own
84            * org.bremersee.spring.security.core.userdetails.ldaptive.LdaptiveRememberMeTokenProvider
85            * and org.bremersee.spring.security.authentication.ldaptive.AccountControlEvaluator!""";
86      } else {
87        message = String.format("OK: Using '%s' as password-last-set attribute.",
88            properties.getPasswordLastSetAttribute());
89      }
90      log.info(String.format("""
91              
92              *********************************************************************************
93              * %s
94              * %s
95              * %s
96              *********************************************************************************""",
97          ClassUtils.getUserClass(getClass()).getSimpleName(),
98          rememberMeProperties,
99          message));
100   }
101 
102   /**
103    * Creates remember me services.
104    *
105    * @param authenticationManager the authentication manager
106    * @return the remember me services
107    */
108   @ConditionalOnBean(LdaptiveAuthenticationManager.class)
109   @ConditionalOnMissingBean
110   @Bean
111   public RememberMeServices rememberMeServices(
112       LdaptiveAuthenticationManager authenticationManager) {
113     LdaptiveTokenBasedRememberMeServices services = new LdaptiveTokenBasedRememberMeServices(
114         rememberMeProperties.getKey(), authenticationManager);
115     Optional.ofNullable(rememberMeProperties.getAlwaysRemember())
116         .ifPresent(services::setAlwaysRemember);
117     Optional.ofNullable(rememberMeProperties.getCookieName())
118         .ifPresent(services::setCookieName);
119     Optional.ofNullable(rememberMeProperties.getCookieDomain())
120         .ifPresent(services::setCookieDomain);
121     Optional.ofNullable(rememberMeProperties.getUseSecureCookie())
122         .ifPresent(services::setUseSecureCookie);
123     Optional.ofNullable(rememberMeProperties.getParameterName())
124         .ifPresent(services::setParameter);
125     Optional.ofNullable(rememberMeProperties.getTokenValiditySeconds())
126         .ifPresent(services::setTokenValiditySeconds);
127     return services;
128   }
129 
130   /**
131    * Creates remember me authentication filter.
132    *
133    * @param authenticationManager the authentication manager
134    * @param rememberMeServices the remember me services
135    * @return the remember me authentication filter
136    */
137   @ConditionalOnBean(LdaptiveAuthenticationManager.class)
138   @ConditionalOnMissingBean
139   @Bean
140   public RememberMeAuthenticationFilter rememberMeAuthenticationFilter(
141       LdaptiveAuthenticationManager authenticationManager,
142       RememberMeServices rememberMeServices) {
143     return new RememberMeAuthenticationFilter(authenticationManager, rememberMeServices);
144   }
145 
146 }