Disable http in finatra app - scala

I am deploying a Finatra app to Heroku. Thanks to Twitter guys together with Heroku this is a very easy task. The thing is that Heorku gives you https out of the box (if im trying to reach my service through https it just works). Nevertheless it also works with http requests. Is there any way to disable http requests and leave only https?
Thanks

You can disable the http request by override the defaultHttpPort value to an empty String (and do not pass a value for the -http.port flag)
import com.twitter.finagle.Http
import com.twitter.finatra.http.HttpServer
import com.twitter.finatra.http.routing.HttpRouter
object ExampleHttpsServerMain extends ExampleHttpsServer
class ExampleHttpsServer
extends HttpServer
with Tls {
override val defaultHttpPort: String = "" // disable the default HTTP port
override val defaultHttpsPort: String = ":443"
override def configureHttp(router: HttpRouter): Unit = {
router
.add[ExampleController]
}
}

Related

Set Finatra HTTP request timeout

Is it possible to set HTTP request-response timeout in a Finatra server?
The http controller callback typically returns a Future, that once resolved the response is transmitted. I would like to define, within Finatra, how long the server should wait before returning a 500 or 400 response.
You can extend the HttpServer and define your own timeout
trait CustomServer extends HttpServer with Tls {
then you overwrite the configureHttpServer method and you define timeout, requests sites and other attributes
override def configureHttpServer(server: Http.Server): Http.Server = {
server.withAdmissionControl.concurrencyLimit(maxConcurrentRequests = 2000, maxWaiters = 0)
.withResponseClassifier(HttpResponseClassifier.ServerErrorsAsFailures)
.withMaxRequestSize(StorageUnit.fromMegabytes(200))
.withRequestTimeout(50.seconds)
}
I think, you are looking for Future.within

Using Proxy Authorization Header with ScalajHTTP

I'm getting a 407 error using scalajHTTP. I read through the repository and it seems like I should be able to pass the basic auth credentials as a base64 encoded value. I've also tried using the helper method described in the GitHub issues .proxyAuth but that is no longer part of HTTPRequest in ScalaJ according to error messages (as well as it not being in the documentation)
Any ideas? My endpoint URL is HTTPS as well as my proxy (for additional context)
val proxyHost= s"https://$forwardProxy"
val requestForward = Http(url).postData(redactedSecret)
.option(HttpOptions.allowUnsafeSSL)
.headers(("Content-Type", "application/json"), ("Proxy-Authorization", s"Basic $proxyAuth"))
.proxy(proxyHost, 8080).asString
val responseForward: HttpResponse[String] = requestForward
This issued posted in Github but still not resolved, https://github.com/scalaj/scalaj-http/issues/87
I found a solution to this problem. I researched around and after trying http client libraries, I kept getting 407 errors even though they all support proxy auth. Anyway, I ended up having to do the following.
add
import java.net.{Authenticator,PasswordAuthentication}
and the modified code body that I previously above looks like:
val requestForward: HttpRequest = Http(url).postData(data)
.header("Content-Type", "application/json")
.proxy(proxyHost, 8080)
.option(HttpOptions.allowUnsafeSSL)
Authenticator.setDefault(new Authenticator() {
override def getPasswordAuthentication(): PasswordAuthentication = {
new PasswordAuthentication( s"$username", s"$password".toCharArray())
}
})
So as you can see I removed the header from the original request object and instead overrode the credentials. Make sure you do this before you call on the response object.

Akka http redirect request to https with FQDN

Using Akka http, how can I redirect any request on http to https and, if necessary, add the full domain to the host name?
I was looking at the Directives.redirect function but it seems to be protocol unaware...
[Edit]: Typo in title, "Akke" -> "Akka".
For future reference, I used Http().bindAndHandle and constructed the route as follows:
lazy val httpsRedirectRoute: Route = extractUri(redirectHttps)
def redirectHttps(uri: Uri): Route = redirect(toHttps(uri), StatusCodes.PermanentRedirect)
def toHttps(uri: Uri): Uri = uri.copy(scheme = "https")

Restrict access to specific IP in Play Framework (Scala)

How can I restrict access to list of IP in Play Framework using Scala?
I'm using Play Framework 2.2.4
I found solution for Java:
http://feadro.com/simple-ip-access-list-for-play-2-1-with-java/
How should I do it in Scala?
Stick the IPs you want to restrict to in the application.conf.
myapp.ipwhitelist = ["192.168.1.1", ...]
Then make a global filter which is applied to every incoming request, something like:
import scala.collection.JavaConverters._
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.iteratee.Iteratee
import play.api.Play.current
import play.api.mvc._
object IPFilter extends EssentialFilter {
def apply(nextFilter: EssentialAction) = new EssentialAction {
def apply(requestHeader: RequestHeader) = {
// read the IPs as a Scala Seq (converting from the Java list)
val ips: Seq[String] = current.configuration.getStringList("myapp.ipwhitelist")
.map(_.asScala).getOrElse(Seq.empty)
// Check we've got an allowed IP, otherwise ignore the
// request body and immediately return a forbidden.
if (ips.contains(requestHeader.remoteAddress)) nextFilter(requestHeader)
else Iteratee.ignore[Array[Byte]]
.map(_ => Results.Forbidden(s"Bad IP! ${requestHeader.remoteAddress}"))
}
}
}
Then enable that in your application Global object:
object Global extends WithFilters(IPFilter) with GlobalSettings
If you want more flexibility you can use the same logic but with Action composition instead of a global filter.
I think that for production HTTP environment requiring more than simple configuration (public, accepting any HTTP request), an HTTP frontend service should be used to dispatch appropriately request to Play.
As for Can I (DNS) map one subdomain to multiple Play Framework entry points , there is advantage of using a service such Apache, Nginx or Varnish to configure HTTP ACL (Access Control List). For example in Varnish:
acl my-acl {
"an-authorized-host";
"1.2.3.4";
}
# Then ...
if (!client.ip ~ my-acl) {
error 405 "Not allowed.";
}

Play Framework 2.1: Scala: how to get the whole base url (including protocol)?

Currently I am able to get the host from the request, which includes domain and optional port. Unfortunately, it does not include the protocol (http vs https), so I cannot create absolute urls to the site itself.
object Application extends Controller {
def index = Action { request =>
Ok(request.host + "/some/path") // Returns "localhost:9000/some/path"
}
}
Is there any way to get the protocol from the request object?
Actually there's a simple way to do it using Call class that reverse routers use to achieve similar thing.
Given that you are within the scope of implicit request, you can do something like this:
new Call(request.method, input.request).absoluteURL()
and it will provide you with the complete url (protocol, host, route and parameters).
In Play 2.3 and later you can use the secure property of the Request class.
I don't think there is.
Play Framework 2.0 itself does not support https, see: play-framework [2.0] HTTPS
The implementation of absoluteURL method of the Call class of the Play Framework 2.0 does not suggest it.
A workaround is to use a protocol relative urls using //domain.com/path.
This however does not help you with links in email. In that case you could put the protocol in the application.conf. In most cases the difference is made because production supports https and development does not.
I have yet to find a situation where the above workarounds do not work.
Actually your portnumber will give you if it's http or https.
Start your Play server with https support JAVA_OPTS=-Dhttps.port=9001 play start
Here's a code snippet (you can make the validation more stable with a regex, take the https port number from properties ...)
def path = Action { request =>
val path =
if(request.host.contains(":9000"))
"http://" + request.host + "/some/path"
else
"https://" + request.host + "/some/path"
Ok(path)
}
The code will return
http://ServerIp:9000/some/path if it's thru http
https://ServerIp:9001/some/path if it's thru https
My solution was to pass the beginning of the url as an additional parameter from javascript.
The application.conf solution does not work for me, because the same application is accessible on http and https but from different subnet and domain.