View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.spring.security;
20  
21  import java.util.List;
22  import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
23  import org.apache.syncope.common.keymaster.client.api.DomainOps;
24  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
25  import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
26  import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
27  import org.apache.syncope.core.persistence.api.dao.DelegationDAO;
28  import org.apache.syncope.core.persistence.api.dao.GroupDAO;
29  import org.apache.syncope.core.persistence.api.dao.RealmDAO;
30  import org.apache.syncope.core.persistence.api.dao.RoleDAO;
31  import org.apache.syncope.core.persistence.api.dao.UserDAO;
32  import org.apache.syncope.core.provisioning.api.AuditManager;
33  import org.apache.syncope.core.provisioning.api.ConnectorManager;
34  import org.apache.syncope.core.provisioning.api.MappingManager;
35  import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
36  import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
37  import org.springframework.context.annotation.Bean;
38  import org.springframework.context.annotation.Configuration;
39  import org.springframework.security.authentication.AuthenticationManager;
40  import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
41  import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
42  import org.springframework.security.config.annotation.web.builders.HttpSecurity;
43  import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
44  import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
45  import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
46  import org.springframework.security.web.SecurityFilterChain;
47  import org.springframework.security.web.access.AccessDeniedHandler;
48  import org.springframework.security.web.access.intercept.AuthorizationFilter;
49  import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
50  import org.springframework.security.web.firewall.DefaultHttpFirewall;
51  import org.springframework.security.web.firewall.HttpFirewall;
52  import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
53  
54  @EnableWebSecurity
55  @EnableMethodSecurity(prePostEnabled = true)
56  @Configuration(proxyBeanMethods = false)
57  public class WebSecurityContext {
58  
59      @Bean
60      public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
61          DefaultHttpFirewall firewall = new DefaultHttpFirewall();
62          firewall.setAllowUrlEncodedSlash(true);
63          return firewall;
64      }
65  
66      @Bean
67      public WebSecurityCustomizer webSecurityCustomizer(final HttpFirewall allowUrlEncodedSlashHttpFirewall) {
68          return web -> web.httpFirewall(allowUrlEncodedSlashHttpFirewall);
69      }
70  
71      @Bean
72      public SecurityFilterChain filterChain(
73              final HttpSecurity http,
74              final UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider,
75              final AccessDeniedHandler accessDeniedHandler,
76              final AuthDataAccessor dataAccessor,
77              final DefaultCredentialChecker defaultCredentialChecker) throws Exception {
78  
79          AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class).
80                  parentAuthenticationManager(null).
81                  authenticationProvider(usernamePasswordAuthenticationProvider).
82                  build();
83          http.authenticationManager(authenticationManager);
84  
85          SyncopeAuthenticationDetailsSource authenticationDetailsSource =
86                  new SyncopeAuthenticationDetailsSource();
87  
88          SyncopeBasicAuthenticationEntryPoint basicAuthenticationEntryPoint =
89                  new SyncopeBasicAuthenticationEntryPoint();
90          basicAuthenticationEntryPoint.setRealmName("Apache Syncope authentication");
91          http.httpBasic(customizer -> customizer.
92                  authenticationEntryPoint(basicAuthenticationEntryPoint).
93                  authenticationDetailsSource(authenticationDetailsSource));
94  
95          JWTAuthenticationFilter jwtAuthenticationFilter = new JWTAuthenticationFilter(
96                  authenticationManager,
97                  basicAuthenticationEntryPoint,
98                  authenticationDetailsSource,
99                  dataAccessor,
100                 defaultCredentialChecker);
101         http.addFilterBefore(jwtAuthenticationFilter, BasicAuthenticationFilter.class);
102 
103         MustChangePasswordFilter mustChangePasswordFilter = new MustChangePasswordFilter();
104         http.addFilterBefore(mustChangePasswordFilter, AuthorizationFilter.class);
105 
106         http.authorizeHttpRequests(customizer -> customizer.
107                 requestMatchers(AntPathRequestMatcher.antMatcher("/actuator/**")).
108                 hasAuthority(IdRepoEntitlement.ANONYMOUS).
109                 requestMatchers(AntPathRequestMatcher.antMatcher("/**")).permitAll());
110         http.securityContext(AbstractHttpConfigurer::disable);
111         http.sessionManagement(AbstractHttpConfigurer::disable);
112         http.headers(AbstractHttpConfigurer::disable);
113         http.csrf(AbstractHttpConfigurer::disable);
114         http.exceptionHandling(customizer -> customizer.accessDeniedHandler(accessDeniedHandler));
115 
116         return http.build();
117     }
118 
119     @ConditionalOnMissingBean
120     @Bean
121     public UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider(
122             final SecurityProperties securityProperties,
123             final DomainOps domainOps,
124             final AuthDataAccessor dataAccessor,
125             final UserProvisioningManager provisioningManager,
126             final DefaultCredentialChecker credentialChecker) {
127 
128         return new UsernamePasswordAuthenticationProvider(
129                 domainOps,
130                 dataAccessor,
131                 provisioningManager,
132                 credentialChecker,
133                 securityProperties);
134     }
135 
136     @Bean
137     public AccessDeniedHandler accessDeniedHandler() {
138         return new SyncopeAccessDeniedHandler();
139     }
140 
141     @ConditionalOnMissingBean
142     @Bean
143     public AuthDataAccessor authDataAccessor(
144             final SecurityProperties securityProperties,
145             final RealmDAO realmDAO,
146             final UserDAO userDAO,
147             final GroupDAO groupDAO,
148             final AnySearchDAO anySearchDAO,
149             final AccessTokenDAO accessTokenDAO,
150             final ConfParamOps confParamOps,
151             final RoleDAO roleDAO,
152             final DelegationDAO delegationDAO,
153             final ConnectorManager connectorManager,
154             final AuditManager auditManager,
155             final MappingManager mappingManager,
156             final List<JWTSSOProvider> jwtSSOProviders) {
157 
158         return new AuthDataAccessor(
159                 securityProperties,
160                 realmDAO,
161                 userDAO,
162                 groupDAO,
163                 anySearchDAO,
164                 accessTokenDAO,
165                 confParamOps,
166                 roleDAO,
167                 delegationDAO,
168                 connectorManager,
169                 auditManager,
170                 mappingManager,
171                 jwtSSOProviders);
172     }
173 }