An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 406 Not Acceptable - spring

I am trying use spirng-oauth2-client to connect my project with a third-party authentication server (following this instruction), ans right now when I run the application, after the authorization step, I am redirect back for my application, and a page with this error is displayed:
[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 406 Not Acceptable: [Media is not supported]
In the comments for an answer in another Stack Overflow post, someone suggested that this is happening because "Spring makes the POST for the authenntication code with FORM parameters, whereas mercadolibre expects no body, only query parameters".
I have this configuration right now:
application.properties
spring.security.oauth2.client.registration.mercadolivre.provider=mercadolivre
spring.security.oauth2.client.registration.mercadolivre.client-id=...
spring.security.oauth2.client.registration.mercadolivre.client-secret=...
spring.security.oauth2.client.registration.mercadolivre.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.mercadolivre.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.provider.mercadolivre.authorization-uri=https://auth.mercadolivre.com.br/authorization
spring.security.oauth2.client.provider.mercadolivre.token-uri=https://api.mercadolibre.com/oauth/token
security.java
#Configuration
public class Security extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.defaultSuccessUrl("/");
}
}
Anyone knows how to change the Spring behavior to match th required for the service? I mean, making the POST for the authenntication code with no body, only query parameters?

For me the error was [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized
The issue was an expired/outdated Client Id and Secret. (I used the Client Id and Secret before and it worked)

This error relates to the response you get from the authentication server, either during client authentication or during fetching of the user-info. We can force the method for both requests to be BASIC instead of POST with these properties
spring.security.oauth2.client.registration.mercadolivre.client-authentication-method=BASIC
spring.security.oauth2.client.provider.mercadolivre.user-info-authentication-method=BASIC

In you controller tha you is redirected for, try to put consumes Json like this:
#GetMapping(value = "", consumes = MediaType.APPLICATION_JSON_VALUE)
public String indexPage() {
.
.
}
Or MediaType.ALL_VALUE

Related

401 on .permitAll() request in Spring Security

I have specified .permitAll() on the endpoint "/api/v2/user/login/**" but it still gives 401 when I don't give any authentication details in postman.
In fact, it's showing abnormal behaviour, below are my observations.
Gives 200 for any correct user details (regardless of role).
If I make a request with correct user details, it gives 200. If just after that request I do another request with incorrect password, it still gives 200. But incorrect username isn't tolerated.
Once it gives 401, it will keep giving 401 for all requests until I enter correct credentials.
CSRF is disabled so that shouldn't be an issue. I have tried playing with the order of permitAll request but that hasn't worked yet. Checkout the last antMatchers.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().
authorizeRequests().
antMatchers(HttpMethod.POST, "/api/v2/user/", "/api/v2/user", "/api/v2/user/change-role/**").hasAuthority("ROOT").
antMatchers(HttpMethod.GET, "/api/v2/user/", "/api/v2/user").hasAuthority("ROOT").
antMatchers(HttpMethod.POST, "/api/v1/customers/", "/api/v1/customers").hasAnyAuthority("ADMIN", "ROOT").
antMatchers(HttpMethod.GET, "/api/v1/customers/", "/api/v1/customers").hasAnyAuthority("EMPLOYEE", "ADMIN", "ROOT").
antMatchers(HttpMethod.POST, "/api/v2/user/login/**").permitAll().
anyRequest().
authenticated().
and().
httpBasic();
}
And here's the relevant controller method.
#RequestMapping(value = "/user/login", method = RequestMethod.POST)
public ResponseEntity<Boolean> loginUser(#RequestParam String username, #RequestParam String password){
return myUsersService.loginUser(username, password);
}
Any ideas are appreciated. Thanks!
Put antMatchers with permitAll first in the chain and remove /** to match the actual path you want to permit without auth.

Request body is empty when no authentication is present for secure APIs

I am trying to log the request body on all requests in a spring boot reactive application secured with spring security. But I am running into an issue where the request body is logged only if the basic auth header is present (even if the username and password are invalid). But if no auth header is present the request body does not get logged. I am unsure what I am missing and would like to find out how I maybe able to get access to the request body for cases where there is no authentication header present.
The request body logging is done using an authentication entry point set on HttpBasicSpec. The security configuration looks as follows:
#Configuration
#EnableWebFluxSecurity
class SecurityConfiguration {
private val logger = LoggerFactory.getLogger(this::class.java)
#Bean
fun securityConfigurationBean(http: ServerHttpSecurity) =
http.csrf().disable()
.cors().disable()
.httpBasic()
.authenticationEntryPoint { exchange, _ ->
exchange.request.body
.subscribe { logger.info(CharsetUtil.UTF_8.decode(it.asByteBuffer()).toString()) }
.let { Mono.error(HttpServerErrorException(HttpStatus.UNAUTHORIZED)) }
}.and().authorizeExchange().anyExchange().authenticated().and().build()
}
There is a test router config that has a one route:
#Configuration
class TestRouterConfig {
#Bean
fun testRoutes() =
router {
POST("/test") {
ServerResponse.ok().bodyValue("This is a test route")
}
}
}
When I make a request to http:localhost:8080/test with a request body of
{"sample": "sample"}
with an invalid username and password in the basic auth header, I see the following in the console:
2019-12-06 11:51:18.175 INFO 11406 --- [ctor-http-nio-2] uration$$EnhancerBySpringCGLIB$$5b5f0067 : {"sample": "sample"}
But when I remove authentication all together I don't see the above logging statement for the same endpoint (I am using a rest client to make these calls).
The versions of tools/frameworks/languages:
Kotlin: 1.3.50
Spring boot: 2.2.1
Java: 12
Gradle: 5.6.4
Spring dependency management: 1.0.8.RELEASE
I would like to be able to log the request body for all requests that result in an authentication failure including the absence of an authentication header and would appreciate any help in this regard. My apologies if this has been discussed/posted elsewhere.
Thank you!

Handle 403-error in Spring

I want to handle 403 error to show normal message:
#ExceptionHandler(AccessDeniedException.class)
#ResponseBody
public String accessDeniedException () {
return "my message";
}
But AccessDeniedException not handle 403 error.
Same not working follow:
#ResponseStatus(value = HttpStatus.FORBIDDEN)
#ExceptionHandler(SecurityException.class)
#ResponseBody
As I know, If an exception is not being thrown by the code called through your controller, you can't handle it by using #ExceptionHandler (or #ControllerAdvice). For example, exceptions thrown directly from Spring Security, like the CSRF exception, can't be caught this way.
This most likely is coming via Spring Security. If that's the case you need to setup and register an access-denied-handler.
Here is a detailed tutorial of how to do that.

unable to get Oauth2 token from auth server

I have an auth-server configured in spring with
clients
.inMemory()
.withClient("my-web-app")
.secret("my-web-app-secret")
.authorizedGrantTypes(//
"authorization_code",//
"refresh_token",//
"password"//
).scopes("openid")
Now I want to develop a command line application for the webapp. Hence I need to register one more client with a seperate client id and secret.
I have done something like this
.and()
.inMemory()
.withClient("my-cli")
.secret("my-cli-secret")
.authorizedGrantTypes("authorization_code","client_credentials")
.scopes("read","write","trust").authorities("ROLE_USER");
What I want to achieve is use simply provide the username/password and the client app should be able to get the auth token from the auth server.
What I have tried and understood is I should be using Resource Owner password Grant. I have to use the spring Oauth2restTemplate after this.
The problem in this configuration is when I m hitting the tokenuri i m getting
{
error: "unauthorized"
error_description: "Full authentication is required to access this resource"
}
and everytime it is hitting with the anonymous user.
If you want to user username/password for obtaining the access token you definitely need to use grant_type=password.
You also don't need to specify .inMemory() twice - just two clients with .and() between them.
So the configuration then have to be something like
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
// First client
.withClient("my-web-app")
.secret("my-web-app-secret")
.authorizedGrantTypes(//
"authorization_code",//
"refresh_token",//
"password"//
).scopes("openid")
// Second Client(CLI)
.and()
.withClient("my-cli")
.secret("my-cli-secret")
.authorizedGrantTypes("password")
.scopes("read", "write", "trust")
.authorities("ROLE_USER");
}
And other very important thing - you need to set the Authorization: header in the http request for the token. So the header should be
"Authorization: Basic " + Base64.encodeBase64String((clientId + ":" + clientSecret).getBytes())
This header is checked before the username\password and defines that the client(CLI in your case) is an authorized client (this can cause the error from your question).
That would be really good if you can add the code how exactly you use Oauth2RestTemplate

POST request to Spring REST web service fails with HTTP status 415

I have set up a spring RESTful web service for taking in the username and password from a user. Been following the tutorial on Spring IO
My service is set up to accept user name and password as shown below:
#Controller
#RequestMapping("/users")
public class UserCommandController {
private static Logger log = LoggerFactory.getLogger(UserCommandController.class);
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity createUser(#RequestBody UserDetail userDetail, UriComponentsBuilder builder) {
User newUser = new User();
newUser.setEmail(userDetail.getEmail());
newUser.setPassword(userDetail.getPassword());
newUser.setUserName(userDetail.getUsername());
try {
UserFactory.getInstance().saveNewUser(newUser);
} catch(UserException ue) {
log.error("Saving user failed. Exception: "+ue.getMessage());
}
return new ResponseEntity(HttpStatus.OK);
}
}
I am sending POST parameters to the service as a test through Google chrome plugin POSTMAN but I get "HTTP: 415..The server refused this request because the request entity is in a format not supported by the requested resource for the requested method."
Does anyone have an idea what I am doing wrong ?
Set the header:
Content-Type=application/json
This solved my problem!
The HTTP 415 response code means that the server expected data posted with a different content type. It appears you simply posted a form with username, password and email as parameters. That would result in a content-type of application/x-www-form-urlencoded.
Try posting with a content-type of application/xml or application/json. In your post body, you will need to put your data in the corresponding format. For example, if you use application.xml, the XML body should look something like:
<userDetail>
<userName>xxx</userName>
<password>xxx</password>
<email>xxx</email>
</userDatail>
Of course the exact format (i.e. element names) depends on the XML bindings. In fact, whether or not the expected format is XML or JSON or something else is also likely a server configuration.
Posting a request of this type cannot easily be done with a browser. You will need some other HTTP client. A tool like SOAP-UI might be a good bet.

Resources