Integrating Spring Security With Third Party Authentication

Recently I had the opportunity to write a web application using Spring Security and a third party application for authentication. (We’ll call the third party TPS for Third Party Security. Also: TPS Reports :D)

Spring Security is a great framework, but I was confused about how to do the authentication and how best to work with it. Should I subclass the TPS User to implement UserDetails? Should I implement UserDetailsService to get said Users? How does AuthenticationManager, ProviderManager, and AuthenticationProvider play into this?

The legacy system authenticated with username and password, so that was easy to grasp. I started out with what I knew: User and UserDetails, since that was what I’d used from before with the DaoAuthenticationProvider. The problem was that I couldn’t use DaoAuthenticationProvider anymore because I didn’t have access to the password encoding and couldn’t let that default provider compare hashed passwords itself.

So I moved on to AuthenticationProvider and found a  sample and conversations around its use. This turned out to be the correct path for integrating with TPS. Here is the implementation of a @Service that implements AuthenticationProvider:


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

    String username = authentication.getName();
    String password = authentication.getCredentials().toString();

    // authenticate using third party API
    com.legacytps.security.User user = TPSSecurity.getUser(username);
    if (user == null) {
        throw new UsernameNotFoundException(username + " not found");
    }

    if (!user.isAuthenticated(password)) {
        throw new BadCredentialsException(username + " password is not authenticated");
    }

    // once authenticated, construct successful authentication object
    // the returned auth object should have .isAuthenticated() return true, that's a common gotcha
    Collection<GrantedAuthority> authorities = ... // legacy access of this
    boolean accountNonExpired = // legacy access of this
    boolean accountNonLocked = ... // legacy access of this
    boolean credentilsNonExpired = // legacy access of this
    boolean enabled = // legacy access of this

    // this is the spring security user class
    User appUser = new User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
    Authentication auth = new PreAuthenticatedAuthenticationToken(appUser, password, appUser.getAuthorities());

    return auth;
}

@Override

public boolean supports(Class<?> type) {
    return type.equals(UsernamePasswordAuthenticationToken.class);
}

Note that we’re using Spring Security classes for the Authentication and UserDetails. This is actually a really nice way to isolate the dependency on TPS (by restricting it to a single class, the AuthenticationProvider), otherwise those dependencies would be spread across more classes, increasing the burden of testing and of managing Spring Profiles.

One important gotcha is that if authentication is successful, the returned Authentication object must have .isAuthenticated() return true. This is tricky because many implementations of Authentication return false by default. If that happens, your app will never authenticate anybody and you won’t know why until you look in the debugger!

Have you had to integrate with third party or legacy security systems? How difficult was it, and what were some common problems?

Advertisements

Leave a comment

Filed under Software Engineering

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