Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play framework redirect HTTP to https

I used play framework version 2.2.3 and I run activator using following command for accessing site using https.

./activator run  -Dhttp.port=disabled  -Dhttps.port=9043

and I typed URL in browser as below

https://localhost:9043/signin

Then it work fine and it redirects to https. But problem is that when I changed my URL as below

http://localhost:9043/signin

then I want to redirect above URL to https, how should this handled in play framework?

like image 525
Yogesh Avatar asked Aug 21 '14 12:08

Yogesh


3 Answers

as of play 2.6.x it's now supported by a configuration

play.filters.enabled += play.filters.https.RedirectHttpsFilter
like image 62
LiorH Avatar answered Oct 04 '22 22:10

LiorH


There are two question in there

  • How do we detect SSL in Play?

For Play 2.2 myself, I use a reverse proxy to handle SSL which will automatically add a request header "X-Forwarded-Proto". I then check that header to verify that the connect is coming in via SSL.

    String protocolHeaders = context.request().getHeader("X-Forwarded-Proto");
    if(protocolHeaders != null) {
        String[] split = protocolHeaders.split(",");
        for(int i=0;i<split.length;i++) {
            if(split[i].trim().equalsIgnoreCase("https")) {
                return delegate.call(context);
            }
        }
    }

I upgrading Play is an option, with Play 2.3 https detection is automatic, the header class has a built in secure() method which detects SSL and handle reverse proxied SSL as well.

https://www.playframework.com/documentation/2.3.x/api/java/play/mvc/Http.RequestHeader.html#secure()

  • How to handle redirecting insecure (http) requests to secure (https)?

I used an Action which I annotated my controllers (or base controllers) with.

public class SslEnforcerAction  extends play.mvc.Action<SslEnforced>  {


    @Override
    public Promise<SimpleResult> call(Context context) throws Throwable {

        Logger.info("Running ssl enforcer");

        String sslEnabled = Play.application().configuration().getString("app.ssl.enabled");
        if(!StringUtils.equals(sslEnabled, "true")) {
            return delegate.call(context);
        }

        Logger.info("X-Forwarded-Proto : {}", context.request().getHeader("X-Forwarded-Proto"));

        String protocolHeaders = context.request().getHeader("X-Forwarded-Proto");
        if(protocolHeaders != null) {
            String[] split = protocolHeaders.split(",");
            for(int i=0;i<split.length;i++) {
                if(split[i].trim().equalsIgnoreCase("https")) {
                    return delegate.call(context);
                }
            }
        }

        Controller.flash("success", "For your security we've switched to SSL");

        String target = "";
        if(configuration.response() == SslEnforcedResponse.SELF) {
            target = "https://" + context.request().host() + context.request().uri();
        }
        else {
            target = controllers.my.dashboard.routes.DashboardController.index().absoluteURL(true, context._requestHeader());
        }
        //if we are here then ssl is enabled and the request wasn't ssl, so reject them
        return Promise.pure(Controller.redirect(target));
    }
}



/** allow controllers to send insure requests to themselves to dashboard */
public enum SslEnforcedResponse {

    SELF,
    DASHBOARD
}


@With(SslEnforcerAction.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SslEnforced {
   SslEnforcedResponse response() default SslEnforcedResponse.SELF;
}



@SslEnforced
public class Application extends Controller {
    ....
}
like image 30
fredjam Avatar answered Oct 04 '22 22:10

fredjam


For those of us who run Play 2.5 and keep landing on this page 4 years later:

In build.sbt add:

libraryDependencies += "com.github.enalmada" %% "play-https-redirect" % "1.0.2"

Create a Filters.java file inside the app/ folder. The following example redirects and also zips the response, you can delete the Gzip bits if you need:

import com.github.enalmada.filters.HttpsRedirectFilter;
import play.filters.gzip.GzipFilter;
import play.http.HttpFilters;
import play.mvc.EssentialFilter;

import javax.inject.Inject;

public class Filters implements HttpFilters {

private EssentialFilter[] filters;

@Inject
public Filters(GzipFilter gzipFilter, HttpsRedirectFilter httpsRedirectFilter) {
    filters = new EssentialFilter[] { gzipFilter.asJava(),  httpsRedirectFilter.asJava()};
}

public EssentialFilter[] filters() {
    return filters;
}

}

In application.conf, root level, add:

httpsRedirect {
  enabled=true
  modes=["Prod", "Dev"]
  excluded=["/url-to-exclude"]
  hsts {
     enabled=true
     maxAge=31536000
     preload = true
     includeSubDomains = true
  }
}

play.filters.enabled += play.filters.https.RedirectHttpsFilter

Download play-https-redirect example project and see it working in your localhost.

like image 21
HelpfulPanda Avatar answered Oct 04 '22 20:10

HelpfulPanda