1
1
package com .vaadin .flow .spring .flowsecurity ;
2
2
3
+ import com .vaadin .flow .component .UI ;
4
+ import com .vaadin .flow .internal .UrlUtil ;
5
+ import com .vaadin .flow .server .HandlerHelper ;
6
+ import com .vaadin .flow .spring .RootMappedCondition ;
7
+ import com .vaadin .flow .spring .VaadinConfigurationProperties ;
8
+ import com .vaadin .flow .spring .flowsecurity .data .UserInfo ;
9
+ import com .vaadin .flow .spring .flowsecurity .service .UserInfoService ;
10
+ import com .vaadin .flow .spring .flowsecurity .views .LoginView ;
11
+ import com .vaadin .flow .spring .security .AuthenticationContext ;
12
+ import com .vaadin .flow .spring .security .NavigationAccessControlConfigurer ;
13
+ import com .vaadin .flow .spring .security .RequestUtil ;
14
+ import com .vaadin .flow .spring .security .SpringAccessPathChecker ;
15
+ import com .vaadin .flow .spring .security .UidlRedirectStrategy ;
3
16
import jakarta .servlet .ServletContext ;
4
- import java .util .stream .Collectors ;
5
-
6
17
import org .springframework .beans .factory .annotation .Autowired ;
7
18
import org .springframework .boot .security .autoconfigure .servlet .PathRequest ;
8
19
import org .springframework .context .annotation .Bean ;
15
26
import org .springframework .security .core .userdetails .UserDetails ;
16
27
import org .springframework .security .core .userdetails .UsernameNotFoundException ;
17
28
import org .springframework .security .provisioning .InMemoryUserDetailsManager ;
29
+ import org .springframework .security .web .DefaultSecurityFilterChain ;
18
30
import org .springframework .security .web .SecurityFilterChain ;
31
+ import org .springframework .security .web .access .AuthorizationManagerWebInvocationPrivilegeEvaluator ;
32
+ import org .springframework .security .web .access .PathPatternRequestTransformer ;
33
+ import org .springframework .security .web .authentication .logout .SimpleUrlLogoutSuccessHandler ;
19
34
20
- import com .vaadin .flow .component .UI ;
21
- import com .vaadin .flow .internal .UrlUtil ;
22
- import com .vaadin .flow .spring .RootMappedCondition ;
23
- import com .vaadin .flow .spring .VaadinConfigurationProperties ;
24
- import com .vaadin .flow .spring .flowsecurity .data .UserInfo ;
25
- import com .vaadin .flow .spring .flowsecurity .service .UserInfoService ;
26
- import com .vaadin .flow .spring .flowsecurity .views .LoginView ;
27
- import com .vaadin .flow .spring .security .AuthenticationContext ;
28
- import com .vaadin .flow .spring .security .NavigationAccessControlConfigurer ;
29
- import com .vaadin .flow .spring .security .RequestUtil ;
35
+ import java .security .Principal ;
36
+ import java .util .stream .Collectors ;
30
37
31
38
import static com .vaadin .flow .spring .flowsecurity .service .UserInfoService .ROLE_ADMIN ;
32
39
import static com .vaadin .flow .spring .security .RequestUtil .antMatchers ;
33
- import static com .vaadin .flow .spring .security .VaadinSecurityConfigurer .vaadin ;
34
40
35
41
@ EnableWebSecurity
36
42
@ Configuration
@@ -58,54 +64,87 @@ public AuthenticationContext authenticationContext() {
58
64
@ Bean
59
65
static NavigationAccessControlConfigurer navigationAccessControlConfigurer () {
60
66
return new NavigationAccessControlConfigurer ()
61
- .withRoutePathAccessChecker ();
67
+ .withLoginView (LoginView .class ).withRoutePathAccessChecker ();
68
+ }
69
+
70
+ @ Bean
71
+ AuthorizationManagerWebInvocationPrivilegeEvaluator .HttpServletRequestTransformer customRequestTransformer () {
72
+ return SpringAccessPathChecker .principalAwareRequestTransformer (
73
+ new PathPatternRequestTransformer ());
62
74
}
63
75
64
76
@ Bean
65
77
public SecurityFilterChain webFilterChain (HttpSecurity http ,
66
78
AuthenticationContext authenticationContext ) throws Exception {
67
79
// Setup
68
80
http .csrf (AbstractHttpConfigurer ::disable ); // simple for testing
69
- // purpose
81
+ // purpose
70
82
71
83
// Homemade security for Vaadin application, not fully functional as the
72
84
// configuration provided by VaadinWebSecurity
73
85
// @formatter:off
74
86
http .authorizeHttpRequests (auth -> auth
87
+ // Ensures that SpringPathAccessChecker does not fail when matchers get Principal from HTTP request
88
+ .requestMatchers (request -> {
89
+ Principal principal = request .getUserPrincipal ();
90
+ if (principal == null ) {
91
+ // Do nothing, just avoid IDE complain about not used variable
92
+ }
93
+ return false ; // no need to match rule, we just want to access principal.
94
+ }).denyAll ()
75
95
// Permit access to static resources
76
96
.requestMatchers (PathRequest .toStaticResources ().atCommonLocations ())
77
- .permitAll ()
97
+ .permitAll ()
98
+ // Permit access to vaadin's internal communication
99
+ .requestMatchers (request -> HandlerHelper
100
+ .isFrameworkInternalRequest ("/*" , request ))
101
+ .permitAll ()
102
+ .requestMatchers (requestUtil ::isAnonymousRoute )
103
+ .permitAll ()
104
+ // Permit technical access to vaadin's static files
105
+ .requestMatchers ("/VAADIN/**" ).permitAll ()
106
+ // custom request matchers. using 'routeAwareAntMatcher' to
107
+ // allow checking route and alias paths against patterns
78
108
.requestMatchers (antMatchers ("/admin-only/**" , "/admin" ))
79
- .hasAnyRole (ROLE_ADMIN )
109
+ .hasAnyRole (ROLE_ADMIN )
80
110
.requestMatchers (antMatchers ("/private" ))
81
- .authenticated ()
111
+ .authenticated ()
82
112
.requestMatchers (antMatchers ("/" , "/public/**" , "/another" ))
83
- .permitAll ()
113
+ .permitAll ()
84
114
85
115
.requestMatchers (antMatchers ("/error" ))
86
- .permitAll ()
116
+ .permitAll ()
87
117
// routes aliases
88
118
.requestMatchers (antMatchers ("/alias-for-admin" ))
89
- .hasAnyRole (ROLE_ADMIN )
119
+ .hasAnyRole (ROLE_ADMIN )
90
120
.requestMatchers (antMatchers ("/home" , "/hey/**" ))
91
- .permitAll ()
92
- .requestMatchers (antMatchers ("/all-logged-in/**" ))
93
- .authenticated ()
94
- );
121
+ .permitAll ()
122
+ .requestMatchers (antMatchers ("/all-logged-in/**" , "/passthrough/**" ))
123
+ .authenticated ()
124
+ );
95
125
// @formatter:on
96
- http .with (vaadin (),
97
- cfg -> cfg .loginView (LoginView .class , getLogoutSuccessUrl ())
98
- .addLogoutHandler (
99
- (request , response , authentication ) -> {
100
- UI ui = UI .getCurrent ();
101
- ui .accessSynchronously (() -> ui .getPage ()
102
- .setLocation (UrlUtil
103
- .getServletPathRelative (
104
- getLogoutSuccessUrl (),
105
- request )));
106
- }));
107
-
108
- return http .build ();
126
+ http .logout (cfg -> {
127
+ SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler ();
128
+ logoutSuccessHandler .setDefaultTargetUrl (getLogoutSuccessUrl ());
129
+ logoutSuccessHandler
130
+ .setRedirectStrategy (new UidlRedirectStrategy ());
131
+ cfg .logoutSuccessHandler (logoutSuccessHandler );
132
+ cfg .addLogoutHandler ((request , response , authentication ) -> {
133
+ UI ui = UI .getCurrent ();
134
+ ui .accessSynchronously (() -> ui .getPage ().setLocation (
135
+ UrlUtil .getServletPathRelative (getLogoutSuccessUrl (),
136
+ request )));
137
+ });
138
+ });
139
+ // Custom login page with form authentication
140
+ http .formLogin (cfg -> cfg .loginPage ("/my/login/page" ).permitAll ());
141
+ DefaultSecurityFilterChain filterChain = http .build ();
142
+ // Test application uses AuthenticationContext, configure it with
143
+ // the logout handlers
144
+ AuthenticationContext .applySecurityConfiguration (http ,
145
+ authenticationContext );
146
+
147
+ return filterChain ;
109
148
}
110
149
111
150
public String getLogoutSuccessUrl () {
@@ -145,4 +184,4 @@ public UserDetails loadUserByUsername(String username)
145
184
};
146
185
}
147
186
148
- }
187
+ }
0 commit comments