Using regex-defined scopes with OpenAM

Steffo Weber
Sep 3, 2018 · 4 min read

In many shopping scenarios — especially in PSDII world — ones need to express consent in form “I consent to let Amazon withdraw amount X from (from my bank account) in order to purchase product Y”. While this perfectly aligns with the ideas of OAuth2 protocol, there some pitfalls.

Most OAuth2 implementations use a static list of fixed scopes to express something like

Do you consent to give <OAuth2Client> READ access (to some resource)?

Here READ is a scope (that can be mail, twitter-feed etc in other implementations). With OAuth2’s growing popularity and adoption in frameworks like OpenBanking or BerlinGroup’s NextGen PSD2 this fixed list of scopes needs to be enhanced to express consent/authorization decisions of the form

I consent, that <OAuth2Client> can withdraw 965 EUR from my bank account in order to pay for guitar G (or any other product you would like to purchase).

Here scopes have the form (in OpenBanking and NextGenPSDII word, the part behind the : is the PaymentID which is a reference to the purchase; also note that OpenBanking uses OIDC RequestParamter to express this consent).

WITHDRAW:965#Guitar

The only fixed thing here is the WITHDRAW action. Everything after the “:” is variable and depends on what you purchase. There’s nothing in the OAuth2 specs that would restrict the set of possible scopes an OAuth2 client can ask for to be defined by a regular expression. Actually in my discussion w OAuth2 experts, everybody seems to have different hidden assumptions on on the definition of scopes. Are they finite? Are they defined with help of non-terminating characters? Does the AS (authorization server) need to parse them? Long story short: we want to have variable scopes (sometimes called dynamic scopes).

OpenAM implementation

OpenAM assumes a fixed list of scopes that are available for each OAuth2 client, where each scope consists terminating characters only. The OpenAMScopeValidator class efficiently checks, if a client only asks for scopes, he’s allowed to ask for.

OpenAM OOTB Scope Implementation Class

In order to allow for scopes defined by regular expression like ^WITHDRAW:. which matches our example above, you just need to amend the OOTB implementation to do a bit of pattern matching:

@Overridepublic Set<String> validateAccessTokenScope(ClientRegistration clientRegistration, Set<String> scope,OAuth2Request request) {List<String> requestedScopes = new ArrayList(scope);List<String> authorizedScopes = new ArrayList();List<String> allowedScopes = new ArrayList(clientRegistration.getAllowedScopes());if (scope == null || scope.isEmpty()) {
return clientRegistration.getDefaultScopes();
}
Iterator it = allowedScopes.iterator();
while (it.hasNext()) { authorizedScopes.addAll(filter(requestedScopes, (String)it.next()));
}
return new HashSet<>(authorizedScopes);
}

The magic is in filter method.

private List<String> filter(List<String> reqestedScopes, String regex) {   Pattern pattern = Pattern.compile(regex); //move outside method in production
List<String> matching = reqestedScopes.stream().filter(pattern.asPredicate()).collect(Collectors.toList());
return matching;
}

Simply put that piece of code in your custom scope validator class (you’ll find sample code including Maven build files in OpenAM Samples directory).

After that, change the scope validator class to your new class.

Configure OAuth2 Provider to use custom class.

Now you can configure your OAuth2 agents to use regex defined scopes.

Let’s give it a try with Postman.

And verify the opaque token at tokeninfo endpoint

We get all the scopes that are permitted for this client (including the ones that start with letter a).


Summary

OpenAM can be easily modified to cater the scope implementation that’s best for your use case. Note that different implementations can have different impact on performance etc. Thus, if you only have a classic list of fixed values, stick with the OOTB implementation. However, if you need to cater variable scopes (defined by regular exporessions) use your custom class.

This allows OpenAM to be used in scenarios like NextGenPSDII (defined by Berlin Group) and many other modern OAuth2 use cases.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade