1

I have a set of micro-services, written using Springboot 1.5.6, which contain the business logic to be consumed by a SinglePageApplication. The task is to implement method based security for the Restful APIs using OAuth2 and providing both username-password based and social login based security.

I created (with great difficulty and sub-par understanding) a new micro-service and implemented an Auth Server (AS), allowing username-password based authentication. I incidentally, also managed to convert the tokens to JWT, so that the numerous calls between Resource Server (RS) and Authorisation Server (AS) are prevented.

While I have not understood the spring security framework to any reasonable satisfaction, the username-password based authentication is, nevertheless, working. I have also exposed a simple login API in AS, which takes username, password as argument, and in turn calls its own oauth/token method to generate access token and return to the web client. This API is used by the front-end for username-password based login (or form based login, if it is so called).

The portion of application.yml, which allows AS to call its own Spring exposed method to get access token, is as follows:

security:
  oauth2:
    client:
      accessTokenUri: http://localhost:8200/oauth/token
      clientId: myClientId-used-by-RS
      clientSecret: myClient-secret `

However, the objective is to allow social login for authentication (so that the identity of the user is ascertained and the nuisance of remembering password is eliminated).

After having read hundreds of article, and many fail attempts, and yet not being unable to understand how to implement social login, I ultimately followed https://spring.io/guides/tutorials/spring-boot-oauth2/ to set up google based login. In order to authenticate with Google, I created credentials, and set re-direct url as http://localhost:8200/redirect/google.

The java code where google auth server details are configured is as follows:

@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google() {
    AuthorizationCodeResourceDetails acrd = new AuthorizationCodeResourceDetails();
    return acrd;
}
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource() {
    return new ResourceServerProperties();
}
private Filter ssoGoogleFilter() {
    OAuth2ClientAuthenticationProcessingFilter googleFilter =
            new OAuth2ClientAuthenticationProcessingFilter("/redirect/google");
    OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oauth2ClientContext);
    googleFilter.setRestTemplate(googleTemplate);
    googleFilter.setTokenServices(new UserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId()));
    return googleFilter;
}

The properties for authentication with google are as follows

google:
   client:
       clientId: 1512877066*******
       clientSecret: 2yEq**********
       accessTokenUri: https://www.googleapis.com/oauth2/v3/token
       userAuthorizationUri: https://accounts.google.com/o/oauth2/auth
       tokenName: oauth_token
       authenticationScheme: query
       clientAuthenticationScheme: form
       scope: profile
       pre-established-redirect-uri: http://localhost:8200/redirect/google
   resource:
       userInfoUri: https://www.googleapis.com/userinfo/v2/me
       preferTokenInfo: false

In the current setup, when 'Login with Google' button is pressed, the following URL is called http://localhost:8200/redirect/google, and which in turn (and magically) opens up the google authentication page. The redirect url is not visible through swagger! Yet, Spring somehow creates it, and which redirects to the google AS, which deals with the browser, and sends a redirect at the prescribed address.

On selecting an account, Google, seemingly correctly, calls the redirect URL, along with authorisation code. http://localhost:8200/redirect/google?state=bCYxB8&code=4/7ADdFDUL1x653-RL7H3iAJ_dTEjnznN88B7HRjj73ZXhlakIItH_6UzEFL25adS1kFdPvGRO8&scope=profile%20https:// The problem starts now! I get error 401. My security config is follows:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("**").permitAll()
            .and()
            .addFilterBefore(dandiSocialLogin.ssoFilter(), BasicAuthenticationFilter.class);
            ;
}

I am unable to expose an endpoint to receive authorization code. The end-point is exposed by Spring and not under my control. Would there be some hook where I can get the auth code, and return local access token in respose? Ideally, I would expose an endpoint like this

    @RequestMapping(value = "", method = RequestMethod.GET)
public DandiTokenResponse googleCallback(@RequestParam(value = "code", defaultValue = "") String code,
                                         @RequestParam (value = "state", defaultValue = "") String state,
                                         @RequestParam (value = "scope", defaultValue = "") String scope){
    /**
     * Use the authorization code, to get access token, or get profile information.
     * If authorization code is valid, then assume that the user has successfully authenticated with google.
     * Create your own fictitious password, store it in the db, and call the local login method of
     * AS to get access token generated by the local AS (and not google). Return the access token to the
     * front end.
     */
    return null;
}

The moment I expose an end point resolving to /redirect/google, my original attempt to call this API (and getting redirected to google for authentication) fails. If I change the redirect url in google console to something different than new OAuth2ClientAuthenticationProcessingFilter("/redirect/google"); I get a redirect url mismatch error. If I do not get the authorization code sent by google, there is no use of this flow!

It has been weeks since I have been struggling to get social login + username-password based login for Restful APIs to work. All links for all related keywords for the first few pages of google research have been exhausted. And since there is no talk about the subject at all, I believe that I am missing something so fundamental, that it is not being asked by anyone. Please let me know,(1) how should I get access to the authorization code on the server?, (2) Whether I should create http request in java code to exchange auth code for access token (google)/profile info or whether some property setting in Spring will do, (3) Is this the right way, or is there a more recommended method for achieving the same? I see hundreds of web-sites allowing this feature, and yet I am unable to do it from the past two months, means that there should something fundamentally amiss in my approach!

Since the description length has already crossed limits of decency, I will hold myself back for specific questions. Thanks

Abhishek Prabhat
  • 917
  • 1
  • 6
  • 15

0 Answers0