Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intercept request and check authorization in playframework

I'm using play framework 2.4.2 with Java and I want to validate that a user is logged in by intercepting all requests and checking if a session value is set. So I have extended the DefaultHttpRequestHandler and overridden the createAction Method to intercept all requests. However, I have not found a good way to validate the session.

Option 1 - Fail

When I try to fetch the session value I get a runtime exception: There is no HTTP Context available from here

Below is the class I'm working with:

public class RequestHandler extends DefaultHttpRequestHandler {
    @Override
    public Action createAction(Http.Request request, Method method) {
        session("loggedIn"); // Throws runtime Exception: no HTTP Context
    }
}

Option 2 - Ugly

Since the session is technically a cookie I can retrieve the value from the header with code like the following:

for(String cookie : request.headers().get("Cookie")){
    System.out.println("cookie: "+cookie);
}

But then I have to parse the cookie string which looks like the following line to get the loggedIn value. To dirty for my taste.

_ga=GA1.1.1508004144.1421266376; ki_r=; ki_t=1438789543788%378129908%3B1438789543788%3B1%3B1; PLAY_SESSION=0570411c3eb55ad230681539ddcfaa4220583fd-loggedIn=1

Option 3 - Too easy to forget the annotation

I notice some websites document a different approach and instead create an
action composition and add the appropriate annotation to every controller class or method.

The problem with this approach is it requires the developer to remember to add the annotation. I would prefer to reverse this to block every route by default and then add an annotation to the routes that do not need the validation.

A couple sites that document action composition:

  1. http://alexgaribay.com/2014/06/16/authentication-in-play-framework-using-java/
  2. https://www.playframework.com/documentation/2.2.1/JavaGuide4

Question

Is there a way to globally validate if a user should have access to a page and how do I get at the session variable?

*Please note that I'm not interested in using a third party plugin for authentication.

like image 975
Brett Avatar asked Mar 16 '23 04:03

Brett


1 Answers

Even if I would re-consider using action composition, you can fix Option 1.

Create a custom annotation to mark the actions that don't need validation.

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoAuthRequired {}

Then change your HttpRequestHandler implementation.

public class RequestHandler extends DefaultHttpRequestHandler {
    @Override
    public Action createAction(Http.Request request, Method actionMethod) {
        return new Action.Simple() {
            @Override
            public F.Promise<Result> call(Http.Context ctx) throws Throwable {
                // if the action is annotated with @NoAuthRequired or user is logged in delegate to it
                if (actionMethod.isAnnotationPresent(NoAuthRequired.class) || ctx.session().containsKey("loggedIn")) {
                    return delegate.call(ctx);
                }
                // otherwise, block access
                else {
                    return F.Promise.pure(forbidden("You're not allowed"));
                }
            }
        };
    }
}

In this way, every route requires validation unless explicitly annotated.

As you can see from the code, the session is available through the Context.

like image 174
franz.fonta Avatar answered Apr 06 '23 18:04

franz.fonta