Question

I'm fairly new to Spring.

My goal is to have some AuthenticationProvider with a custom authenticate Method that takes an Authenticate object as argument with more than just a user name and password. Let's say a realm name (and there can be 2 users with the same user name when they are in different realms). I already looked for answers to my question, but the simple answers to questions about authentication only explain how to extend AbstractUserDetailsAuthenticationProvider, which doesn't cater my needs because the retrieve method only takes a user name as argument while I need the realm name as well to retrieve the user. The complex ones are about extending or implementing all kinds of different Spring classes and interfaces without the context being explained.

So the simple question is:

How do I have to implement / extend an AuthenticationProvider to be able to read custom data out of an Authentication object?

My call would look like this (yes, I want to get an OAuth2 token):

curl -vX POST http://localhost:9001/oauth/token \
-d "client_id=myId&client_secret=secret&grant_type=password&username=myUser&password=1234&realm=realm3"

Notice the realm=realm3 at the end.

The call without the extra data and with my own sub class of AbstractUserDetailsAuthenticationProvider already works when there's just one realm.

Thanks in advance!

Was it helpful?

Solution

How do I have to implement / extend an AuthenticationProvider to be able to read custom data out of an Authentication object?

RealmAuthenticationProvider

public class RealmAuthenticationProvider implements AuthenticationProvider {

    private RUPAuthenticator rupAuthenticator;

    public RealmAuthenticationProvider(RUPAuthenticator rupAuthenticator) {
        this.rupAuthenticator = rupAuthenticator;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        Object principal = authentication.getPrincipal();
        Object credentials = authentication.getCredentials();
        Object realm = authentication.getDetails();
        if (rupAuthenticator.authenticate(principal, credentials, realm)) {
            List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER")); //use any GrantedAuthorities you need
            return new RealmAuthenticationToken(principal, credentials, realm, grantedAuths);
        };
        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return RealmAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

RealmAuthenticationToken

public class RealmAuthenticationToken extends UsernamePasswordAuthenticationToken {

    private Object realm;

    public RealmAuthenticationToken(Object principal, Object credentials, Object realm, Collection<? extends GrantedAuthority> authorities) {
        super(principal,credentials, authorities);
        this.realm = realm;
    }
}

RUPAuthenticator

public interface RUPAuthenticator {
    boolean authenticate(Object username, Object password, Object realm);
}

You would just have to provide an implementation for RUPAuthenticator that states whether the username, password, realm combinations are correct.

And then register the custom AuthenticationProvider (RealmAuthenticationProvider) as a bean. Below is an example of an authentication provider that accepts requests from a specific user:

@Bean
public AuthenticationManager authenticationManager() {
        List<AuthenticationProvider> providers = new ArrayList<AuthenticationProvider>();
        providers.add(new RealmAuthenticationProvider(new RUPAuthenticator() {
            @Override
            public boolean authenticate(Object username, Object password, Object realm) {
                return (username.equals("sa") && password.equals("sa") && realm.equals("realm2"));
            }
        }));
        return new ProviderManager(providers);
    }

I hope this is what you were looking for.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top