Question

I'm using Spring Security OAuth2. The client application (that we own) makes a "password" grant request that passes the user's username and password. Just like the draft specifies.

I need this mechanism to also support other types of credentials, like card number, PIN, and even a pre-authenticated, password not required grant.

Please keep in mind, these requests will only be permitted by a privileged client_id, one that will only be used from the application we own.

Was it helpful?

Solution

Dave, thanks for the quick response. I actually found the perfect solution, one which you took part in. It has to do with "custom-grant" token granters... https://jira.spring.io/browse/SECOAUTH-347

Had I updated my rather old 1.0.0.M5 version I might have known about those.

My approach was to extend AbstractTokenGranter with a class that supports a custom grant type (I call it "studentCard"). Once an authentication request makes it here, I examine the parameter list just like ResourceOwnerPasswordTokenGranter, but instead look for my custom "cardNumber" parameter. I then pass my own, id-based version of UsernamePasswordAuthenticationToken to my AuthenticationProvider, which knows how to authenticate users based on id card.

Here is the custom token granter class I came up with:

public class StudentCardTokenGranter extends AbstractTokenGranter {
    private static final String         GRANT_TYPE = "studentCard";

    private final AuthenticationManager authenticationManager;

    public StudentCardTokenGranter(AuthenticationManager authenticationManager,
        AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService) {
    super(tokenServices, clientDetailsService, GRANT_TYPE);
    this.authenticationManager = authenticationManager;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest clientToken) {

    Map<String, String> parameters = clientToken.getAuthorizationParameters();
    String cardNumber = parameters.get("cardNumber");

    Authentication userAuth = new StudentCardAuthenticationToken(cardNumber);
    try {
        userAuth = authenticationManager.authenticate(userAuth);
    } catch (BadCredentialsException e) {
        // If the username/password are wrong the spec says we should send 400/bad grant
        throw new InvalidGrantException(e.getMessage());
    }
    if (userAuth == null || !userAuth.isAuthenticated()) {
        throw new InvalidGrantException("Could not authenticate student: " + cardNumber);
    }

    return new OAuth2Authentication(clientToken, userAuth);
    }
}

And my authorization server config:

<!-- Issues tokens for both client and client/user authorization requests -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices">
    <oauth:refresh-token />
    <oauth:client-credentials />
    <oauth:password authentication-manager-ref="myUserManager" />
    <oauth:custom-grant token-granter-ref="studentCardGranter" />
</oauth:authorization-server>
<bean id="studentCardGranter" class="com.api.security.StudentCardTokenGranter">
    <constructor-arg name="authenticationManager" ref="myUserManager" />
    <constructor-arg name="tokenServices" ref="tokenServices" />
    <constructor-arg name="clientDetailsService" ref="clientDetails" />
</bean>

OTHER TIPS

The spec doesn't explicitly allow direct, non-password-based exchange of user tokens between a client and the auth server directly. I think it would be quite natural to extend the password grant to other forms of authentication though. It's in the spirit of the spec, if not by the letter, so if you own both sides of the relationship there isn't much to go wrong. Spring OAuth doesn't explictly support anything that extends the password grant in this way, but its not hard to do (it's really just about the security of the /token endpoint). An alternative approach I've seen is to stick to the password grant protocol, but make the "password" a one-time token that the client can only get by knowing the user has authenticated in one of those alternative ways.

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