How to disable CSRF for a specific SIRD route in play? - scala

I can see from this play documentation,+nocsrf can be added to each route that doesn't need a csrf filter.
Example:
+ nocsrf
POST /api/new controllers.Api.newThing
But the same +nocsrf is not working for SIRD based route like the example below
-> /api api.ApiRouter
ApiRouter.scala:
package api
import javax.inject.Inject
import play.api.mvc._
import play.api.routing.Router.Routes
import play.api.routing.SimpleRouter
import play.api.routing.sird._
class ApiRouter #Inject() (controller: ApiController) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/") => controller.index
}
}
SIRD Play Documentaion
How can SIRD route in play accomplish the +nocsrf utility given by play or implement one?

Related

Unable to resolve mock[....] in playframework 2.6.17

I want to mock ReactiveMongoAPI and for this i am writing the below code,
package controllers
import org.scalatest.mockito.MockitoSugar
import org.scalatestplus.play._
import org.scalatestplus.play.guice._
import play.api.test.Helpers._
import play.api.test._
import play.modules.reactivemongo.ReactiveMongoApi
/**
* Add your spec here.
* You can mock out a whole application including requests, plugins etc.
*
* For more information, see https://www.playframework.com/documentation/latest/ScalaTestingWithScalaTest
*/
class HomeControllerSpec extends PlaySpec with GuiceOneAppPerTest with Injecting with MockitoSugar {
val reactiveMongoApi: mock[ReactiveMongoApi]
"HomeController GET" should {
"render the index page from a new instance of controller" in {
val controller = new HomeController(stubControllerComponents(), reactiveMongoApi)
val home = controller.index().apply(FakeRequest(GET, "/"))
It gives me the error that it cannot resolve the mock[...].
Is there any way to resolve this ?
I bet you want to do as follows:
val reactiveMongoApi: ReactiveMongoApi = mock[ReactiveMongoApi]

how to mock external WS API calls in Scala Play framework

I have an existing Scala play application which has a REST API that calls another external REST API. I want to mock the external Web service returning fake JSON data for internal tests. Based on example from: https://www.playframework.com/documentation/2.6.x/ScalaTestingWebServiceClients
I followed example exactly as in Documentation and I'm getting compiler errors due to deprecated class Action.
import play.core.server.Server
import play.api.routing.sird._
import play.api.mvc._
import play.api.libs.json._
import play.api.test._
import scala.concurrent.Await
import scala.concurrent.duration._
import org.specs2.mutable.Specification
import product.services.market.common.GitHubClient
class GitHubClientSpec extends Specification {
import scala.concurrent.ExecutionContext.Implicits.global
"GitHubClient" should {
"get all repositories" in {
Server.withRouter() {
case GET(p"/repositories") => Action {
Results.Ok(Json.arr(Json.obj("full_name" -> "octocat/Hello-World")))
}
} { implicit port =>
WsTestClient.withClient { client =>
val result = Await.result(
new GitHubClient(client, "").repositories(), 10.seconds)
result must_== Seq("octocat/Hello-World")
}
}
}
}
}
object Action in package mvc is deprecated: Inject an ActionBuilder
(e.g. DefaultActionBuilder) or extend
BaseController/AbstractController/InjectedController
And this is the primary example from latest official docs which in fact contains a compile time error, given this example doesn't work how should be the proper way to easily mock an external API using Scala Play?
You may change your example to:
Server.withRouterFromComponents() { cs => {
case GET(p"/repositories") => cs.defaultActionBuilder {
Results.Ok(Json.arr(Json.obj("full_name" -> "octocat/Hello-World")))
}
}
} { implicit port =>
WsTestClient.withClient { client =>
val result = Await.result(
new GitHubClient(client, "").repositories(), 10.seconds)
result should be(Seq("octocat/Hello-World"))
}
}
To be honest, I'm not 100% sure if this is the nicest way. However I have submitted a PR to the play framework so you might watch that space for comments from the makers.
If you're using standalone version of play-ws you can use this library https://github.com/f100ded/play-fake-ws-standalone like this
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import org.f100ded.play.fakews._
import org.scalatest._
import play.api.libs.ws.JsonBodyWritables._
import scala.concurrent.duration.Duration
import scala.concurrent._
import scala.language.reflectiveCalls
/**
* Tests MyApi HTTP client implementation
*/
class MyApiClientSpec extends AsyncFlatSpec with BeforeAndAfterAll with Matchers {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
import system.dispatcher
behavior of "MyApiClient"
it should "put access token to Authorization header" in {
val accessToken = "fake_access_token"
val ws = StandaloneFakeWSClient {
case request # GET(url"http://host/v1/foo/$id") =>
// this is here just to demonstrate how you can use URL extractor
id shouldBe "1"
// verify access token
request.headers should contain ("Authorization" -> Seq(s"Bearer $accessToken"))
Ok(FakeAnswers.foo)
}
val api = new MyApiClient(ws, baseUrl = "http://host/", accessToken = accessToken)
api.getFoo(1).map(_ => succeed)
}
// ... more tests
override def afterAll(): Unit = {
Await.result(system.terminate(), Duration.Inf)
}
}

Implementing Akka in Play Framework 2.4 for Scala

I am trying to replicate the basic example proposed in the Integrating with Akka, Play 2.4 for Scala doc. But I have difficulties in placing the final pieces together...
I have defined the actor (see paragraph Writing actors) at app/actors/HelloActor.scala with the following code:
package actors
import akka.actor._
object HelloActor {
def props = Props[HelloActor]
case class SayHello(name: String)
}
class HelloActor extends Actor {
import HelloActor._
def receive = {
case SayHello(name: String) =>
sender() ! "Hello, " + name
}
}
Then (see Creating and using actors) I suppose I should create a controller at app/controllers/Hello.scala with something like:
package controllers
import play.api.mvc._
import akka.actor._
import javax.inject._
import actors.HelloActor
#Singleton
class Hello #Inject() (system: ActorSystem) extends Controller {
val helloActor = system.actorOf(HelloActor.props, "hello-actor")
...
}
The question: where and how I utilize the code in the following paragraph Asking things of actors to have a working solution? I have tried to add it to the above Hello.scala controller but without success.
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.duration._
import akka.pattern.ask
implicit val timeout = 5.seconds
def sayHello(name: String) = Action.async {
(helloActor ? SayHello(name)).mapTo[String].map { message =>
Ok(message)
}
}
Found the solution, I had some problems with defining the implicit timeout, this is the working controller:
package controllers
import play.api.mvc._
import akka.actor._
import javax.inject._
import actors.HelloActor
import actors.HelloActor.SayHello
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.duration._
import akka.pattern.ask
import akka.util.Timeout
#Singleton
class Hello #Inject() (system: ActorSystem) extends Controller {
val helloActor = system.actorOf(HelloActor.props, "hello-actor")
implicit val timeout: Timeout = 5.seconds
def sayHello(name: String) = Action.async {
(helloActor ? SayHello(name)).mapTo[String].map { message ⇒
Ok(message)
}
}
}
Plus I added the following route in app/conf/routes:
# Actor test
GET /hello/:name controllers.Hello.sayHello(name)

Scala Play Framework, How to handle unknown url

Hey i am working on scala play framework, what i need to do is, when someone enter some random(unknown) url, that is not defined in routes file, they need to be routed to the some another not found page, with 404 page not found http header response. instead of displaying the whole routes file as error.
using sbt : sbt launcher version 0.13.8
using scala : scalaVersion := "2.11.6"
using play framework 2x
You can override these in your Global.scala / Global.java file. For Java the could look similar to this:
public F.Promise<Result> onHandlerNotFound(Http.RequestHeader request) {
return F.Promise.<Result>pure(notFound(
Messages.get("error.routeNotFound")
));
}
I guess you are looking for Scala code for Global.scala to display your own 404 Page.
Global.scala should be under your /views folder. And override the onHandlerNotFound method in it, like this:
override def onHandlerNotFound(request: RequestHeader) = {
var cookies: Seq[Cookie] = Seq()
Future.successful(NotFound("hello world!!!!").withCookies(cookies:_*))
}
The NotFound is a PageCtrl.Status method which may need a import at the top of Global.scala. You can try using NotFound("Hello World") to see what's happening. It will display pure text "hello world" instead of default 404 page.
So the final code should be like
override def onHandlerNotFound(request: RequestHeader) = {
var cookies: Seq[Cookie] = Seq()
Future.successful(NotFound(view.html.yourOwn404PageHtml).withCookies(cookies:_*))
}
The withCookies is just used to create a Result object. You can use other method belongs to NotFound().
In Play2.6 you can handle unknown/broken API call buy using below code.
import javax.inject._
import models.Response
import play.api._
import play.api.http.DefaultHttpErrorHandler
import play.api.libs.json.Json
import play.api.mvc.Results._
import play.api.mvc._
import play.api.routing.Router
import _root_.controllers.JSONHelper.ResponseWrites
import scala.concurrent._
class ErrorHandler #Inject()(env: Environment,
config: Configuration,
sourceMapper: OptionalSourceMapper,
router: Provider[Router])
extends DefaultHttpErrorHandler(env, config, sourceMapper, router) {
override protected def onNotFound(request: RequestHeader, message: String): Future[Result] = {
Future.successful(
NotFound(Json.toJson(Response(isSuccess = false,"Resource Not Found", ("", ""))))
)
}
}
You can use customized ErrorHandler to return a json format error message, status result with status code or blank page instead.
package errors
import play.api.http.HttpErrorHandler
import play.api.mvc._
import play.api.mvc.Results._
import scala.concurrent._
import javax.inject.Singleton
#Singleton
class MyErrorHandler extends HttpErrorHandler {
def onClientError(request: RequestHeader, statusCode: Int, message: String) = {
Future.successful(
Ok() // Replace with your error handle here
)
}
def onServerError(request: RequestHeader, exception: Throwable) = ???
}
In application.conf
play.http.errorHandler = "errors.MyErrorHandler"
You can find detail on playframework document.
https://www.playframework.com/documentation/2.6.x/ScalaErrorHandling

Add a cookie in a Play Framework 2.x filter?

Is it possible to add a cookie in the Play Framework's doFilter method in the Global class?
I've tried:
override def doFilter(action: EssentialAction): EssentialAction = EssentialAction { request =>
if (request.queryString.contains("q")) {
action.apply(request).map(_.withCookies(
Cookie("q", request.queryString.get("q").get(0), 3600)
))
}
}
but the cookie doesn't get sent to the browser.
I'm using Playframework 2.2 and use a similar thing:
import play.api.mvc._
import play.api._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object ResponseFilter extends Filter {
def apply(next: (RequestHeader) => Future[SimpleResult])(rh: RequestHeader) = {
next(rh).map(_.withHeaders("Access-Control-Allow-Origin" -> "*").as("application/json; charset=utf-8"))
}
}
And my Global object looks like this:
import play.api._
import play.api.mvc._
import service.ResponseFilter
object Global extends WithFilters(ResponseFilter) with GlobalSettings
This works fine for me. So I suppose you could replace the _.withHeaders(...) part with the _.withCookies(...) part and that would work for you as well.
Please note that things are a bit different in earlier versions of playframework