extract token from http request header using GenericHttpCredentials - scala

I am trying to extract the token from the authorization header of my HTTP request. The authorization header has the form Authorization: Token token=abcdefg123. I would like to have the following function signature but when I tried the following code snippet, a compilation error is Cannot resolve symbol Map. Cannot resolve method Map.unapply. I am not sure why this is happening. Any help is appreciated.
def extractToken(request: HttpRequest): Option[String] = {
for {
Authorization(GenericHttpCredentials("Token", "", Map("token"->token)))
<- request.header[Authorization]
} yield token
}

Figured out a working function,
private def extractToken(request: HttpRequest): Option[String] = {
for {
Authorization(GenericHttpCredentials("Token", "", params)) <- request.header[Authorization]
token <- params.get("token")
} yield token
}

Related

Retrofit2 post request is successful but I'm not able to retrieve token from response body

So I'm trying to making a login(post) request to an API (https://reqres.in/api/login) with retrofit 2. The connection was successful as the response code is 200, when I did the same on Postman I received a response which contains a token string which I want but in android studio when I log the response body it gives different output. I am new to kotlin so I think I must be doing something wrong while retrieving response.
Output I'm receiving:
Response{protocol=h2, code=200, message=, url=https://reqres.in/api/login}
Output I want (token field)
{
"token": "QpwL5tke4Pnpja7X4"
}
Retrofit Builder
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(apiUrl)
.build()
val api : reqresAPI = retrofit.create(reqresAPI::class.java)
API Interface
interface reqresAPI {
// FOR REFERENCE
// https://reqres.in/api/login
// ANNOTATE WITH POST TO SEND DATA
#POST(value = "login")
fun sendData(
#Body user: User
): Call<ResponseModel> // CALL IS USED TO MAKE AN API CALL
}
Response Model
class ResponseModel{
val token : String = ""
get() = field
}
User model with 2 parameters email and password
class User (
val email :String,
val password :String
)
Calling API
val call = api.sendData(user)
call.enqueue(object : Callback<ResponseModel>{
override fun onResponse(call: Call<ResponseModel>, response: Response<ResponseModel>) {
Log.d("LOGGER", response.toString())
}
override fun onFailure(call: Call<ResponseModel>, t: Throwable) {
Log.d("LOGGER", "ERROR "+t.message.toString())
}
})
Please change this
class ResponseModel{
val token : String = ""
get() = field
}
to this
class ResponseModel{
#SerializedName("token")
val token : String
}

how can i have two barer token in header using akka http

i have an app in akka http i am using its header directive for using accessToken as barer token everything is working fine , now i want to have two barer token instead of one, first should be accessToken and second should be a refreshToken
here is my working code for one barer token
private def bearerToken: Directive1[Option[String]] =
for {
authBearerHeader <- optionalHeaderValueByType(classOf[Authorization]).map(extractBearerToken)
xAuthCookie <- optionalCookie("X-Authorization-Token").map(_.map(_.value))
} yield authBearerHeader.orElse(xAuthCookie)
private def extractBearerToken(authHeader: Option[Authorization]): Option[String] =
authHeader.collect {
case Authorization(OAuth2BearerToken(token)) => token
}
a route defined in my main controller
def accessProtectedResource: server.Route =
path("access-protected-resource") {
get {
bearerToken { accessToken =>
accessToken match {
case Some(token) =>
case Failure(e)=>failWith(ex)
}
}
}
and from postman i added barer token in Authorization tab of postman
can anyone please guide what changes i need to make if i need to pass two barer token (accessToken and refreshToken)

Why won't gatling post an auth token from a POST return body to a GET header

I tried all the suggestions I found from other examples on this site and I still cannot get my Gatling test to pass the authentication token from a POST to the following GETs. The token is taken from the return body of the POST and passed in as a header to the GET
Initially the login was in BaseSimulationTest but I put it in GetDealsTests for troubleshooting
Steps I have tried:
I added this:
//println(" Token value" + session("accessToken").as[String])
And I was able to see that I got a string back in the terminal that seemed to indicate accessToken was a null value
I tried declaring var accessValue and var accessToken both in the method and globally. No change.
I tried checking the header value on the GET after passing the token in but .check(header.is(expected = ${accessToken})) seems to just error out
I have put the login POST and GET in the same method, different methods etc
I have tried passing in the username and password from .formParam instead of in the body of the request statement
Do I need to do the headers as a map? Is this a scope thing? Do I need to declare variables differently? The tests are running with an "expected 200 but received 401" type result. I think the POST doesn't even see the token being passed to it.
class GetDealsTests extends BaseSimulationTest {
def logIn2() = {
exec(http("Log in")
.post(getUrl() + "login")
.header("Content-Type", "application/json")
.body(ElFileBody("bodies/Login.json")).asJson
.check(status.is(200))
.check(jsonPath("$.access_token").saveAs("accessToken")))
exec(
session=>{
accessValue = session("accessToken").as[String]
session
})
}
def getAllDeals() = {
exec(_.set("accessToken", accessValue))
.exec(
http("Get all deals")
.get("deals/all")
.header("Authorization", "Bearer" + "${accessToken}")
.check(status.is(200))
)
}
val scnGetAllDeals = scenario("Get All Deals endpoint tests")
.forever() {
exec(logIn2())
exec(getAllDeals())
}
setUp(
scnGetAllDeals.inject(
nothingFor(5 seconds),
atOnceUsers(users))
).protocols(httpConf.inferHtmlResources())
.maxDuration(FiniteDuration(duration.toLong, MINUTES))
}
I looked at the following: Gatling won't save access token, Gatling Scala:Unable to send auth token to the method using session variable, Gatling - Setting Authorization header as part of request and don't see what I'm doing wrong
Lots of things:
Both logIn2 and getAllDeals are missing dots to properly chain the different method calls. As an example, here's what your logIn2 is actually doing (properly formatting helps):
def logIn2() = {
val discardedResult = exec(http("Log in")
.post(getUrl() + "login")
.header("Content-Type", "application/json")
.body(ElFileBody("bodies/Login.json")).asJson
.check(status.is(200))
.check(jsonPath("$.access_token").saveAs("accessToken")))
return exec(
session => {
accessValue = session("accessToken").as[String]
session
})
}
You probably shouldn't be using a global var. You don't need it and such construct is not threadsafe, so under load, virtual users will be updating and reading from this reference concurrently and result will be a mess.
You're missing a space in your Authorization header, between Bearer and the actual value.
asJson is merely a shortcut for .header("Content-Type", "application/json"), so you setting this header twice.
class GetDealsTests extends BaseSimulationTest {
val logIn2 =
exec(http("Log in")
.post(getUrl() + "login")
.body(ElFileBody("bodies/Login.json")).asJson
.check(status.is(200))
.check(jsonPath("$.access_token").saveAs("accessToken")))
val getAllDeals =
exec(
http("Get all deals")
.get("deals/all")
.header("Authorization", "Bearer ${accessToken}")
.check(status.is(200))
)
val scnGetAllDeals = scenario("Get All Deals endpoint tests")
.forever {
exec(logIn2)
.exec(getAllDeals)
}
setUp(
scnGetAllDeals.inject(
nothingFor(5 seconds),
atOnceUsers(users))
).protocols(httpConf.inferHtmlResources())
.maxDuration(FiniteDuration(duration.toLong, MINUTES))
}

Get cookies in middleware in http4s?

I'm trying to write middleware that would extract specific cookie and store information in ContextRequest.
Here is my test code:
def cookie[F[_]: Sync](
logger: Logger[F]
): Kleisli[F, Request[F], ContextRequest[F, Option[Cookie]]] =
Kleisli { request: Request[F] =>
for {
_ <- logger.debug(s"finding cookie")
_ <- logger.debug(request.cookies.map(_.name).mkString(","))
} yield ContextRequest(none[Cookie], request)
}
Then I use it like this:
def httpApp: HttpApp[F] = cookie(logger).mapK(OptionT.liftK).andThen(routesWithCookieContext).orNotFound
The problem is: request doesn't have any cookies even so I see them in the Chrome dev tools and in the request's details in the logs. What I'm doing wrong and how to make it work?
Turned out it was the problem with a cookie content. I was using Circle's .asJson.noSpaces to convert case class into string and write it into cookie's value. But for some reason cookies with json in their value doesn't work.

Custom spray.io directive to validate request header value

I am new to spray and I am trying to write a custom directive. I would like the directive to reject the request if the header value is not valid otherwise leave the request alone.
I've tried to absorb this page:
http://spray.io/documentation/1.1.2/spray-routing/key-concepts/directives/
Specifically, the part about the responder chain. I'm trying to create something at the level of the bar Directive in the illustration. I'm just not getting how to pass the context unchanged to the inner route.
My else block below is not correct but expresses what I am trying to do. I just can't figure out how to implement it.
Any help would be greatly appreciated.
trait ApiKeyDirective {
import spray.routing.directives.HeaderDirectives._
import spray.routing.directives.BasicDirectives._
def validateApiKey(): Directive1 = {
headerValueByName("api-key") {key =>
val valid = key == "123"
if (!valid) reject() else pass
}
}
}
object ApiKeyDirective extends ApiKeyDirective
You can combine
headerValueByName:
def headerValueByName(headerName: String): Directive1[String]
with validate:
def validate(check: ⇒ Boolean, errorMsg: String): Directive0
For example:
def validateApiKey(route: Route) =
headerValueByName("api-key") { key =>
validate(key == "123", "Invalid API key") {
route
}
}
or without validate:
def validateApiKey(route: Route) =
headerValueByName("api-key") { key =>
if (key == "123")
route
else
reject(ValidationRejection("Invalid API key"))
}
Usage:
lazy val route = ...
... ~
pathPrefix("test_directive") {
get {
validateApiKey {
complete("ok")
}
}
} ~
...
Test from cmd/shell:
# curl http://localhost:8080/test_directive
Request is missing required HTTP header 'api-key'
# curl http://localhost:8080/test_directive -H 'api-key: bad'
Invalid API key
# curl http://localhost:8080/test_directive -H 'api-key: 123'
"ok"
I'm just not getting how to pass the context unchanged to the inner
route.
Spray does that for you!
Your code is mostly correct, there are just 2 simple problems to fix!
Firstly, you need to flatMap headerValueByName("api-key") directive.
Secondly, the return type will be Directive0 because the directive won't provide any value.
So final code would look like this:
object ApiKeyDirective {
import spray.routing.Directives._
val validateApiKey: Directive0 =
headerValueByName("api-key").flatMap { key =>
val valid = key == "123"
if (!valid) reject() else pass
}
}
Also, I recommend you to add a custom rejection to reject() block so that API users will be informed when their api key is invalid.