Spring boot Oauth2 – Client

Connect an OAuth Client to a server using Spring OAuth2 library is a lightweight way to get information from third part where this protocol is available.
In this post I’ll show you how to make it using few configurations and code files.

Starting from my previous example (Spring boot Oauth2 with MongoDb e custom authentication) I wrote the client part of this solution in order to get the information from a remote resource.

As you’ll see, few lines of Java code and configuration are enough to make it work.
Having said that, the question could be: Why did you think that’s worth a dedicated post? Well, I think it’s worth because I’ve spent more time that I did figure to complete the solution and, above all, for the lack of good documentation of the client side.

Spring OAuth2 library is an extension of Spring Security Layer and there’s not official documentation excluding the Api docs. I think that missing discourages the user to adopt this library for their solution, thus, I think of having enough reasons for writing this article so, here we’re!

First of all, the configuration file:


security:
  sessions: always
  oauth2:

    client:

      # Client Id registered in the Server
      clientId: web-client

      # Client Secret registered in the Server
      clientSecret: web-client-secret

      # Url to get the token
      accessTokenUri: http://localhost:8081/oauth/token

      # Url to get the authorization code
      userAuthorizationUri: http://localhost:8081/oauth/authorize   

      # Scope of the calling
      scope: call-services

    resource:

      # Url to get user profile
      userInfoUri: http://localhost:8082/services/me

A point must be made for the userInfoUri. I wrongly thought of this Url as the protected resource where you can put whatever you want.
This was a mistake: this url return the userProfile; you can put other user information (as you can see below in this article I put the user’s birthday) in the Principal details object.

Let me show you what I’m speaking of by using this code of the protected remote resource.


private static final Map<String, String> users = new HashMap<String, String>(){
      {
      	put("Bret", "03/05/2003");
      	put("Antonette", "11/10/2000");
      	put("Samantha", "12/04/2002");
      	put("Karianne", "19/07/2008");
      	put("username", "22/03/2004");
      	put("Leopoldo_Corkery", "01/02/2002");
      	put("Elwyn.Skiles", "12/01/2001");
      	put("Maxime_Nienow", "09/11/2002");
      	put("Delphine", "30/09/2005");
      	put("Moriah.Stanton", "11/07/2009");
      }
  };

@RequestMapping(path = "me", method = RequestMethod.GET)
public Principal me(Principal principal) {    	
	
  final Map<String, String> birthday = new HashMap<String, String>();
  OAuth2Authentication auth = (OAuth2Authentication) principal;	
  birthday.put("birthday", users.get(auth.getName()));	
  auth.setDetails(birthday);
	
  return principal;
}

Knowing the user name, I got the birthday and put it into the Principal detail’s properties.

Other parameters available are:

  • authenticationScheme: Get the bearer token method for this resource.
  • clientAuthenticationScheme: The scheme to use to authenticate the client

All the value are available here:
https://docs.spring.io/spring-security/oauth/apidocs/index.html?org/springframework/security/oauth2/common/AuthenticationScheme.html

For example, for Facebook connect, the parameters configuration are:
authenticationScheme: query
clientAuthenticationScheme: form

Now, we need to run the boot application configuring the security properties and the RequestMapping.

@SpringBootApplication
@EnableOAuth2Sso
@RestController
public class Application extends WebSecurityConfigurerAdapter {

	@RequestMapping("/user")
	public Principal user(Principal principal) {
		return principal;
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.antMatcher("/**").csrf().disable().authorizeRequests()
				.antMatchers("/", "/login**", "/webjars/**").permitAll()
				.anyRequest().authenticated();
		
		
	}

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

The final presentation layer works by calling the OAuth2 authentication layer and the calling the protected resource.

<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Demo</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<base href="/" />
<link rel="stylesheet" type="text/css"
	href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript"
	src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>	
	<div class="container unauthenticated">
		<h1>Login</h1>
		With Auth2 Server: <a href="/login">click here</a>
	</div>
	<div class="container authenticated" style="display: none">
		<h1></h1>
		Logged in as: <span id="user"></span><br> And your birthday is: <span
			id="birthday"></span>
	</div>
	<script type="text/javascript">
		$.get("/user", function(data) {
			if (data) {
				$("#user").html(data.userAuthentication.details.name);
				$("#birthday").html(
						data.userAuthentication.details.details.birthday);
				$(".unauthenticated").hide()
				$(".authenticated").show()
			}
			else
				{
				$(".unauthenticated").show()
				$(".authenticated").hide()
				}
		});
	</script>
</body>
</html>

Once made the OAuth2 authentication, I’ve printed the user’s birthday accessing his data in the principal as highlighted.

I’d like draw the attention of the scope parameter. It works at “authorization” level and must match the protected resource level. I’ve configured the scope as call-services in the protected resource:

@Override
public void configure(HttpSecurity http) throws Exception {
    
	http
        .authorizeRequests()
        .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('call-services')")
            .and()
        .headers().addHeaderWriter(new HeaderWriter() {
            @Override
            public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
                response.addHeader("Access-Control-Allow-Origin", "*");
                if (request.getMethod().equals("OPTIONS")) {
                    response.setHeader("Access-Control-Allow-Methods", 
request.getHeader("Access-Control-Request-Method"));
                    response.setHeader("Access-Control-Allow-Headers", 
request.getHeader("Access-Control-Request-Headers"));
                }
            }
        });                 
}

The client asks for this permission:
scope: call-services

And the client registered must be allowed to access at this permission:

{
	"_id": ObjectId('5a12de3f1c132602e44a092b'),
	"_class": "com.jeenguyen.demo.oauth.api.entities.MongoClientDetails",
	"clientId": "web-client",
	"resourceIds": [
		"project-man"
	],
	"secretRequired": true,
	"clientSecret": "web-client-secret",
	"scoped": false,
	"scope": [
		"call-services",
		"call-medicine"
	],
	"authorizedGrantTypes": [
		"refresh_token",
		"authorization_code"
	],
	"authorities": [
		{
			"role": "ROLE_USER",
			"_class": "org.springframework.security.core.authority.SimpleGrantedAuthority"
		}
	],
	"accessTokenValiditySeconds": 3600,
	"refreshTokenValiditySeconds": 14400,
	"autoApprove": false
}

And now some screenshot of the process flow.
1. Start of the request for the protected resource.

2. Check the user credential.

3. Authorize the user to access the protected resource.

4. Get the protected resource.

Concluding, I think of adopting Spring OAuth2 library only when I’m already using Spring Security library. I can’t figure this solution easily adapting at external authentication service despite there are ways which let this process available.

I’m looking forward to seeing the next versions of this library, I think there’s a lot to do again despite of the good level already achieved.

The complete example is available on GitHub (SpringBootOauth2Client).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s