I have request.headers.get("Authorization") but I still don't receive anything other than none
def test = Action { request =>
Ok("Here " + request.headers.get("Authorization") + " there")
}
I would like to be able to parse the basic auth, but since I currently don't even receive it its kind of a mute point.
Try doing request.headers.getHeaders() (which produces a map) and loop through the map, printing all Key,Value pairs to see if it is truly missing.
Related
I'm writing a load test for an api and want to create a feeder which generates random values to inject into the body of the POST request. I initially tried copying the random email example from the documentation and adding additional fields to the generated map, but when that didn't work I went down to a single field, basically copying the documentation; however, even this doesn't work for some reason. There are a bunch of solutions on here that use this syntax as well, but something about the way I'm doing is causing the fields I try to inject into the body to be null when the request is made.
Current Code:
val userFeeder: Iterator[Map[String, Unit]] =
Iterator.continually(Map("userName" -> ("user_" + Random.alphanumeric.take(15).mkString)))
var scn: ScenarioBuilder = scenario("GENERATE USER")
.feed(userFeeder)
.exec(
http("CREATE USER")
.post(userBaseUrl)
.headers(userHeaders)
.body(StringBody("userName: ${userName}")))
setUp(
scn.inject(atOnceUsers(1))
)
Ideally I'd like to be able to expand the feeder to include multiple values, i.e.
val userFeeder: Iterator[Map[String, Unit]] =
Iterator.continually(Map("userName" -> ("user_" + Random.alphanumeric.take(15).mkString),
"userEmail" -> (Random.alphanumeric.take(15).mkString) + "#random.edu"),
"address" -> Random.alphanumeric.take(15).mkString)))
and so on, but I'm a little stumped as to why my current code doesn't even work, as it seems to follow the documentation example pretty faithfully. The values are always null in my requests despite trying a few different strategies.
Log output
body:StringChunksRequestBody{contentType='application/json', charset=UTF-8, content=userName: ()}
Figured it out. Turns out that even though Feeder is a wrapper for Iterator, the proper way to do what I want is to declare it like this:
val userFeeder: Feeder[Any] =
Iterator.continually(Map("userName" -> ("user_" + Random.alphanumeric.take(15).mkString),
"userEmail" -> (Random.alphanumeric.take(15).mkString) + "#random.edu"),
"address" -> Random.alphanumeric.take(15).mkString)))
I'm something of a beginner with the Play Framework (2.5 and Scala in this case) - and I'm trying to learn by building a bot for Facebook messenger. However I've gotten stuck trying to verify the signature of the messages.
I've followed the Facebook documentation and created a webhook. Which handles POST requests usinggetRawMessages (see code below). This then tries to verify that the request is signed by Facebook using the verifyPayload function. However I can't seem to get the computed and the actual hashes to match up.
I've taken a lead from looking at this question: How to verify Instagram real-time API x-hub-signature in Java? which seems to be doing pretty much what I want, but for the Instagram equivalent. But I still can't seem to get it right.
val secret = "<facebooks secret token>"
def getRawMessages = Action (parse.raw) {
request =>
val xHubSignatureOption = request.headers.get("X-Hub-Signature")
try {
for {
signature <- xHubSignatureOption
rawBodyAsBytes <- request.body.asBytes()
} yield {
val rawBody = rawBodyAsBytes.toArray[Byte]
val incomingHash = signature.split("=").last
val verified = verifyPayload(rawBody, secret, incomingHash)
Logger.info(s"Was verified? $verified")
}
Ok("Test")
}
catch {
case _ => Ok("Test")
}
}
val HMAC_SHA1_ALGORITHM = "HmacSHA1"
def verifyPayload(payloadBytes: Array[Byte], secret: String, expected: String): Boolean = {
val secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HMAC_SHA1_ALGORITHM)
val mac = Mac.getInstance(HMAC_SHA1_ALGORITHM)
mac.init(secretKeySpec)
val result = mac.doFinal(payloadBytes)
val computedHash = Hex.encodeHex(result).mkString
Logger.info(s"Computed hash: $computedHash")
computedHash == expected
}
The Facebook webhook docs state:
The HTTP request will contain an X-Hub-Signature header which contains
the SHA1 signature of the request payload, using the app secret as the
key, and prefixed with sha1=. Your callback endpoint can verify this
signature to validate the integrity and origin of the payload
Please note that the calculation is made on the escaped unicode
version of the payload, with lower case hex digits. If you just
calculate against the decoded bytes, you will end up with a different
signature. For example, the string äöå should be escaped to
\u00e4\u00f6\u00e5.
I'm guessing that what I'm missing is getting the payload properly escaped to unicode, but I can't seem to find a way to do it. And the answer in the referenced question also appeared to just get the byte array without doing anything more with it (jsonRawBytes = jsonRaw.asBytes();).
Any help with how to proceed would be much appreciated.
Turns out I was using the wrong secret all along. Should anyone else make the same mistake, please note that it "App Secret" that is available on the application dashboard that you want. See the screenshot below.
So i have asked about this before and have changed a lot of code around.
Spray Routing Doesn't match anything
Now I am executing my functions that return HTTPresponses insided detach() blocks so that i dont block. These then are completed and return to the client, but I still can't seem to get my routing to work.
In my tests, a request to a single slash works fine, but anything else, such as this create user path shown below fails. I can't seem to figure out why, and spray routing uses so many constructs I'm having a hard time figuring out how the system works well enough to find out whats happening.
I tried inserting logRequest blocks around certain paths thinking that might show me whats happening, but none of them seem to get hit. Any help would be greatly appreciated.
val route: Route = {
host("fakebook.com", "www.fakebook.com") {
pathSingleSlash {
complete("pong")
} ~
pathPrefix("users") { req =>
path("newuser") {
put {
detach() {
complete(genericPut(CreateUser(req.request)))
}
}
} ~
... rest of routing
And here is what my scalatests look like, the simple Put passes, but the put with newuser doesn't
val createUserSuccessRequest = Put(Uri("http://www.fakebook.com/users/newuser") withQuery(F_User.lastNameString -> "Doe", F_User.firstNameString -> "John", F_User.bioString -> "i like foobar",
F_User.ageString -> "42", F_User.dobString -> dateFormatter.format(new Date(1970 - 1900, 5, 7))))
"The FakeBook route" when {
"When sending a single slash request" should {
"respond with a simple pong" in {
Get() ~> logRequestResponse("plain get final request and response")(sealRoute(route)) ~> check {
assert(responseAs[String] == "pong")
}
}
}
"Running route to create a user with PUT" should {
"forward a message to the backbone to create a new user" in {
createUserSuccessRequest ~> logRequest("create user final request and response"){sealRoute(route)} ~> check {
expectMsg(CreateUser(createUserSuccessRequest))
}
}
}
}
For anyone else trying to solve this issue:
a lot of these directives actually DONT extract anything, so having the lambda inputs i have like req => and req2 => will not work.
It turns out, spray routing is designed so that you never have to touch the RequestContext as I have done with my functions (which is why I try to access it). They extract only the useful data. Rather than do things as I should and change my function signatures, i am going to (for now) do a hotfix that has worked.
if you absolutely must have the requestcontext, so long as you don't break it somehow, you can extract it by making your own extraction directive like so
val extractRequestContext = extract(x => x) and wrap your code in that
I did this
path("somepath") {
detach() {
extractRequestContext { request => complete(someFunc(request)) }
}
}
In the future I should learn to use the DSL more correctly and extract what I need from the request context using directives and pass THOSE to the functions
is there a way to return a value inside Action controller.
I have a method in my User model which returns the number of friends of a given user.
def nrOfFriends(current_user: Long): Int = {
DB.withConnection{ implicit connection =>
var nr: Int = SQL("select count(*) from friend where user_id_1=" + current_user + " or user_id_2=" + current_user).as(scalar[Int].single)
nr
}
}
In my controller, I just want to return the value from the model
def freunde() = IsAuthenticated { username => _ =>
User.findByUsername(username).map { user =>
var nr: Int = Friend.nrOfFriends(user.id.get)
Ok(""+nr)
}.getOrElse(Forbidden)
}
But in the way that is written, it will print "empty string " concatenated with the number
If I replace Ok(""+nr) with Ok(nr) I receive the following error:
"Cannot write an instance of Int to HTTP response. Try to define a Writeable[Int]"
I need for my action to return a value so that I can pass the value from the action to header.views.html inside the navbar something like that
#Freund.freunde Friends
if you want your response to just be the value of nr you can simply call nr.toString:
def freunde() = IsAuthenticated { username => _ =>
User.findByUsername(username).map { user =>
var nr: Int = Friend.nrOfFriends(user.id.get)
Ok(nr.toString)
}.getOrElse(Forbidden)
}
The error you're getting makes reference to the fact that Int doesn't have an implicit Writeable[Int] in scope. So play doesn't know how display an Int in an http response.
You can add make Int writeable by putting this in scope:
implicit val intWriteable = play.api.http.Writeable[Int](_.toString.getBytes, None)
Then you would be able to just say:
Ok(nr)
without error.
However, it sounds like you just want the result of nrOfFriends inside an unrelated template. If that's the case, you should be using an Action at all. Instead just call your model function inside the template where you need the data.
#User.nrOfFriends(user.id) Friends
Of course you would need to pass in the user to the template as well.
You didn't post a full sample of all the code involved in what you are trying to accomplish so I think this is the best I can do for now. Perhaps try posting the base template that your <a> is in.
An important point is that Actions are for production an HTTP response, and not just plain data internally to the application.
An action of a controller handles a request and generates a result to be sent to the client. In other words, an action returns a play.api.mvc.Result value, representing the HTTP response to send to the web client. In your example Ok constructs a 200 OK response. The body of the response must be one of the predefined types, including text/plain, json, and html. The number of a friends is an integer and is NOT an acceptable type of the body. Therefore, a simple way to address this problem is to convert it into a text/plain using .toString().
On the other hand, you can define a writer for Int that lets Play know how to convert an integer into a json format.
For more details, please take a look at this https://www.playframework.com/documentation/2.2.x/ScalaActions.
I am attempting to retrieve the sizes various websites whose URL will be passed to my script, but I'm not getting an exception when I pass an invalid URL, instead simply getting a very small page. I'm using Source.fromURL, and I get the following results:
thisIsClearlyABoggusURLThatCantPossiblyLeadAnyway 1052
www.bbc.co.uk 113871
The first one, as it says, shouldn't have anything in it, but it does. My script is as follows:
def main( args:Array[String] ){
val tasks = for(arg <- args) yield future {
try {
println(arg + " " + Source.fromURL( attachPrefix(arg) ).length)
} catch {
case e : java.net.UnknownHostException => println(arg + " *")
}
}
awaitAll(20000L, tasks: _*)
}
def attachPrefix( url:String ) = url.slice(0, 4) match {
case "http" => url
case "www." => "http://" + url
case _ => "http://www." + url
}
Each argument is being passed into the function attachPrefix to ensure it has the necessary prefix before being used. This problem has only come about since I started passing the url in as a parameter instead of mapping it onto the arg, which is what I was doing earlier with
args map attachPrefix
What's the difference between the two, and why is my current one giving such behaviour?
You can use the Source.fromURL(URI) signature. Creating a URI will effectively validate the URL as documented here. However, in this case, the URL http://www.thisIsClearlyABoggusURLThatCantPossiblyLeadAnyway is valid as far as the URI is concerned. On the other hand, the UrlValidator suggested by om-nom-nom considers it invalid, because the top level domain segment has more than 4 characters which is already out of date. I don't know of any entirely Scala validation libraries or why this would be a requirement, but you could try using a regular expression for validation. For example, this will catch your example, because the top level domain exceeds 6 letters:
val re = """^(https?://)?(([\w!~*'().&=+$%-]+: )?[\w!~*'().&=+$%-]+#)?(([0-9]{1,3}\.){3}[0-9]{1,3}|([\w!~*'()-]+\.)*([\w^-][\w-]{0,61})?[\w]\.[a-z]{2,6})(:[0-9]{1,4})?((/*)|(/+[\w!~*'().;?:#&=+$,%#-]+)+/*)$""".r
re.pattern.matcher("http://google.com").matches // true
re.pattern.matcher("http://www.thisIsClearlyABoggusURLThatCantPossiblyLeadAnyway").matches // false