20
20
import jakarta .servlet .http .HttpServletResponse ;
21
21
22
22
import java .util .Map ;
23
+ import java .util .concurrent .atomic .AtomicReference ;
23
24
import java .util .function .Consumer ;
24
25
25
26
import org .junit .Assert ;
26
27
import org .junit .Test ;
27
28
import org .junit .runner .RunWith ;
28
29
import org .mockito .Mockito ;
30
+ import org .springframework .beans .BeansException ;
31
+ import org .springframework .beans .factory .ObjectProvider ;
29
32
import org .springframework .beans .factory .annotation .Autowired ;
30
33
import org .springframework .context .ApplicationContext ;
31
34
import org .springframework .security .config .ObjectPostProcessor ;
32
35
import org .springframework .security .config .annotation .authentication .builders .AuthenticationManagerBuilder ;
33
36
import org .springframework .security .config .annotation .configuration .ObjectPostProcessorConfiguration ;
34
37
import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
35
38
import org .springframework .security .config .annotation .web .builders .WebSecurity ;
39
+ import org .springframework .security .config .annotation .web .configurers .LogoutConfigurer ;
36
40
import org .springframework .security .core .Authentication ;
37
- import com .vaadin .flow .spring .security .AuthenticationContext .CompositeLogoutHandler ;
41
+ import org .springframework .security .oauth2 .client .oidc .web .logout .OidcClientInitiatedLogoutSuccessHandler ;
42
+ import org .springframework .security .oauth2 .client .registration .ClientRegistrationRepository ;
38
43
import org .springframework .security .web .authentication .logout .LogoutHandler ;
44
+ import org .springframework .security .web .authentication .logout .LogoutSuccessHandler ;
39
45
import org .springframework .test .context .ContextConfiguration ;
40
46
import org .springframework .test .context .junit4 .SpringRunner ;
41
47
import org .springframework .test .util .ReflectionTestUtils ;
42
48
43
49
import com .vaadin .flow .server .auth .NavigationAccessControl ;
50
+ import com .vaadin .flow .spring .security .AuthenticationContext .CompositeLogoutHandler ;
44
51
45
52
import static org .mockito .ArgumentMatchers .any ;
53
+ import static org .mockito .ArgumentMatchers .anyString ;
46
54
import static org .mockito .Mockito .mock ;
47
55
48
56
@ RunWith (SpringRunner .class )
@@ -83,12 +91,7 @@ public void navigationAccessControl_enabledByDefault() throws Exception {
83
91
Map .of (ApplicationContext .class , appCtx ));
84
92
VaadinWebSecurity testConfig = new VaadinWebSecurity () {
85
93
};
86
- NavigationAccessControl accessControl = new NavigationAccessControl ();
87
- ReflectionTestUtils .setField (testConfig , "accessControl" ,
88
- accessControl );
89
- RequestUtil requestUtil = mock (RequestUtil .class );
90
- Mockito .when (requestUtil .getUrlMapping ()).thenReturn ("/*" );
91
- ReflectionTestUtils .setField (testConfig , "requestUtil" , requestUtil );
94
+ mockVaadinWebSecurityInjection (testConfig );
92
95
93
96
testConfig .filterChain (httpSecurity );
94
97
Assert .assertTrue (
@@ -108,19 +111,101 @@ protected boolean enableNavigationAccessControl() {
108
111
return false ;
109
112
}
110
113
};
111
- NavigationAccessControl accessControl = new NavigationAccessControl ();
112
- ReflectionTestUtils .setField (testConfig , "accessControl" ,
113
- accessControl );
114
- RequestUtil requestUtil = mock (RequestUtil .class );
115
- Mockito .when (requestUtil .getUrlMapping ()).thenReturn ("/*" );
116
- ReflectionTestUtils .setField (testConfig , "requestUtil" , requestUtil );
114
+ mockVaadinWebSecurityInjection (testConfig );
117
115
118
116
testConfig .filterChain (httpSecurity );
119
117
Assert .assertFalse (
120
118
"Expecting navigation access control to be disable by VaadinWebSecurity subclass" ,
121
119
testConfig .getNavigationAccessControl ().isEnabled ());
122
120
}
123
121
122
+ @ Test
123
+ public void filterChain_oauth2login_configuresLoginPageAndLogoutHandler ()
124
+ throws Exception {
125
+ assertOauth2Configuration (null );
126
+ assertOauth2Configuration ("/session-ended" );
127
+ }
128
+
129
+ private void assertOauth2Configuration (String postLogoutUri )
130
+ throws Exception {
131
+ String expectedLogoutUri = postLogoutUri != null ? postLogoutUri
132
+ : "{baseUrl}" ;
133
+ HttpSecurity httpSecurity = new HttpSecurity (postProcessor ,
134
+ new AuthenticationManagerBuilder (postProcessor ),
135
+ Map .of (ApplicationContext .class , appCtx ));
136
+ AtomicReference <String > postLogoutUriHolder = new AtomicReference <>(
137
+ "NOT SET" );
138
+ VaadinWebSecurity testConfig = new VaadinWebSecurity () {
139
+ @ Override
140
+ protected void configure (HttpSecurity http ) throws Exception {
141
+ super .configure (http );
142
+ if (postLogoutUri != null ) {
143
+ setOAuth2LoginPage (http , "/externalLogin" , postLogoutUri );
144
+ } else {
145
+ setOAuth2LoginPage (http , "/externalLogin" );
146
+ }
147
+ }
148
+
149
+ @ Override
150
+ protected LogoutSuccessHandler oidcLogoutSuccessHandler (
151
+ String postLogoutRedirectUri ) {
152
+ postLogoutUriHolder .set (postLogoutRedirectUri );
153
+ return super .oidcLogoutSuccessHandler (postLogoutRedirectUri );
154
+ }
155
+ };
156
+ TestNavigationAccessControl accessControl = mockVaadinWebSecurityInjection (
157
+ testConfig );
158
+ ClientRegistrationRepository repository = mock (
159
+ ClientRegistrationRepository .class );
160
+ ObjectProvider <ClientRegistrationRepository > provider = new ObjectProvider <ClientRegistrationRepository >() {
161
+ @ Override
162
+ public ClientRegistrationRepository getObject ()
163
+ throws BeansException {
164
+ return repository ;
165
+ }
166
+ };
167
+ ApplicationContext appCtx = Mockito .mock (ApplicationContext .class );
168
+ Mockito .when (appCtx .getBeanProvider (ClientRegistrationRepository .class ))
169
+ .thenReturn (provider );
170
+ ReflectionTestUtils .setField (testConfig , "applicationContext" , appCtx );
171
+ httpSecurity .setSharedObject (ClientRegistrationRepository .class ,
172
+ repository );
173
+
174
+ testConfig .filterChain (httpSecurity );
175
+
176
+ Assert .assertEquals ("/externalLogin" , accessControl .getLoginUrl ());
177
+ LogoutSuccessHandler logoutSuccessHandler = httpSecurity
178
+ .getConfigurer (LogoutConfigurer .class )
179
+ .getLogoutSuccessHandler ();
180
+ Assert .assertNotNull ("Expected logout success handler to be configured" ,
181
+ logoutSuccessHandler );
182
+ Assert .assertTrue (
183
+ "Expected logout success handler to be of type OidcClientInitiatedLogoutSuccessHandler, but was "
184
+ + logoutSuccessHandler .getClass ().getName (),
185
+ logoutSuccessHandler instanceof OidcClientInitiatedLogoutSuccessHandler );
186
+ Assert .assertEquals ("Unexpected post logout uri" , expectedLogoutUri ,
187
+ postLogoutUriHolder .get ());
188
+ }
189
+
190
+ private static TestNavigationAccessControl mockVaadinWebSecurityInjection (
191
+ VaadinWebSecurity testConfig ) {
192
+ TestNavigationAccessControl accessControl = new TestNavigationAccessControl ();
193
+ ReflectionTestUtils .setField (testConfig , "accessControl" ,
194
+ accessControl );
195
+ RequestUtil requestUtil = mock (RequestUtil .class );
196
+ Mockito .when (requestUtil .getUrlMapping ()).thenReturn ("/*" );
197
+ Mockito .when (requestUtil .applyUrlMapping (anyString ())).then (i -> {
198
+ String path = i .getArgument (0 , String .class );
199
+ if (!path .startsWith ("/" )) {
200
+ path = "/" + path ;
201
+ }
202
+ return path ;
203
+ });
204
+ ReflectionTestUtils .setField (testConfig , "requestUtil" , requestUtil );
205
+ ReflectionTestUtils .setField (testConfig , "servletContextPath" , "" );
206
+ return accessControl ;
207
+ }
208
+
124
209
static class TestConfig extends VaadinWebSecurity {
125
210
LogoutHandler handler1 = mock (LogoutHandler .class );
126
211
LogoutHandler handler2 = mock (LogoutHandler .class );
@@ -144,4 +229,12 @@ protected void addLogoutHandlers(Consumer<LogoutHandler> registry) {
144
229
}
145
230
}
146
231
232
+ static class TestNavigationAccessControl extends NavigationAccessControl {
233
+
234
+ @ Override
235
+ protected String getLoginUrl () {
236
+ return super .getLoginUrl ();
237
+ }
238
+ }
239
+
147
240
}
0 commit comments