I am writing application in spring boot 2.7.4 version which has new version of spring security. So I need to rewrite my old code to the new one.
Here is my old security configuration with WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
class AppWebConfig(
val customUserDetailsService: CustomUserDetailsService,
val passwordEncoder: PasswordEncoder,
val tokensService: TokensService
) : WebSecurityConfigurerAdapter() {
#Throws(Exception::class)
override fun configure(auth: AuthenticationManagerBuilder) {
auth
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder)
}
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.cors()
.and()
.csrf().disable()
.exceptionHandling()
//urls permissions...
.addFilter(AppAuthorizationFilter(authenticationManager(), tokensServicee))
}
}
And here is the new code
#Configuration
#EnableWebSecurity
class AppWebConfig(
val tokensService: TokensService,
) {
#Bean
#Throws(Exception::class)
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? {
return authenticationConfiguration.authenticationManager
}
#Bean
#Throws(Exception::class)
protected fun fitlerChain(http: HttpSecurity): SecurityFilterChain {
val authenticationManager = http.getSharedObject(AuthenticationManager::class.java)
return http
.cors()
.and()
.csrf().disable()
//urls permissions...
.addFilter(AppAuthorizationFilter(authenticationManager, tokensService))
.build()
}
Here is the AppAuthorizationFilter which hasn't changed in both versions and where the authenticationManager is used:
class AppAuthorizationFilter(
authenticationManager: AuthenticationManager,
tokensService: TokensService,
) : BasicAuthenticationFilter(authenticationManager) {
private val tokensService: TokensService
init { this.tokensService = tokensService }
#Throws(IOException::class, ServletException::class)
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
chain: FilterChain,
) {
val header = request.getHeader(Objects.requireNonNull(HttpHeaders.AUTHORIZATION))
if (header != null) {
val authorizedUser = tokensService.parseAccessToken(header)
SecurityContextHolder.getContext().authentication = authorizedUser
}
chain.doFilter(request, response)
}
}
And the problem is with authenticationManager from AppWebConfig. I get the error that this its null.
Caused by: java.lang.NullPointerException: authenticationManager must not be null at com.app.security.config.WebConfig.fitlerChain(WebConfig.kt:68)
I tried the solution I showed above by getting authenticationManager from shared objects http.getSharedObject(AuthenticationManager::class.java) but it does not work as you can see.
I solved the problem by getting authenticationManager from WebApplicationContext but I am not sure if it is the best way to do it
val authenticationManager = applicationContext.getBean("authenticationManager") as AuthenticationManager
Try to add this annotation (#Primary) to you authenticationManager bean. If didn't work, then go with the solution you mentioned.
#Bean
#Primary // try to add this
#Throws(Exception::class)
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? {
return authenticationConfiguration.authenticationManager
}
Please access the authentication manager once you build it or after it builds.
public SecurityFilterChain securityFilterChain(HttpSecurity http, ResourceProtectAware protectAware) throws Exception {
protectAware.addUrlAuthorization(http);
http.cors();
http.httpBasic().authenticationEntryPoint(entryPoint());
// http.addFilterBefore(spnegoAuthenticationFilter(configuration.getAuthenticationManager()), BasicAuthenticationFilter.class);
DefaultSecurityFilterChain build = http.build();
//access it after you build.
AuthenticationManager sharedObject = http.getSharedObject(AuthenticationManager.class);
return build;
}
Related
I have custom authentication provider that works fine:
#Component
public class ApiAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
final String name = authentication.getName();
final String password = authentication.getCredentials().toString();
if (isAuthorizedDevice(name, password)) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority(ApiInfo.Role.User));
final UserDetails principal = new User(name, password, grantedAuths);
return new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
} else {
return null;
}
}
But it always return 401. I would like to change it in some cases to 429 for brute force mechanism. Instead of returning null I would like to return error: f.e.: 429. I think It should not be done here. It should be done in configuration: WebSecurityConfig but I have no clue how to achieve this.
I tried already throwing exceptions like:
throw new LockedException("InvalidCredentialsFilter");
throw new AuthenticationCredentialsNotFoundException("Invalid Credentials!");
or injecting respone object and setting there status:
response.setStatus(429);
But non of it worked. It always return 401.
F.e.:
curl http://localhost:8080/api/v1.0/time --header "Authorization: Basic poaueiccrmpoawklerpo0i"
{"timestamp":"2022-08-12T20:58:42.236+00:00","status":401,"error":"Unauthorized","path":"/api/v1.0/time"}%
And body:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Aug 12 22:58:17 CEST 2022
There was an unexpected error (type=Unauthorized, status=401).
Also could not find any docs or Baeldung tutorial for that.
Can You help me?
P.S My WebSecurityConfig:
#Configuration
#EnableWebSecurity
class WebSecurityConfig {
AuthenticationProvider apiAuthenticationProvider;
#Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.formLogin().disable()
.httpBasic().and()
.authenticationProvider(apiAuthenticationProvider)
.authorizeRequests()
.antMatchers(ApiInfo.BASE_URL + "/**")
.fullyAuthenticated()
.and()
.build();
}
As I did not useful answer I will post my solution.
Generally I've added custom implementation of AuthenticationEntryPoint, which handles all unauthorized request and it is proceeded after AuthenticationProvider:
#Component
public class BruteForceEntryPoint implements AuthenticationEntryPoint {
final BruteForce bruteForce;
static final String WWW_AUTHENTICATE_HEADER_VALUE = "Basic realm=\"Access to API\", charset=\"UTF-8\"";
public BruteForceEntryPoint(BruteForce bruteForce) {
this.bruteForce = bruteForce;
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
addWwwAuthenticateHeader(request, response);
bruteForce.incrementFailures(request.getRemoteAddr());
if (bruteForce.IsBlocked(request.getRemoteAddr())) {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
OutputStream responseStream = response.getOutputStream();
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(responseStream, HttpStatus.TOO_MANY_REQUESTS);
responseStream.flush();
} else {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
OutputStream responseStream = response.getOutputStream();
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(responseStream, HttpStatus.UNAUTHORIZED);
responseStream.flush();
}
}
void addWwwAuthenticateHeader(HttpServletRequest request, HttpServletResponse response) {
if (isWwwAuthenticateSupported(request)) {
response.addHeader(WWW_AUTHENTICATE, WWW_AUTHENTICATE_HEADER_VALUE);
}
}
}
Config:
#Configuration
class WebSecurityConfig {
AuthenticationProvider apiAuthenticationProvider;
AuthenticationEntryPoint customAuthenticationEntryPoint;
public WebSecurityConfig(AuthenticationProvider apiAuthenticationProvider, AuthenticationEntryPoint customAuthenticationEntryPoint) {
this.apiAuthenticationProvider = apiAuthenticationProvider;
this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
}
#Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
return
http
.httpBasic()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers(AapiInfo.BASE_URL + "/**").authenticated()
.and()
.authenticationProvider(apiAuthenticationProvider)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.formLogin().disable()
.logout().disable()
.build();
}
I use the following security configuration for authorization. I now want to add token secured endpoints to this project.
However, whenever I send a request to the secured endpoint I always find myself redirected to the login-page ("/oauth_login") as if I were unauthorized.
What am I doing wrong here? I tried to debug this and it seems the overriden decode() function of my accessTokenConverter is never called when I try to access the endpoint with a valid token.
This is the security config I already have:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#PropertySource("application.properties")
#Order(1)
class SecurityConfig(
private val userDetailsService: CustomUserDetailsService,
private val inMemoryClientRegistrationRepository: InMemoryClientRegistrationRepository,
private val secretAuthenticationFilter: SecretAuthenticationFilter
) : WebSecurityConfigurerAdapter() {
#Bean
#Throws(Exception::class)
override fun authenticationManager() = super.authenticationManager()
#Throws(Exception::class)
override fun configure(auth: AuthenticationManagerBuilder?) {
auth!!.userDetailsService(userDetailsService)
.passwordEncoder(BCryptPasswordEncoder(10))
}
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http.addFilterAfter(secretAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)
http
.authorizeRequests()
.antMatchers("/oauth_login")
.permitAll()
.antMatchers("/accounts/password")
.permitAll()
.anyRequest()
.authenticated()
.permitAll()
.and()
.logout()
.logoutUrl("/logoutconfirm")
.logoutSuccessUrl("/oauth_login")
.invalidateHttpSession(true)
.and()
.oauth2Login().loginPage("/oauth_login")
.authorizationEndpoint()
.baseUri("/oauth2/authorize-client")
.authorizationRequestRepository(authorizationRequestRepository())
.authorizationRequestResolver(CustomAuthorizationRequestResolver(inMemoryClientRegistrationRepository, "/oauth2/authorize-client"))
.and()
.tokenEndpoint()
.accessTokenResponseClient(accessTokenResponseClient())
.and()
.defaultSuccessUrl("/loginSuccess")
.failureUrl("/loginFailure")
.addObjectPostProcessor(object : ObjectPostProcessor<Any> {
override fun <O : Any> postProcess(obj: O) = when (obj) {
is OAuth2LoginAuthenticationProvider -> CustomOAuth2LoginAuthenticationProvider(obj) as O
is LoginUrlAuthenticationEntryPoint -> customizeLoginUrlAuthenticationEntryPoint(obj) as O
else -> obj
}
})
}
This is the ResourceServerConfig I want to add:
#Configuration
#EnableResourceServer
#Order(2)
class ResourceServerConfig(
private val defaultTokenServices: DefaultTokenServices
) : ResourceServerConfigurerAdapter() {
override fun configure(config: ResourceServerSecurityConfigurer) {
config.tokenServices(tokenServices())
}
override fun configure(http: HttpSecurity) {
http.authorizeRequests().anyRequest().authenticated()
}
fun tokenStore() = JwtTokenStore(accessTokenConverter())
fun accessTokenConverter(): JwtAccessTokenConverter {
val converter = object : JwtAccessTokenConverter() {
override fun decode(token: String) = if (token.isCorrectJwtToken(token)) {
super.decode(token)
} else {
mapOf()
}
}
val keyStoreKeyFactory = KeyStoreKeyFactory(ClassPathResource("mykeys.jks"),
"mykeys".toCharArray())
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mykeys"))
return converter
}
fun tokenServices() = DefaultTokenServices().apply {
setTokenStore(tokenStore())
setSupportRefreshToken(true)
}
This is the secured endpoint I want to be able to access with a valid token:
#PreAuthorize("hasAuthority('ROLE_USER')")
#PostMapping("/accounts/password")
fun updatePassword(#RequestBody newPassword: JsonWrappedValue<String>): Boolean {
// Update password
}
I found a solution to my problem.
I merged all configs into a single file so the security config looks like that
#EnableAuthorizationServer
#EnableResourceServer
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#PropertySource("application.properties")
class SecurityConfig(
private val accountRepository: AccountRepository,
private val userDetailsService: CustomUserDetailsService,
private val inMemoryClientRegistrationRepository: InMemoryClientRegistrationRepository,
private val secretAuthenticationFilter: SecretAuthenticationFilter
) : AuthorizationServerConfigurer, ResourceServerConfigurer, WebSecurityConfigurerAdapter()
This made me able to finally reach my endpoint with a token but destroyed my social login.
Then I had to fix the configure(http: HttpSecurity) method as the ResourceServerConfig's default implementation sets the SessionCreationPolicy to SessionCreationPolicy.Never.
This caused my social login to get destroyed because the request parameters containing redirectUri and so on could not be restored. After adding
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
to configure(http: HTTPSecurity) the complete configuration works well.
I'm wondering where the issue is with my code, every time I run a post test (irrespective of what controller it targets, or method), I return a 403 error, when in some cases I expect a 401, and in others a 200 response (with auth).
This is a snippet from my controller:
#RestController
#CrossOrigin("*")
#RequestMapping("/user")
class UserController #Autowired constructor(val userRepository: UserRepository) {
#PostMapping("/create")
fun addUser(#RequestBody user: User): ResponseEntity<User> {
return ResponseEntity.ok(userRepository.save(user))
}
}
And my unit test targeting this controller
#RunWith(SpringRunner::class)
#WebMvcTest(UserController::class)
class UserControllerTests {
#Autowired
val mvc: MockMvc? = null
#MockBean
val repository: UserRepository? = null
val userCollection = mutableListOf<BioRiskUser>()
#Test
fun testAddUserNoAuth() {
val user = BioRiskUser(
0L,
"user",
"password",
mutableListOf(Role(
0L,
"administrator"
)))
repository!!
`when`(repository.save(user)).thenReturn(createUser(user))
mvc!!
mvc.perform(post("/create"))
.andExpect(status().isUnauthorized)
}
private fun createUser(user: BioRiskUser): BioRiskUser? {
user.id=userCollection.count().toLong()
userCollection.add(user)
return user
}
}
What am I missing?
As requested, my security config...
#Configuration
#EnableWebSecurity
class SecurityConfig(private val userRepository: UserRepository, private val userDetailsService: UserDetailsService) : WebSecurityConfigurerAdapter() {
#Bean
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
override fun configure(auth: AuthenticationManagerBuilder) {
auth.authenticationProvider(authProvider())
}
override fun configure(http: HttpSecurity) {
http
.csrf().disable()
.cors()
.and()
.httpBasic()
.realmName("App Realm")
.and()
.authorizeRequests()
.antMatchers("/img/*", "/error", "/favicon.ico", "/doc")
.anonymous()
.anyRequest().authenticated()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/user")
.permitAll()
}
#Bean
fun authProvider(): DaoAuthenticationProvider {
val authProvider = CustomAuthProvider(userRepository)
authProvider.setUserDetailsService(userDetailsService)
authProvider.setPasswordEncoder(encoder())
return authProvider
}
}
and the auth provider
class CustomAuthProvider constructor(val userRepository: UserRepository) : DaoAuthenticationProvider() {
override fun authenticate(authentication: Authentication?): Authentication {
authentication!!
val user = userRepository.findByUsername(authentication.name)
if (!user.isPresent) {
throw BadCredentialsException("Invalid username or password")
}
val result = super.authenticate(authentication)
return UsernamePasswordAuthenticationToken(user, result.credentials, result.authorities)
}
override fun supports(authentication: Class<*>?): Boolean {
return authentication?.equals(UsernamePasswordAuthenticationToken::class.java) ?: false
}
}
In my case, the csrf-Protection seems to be still active in my WebMvcTest (even if disabled in your configuration).
So to workaround this, I simply changed my WebMvcTest to something like:
#Test
public void testFoo() throws Exception {
MvcResult result = mvc.perform(
post("/foo").with(csrf()))
.andExpect(status().isOk())
.andReturn();
// ...
}
So the missing .with(csrf()) was the problem in my case.
You need to add #ContextConfiguration(classes=SecurityConfig.class) to the top of your UserControllerTests class after the #WebMvcTest(UserController::class) annotation.
Your problem comes from the CSRF, if you enable debug logging the problem will become obvious, and it comes from the fact that #WebMvcTest load only the web layer and not the whole context, your KeycloakWebSecurityConfigurerAdapter is not loaded.
The loaded config comes from org.springframework.boot.autoconfigure.security.servlet.DefaultConfigurerAdapter (= to org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter contains crsf().
As of today you have 3 options to resolve this:
Options 1
Create a WebSecurityConfigurerAdapter inside your test class.
The solution suits you if you have only few #WebMvcTest annotated class in your project.
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = {MyController.class})
public class MyControllerTest {
#TestConfiguration
static class DefaultConfigWithoutCsrf extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable();
}
}
...
}
Options 2
Create a WebSecurityConfigurerAdapter inside a superclass and make your test extend from it.
The solution suits you if you have multiple #WebMvcTest annotated class in your project.
#Import(WebMvcTestWithoutCsrf.DefaultConfigWithoutCsrf.class)
public interface WebMvcCsrfDisabler {
static class DefaultConfigWithoutCsrf extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable();
}
}
}
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = {MyControllerTest .class})
public class MyControllerTest implements WebMvcCsrfDisabler {
...
}
Options 3
Use the spring-security csrf SecurityMockMvcRequestPostProcessors.
This solution is bulky and prone to error, checking for permission denial and forgeting the with(csrf()) will result in false positive test.
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = {MyController.class})
public class MyControllerTest {
...
#Test
public void myTest() {
mvc.perform(post("/path")
.with(csrf()) // <=== THIS IS THE PART THAT FIX CSRF ISSUE
.content(...)
)
.andExpect(...);
}
}
Here's an issue:
override fun configure(http: HttpSecurity) {
http
.csrf().disable()
.cors()
.and()
.httpBasic()
.realmName("App Realm")
.and()
.authorizeRequests()
.antMatchers("/img/*", "/error", "/favicon.ico", "/doc")
.anonymous()
.anyRequest().authenticated()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/user")
.permitAll()
}
More particularly here:
.anyRequest().authenticated()
You're requiring for each request to be authenticated, therefore you get 403.
This tutorial explains well how to perform testing with mock user.
The easy way is to have something like this:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class SecuredControllerRestTemplateIntegrationTest {
#Autowired
private val template: TestRestTemplate
#Test
fun createUser(): Unit {
val result = template.withBasicAuth("username", "password")
.postForObject("/user/create", HttpEntity(User(...)), User.class)
assertEquals(HttpStatus.OK, result.getStatusCode())
}
}
I'm trying to follow this tutorial in order to get oauth working.
But when I try to make the below request
curl -X POST -d "client_id=client-id&client_secret=secret&grant_type=password&username=demo&password=1234" http://localhost:8080/oauth/token
I get the following error message
{"timestamp":"2018-01-25T14:47:42.286+0000","status":401,"error":"Unauthorized","message":"Unauthorized","path":"/oauth/token"}
My AuthorizationServerConfiguration looks like the following
#Configuration
#EnableAuthorizationServer
class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() {
#Autowired
private val tokenStore: TokenStore? = null
#Autowired
private val userApprovalHandler: UserApprovalHandler? = null
#Autowired
#Qualifier("authenticationManagerBean")
private val authenticationManager: AuthenticationManager? = null
#Throws(Exception::class)
override fun configure(clients: ClientDetailsServiceConfigurer?) {
clients!!.inMemory()
.withClient("client-id")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.secret("secret")
.accessTokenValiditySeconds(120)//Access token is only valid for 2 minutes.
.refreshTokenValiditySeconds(600)//Refresh token is only valid for 10 minutes.
}
#Throws(Exception::class)
override fun configure(endpoints: AuthorizationServerEndpointsConfigurer?) {
endpoints!!.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager)
}
#Throws(Exception::class)
override fun configure(oauthServer: AuthorizationServerSecurityConfigurer?) {
oauthServer!!.realm(REALM + "/client")
}
companion object {
private val REALM = "MY_OAUTH_REALM"
}
}
My ResourceServerConfiguration looks like the following
#Configuration
#EnableResourceServer
class ResourceServerConfiguration : ResourceServerConfigurerAdapter() {
override fun configure(resources: ResourceServerSecurityConfigurer?) {
resources!!.resourceId(RESOURCE_ID).stateless(false)
}
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.anonymous().disable()
.requestMatchers().antMatchers("/users/**")
.and().authorizeRequests()
.antMatchers("/users/**").access("hasRole('ADMIN')")
.and().exceptionHandling().accessDeniedHandler(OAuth2AccessDeniedHandler())
}
companion object {
private val RESOURCE_ID = "my_rest_api"
}
}
My OAuth2SecurityConfiguration looks like the following
#Configuration
#EnableWebSecurity
class OAuth2SecurityConfiguration : WebSecurityConfigurerAdapter() {
#Autowired
private val clientDetailsService: ClientDetailsService? = null
#Autowired
#Throws(Exception::class)
fun globalUserDetails(auth: AuthenticationManagerBuilder) {
auth.inMemoryAuthentication()
.withUser("bill").password("abc123").roles("ADMIN").and()
.withUser("demo").password("1234").roles("USER")
}
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
}
#Bean
#Throws(Exception::class)
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
#Bean
fun tokenStore(): TokenStore {
return InMemoryTokenStore()
}
#Bean
#Autowired
fun userApprovalHandler(tokenStore: TokenStore): TokenStoreUserApprovalHandler {
val handler = TokenStoreUserApprovalHandler()
handler.setTokenStore(tokenStore)
handler.setRequestFactory(DefaultOAuth2RequestFactory(clientDetailsService))
handler.setClientDetailsService(clientDetailsService)
return handler
}
#Bean
#Autowired
#Throws(Exception::class)
fun approvalStore(tokenStore: TokenStore): ApprovalStore {
val store = TokenApprovalStore()
store.setTokenStore(tokenStore)
return store
}
}
Any clue about what I'm doing wrong?
The request of token requires Basic Authentication.
Try to add the following option in your request:
-u "client-id:secret"
The request:
curl -X POST -u "client-id:secret" -d "client_id=client-id&client_secret=secret&grant_type=password&username=demo&password=1234" http://localhost:8080/oauth/token
create a simple spring security configuration on spring boot 2 m6
#Configuration
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class SecurityConfig {
#Bean
public ReactiveUserDetailsService userDetailsRepository() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("test")
.password("test")
.roles("USER")
.build();
return new MapReactiveUserDetailsService(user);
}
#Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
return http.csrf()
.disable()
.authorizeExchange()
.anyExchange().authenticated()
.and()
.httpBasic().and()
.build();
}
but when i try to get authentification object in handler request after authenfication i always get null
ReactiveSecurityContextHolder.getContext().block().getAuthentication()
and when i try to get login as
public Mono<ServerResponse> checkStatus(ServerRequest request) {
System.out.println(request.principal().block());
i also get null
where is the problem ?