[2.0] force https ?

2,157 views
Skip to first unread message

stephanos

unread,
Dec 29, 2011, 1:00:16 PM12/29/11
to play-fr...@googlegroups.com
Maybe I just missed it, but how do I enforce HTTPS for certain pages/views?

Cheers,
Stephan

stephanos

unread,
Jan 2, 2012, 5:38:05 AM1/2/12
to play-fr...@googlegroups.com
I repeat: Is there any way to enforce a secure connection (HTTPS) for an action?

stephanos

unread,
Jan 2, 2012, 5:53:20 AM1/2/12
to play-fr...@googlegroups.com
Well, I tried this - but it obviously does not work since it cannot access the complete URL, just the URI:

def Secured[A](action: Action[A]): Action[A] = {
        action.compose {
            (request, originalAction) =>
                val url = request.uri  // > SHOULD BE URL
                if (url.startsWith("https"))
                    originalAction(request)
                else
                    Redirect(url.replaceFirst("http", "https"))
        }
    }

Any chance to grab the protocol somehow?

Allen

unread,
Jan 2, 2012, 6:07:09 AM1/2/12
to play-framework
Hi,

did you tried:
Http.Request.current().secure

Then use:
Http.Request.current().url
as url to replace the protocol and make your redirect

best,
allen


On 2 Jan., 11:53, stephanos <stephan.beh...@googlemail.com> wrote:
> Well, I tried this - but it obviously does not work since it cannot access
> the complete URL, just the URI:
>
> *def Secured[A](action: Action[A]): Action[A] = {*
> *        action.compose {*
> *            (request, originalAction) =>*
> *                val url = request.uri  // > SHOULD BE URL*
> *                if (url.startsWith("https"))*
> *                    originalAction(request)*
> *                else*
> *                    Redirect(url.replaceFirst("http", "https"))*
> *        }*
> *    }*
> *
> *

stephanos

unread,
Jan 2, 2012, 7:15:17 AM1/2/12
to play-fr...@googlegroups.com
Thanks for you reply. But are we talking about the same thing here?

I'm using play2.0-beta and Http.Request.current().secure does not exist.
However, there is a Http.Context.current().request(), but it has no 'url' either.

Allen

unread,
Jan 2, 2012, 11:41:11 AM1/2/12
to play-framework
sorry, but it was not clear in your post that your are using play2.
My comment was based on 1.2.4

best,
Allen

On 2 Jan., 13:15, stephanos <stephan.beh...@googlemail.com> wrote:
> Thanks for you reply. But are we talking about the same thing here?
>
> I'm using *play2.0-beta* and *Http.Request.current().secure* does not exist.
> However, there is a *Http.Context.current().request()*, but it has no 'url'
> either.

Guillaume Bort

unread,
Jan 2, 2012, 1:12:28 PM1/2/12
to play-fr...@googlegroups.com
Hi,

It is not possible right now but yes I agree we should be able to
access the URL scheme in some way. Please report it to the issue
tracker.

> --
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>

--
Guillaume Bort

stephanos

unread,
Jan 3, 2012, 5:55:45 AM1/3/12
to play-fr...@googlegroups.com
Hm, that sucks. Is there ANY workaround?
I just need to redirect the user if he's using a HTTP connection, and on Heroku I cannot use nginx for this...

Guillaume Bort

unread,
Jan 3, 2012, 9:51:19 AM1/3/12
to play-fr...@googlegroups.com
Well in fact as Play 2.0 doesn't support HTTPS itself, the request
will never be secured from the Play server point of view. If you are
using Heroku then their reverse proxy handle SSL, but for you the
request is not HTTPS.

It looks like the Heroku reverse proxy add the "x-forwarded-proto"
header in the request. So you can check it to determine if the
original request was https.

> --
> You received this message because you are subscribed to the Google Groups
> "play-framework" group.

> To view this discussion on the web visit
> https://groups.google.com/d/msg/play-framework/-/omkV6a5CFjcJ.

stephanos

unread,
Jan 3, 2012, 10:23:49 AM1/3/12
to play-fr...@googlegroups.com
Thanks a lot, Guillaume! I didn't even think of that.

This is what I did now (not tested yet):
    def Secured[A](action: Action[A]): Action[A] = {
        action.compose {
            (request, originalAction) =>
                request.headers.get("x-forwarded-proto") match {
                    case Some("https") => originalAction(request)
                    case _ => Redirect("https://" + request.headers.get("host").get + request.uri)
                }
        }
    }

Ben McCann

unread,
Jan 3, 2012, 5:33:20 PM1/3/12
to play-fr...@googlegroups.com
I just run nginx in front of my apps and configure it to do the SSL:

-Ben

Magnus Andersson

unread,
Apr 15, 2012, 5:49:18 AM4/15/12
to play-fr...@googlegroups.com
Hi

Is there any news on functionality to redirect all unsecure traffic to a secure URL? I'm experimenting with Heroku and right now during dev stages I am using the piggyback wildcard-SSL certificate (*.herokuapp.com). The piggyback SSL doesn't set x-forwarded-proto as far as I can see.

BR Magnus Andersson 

Bjorn Roche

unread,
Apr 15, 2012, 10:15:24 AM4/15/12
to play-fr...@googlegroups.com
On Apr 15, 2012, at 5:49 AM, Magnus Andersson wrote:

Hi

Is there any news on functionality to redirect all unsecure traffic to a secure URL? I'm experimenting with Heroku and right now during dev stages I am using the piggyback wildcard-SSL certificate (*.herokuapp.com). The piggyback SSL doesn't set x-forwarded-proto as far as I can see.

Heroku piggyback most definitely does set x-forwarded-proto. I use this with restlet for my http/https redirects.


BR Magnus Andersson 

Den torsdagen den 29:e december 2011 kl. 19:00:16 UTC+1 skrev stephanos:
Maybe I just missed it, but how do I enforce HTTPS for certain pages/views?

Cheers,
Stephan

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/PcgcqPUEBacJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

-----------------------------
Bjorn Roche
Audio Collaboration




Arun Ramakrishnan

unread,
May 14, 2012, 5:25:00 PM5/14/12
to play-fr...@googlegroups.com
I am using heroku and I am using their new ssl:endpoint addon. I am able to see the x-forwarded-proto in the headers. i.e in the controller I am able to do

val secure = request.headers.get("x-forwarded-proto") match { case None => false; case Some(protos) => protos.contains("https") }

The problem is on the heroku side, there is no way to enforce only https connections. So, my question is on the play side ( Play 2.0 )

1) how do i restrict only https connections in play. I am sure this is doable, but haven't read all the docs, so am not sure about the canonical way to achieve this without having to specify in every Action.

2) Is it possible to redirect all http connections to https ?

ps: I am surprised by the lack of features on heroku. like there is no auto load balancing based on a configured health check. It seems primitive to me one has to calculate and provision and take down the no of dynos and all that. Lack of ability to specify the protocol such as only https and redirects accordingly. Will  have to investigate AWS EBS and Cloud formation for a better solution later.

thanks
Arun

James Ward

unread,
May 18, 2012, 1:39:41 PM5/18/12
to play-fr...@googlegroups.com
Here is a Scala trait I wrote to enforce https on Heroku:

package controllers

import play.mvc.{Before, Controller}

trait HttpsEnforcer {
  self: Controller =>

  // if this is a forwarded request then check to see if the original request was https
  //   if so then set the request.secure flag to true
  //   if not then redirect to https
  @Before def enforceHttps {
    if (request.headers.get("x-forwarded-proto") != null) {
      if (request.headers.get("x-forwarded-proto").values.indexOf("https") == 0) {
        request.secure = true
      }
      else {
        Redirect("https://" + request.host + request.url);
      }
    }
  }

}


BTW: You can do autoscaling based on the Heroku APIs or third party tools like:


Hope that helps.

-James


On Monday, May 14, 2012 3:25:00 PM UTC-6, RottenBits wrote:
I am using heroku and I am using their new ssl:endpoint addon. I am able to see the x-forwarded-proto in the headers. i.e in the controller I am able to do

val secure = request.headers.get("x-forwarded-proto") match { case None => false; case Some(protos) => protos.contains("https") }

The problem is on the heroku side, there is no way to enforce only https connections. So, my question is on the play side ( Play 2.0 )

1) how do i restrict only https connections in play. I am sure this is doable, but haven't read all the docs, so am not sure about the canonical way to achieve this without having to specify in every Action.

2) Is it possible to redirect all http connections to https ?

ps: I am surprised by the lack of features on heroku. like there is no auto load balancing based on a configured health check. It seems primitive to me one has to calculate and provision and take down the no of dynos and all that. Lack of ability to specify the protocol such as only https and redirects accordingly. Will  have to investigate AWS EBS and Cloud formation for a better solution later.

thanks
Arun


On Sun, Apr 15, 2012 at 7:15 AM, Bjorn Roche <bj...@xowave.com> wrote:
On Apr 15, 2012, at 5:49 AM, Magnus Andersson wrote:

Hi

Is there any news on functionality to redirect all unsecure traffic to a secure URL? I'm experimenting with Heroku and right now during dev stages I am using the piggyback wildcard-SSL certificate (*.herokuapp.com). The piggyback SSL doesn't set x-forwarded-proto as far as I can see.

Heroku piggyback most definitely does set x-forwarded-proto. I use this with restlet for my http/https redirects.

BR Magnus Andersson 

Den torsdagen den 29:e december 2011 kl. 19:00:16 UTC+1 skrev stephanos:
Maybe I just missed it, but how do I enforce HTTPS for certain pages/views?

Cheers,
Stephan

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/PcgcqPUEBacJ.
To post to this group, send email to play-framework@googlegroups.com.
To unsubscribe from this group, send email to play-framework+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

-----------------------------
Bjorn Roche
Audio Collaboration




--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-framework@googlegroups.com.
To unsubscribe from this group, send email to play-framework+unsubscribe@googlegroups.com.

Alex Hanschke

unread,
Jul 12, 2012, 4:48:57 PM7/12/12
to play-fr...@googlegroups.com
I know, I'm late to the party, but is there also a Java solution and, possibly missing something, where do I find the secure flag (2.0.2-java)?

Thanks,
Alex

Magnus Andersson

unread,
Jul 12, 2012, 5:11:51 PM7/12/12
to play-fr...@googlegroups.com
Hi 

I only have time for a quick answer but hopefully I can point you in the right direction:

You should be able to get the headers in an Controller by using something like request().headers.get("x-forward-proto") and see if the value exists and if it is https like in the earlier example.


You'll have to test your way forward from there or hope someone writes a code snippet here.

computerpunc

unread,
Jul 24, 2012, 11:05:22 AM7/24/12
to play-fr...@googlegroups.com
The browser (at least a modern one) can also enforce HTTPS (in addition to server redirects) by replying with the response header Strict-Transport-Security as can be seen in the following code:

def ActionOverHttps(f: Request[AnyContent] => Result): Action[AnyContent] = Action { request =>
    request.headers.get("x-forwarded-proto") match {
      case Some(header)=> if ("https"==header) {
        f(request) match {
          case res:PlainResult=> res.withHeaders(("Strict-Transport-Security", "max-age=31536000")) // or "max-age=31536000; includeSubDomains"
          case res:Result=> res
        }
      } else Redirect("https://"+request.host+request.uri)
      case None=> f(request)
    }
  }

computerpunc.

Aurélien

unread,
Sep 9, 2012, 10:22:05 AM9/9/12
to play-fr...@googlegroups.com
Hi

To apply this to all your controllers, you can create an abstract controller with the annotation @With(ForceHttps.class) that extends the default Play Controller. Then you make all your controllers extends this abstract controller.

I don't know if it is "the right way" to do this, but it works.

Aurélien

Le dimanche 9 septembre 2012 13:08:49 UTC+2, Arthur Clement a écrit :
Hi

I have written the following (which is basically an equivalent of James's trait) in Java :

public class ForceHttps extends Action.Simple{

private static String SSL_HEADER_CLOUD_FOUNDRY = "SSLSESSIONID";
@Override
public Result call(Context ctx) throws Throwable {

if(!isHttpsRequest(ctx.request())){
return redirect("https://" + ctx.request().host() + ctx.request().uri());
}
return delegate.call(ctx);
}
private boolean isHttpsRequest(Request request){
 
if(Play.isDev()){
return true;
}
if(StringUtils.isNotEmpty(request.getHeader(SSL_HEADER_CLOUD_FOUNDRY))){
return true;
}
return false;
}
}

You can then use that on your controllers with the "With" annotation :

@With(ForceHttps.class)
public class Application extends Controller {
...
}

I haven't found a way to apply this to all my controllers automatically though, so it's not perfect but it does the job for me for the moment.
Message has been deleted

Dimitry Kudryavtsev

unread,
May 14, 2014, 2:20:19 AM5/14/14
to play-fr...@googlegroups.com
This will work with Play 2.2 and AWS Load Balancer

import com.typesafe.scalalogging.slf4j.Logging
import play.api.mvc._
import scala.concurrent.Future
import play.mvc.Results._
import play.api.libs.concurrent.Execution.Implicits.defaultContext

object HTTPSRedirectFilter extends Filter with Logging {

    def apply(nextFilter: (RequestHeader) => Future[SimpleResult])(requestHeader: RequestHeader): Future[SimpleResult] = {
        //play uses lower case headers.
        requestHeader.headers.get("x-forwarded-proto") match {
            case Some(header) => {
                if ("https" == header) {
                    nextFilter(requestHeader).map { result =>
                        result.withHeaders(("Strict-Transport-Security", "max-age=31536000"))
                    }
                } else {
                    Future.successful(Results.Redirect("https://" + requestHeader.host + requestHeader.uri, 301))
                }
            }
            case None => nextFilter(requestHeader)
        }
    }
}


Reply all
Reply to author
Forward
0 new messages