Quick Expense Manger. Your free expense manager. Lots of features. The application is also ad free.

Oauth Integration with Spring Security

Posted on Nov. 10, 2017
oauth-spring-security-integration

I will explain about Spring Security using oauth 2.0 in details with runnable code. I will explain how to create a authorization server and generate authorization token and use the same to access the protected resources.


Let me explain first how an authorization token works. Whenever you visit some website, it gives you the option to login using your facebook account, google plus account etc.


When you try to use such an option say - login with facebook, you are first redirected to facebook to get an authorization token and the browser then sends the token that it has got from facebook to the website you are trying to login.


The website then again checks the token it has got from your browser with facebook to verify if it is a valid token or not. If it is valid, then you are allowed to see the protected resources.


This whole process is transparent to you if you are already logged in to facebook. Otherwise, you will be redirected to login to facebook.


Most of the time the website will also try to get some additional data from your facebook account like your email id, public profile info etc.(To spam you with their products ?) In such case, facebook will ask your permission before giving such info to the third party website.


So, facebook acts like an authorization server between you and the third party website and it generates authorization tokens. The third party website can keep such tokens in their database, and next time when you try to login to their website using facebook, your browser will again send the authorization token to the website and this time they don't have to verify with facebook. They can directly check in their database regarding validity of the token.


This process is indeed very secure as you are not exposing your credentials to the third party website and facebook handles the entire authentication process.


But if the third party website stores the tokens in their database and if that database gets compromised, then the hacker can use the token and post messages on your behalf from your facebook account.


So, the third party website that stores the tokens in their database should encrypt the tokens before storing them.


Now you have got an overview how authorization token works. We will now see how to create our own authorization server and generate such tokens.


Authorization can have different meanings when you are using different devices. You can have different level of authorizations. So, if someone is trying to access your data from your app you can have different level of authorization checks compared to someone trying to access your data from a browser.


Without any further delay, let us see some code in action. I have used Spring Boot for writing all my code.

package com.kaushikbaruah.javamaniacauth.oauth;

@Configuration
@EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter{

private AuthenticationManager authenticationManager;


@Autowired
public OAuthConfiguration(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
super.configure(clients);
clients.inMemory()
.withClient("yourClientId")
.secret("yourClientSecret")
.authorizedGrantTypes("password")
.scopes("openid");
}

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


The main thing in the above code is the Client. I have created an in memory client with a client Id and a client secret. So, anyone who tries to login to my site has to get an access token.


And to get the token, they have to provide the client Id and the client secret and on top of that they have to use appropriate user id and password.


The strings yourClientId and yourClientSecret can be any string you wish, but the browser (or anything else) that is trying to access your site has to use the same client Id and client secret.


The authenticationManager that I have injected is basic Spring Security which I will explain later in this article. In simple terms, using this I am telling oauth about Spring Security.


While writing the code for my website, I faced some issues regarding how to exactly pass the clientId, clientSecret etc. along with the user name and password. You can use the similar code as below to pass the information to the Authorization server.

@Configuration
public class AuthorizationHandler {

private final String plainClientCredentials;


public AuthorizationHandler() {
this.plainClientCredentials = "yourClientId:yourClientSecret";
}

private String getPlainClientCredentials() {
return plainClientCredentials;
}


public Map<String,String> getHeadersWithClientCredentials(){
String base64ClientCredentials = new String(Base64.encodeBase64(
getPlainClientCredentials().getBytes()));
Map<String,String> map = new HashMap<>();
map.put("Accept","application/json");
map.put("Authorization", "Basic " + base64ClientCredentials);
return map;
}
}

You can use the below Rest Controller to intercept your authentication requests.

@RestController
class Controller{

@Autowired
private AuthorizationHandler authorizationHandler;

@Autowired
private AuthInterceptor authInterceptor;

@RequestMapping(method = RequestMethod.POST,value = "/authenticate-me")
public List<String> authenticateMe(@RequestBody LoginForm loginDetails)
throws IOException{


Map<String,String> headers = authorizationHandler.getHeadersWithClientCredentials();
Map<String,String> map = authInterceptor.getToken(headers.get("Accept"),
headers.get("Authorization"),formDataMap(loginDetails));
List<String> list = new ArrayList<>();
list.add(map.get("access_token"));
return list;
}

The above code is very simple and easy to implement. The AuthInterceptor that I am using is just a Feign Proxy to connect to the Actual Authorization server.

@FeignClient(name="auth-service",configuration = CoreFeignConfiguration.class)
public interface AuthInterceptor{

@RequestMapping(method = RequestMethod.POST,value="/oauth/token",consumes =
MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@Headers("Content-Type: application/x-www-form-urlencoded")
@ResponseBody
Map<String,String> getToken(@RequestHeader("Accept") String accept,
@RequestHeader("Authorization") String key, @RequestBody Map<String, ?> formParams);

@RequestMapping("/user")
@ResponseBody
Map<String,String> getUserDetails(@RequestHeader("Authorization") String key);

}

You can use the getUserDetails to get more info from the token provided you define an endpoint in your Authorization Server as below.

@RestController
@EnableResourceServer
public class PrincipalController {

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

The above method will convert your authorization token to a Principal object and same will be returned to you. However in practice it is not advisable to return the Principal as it contains too much information. The information should be parsed and you should return what is absolutely necessary.


The @EnableResourceServer will protect your end points from unauthorized access. You have to pass proper authorization token to access any resource annotated with this.


This is all that you need to implement your Authorization server.


Now I will explain simple Spring Security. Let's have a look at the below code and that's all what you need.

@Service
public class AccountDetailsService implements UserDetailsService{

private AccountRepository accountRepository;

@Autowired
public AccountDetailsService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}


@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Account account = accountRepository.findAccountUsingEmail(email);
if(account==null)
throw new UsernameNotFoundException(email);

else
return new User(account.getEmail(),account.getPassword(),account.isActive(),
account.isActive(),
account.isActive(),account.isActive(),
AuthorityUtils.createAuthorityList(account.getUserRoles()));
}
}

We just need to simply implement the UserDetailsService Interface and override the loadUserByUsername() method. Spring will automatically detect this and would use our AccountDetailsService for Spring Security. I will not be explaining the AccountRepository as it is simply how you access your database to get the user information.


That's it. This is all about oauth integration with Spring Security.

Sharing is Caring!

Quick Expense Manger. Your free expense manager. Lots of features. The application is also ad free.

GET FREE UPDATES


RECOMMENDED POSTS FOR YOU


profile image

Kaushik Baruah


ABOUT

My name is Kaushik Baruah and I am the chief blogger on this Blog and here I like to share my experience as software engineer and research engineer with my online readers. I will try to focus on career planning, latest emerging technologies and tutorials on various computer science subjects. You can follow me on Twitter, Facebook and Google+

GET FREE UPDATES

POPULAR POSTS

Copyright © 2016
About Us

My name is Kaushik Baruah and I am the chief blogger on this Blog and here I like to share my experience as software engineer and research engineer with my online readers. I will try to focus on career planning, latest emerging technologies and tutorials on various computer science subjects.

Get Free Updates