Spring OAuth2 - how to use the /oauth/authenticate endpoint? - spring

So...I'm struggling to implement an authorization server with using Spring Boot OAuth2. For now I get a 403 response on:
GET oauth/authorize?username=demo&password=demo&client_id=demo&response_type=token
For the love of god, is the request okay? I would like to call this endpoint from a browser application and it should return an access_token and a refresh_token. Why do I need to provide a client_id for this? I'm on the edge of a mental breakdown because of this. How are you supposed to send a request to this endpoint?
The response is:
{
"timestamp": "2019-09-15T05:03:17.206+0000",
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/oauth/authorize"
}
Edit:
My simplified question would be this: Is there an endpoint that comes with #EnableAuthorizationServer, and it works as I am imagining it? You provide a username and a password, and it returns an access_token and a refresh_token.

The answer is yes the endpoint is POST /oauth/token
With parameters :
username -> YOUR_USERNAME
password -> YOUR_PASSWORD
grant_type -> password
The clientId and the secret must be send in the Authorization header.

ClientId is just for user to accessing the server. so first create a server and then try to create client:
in server add this code:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("ClientId")
.secret("secret")
.authorizedGrantTypes("authorization_code")
.scopes("user_info")
.autoApprove(true);
}
Client : add you client id properly in spring property what you have kept in server

Related

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

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

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!

Authentication of users by authenticationProvider from spring security through ReST API Call

I am now exploring that authentication of users in microservice. For that I am created my authentication service - checkUserAuthentication. Also providing Microservice also. this is already deployed in cloud.
Now I am creating new service with specific business logic. In this service , need to authenticate and check authorization of user to access this end-point by using authenticationProvider from spring security.
For this I am reading and exploring the following tutorials,
https://dzone.com/articles/spring-security-custom
http://roshanonjava.blogspot.in/2017/04/spring-security-custom-authentication.html
http://javasampleapproach.com/spring-framework/spring-security/spring-security-customize-authentication-provider
http://www.baeldung.com/spring-security-authentication-provider
In here they are implements AuthenticationProvider in class CustomAuthenticationProvider.
and in method they are receiving username and password is like following,
public Authentication authenticate(Authentication authentication) throws
AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
Optional<User> optionalUser = users.stream().filter(u -> u.index(name,
password)).findFirst();
if (!optionalUser.isPresent()) {
logger.error("Authentication failed for user = " + name);
throw new BadCredentialsException("Authentication failed for user = " + name);
}
// find out the exited users
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new SimpleGrantedAuthority(optionalUser.get().role));
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(name, password,
grantedAuthorities);
logger.info("Succesful Authentication with user = " + name);
return auth;
}
These are codes from documentation. Instead of this method, I need to do in different way. Here I am adding my requirements:
My requirement: I need to receive username and password from API Request.And For checking this username and password, I need to call my deployed APIs checkUserAuthentication and checkUserAuthorization.
My doubts on this:
Can I directly call these API within "public Authentication authenticate(Authentication authentication)" method ?
How I receive username and password from the received request ?
Why we are using UsernamePasswordAuthenticationToken ? , If we are sending JWT token instead of username and password, then which class will use for providing reply?
Since I only started with Spring Security, I am new to security world.
Can I directly call these API within "public Authentication authenticate(Authentication authentication)" method ?
Yes.
How I receive username and password from the received request ?
Same as they are doing in authenticate method.
Why we are using UsernamePasswordAuthenticationToken ? , If we are sending JWT token instead of username and passowrd, then which class
will use for providing reply?
UsernamePasswordAuthenticationToken is used internally by spring security. This
comes into the picture when you create a session in spring. it contains the user information (eg. email etc.) and authorities (role).For example, when you receive a JWT token in your application, you will validate the JWT token (signature etc. ) and upon successfull validation of JWT, you will create an object of UsernamePasswordAuthenticationToken and spring will save it in session. For each incoming request, spring will call boolean isAuthenticated() method on this object to find if user can access the required resource.
Now when you have got all your answers, my recommendation is to go with Oauth2 for your boot microservices. there are plenty of example how to implement it and customize it for your requirement. (Basically, you have to implement your Authorization server which will authenticate the user with your service checkUserAuthentication and generate the accesstoken. Each consumer of your microservice needs to send this accesstoken which they have got from Authorization server and you need to validate it in your microservice. So your microservice will act as Resource Server).
Hope it will help.

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

ASP.NET Web API Authentication and Validation

I use ASP.NET Web API and use Authentication by reference to http://stevescodingblog.co.uk/basic-authentication-with-asp-net-webapi/
It works well.If the request which has not Authorization header, response HttpStatusCode is "Unauthorized".
But when some json data send from clientside which has some incorrect column, response HttpStatusCode is "Internal Server Error" though the request has not Authorization header.
[BasicAuthentication]
public HttpResponseMessage Create(Customer customer)
{
//
}
public class Customer{
public int id{set;get;}
public string name{set;get;}
}
For example, send POST method to /Create, Content-Type is application/json, and Request Body { "id": "abc", "name": "someone" }(id is wrong:not int but string) and don't have Authorization header. Response HttpStatusCode is "Internal Server Error" not "Unauthorized".
Maybe creating customer instance is earlier than Authorization. Do you know to change Authorization first?
If you've created your BasicAuthenthication attribute as an ActionFilterAttribute, you can try changing it to a AuthorizationFilterAttribute. OnActionExecuting will then change to OnAuthorization. I think most of the rest of it should be fairly similar.

Resources