Spring-mvc – Own Spring OAuth2 server together with 3rdparty OAuth providers

oauth-2.0spring-mvcspring-securityspring-security-oauth2spring-social

In a Spring Boot application, I have an OAuth2 Authorization/Resource servers. Based on this and Spring Security, I have secured my Spring MVC REST API endpoints.

In addition to this, I'd like to add authentication to my REST endpoints based on 3rd party OAuth providers like Twitter, Facebook, Google.

In my application I have two entities – User and SocialUser. SocialUser represents user profile in social networks. User can have 0-* associated SocialUsers. Right now I can authenticate a user in Twitter and after that I'm creating two records in my database – User and SocialUser. SocialUser contains access/refresh tokens issued by Twitter and some other profile information from this social network.

Right now I don't know how to link this User created from social network with my existing authentication\authorization flow. For this user I'd like to create my own(by my own OAuth2 authorization server) accessToken and provide it to the client.

Also, this user doesn't have username, password and email in his User entity. And also I don't know how to manually create my own access Token and send it to the client for future API calls.

I found some example:

@Inject
private TokenEndpoint tokenEndpoint;

public String createAccessToken(User user) {
    HashMap<String, String> parameters = new HashMap<String, String>();
    parameters.put("client_id", "appid");
    parameters.put("client_secret", "myOAuthSecret");
    parameters.put("grant_type", "password");
    parameters.put("password", user.getPassword());
    parameters.put("scope", "read write");
    parameters.put("username", user.getUsername());

    // principal ??
    return tokenEndpoint.getAccessToken(principal, parameters);
}

but I don't know how to create Principal based on my User entity and also I'm not sure that this is a correct way to go.

So, the main question is – how to manually generate this new token through my own OAuth server for this new user?

Please advise me how can it be correctly implemented. Thanks.

UPDATED:

I have added ProviderSignInController to my application and able right now to perform full OAuth dance with Twitter. Also, I have implemented my own Neo4jConnectionRepository and Neo4jUsersConnectionRepository because I use Neo4j as a primary database.

@Bean
public ProviderSignInController providerSignInController() {
    return new ProviderSignInController(socialAuthenticationServiceLocator, usersConnectionRepository, new SignInAdapter() {

        @Override
        public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
            System.out.println("User ID: " + userId + " social display name: " + connection.getDisplayName());
            return null;
        }
    });
}

So far, everything works good.

The one question is – how to authenticate/authorize User through my own OAuth2 Authorization server in the SignInAdapter.signIn method ?

I think I need to create OAuth2Authentication object for this user and put it into Security context.. Am I right ? If so, could you please show me an example how can this be implemented ?

Best Answer

So what you want to achieve is : when clients redirect users to your authorization server (authorization code or implicit grant) in order to obtain a token, the user can log-in using his favorite social network.

If I understand correctly, you have rolled your own implementation of single sign on (SSO) with Twitter (ProviderSignInController), and now you're left wondering how to generate a token when Twitter responds "OK".

I think you took the problem by the wrong end : Instead of building your Twitter client and generating a token programmatically, the idea is to integrate social SSO inside the flow of spring-security-oauth2, which in reality is how to integrate social SSO in Spring Security.

In the end, it's about how your authorization server secures the AuthorizationEndpoint : /oauth/authorize. Since your authorization server works, you already have a configuration class extending WebSecurityConfigurerAdapter that handles the security for /oauth/authorize with formLogin. That's where you need to integrate social stuff.

Instead of using the Spring Security built-in form authentication mechanism, you will have to plug-in your own security that either allows the user to login with a form, or starts SSO with other providers.
Spring Security is made of a bunch of abstractions, but it really just comes down to populating the SecurityContext with an Authentication object for each request.

Once the authentication process is complete, the user will continue to /oauth/authorize, consent to the client accessing some scopes, and the token will be delivered as it's usually done, without you having to generate tokens programmatically.

I have done that using SAML (Spring Security SAML extension), but in your case you should dig in the Spring Social projects, which seem to support all the major social networks out of the box.
The good news is that you already have a bunch of tools available, the "bad news" is that you will have to understand how they work to a certain degree in order to plug them together.

Related Topic