Spring Security Kotlin Field Injection of Repository Class Failing - spring

I am new to Spring and Kotlin, and am trying to implement OAuth2 with a custom success handler. In the handler, I want to save the user details to my MongoDB database. Here is my security config (AuthenticationSuccessHandler is injected in the constructor):
#EnableWebSecurity
#Configuration
public class SecurityConfig(private val authenticationSuccessHandler : AuthenticationSuccessHandler) {
#Throws(Exception::class)
#Bean
public fun override(http: HttpSecurity): SecurityFilterChain {
return http
.csrf{csrf -> csrf.disable()}
.authorizeRequests{auth ->
auth.antMatchers("/api/brackets").authenticated()
auth.antMatchers("/**").permitAll()
}
.oauth2Login()
.successHandler(AuthenticationSuccessHandler())
.and()
.build()
}
}
and here is my AuthenticationSuccessHandler class (see autowired userRepository):
#Component
public class AuthenticationSuccessHandler : SavedRequestAwareAuthenticationSuccessHandler() {
private val redirectStrategy : RedirectStrategy = DefaultRedirectStrategy();
private val logger : Logger = LoggerFactory.getLogger(javaClass)
#Autowired
private lateinit var userRepository : UserRepository
#Throws(ServletException::class,IOException::class)
override public fun onAuthenticationSuccess(request : HttpServletRequest, response : HttpServletResponse, authentication : Authentication) {
//if redirected from some specific url, need to remove the cachedRequest to force use defaultTargetUrl
val requestCache : RequestCache = HttpSessionRequestCache();
val savedRequest : SavedRequest = requestCache.getRequest(request, response);
val userDetails : DefaultOidcUser = authentication.getPrincipal() as DefaultOidcUser
logger.info(userDetails.getIdToken().getTokenValue())
userRepository.save(User(userDetails.getName(), userDetails.getEmail(), AuthService.GOOGLE))
redirectStrategy.sendRedirect(request, response, "/api/testAuth");
}
}
Unfortunately when this handler is hit, the statement to save a new User fails with the message: "kotlin.UninitializedPropertyAccessException: lateinit property userRepository has not been initialized"
Any ideas why my userRepository is not being injected? Thank you so much!

It looks like the problem is that I wasn't using my injected instance of authenticationSuccessHandler and instead instantiating a new one without use of the spring framework. I was able to fix this by changing .successHandler(AuthenticationSuccessHandler()) to .successHandler(authenticationSuccessHandler) that why the dependency injection worked

Related

How to inject a test UserDetailsManager into CustomProviderManager during SpringBootTest?

