简体   繁体   中英

Implementing the password owner resource flow of OAuth2 in Play (Java)

For my Bachelor's-thesis I have to implement different kinds of Authentication and Authorization with different Frameworks. Currently im at the OAuth2 chapter and have to implement it in the Play Framework (in Java). (I have already implemented it with Spring Boot) While researching on how to approach this Problem, so far, I could not find a lot of helpful tips.

One of the main Questions I have is: after the Client authenticatet itselfe with the users credentials and has gotten the Token, how do I best verify the Token? Basicly: What is the Play- counterpart to the "@PreAuthorize" annotation of Spring?

Any tip or link to a helpful website is appreciated.

So I think I solved my Problem. On the off chance that someone stumbles on the same question I'm gonna post the solution here:

As written in the Play-Docs ( https://www.playframework.com/documentation/2.6.x/JavaOAuth ) with OAuth2 and especially with the Password flow it is pretty simple.

First you need an Authorization-Service, here the implementation is straight forward. Just implement three methods:

POST /oauth/token for passing the user-credentials and recieving an access- and refresh-token

POST /oauth/refresh for when the access-token is no longer valid. Here the refresh-token is passed and a new acces token returned

POST /oauth/check_token for authorization. Here the access Token is passed and in my case I return the role, the user has. Alternativly it would also be possible and maybe eaven better to do the authorization process in the authorization-service. For this you would need to change the "check_token" method and pass the required role.

I just generated uuids as tokens and stored them in a database. I guess one could also use for example jwts and put the needed information (for example the expiration date) in the token.

Then my main question was about the annotations. I found this https://github.com/bekce/oauthly and just lookt at their implementation.

You basicly just need a class and a interface:

The Interface:

@With(AuthorizationServerAuthAction.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorizationServerSecure {
    boolean requireAdmin() default false;
    boolean requirePersonnel() default false;
    boolean requireGuest() default false;
}

The Class:

private WSClient ws;
private final String url = "http://localhost:9001/oauth/check_token";
@Inject
public AuthorizationServerAuthAction(WSClient ws) {
    this.ws = ws;
}

private CompletionStage<JsonNode> callApi(String accessToken) {
    CompletionStage<WSResponse> eventualResponse =  ws.url(url).setContentType("application/x-www-form-urlencoded").setRequestTimeout(Duration.ofSeconds(10))
            .addHeader("Authorization" ,  accessToken).post("none");
    return eventualResponse.thenApply(WSResponse::asJson);
}
@Override
public CompletionStage<Result> call(Http.Context ctx) {
    Optional<String> accessTokenOptional = ctx.request().header("Authorization");
    JsonNode result = null;
    if(!accessTokenOptional.isPresent()){
        return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                .put("message", "No token found in header!")
        ));
    }

    CompletionStage<JsonNode> apiResponse = callApi(accessTokenOptional.get());
    try {
        result = apiResponse.toCompletableFuture().get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    if(result == null) {
        return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                .put("message", "an error occurred")
        ));
    }
    String role = result.get("role").asText();

    if(configuration.requireAdmin()){
        if(role.equals("admin")) {
            return delegate.call(ctx);
        } else {
            return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                    .put("message", "The user is not authorized to perform this action!")
            ));
        }
    } else if(configuration.requirePersonnel()) {
        if(role.equals("personnel") || role.equals("admin")) {
            return delegate.call(ctx);
        } else {
            return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                    .put("message", "The user is not authorized to perform this action!")
            ));
        }
    } else if(configuration.requireGuest()) {
        if(role.equals("guest") || role.equals("personnel") || role.equals("admin")) {
            return delegate.call(ctx);
        } else {
            return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                    .put("message", "The user is not authorized to perform this action!")
            ));
        }
    }
    return CompletableFuture.completedFuture(unauthorized(Json.newObject()
            .put("message", "an error occurred")
    ));

}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM