Spring+AngularJS+Oauth2

Recently there was a requirement at my work to implement security in a REST webservice application. It was really a pain to find some working example in the internet. After struggling a lot finally I could apply the security configuration in the application.

Here in this tutorial I am not going to explain what is Oauth2. Here I am going to explain how to configure it using Spring.We are using Springboot as the application is a microservice.

So, the necessary steps go as follows:

Create project

Please go to the link  and create a Springboot project with web dependency.

The project structure is as shown below.

1

The pom.xml is as shown below.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.example</groupId>
	<artifactId>myoauth</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>oauthtest</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.6.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<angularjs.version>1.5.5</angularjs.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security.oauth</groupId>
			<artifactId>spring-security-oauth2</artifactId>
		</dependency>
		<!-- Web jars -->
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>angularjs</artifactId>
			<version>${angularjs.version}</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

Please note that we have added dependency for oauth2.

Create Authorization Server

Let us create a simple auth server.

package com.anupam.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthServer extends AuthorizationServerConfigurerAdapter {

	private TokenStore tokenStore = new InMemoryTokenStore();

	@Autowired
	private AuthenticationManager authenticationManager;

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.tokenStore(tokenStore).authenticationManager(authenticationManager);
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory().withClient(&quot;web&quot;).secret(&quot;websecret&quot;).scopes(&quot;read&quot;, &quot;write&quot;)
				.accessTokenValiditySeconds(3000).authorizedGrantTypes(&quot;password&quot;, &quot;refresh_token&quot;,&quot;client_credentials&quot;);

	}

}

 

Create Resource Server

Let us create a simple resource server.

package com.anupam.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser(&quot;admin&quot;).password(&quot;1234&quot;).roles(&quot;USER&quot;);

	}

	@Override
	@Bean
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	/**
	 * Resource server.
	 *
	 * @author anupam
	 *
	 */
	@Configuration
	@EnableResourceServer
	public static class ResourceServer extends ResourceServerConfigurerAdapter {

		@Override
		public void configure(ResourceServerSecurityConfigurer resources) {
			resources.resourceId(&quot;test&quot;);
		}

		@Override
		public void configure(HttpSecurity http) throws Exception {
			http.authorizeRequests().antMatchers(&quot;/login&quot;).permitAll();
			http.authorizeRequests().antMatchers(&quot;/data&quot;).authenticated();
		}

	}

}

Here we are securing our application with username=admin and password=1234. And in the resource server we are configuring resource in the paths /data. So the resource in this path is protected by this username and password.

Writing a controller.

I wrote a simple controller MyController.class. When the user makes a request to /login url, it makes a call to the Authorization server which is in the path /oauth/token . This returns an access_token and this access_token is returned to the user. Now for every service call later made by the user, the access_token must be supplied in a query parameter. Will show you this in shortly. I am using TestRestTemplate to make this REST call.

package com.anupam.controller;

import java.util.Map;

import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

	@RequestMapping(path = &quot;/data&quot;, method = RequestMethod.POST)
	public @ResponseBody String getData(@RequestBody String params) {
		return &quot;Get data&quot;;
	}

	@RequestMapping(path = &quot;/login&quot;, method = RequestMethod.POST)
	public String doLogin(@RequestBody Map&lt;String, Object&gt; params) {

		String username = (String) params.get(&quot;username&quot;);
		String password = (String) params.get(&quot;password&quot;);

		String authUrl = &quot;http://localhost:8080/app/oauth/token?&quot;;
		StringBuilder authParams = new StringBuilder(&quot;client_id=web&amp;client_secret=websecret&amp;grant_type=password&quot;);
		authParams.append(&quot;&amp;username=&quot;).append(username).append(&quot;&amp;password=&quot;).append(password);

		String url = authUrl.concat(authParams.toString());
		ResponseEntity&lt;String&gt; response = new TestRestTemplate(&quot;web&quot;, &quot;websecret&quot;).postForEntity(url, null,
				String.class);
		String responseText = response.getBody();
		return responseText;
	}

}

Testing auth server with curl

----Get initial tokens---------
curl web:websecret@localhost:8080/app/oauth/token -d client_id=web -d client_secret=websecret -d grant_type=password -d username=admin -d password=1234

----Get access token using refresh token-----
curl web:websecret@localhost:8080/app/oauth/token -d client_id=web -d grant_type=refresh_token -d refresh_token=a1a4dd48-0cbd-4c7a-9e97-26767b38a92d

Testing webservice with Postman

pp

You can see the access_token in the response.

Now lets use the access_token and call a webservice that is in the url /data. Here is the output.

sasasas

 

Testing webservice with AngularJS


$http.get('/data?access_token=access_token=1ab814ce-9467-47fd-bd60-6d8e06cb1f9a');

That’s it. Thank you for reading the text.

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