33
33
import io .micrometer .observation .ObservationRegistry ;
34
34
import io .micrometer .observation .ObservationTextPublisher ;
35
35
import jakarta .annotation .security .DenyAll ;
36
+ import org .aopalliance .aop .Advice ;
36
37
import org .aopalliance .intercept .MethodInterceptor ;
37
38
import org .aopalliance .intercept .MethodInvocation ;
38
39
import org .junit .jupiter .api .Test ;
42
43
import org .mockito .Mockito ;
43
44
44
45
import org .springframework .aop .Advisor ;
46
+ import org .springframework .aop .Pointcut ;
45
47
import org .springframework .aop .config .AopConfigUtils ;
46
48
import org .springframework .aop .support .DefaultPointcutAdvisor ;
47
49
import org .springframework .aop .support .JdkRegexpMethodPointcut ;
63
65
import org .springframework .core .annotation .AnnotationConfigurationException ;
64
66
import org .springframework .core .annotation .Order ;
65
67
import org .springframework .http .HttpStatusCode ;
68
+ import org .springframework .http .MediaType ;
66
69
import org .springframework .http .ResponseEntity ;
67
70
import org .springframework .security .access .AccessDeniedException ;
68
71
import org .springframework .security .access .PermissionEvaluator ;
95
98
import org .springframework .security .authorization .method .MethodInvocationResult ;
96
99
import org .springframework .security .authorization .method .PrePostTemplateDefaults ;
97
100
import org .springframework .security .config .annotation .SecurityContextChangedListenerConfig ;
101
+ import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
98
102
import org .springframework .security .config .core .GrantedAuthorityDefaults ;
99
103
import org .springframework .security .config .observation .SecurityObservationSettings ;
100
104
import org .springframework .security .config .test .SpringTestContext ;
110
114
import org .springframework .test .context .ContextConfiguration ;
111
115
import org .springframework .test .context .TestExecutionListeners ;
112
116
import org .springframework .test .context .junit .jupiter .SpringExtension ;
117
+ import org .springframework .test .web .servlet .MockMvc ;
118
+ import org .springframework .test .web .servlet .request .MockHttpServletRequestBuilder ;
119
+ import org .springframework .web .bind .annotation .GetMapping ;
120
+ import org .springframework .web .bind .annotation .RequestParam ;
121
+ import org .springframework .web .bind .annotation .RestController ;
113
122
import org .springframework .web .context .ConfigurableWebApplicationContext ;
114
123
import org .springframework .web .context .support .AnnotationConfigWebApplicationContext ;
115
124
import org .springframework .web .servlet .ModelAndView ;
125
+ import org .springframework .web .servlet .config .annotation .EnableWebMvc ;
116
126
117
127
import static org .assertj .core .api .Assertions .assertThat ;
118
128
import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
127
137
import static org .mockito .Mockito .times ;
128
138
import static org .mockito .Mockito .verify ;
129
139
import static org .mockito .Mockito .verifyNoInteractions ;
140
+ import static org .springframework .security .test .web .servlet .request .SecurityMockMvcRequestPostProcessors .user ;
141
+ import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .get ;
142
+ import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .status ;
130
143
131
144
/**
132
145
* Tests for {@link PrePostMethodSecurityConfiguration}.
@@ -148,6 +161,9 @@ public class PrePostMethodSecurityConfigurationTests {
148
161
@ Autowired (required = false )
149
162
BusinessService businessService ;
150
163
164
+ @ Autowired (required = false )
165
+ MockMvc mvc ;
166
+
151
167
@ WithMockUser
152
168
@ Test
153
169
public void customMethodSecurityPreAuthorizeAdminWhenRoleUserThenAccessDeniedException () {
@@ -1181,6 +1197,50 @@ void autowireWhenDefaultsThenAdvisorAnnotationsAreSorted() {
1181
1197
}
1182
1198
}
1183
1199
1200
+ @ Test
1201
+ void getWhenPostAuthorizeAuthenticationNameMatchesThenRespondsWithOk () throws Exception {
1202
+ this .spring .register (WebMvcMethodSecurityConfig .class , BasicController .class ).autowire ();
1203
+ // @formatter:off
1204
+ MockHttpServletRequestBuilder requestWithUser = get ("/authorized-person" )
1205
+ .param ("name" , "rob" )
1206
+ .with (user ("rob" ));
1207
+ // @formatter:on
1208
+ this .mvc .perform (requestWithUser ).andExpect (status ().isOk ());
1209
+ }
1210
+
1211
+ @ Test
1212
+ void getWhenPostAuthorizeAuthenticationNameNotMatchThenRespondsWithForbidden () throws Exception {
1213
+ this .spring .register (WebMvcMethodSecurityConfig .class , BasicController .class ).autowire ();
1214
+ // @formatter:off
1215
+ MockHttpServletRequestBuilder requestWithUser = get ("/authorized-person" )
1216
+ .param ("name" , "john" )
1217
+ .with (user ("rob" ));
1218
+ // @formatter:on
1219
+ this .mvc .perform (requestWithUser ).andExpect (status ().isForbidden ());
1220
+ }
1221
+
1222
+ @ Test
1223
+ void getWhenCustomAdvisorAuthenticationNameMatchesThenRespondsWithOk () throws Exception {
1224
+ this .spring .register (WebMvcMethodSecurityCustomAdvisorConfig .class , BasicController .class ).autowire ();
1225
+ // @formatter:off
1226
+ MockHttpServletRequestBuilder requestWithUser = get ("/authorized-person" )
1227
+ .param ("name" , "rob" )
1228
+ .with (user ("rob" ));
1229
+ // @formatter:on
1230
+ this .mvc .perform (requestWithUser ).andExpect (status ().isOk ());
1231
+ }
1232
+
1233
+ @ Test
1234
+ void getWhenCustomAdvisorAuthenticationNameNotMatchThenRespondsWithForbidden () throws Exception {
1235
+ this .spring .register (WebMvcMethodSecurityCustomAdvisorConfig .class , BasicController .class ).autowire ();
1236
+ // @formatter:off
1237
+ MockHttpServletRequestBuilder requestWithUser = get ("/authorized-person" )
1238
+ .param ("name" , "john" )
1239
+ .with (user ("rob" ));
1240
+ // @formatter:on
1241
+ this .mvc .perform (requestWithUser ).andExpect (status ().isForbidden ());
1242
+ }
1243
+
1184
1244
private static Consumer <ConfigurableWebApplicationContext > disallowBeanOverriding () {
1185
1245
return (context ) -> ((AnnotationConfigWebApplicationContext ) context ).setAllowBeanDefinitionOverriding (false );
1186
1246
}
@@ -1919,4 +1979,76 @@ void onRequestDenied(AuthorizationDeniedEvent<? extends MethodInvocation> denied
1919
1979
1920
1980
}
1921
1981
1982
+ @ EnableWebMvc
1983
+ @ EnableWebSecurity
1984
+ @ EnableMethodSecurity
1985
+ static class WebMvcMethodSecurityConfig {
1986
+
1987
+ }
1988
+
1989
+ @ EnableWebMvc
1990
+ @ EnableWebSecurity
1991
+ @ EnableMethodSecurity
1992
+ static class WebMvcMethodSecurityCustomAdvisorConfig {
1993
+
1994
+ @ Bean
1995
+ AuthorizationAdvisor customAdvisor (SecurityContextHolderStrategy strategy ) {
1996
+ JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut ();
1997
+ pointcut .setPattern (".*AuthorizedPerson.*getName" );
1998
+ return new AuthorizationAdvisor () {
1999
+ @ Override
2000
+ public Object invoke (MethodInvocation mi ) throws Throwable {
2001
+ Authentication auth = strategy .getContext ().getAuthentication ();
2002
+ Object result = mi .proceed ();
2003
+ if (auth .getName ().equals (result )) {
2004
+ return result ;
2005
+ }
2006
+ throw new AccessDeniedException ("Access Denied for User '" + auth .getName () + "'" );
2007
+ }
2008
+
2009
+ @ Override
2010
+ public Pointcut getPointcut () {
2011
+ return pointcut ;
2012
+ }
2013
+
2014
+ @ Override
2015
+ public Advice getAdvice () {
2016
+ return this ;
2017
+ }
2018
+
2019
+ @ Override
2020
+ public int getOrder () {
2021
+ return AuthorizationInterceptorsOrder .POST_FILTER .getOrder () + 1 ;
2022
+ }
2023
+ };
2024
+ }
2025
+
2026
+ }
2027
+
2028
+ @ RestController
2029
+ static class BasicController {
2030
+
2031
+ @ AuthorizeReturnObject
2032
+ @ GetMapping (value = "/authorized-person" , produces = MediaType .APPLICATION_JSON_VALUE )
2033
+ AuthorizedPerson getAuthorizedPerson (@ RequestParam String name ) {
2034
+ return new AuthorizedPerson (name );
2035
+ }
2036
+
2037
+ }
2038
+
2039
+ public static class AuthorizedPerson {
2040
+
2041
+ final String name ;
2042
+
2043
+ AuthorizedPerson (String name ) {
2044
+ this .name = name ;
2045
+ }
2046
+
2047
+ @ PostAuthorize ("returnObject == authentication.name" )
2048
+ public String getName () {
2049
+ return this .name ;
2050
+ }
2051
+
2052
+ }
2053
+
1922
2054
}
0 commit comments