Given is a Spring Boot application with a custom ProviderManager:
#Component
public class CustomProviderManager extends ProviderManager {
public CustomProviderManager(
AuthenticationProvider internalAuthenticationProvider,
AuthenticationProvider devUserAuthenticationProvider) {
super(internalAuthenticationProvider, devUserAuthenticationProvider);
}
}
The SecurityFilterChain is setup with a custom UsernamePasswordAuthenticationFilter:
#Bean
public SecurityFilterChain mvcFilterChain(HttpSecurity http) throws Exception {
return http
//....
.addFilterAt(internalUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
//....
}
And here the custom UsernamePasswordAuthenticationFilter:
#Component
public class InternalUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final SecurityContextRepository securityContextRepository;
private final AuthenticationFailureHandler authenticationFailureHandler;
private final AuthenticationSuccessHandler authenticationSuccessHandler;
#PostConstruct
private void setup() {
super.setUsernameParameter("identifier");
super.setPasswordParameter("password");
super.setFilterProcessesUrl("/authenticate");
super.setSecurityContextRepository(securityContextRepository);
super.setAuthenticationFailureHandler(authenticationFailureHandler);
super.setAuthenticationSuccessHandler(authenticationSuccessHandler);
super.afterPropertiesSet();
}
public InternalUsernamePasswordAuthenticationFilter(
AuthenticationManager customProviderManager,
SecurityContextRepository delegatingSecurityContextRepository,
AuthenticationFailureHandler authenticationFailureHandler,
AuthenticationSuccessHandler authenticationSuccessHandler) {
this.securityContextRepository = delegatingSecurityContextRepository;
this.authenticationFailureHandler = authenticationFailureHandler;
this.authenticationSuccessHandler = authenticationSuccessHandler;
super.setAuthenticationManager(customProviderManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//....
}
}
What I want to do now is testing the authentication logic. But instead of using the authentication providers of the application, I want to use a special UserDetailsManager for testing only. The current TestConfiguration class containing a TestUserDetailsManager looks like that:
#TestConfiguration
public class TestUserDetailsManagerConfig {
#Bean
#Primary
public UserDetailsManager testUserDetailsManager() {
User.UserBuilder users = User.builder();
UserDetails testUser = users
.username("test-user#example.com")
.password("test-user")
.roles("USER")
.build();
UserDetails testAdmin = users
.username("test-admin#example.com")
.password("test-admin")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(testUser, testAdmin);
}
}
And finally, a test method that should authenticate against the TestUserDetailsManager:
#SpringBootTest
#Import(TestUserDetailsManagerConfig.class)
public class InternalAuthenticationTest {
#Autowired WebApplicationContext context;
MockMvc mvc;
#BeforeEach
void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
void form_login_redirects_role_admin_to_page_admin_after_authentication() throws Exception {
MvcResult result = mvc
.perform(SecurityMockMvcRequestBuilders
.formLogin()
.loginProcessingUrl("/authenticate")
.user("identifier", "test-admin#example.com")
.password("password", "test-admin"))
.andExpect(MockMvcResultMatchers.redirectedUrl(AUTH_LOGIN_SUCCESS_ADMIN_REDIRECT_URL))
.andExpect(SecurityMockMvcResultMatchers.authenticated()
.withUsername("test-admin#example.com").withRoles("ADMIN")
.withAuthentication(auth -> assertThat(auth).isInstanceOf(UsernamePasswordAuthenticationToken.class)))
.andReturn();
}
}
My naive approach unfortunately does not work, and as the log shows, the authentication checks are done against the application provider, but not against the TestUserDetailsManager:
Invoking InternalUsernamePasswordAuthenticationFilter (7/12)
Authenticating request with InternalAuthenticationProvider (1/2)
Failed to find user credential for email 'test-admin#example.com'
Authenticating request with $Proxy157 (2/2)
Failed to find user 'test-admin#example.com'
Failed to process authentication request
-> Bad credentials
My question now:
How can I inject the TestUserDetailsManager into the CustomProviderManager so that the authentication (not authorization) tests work with special test users?
edit:
The question somewhat more generally:
How can I test the authentication of a Spring Boot application using a special UserDetailsManager for test cases only?
Many thanks in advance

Can not get user info with Spring Security SAML WITHOUT Spring Boot

I´m working on SAML integration in an older project but I can´t get the user information.
I've guided me with the response of this question:
https://stackoverflow.com/questions/70275050/spring-security-saml-identity-metadata-without-spring-boot
The project has these versions:
spring framework 5.3.24
spring security 5.6.10
opensaml 3.4.6
This is my code:
#Configuration
public class SAMLSecurityConfig {
private static final String URL_METADATA = "https://auth-dev.mycompany.com/app/id/sso/saml/metadata";
#Bean("samlRegistration")
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(URL_METADATA)
.registrationId("id")
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
}
#EnableWebSecurity
public class WebSecurity {
#Configuration
#Order(2)
public static class SAMLSecurityFilter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.saml2Login(Customizer.withDefaults())
.antMatcher("/login/assertion")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
}
#Controller("loginController")
public class BoCRLoginController {
#RequestMapping(value = "/login/assertion", method = {RequestMethod.POST},
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<String> assertLoginData(#AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
System.out.println(principal); //here I get a null
return new ResponseEntity<>(HttpStatus.OK);
}
}
Once I did the login on okta the class: Saml2AuthenticatedPrincipal comes null value.
Could you help me to know why I received null value on the object Saml2AuthenticatedPrincipal where suppose have to receive the user information?

Customise user login behaviour in OAuth based B2B multi tenant Spring Boot application using Spring Security

I am working on a Spring Boot application, which has two tenants as of now: tenant1 and tenant2 (in the future, I will add more tenants). Each of the tenants has its own authentication providers.
In order to achieve the same, as of now, I have made the following changes in my application:
config changes are as follows:
spring.security.oauth2.client.registration.tenant1.client-id=abcd
spring.security.oauth2.client.registration.tenant1.client-authentication-method=basic
spring.security.oauth2.client.registration.tenant1.authorization-grant-type=authorization_code
myapp.oauth2.path=https://external.authorization.server/services/oauth2/
spring.security.oauth2.client.provider.tenant1.token-uri=${myapp.oauth2.path}token
spring.security.oauth2.client.provider.tenant1.authorization-uri=${myapp.oauth2.path}authorize
spring.security.oauth2.client.provider.tenant1.user-info-uri=${myapp.oauth2.path}userinfo
spring.security.oauth2.client.provider.tenant1.user-name-attribute=name
spring.security.oauth2.client.registration.tenant2.client-id=efgh
spring.security.oauth2.client.registration.tenant2.client-secret=secret
spring.security.oauth2.client.registration.tenant2.client-authentication-method=basic
spring.security.oauth2.client.registration.tenant2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.tenant2.token-uri=${myapp.oauth2.path}token
spring.security.oauth2.client.provider.tenant2.authorization-uri=${myapp.oauth2.path}authorize
spring.security.oauth2.client.provider.tenant2.user-info-uri=${myapp.oauth2.path}userinfo
spring.security.oauth2.client.provider.tenant2.user-name-attribute=name
As of now, I am fetching client secrets for both tenants from Vault, so I had to define the OAuth2 configuration as follows:
#EnableConfigurationProperties(OAuth2ClientProperties.class)
#Conditional(ClientsConfiguredCondition.class)
#Configuration
public class OAuth2Configuration {
static final String OAUTH2_CLIENT_SECRET_KEY = "oauth2_client_secret";
private static final Logger log = LoggerFactory.getLogger(OAuth2Configuration.class);
private static final String OAUTH2_REGISTRATION_MISSING =
"oAuth2 registration properties are missing";
private final ApplicationSecretProvider applicationSecretProvider;
private final Map<String, ClientAuthenticationMethod> clientAuthenticationMethodMap =
new HashMap<>();
private final String authenticationMethod;
public OAuth2Configuration(
#Value("${spring.security.oauth2.client.registration.tenant1.client-authentication-method}")
final String authenticationMethod,
final ApplicationSecretProvider applicationSecretProvider) {
this.authenticationMethod = authenticationMethod;
this.applicationSecretProvider = applicationSecretProvider;
this.clientAuthenticationMethodMap
.put(ClientAuthenticationMethod.POST.getValue(), ClientAuthenticationMethod.POST);
this.clientAuthenticationMethodMap
.put(ClientAuthenticationMethod.BASIC.getValue(), ClientAuthenticationMethod.BASIC);
this.clientAuthenticationMethodMap
.put(ClientAuthenticationMethod.NONE.getValue(), ClientAuthenticationMethod.NONE);
}
#Bean
public InMemoryClientRegistrationRepository getClientRegistrationRepository(
OAuth2ClientProperties properties) {
List<ClientRegistration> registrations = new ArrayList<>(
OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties).values());
//We will have only one client registered for oAuth
if (CollectionUtils.isEmpty(registrations)) {
log.error(OAUTH2_REGISTRATION_MISSING);
throw new IllegalStateException(OAUTH2_REGISTRATION_MISSING);
}
ClientRegistration registration = registrations.get(0);
ClientRegistration.Builder builder = ClientRegistration.withClientRegistration(registration);
ClientAuthenticationMethod clientAuthenticationMethod =
getClientAuthenticationMethod(authenticationMethod);
ClientRegistration completeRegistration = builder
.clientSecret(applicationSecretProvider.getSecretForKey(OAUTH2_CLIENT_SECRET_KEY))
.clientAuthenticationMethod(clientAuthenticationMethod)
.build();
ClientRegistration testRegistration = registrations.get(1);
return new InMemoryClientRegistrationRepository(List.of(completeRegistration, testRegistration));
}
protected ClientAuthenticationMethod getClientAuthenticationMethod(String grantType) {
ClientAuthenticationMethod retValue = clientAuthenticationMethodMap.get(grantType);
if (retValue == null) {
return ClientAuthenticationMethod.NONE;
}
return retValue;
}
}
Then I extended DefaultOAuth2UserService in order to save user details in my application as follows:
#Component
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private UserRepository userRepository;
private AuthorityRepository authRepository;
#Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Autowired
public void setAuthorityRepository(AuthorityRepository
authorityRepository) {
this.authorityRepository = authorityRepository;
}
#Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) {
DefaultOAuth2User oAuth2User = (DefaultOAuth2User) super.loadUser(userRequest);
Collection<GrantedAuthority> authorities = new HashSet<>(oAuth2User.getAuthorities());
Map<String, Object> attributes = oAuth2User.getAttributes();
...
return new DefaultOAuth2User(authorities, oAuth2User.getAttributes(), userNameAttributeName);
}
}
Security configuration is as follows:
#EnableWebSecurity
#Import(SecurityProblemSupport.class)
#ConditionalOnProperty(
value = "myapp.authentication.type",
havingValue = "oauth",
matchIfMissing = true
)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customoAuth2UserService;
public SecurityConfiguration(CustomOAuth2UserService customoAuth2UserService) {
this.customoAuth2UserService = customoAuth2UserService;
}
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.authorizeRequests()
.antMatchers("/login**").permitAll()
.antMatchers("/manage/**").permitAll()
.antMatchers("/api/auth-info").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll()
.antMatchers("/management/prometheus").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.anyRequest().authenticated()
//.and().oauth2ResourceServer().jwt()
.and()
//.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/oauth2**")
.and()
.failureUrl("/api/redirectToHome")
.userInfoEndpoint().userService(customoAuth2UserService);
http.cors().disable();
}
}
With this on /login page, users from both the tenants are able to see both the login links.
I have following question in this regard:
(1) Instead of showing multiple links on the login page, would like to have a common entry page for all users, where users can enter the email and based on tenant id (derived from email), user can be redirected to the appropriate authentication provider and post successful authentication, authenticated user details can be saved in application database as done in CustomOAuth2UserService. How would I achieve this?
In this regard, I have gone through several articles/posts but did not get any concrete idea regarding what changes should I do in the existing code base to achieve this.

