Skip to content

Instantly share code, notes, and snippets.

@jcassee
Created May 23, 2020 22:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcassee/8ce917387263d40b9908506af5b5c578 to your computer and use it in GitHub Desktop.
Save jcassee/8ce917387263d40b9908506af5b5c578 to your computer and use it in GitHub Desktop.
Implementation of Micronaut Security annotation for securing routes using JWT scopes (micronaut-projects/micronaut-security#254)
package example;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ScopeSecured {
String[] value();
}
package example;
import io.micronaut.http.HttpRequest;
import io.micronaut.security.rules.AbstractSecurityRule;
import io.micronaut.security.rules.SecurityRuleResult;
import io.micronaut.web.router.MethodBasedRouteMatch;
import io.micronaut.web.router.RouteMatch;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import static java.util.Collections.emptyList;
@Singleton
public class ScopeSecuredAnnotationRule extends AbstractSecurityRule {
public ScopeSecuredAnnotationRule() {
super(claims -> emptyList()); // scopes are not roles
}
@Override
public SecurityRuleResult check(HttpRequest request, @Nullable RouteMatch routeMatch, @Nullable Map<String, Object> claims) {
var allowedScopes = getAllowedScopes(routeMatch);
if (allowedScopes.isPresent()) {
var claimScopes = getClaimScopes(claims);
return checkScopes(allowedScopes.get(), claimScopes);
}
return SecurityRuleResult.UNKNOWN;
}
private Optional<String[]> getAllowedScopes(@Nullable RouteMatch<?> routeMatch) {
if (routeMatch instanceof MethodBasedRouteMatch) {
var methodRoute = ((MethodBasedRouteMatch<?, ?>) routeMatch);
if (methodRoute.hasAnnotation(ScopeSecured.class)) {
return methodRoute.getValue(ScopeSecured.class, String[].class);
}
}
return Optional.empty();
}
private String[] getClaimScopes(@Nullable Map<String, Object> claims) {
if (claims != null) {
var claim = claims.get("scope");
if (claim instanceof String) {
return ((String) claim).strip().split("\\s+");
}
}
return new String[0];
}
private SecurityRuleResult checkScopes(String[] allowedScopes, String[] claimScopes) {
for (String scope : allowedScopes) {
if (Arrays.asList(claimScopes).contains(scope)) {
return SecurityRuleResult.ALLOWED;
}
}
return SecurityRuleResult.UNKNOWN;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment