herokuの無料SSL(https://?.herokuapp.com)を使ってHTTPS通信を強制する方法

まず、ローカルで起動した際にHTTPS通信を強制してみます。
コントローラとしてApplicationクラスのみを使っているとして、Applicationクラスに次のメソッドを追加します。

    @Before
    static void before() {
        if(!request.secure) {
            int port = Integer.parseInt(Play.configuration.getProperty("https.port", "443"));
            redirect("https://" + request.domain + (port == 443 ? "" : ":" + port) + request.url);
        }
    }

それと、application.conf にたとえば次のように port の設定をして、証明書を用意しておきます。
http.port=8880
https.port=4443
これで起動して http://localhost:8880 にアクセスすれば、強制的に https://localhost:4443 にリダイレクトされるようになります。

次に heroku で同じようにしたいところですが、このままではうまくいきません。
heroku では https.port の設定や証明書がなくても、普通に play アプリを push すれば https のURLが使えるようになります。
heroku 内部で複数のサーバが連携しているためです。
それに対応するために、上で追加した before メソッドを次のように修正します。

    @Before
    static void before() {
        Header proto = request.headers.get("x-forwarded-proto");
        if(proto != null) {
            if("http".equals(proto.value())) redirect("https://" + request.domain + request.url);
            request.secure = true;
        } else if(!request.secure) {
            int port = Integer.parseInt(Play.configuration.getProperty("https.port", "443"));
            redirect("https://" + request.domain + (port == 443 ? "" : ":" + port) + request.url);
        }
    }

heroku 上のアプリにアクセスした際、requestヘッダには x-forwarded-proto がセットされ、http通信の場合には http、https通信の場合にはhttps が値としてセットされています。
普通にローカルで動かしている場合、これらはセットされません。
なので、ヘッダがあるかどうかで場合分けをして、ヘッダがない場合は上で最初に書いた処理を動かします。
ヘッダがあり、かつ、値が http の場合は https のURLにリダイレクトします。
最後に、値が https でも request.secure が false のままになっているので、true に設定します。
これで、play の redirect メソッド等を使用した場合でも https を保ったままにすることができます。