Spring Boot app requires a bean annotated with #Primary to start

I'm seeing the following message on a Spring Boot app startup:
> *************************** APPLICATION FAILED TO START
> ***************************
>
> Description:
>
> Field oauthProps in com.example.authservice.AuthorizationServerConfig
> required a single bean, but 2 were found:
> - OAuthProperties: defined in file [/Users/simeonleyzerzon/abc/spring-security/spring-security-5-oauth-client/auth-service/target/classes/com/example/authservice/config/OAuthProperties.class]
> - kai-com.example.authservice.config.OAuthProperties: defined in null
>
>
> Action:
>
> Consider marking one of the beans as #Primary, updating the consumer
> to accept multiple beans, or using #Qualifier to identify the bean
> that should be consumed
I'm wondering what's causing the duplication of that bean and how one can remove it without the necessity of using the #Primary annotation? Not sure where the kai-com package(?) from the above is coming from.
Here's the bean in question:
package com.example.authservice.config;
//#Primary
#Component
#ConfigurationProperties(prefix="kai")
#Setter #Getter
public class OAuthProperties {
private String[] redirectUris;
private String clientId;
private String clientSecret;
private final Token token = new Token();
#Setter #Getter
public static class Token{
private String value;
private String type="";
}
}
and the app/config, etc.:
package com.example.authservice;
import ...
#SpringBootApplication
public class AuthServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServiceApplication.class, args);
}
}
#Controller
class MainController {
#GetMapping("/")
String index() {
return "index";
}
}
#RestController
class ProfileRestController {
#GetMapping("/resources/userinfo")
Map<String, String> profile(Principal principal) {
return Collections.singletonMap("name", principal.getName());
}
}
#Configuration
#EnableResourceServer
class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/resources/**")
.authorizeRequests()
.mvcMatchers("/resources/userinfo").access("#oauth2.hasScope('profile')");
}
}
#Configuration
#EnableAuthorizationServer
#EnableConfigurationProperties(OAuthProperties.class)
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired private OAuthProperties oauthProps;
private final AuthenticationManager authenticationManager;
AuthorizationServerConfig(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(oauthProps.getClientId())
.secret(oauthProps.getClientSecret())
.authorizedGrantTypes("authorization_code")
.scopes("profile")
.redirectUris(oauthProps.getRedirectUris());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(this.authenticationManager);
if (oauthProps.getToken().getType().equals("jwt")) {
endpoints.tokenStore(this.tokenStore()).accessTokenConverter(jwtAccessTokenConverter());
}else {
endpoints.tokenEnhancer(eapiTokenEnhancer());
}
}
TokenEnhancer eapiTokenEnhancer() {
return new TokenEnhancer() {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
result.setValue(oauthProps.getToken().getValue());
return result;
}
};
}
#Bean
JwtAccessTokenConverter jwtAccessTokenConverter() {
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource(".keystore-oauth2-demo"), //keystore
"admin1234".toCharArray()); //storepass
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setKeyPair(factory.getKeyPair("oauth2-demo-key")); //alias
return jwtAccessTokenConverter;
}
#Bean
TokenStore tokenStore() {
return new JwtTokenStore(this.jwtAccessTokenConverter());
}
}
#Service
class SimpleUserDetailsService implements UserDetailsService {
private final Map<String, UserDetails> users = new ConcurrentHashMap<>();
SimpleUserDetailsService() {
Arrays.asList("josh", "rob", "joe")
.forEach(username -> this.users.putIfAbsent(
username, new User(username, "pw", true, true, true, true, AuthorityUtils.createAuthorityList("USER","ACTUATOR"))));
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return this.users.get(username);
}
}
#Configuration
#EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
Eclipse too seems to be only aware of a single instance of the bean:
When using #EnableConfigurationProperties with #ConfigurationProperties you will get a bean named <prefix>-<fqn>, the kai-com.example.authservice.config.OAuthProperties. (See also the reference guide).
When the #ConfigurationProperties bean is registered that way, the bean has a conventional name: <prefix>-<fqn>, where <prefix> is the environment key prefix specified in the #ConfigurationProperties annotation and <fqn> is the fully qualified name of the bean. If the annotation does not provide any prefix, only the fully qualified name of the bean is used.
The bean name in the example above is acme-com.example.AcmeProperties. (From the Reference Guide).
The #Component will lead to another registration of the bean with the regular name of the classname with a lowercase character. The other instance of your properties.
the #EnableConfigurationProperties annotation is also automatically applied to your project so that any existing bean annotated with #ConfigurationProperties is configured from the Environment. You could shortcut MyConfiguration by making sure AcmeProperties is already a bean, as shown in the following example: (From the Reference Guide).
The key here is that #EnableConfigurationProperties is already globally applied and processes any bean annotated with #ConfigurationProperties.
So basically you where mixing the 2 ways of using #ConfigurationProperties and Spring Boot 2 now prevents that misuse. This way you write better code (and reduce the memory footprint and performance slightly).
So either remove the #Component or remove the #EnableConfigurationProperties, either way will work.
The following change (removing of #EnableConfigurationProperties) seems to help relieving the need for the #Primary annotation:
#Configuration
#EnableAuthorizationServer
//#EnableConfigurationProperties(OAuthProperties.class)
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired private OAuthProperties oauthProps;
Perhaps someone can describe the internal Spring mechanics of secondary bean creation (and its namespace/package assignment) by that annotation which seemingly causes the collision with the #Autowired one, or point me to the appropriate documentation of this behavior.

PreAuthorize not getting honored over ResourceServerConfigurerAdaptor

I have a Spring Resource Server with Spring Security enabled. In Resource Server, i am extending the ResourceServerConfigurerAdaptor, some like the following.
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable().requestMatcher(new OAuthRequestedMatcher()).authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/admin/**").hasAnyRole("ADMIN")
.anyRequest().authenticated();
}
private static class OAuthRequestedMatcher implements RequestMatcher {
public boolean matches(HttpServletRequest request) {
String auth = request.getHeader("Authorization");
boolean haveOauth2Token = (auth != null) && auth.toLowerCase().startsWith("bearer");
boolean haveAccessToken = request.getParameter("access_token") != null;
return haveOauth2Token || haveAccessToken;
}
}
}
Here i am expecting /api/admin/** to be accessible to ADMIN Role only.
Everything works fine till now.
But now i am trying to override this behavior at the method level using #PreAuthorize method level annotation.
Following is the RestController
#RestController
#RequestMapping("/api/admin/event")
public class ShunyaEventResource {
#Autowired
private ShunyaEventService eventService;
#PreAuthorize("hasRole('ADMIN') or #oauth2.hasScope('write')")
#PostMapping
public void createEvent(#RequestBody ShunyaEvent event, Principal user) {
eventService.create(event);
}
}
So, i want to allow /api/admin/event to be accessible to #oauth2 write scope as well. But this does not work, unless either i remove /api/admin/** from antmatcher altogether or i add #oauth2.hasScope('write') in antmatcher itself.
I have already defined the below configuration
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
Here my question is why Method Level security not working for an endpoint that is already covered by ResourceServerConfigurerAdapter? What is precedence of security filter when same endpoint is covered by MethodLevel Security (using PreAuthorize) and HttpSecurity antMatcher?
Really appreciate any help on this.

Resources