akka-http custom directives

545 views
Skip to first unread message

Tim Pigden

unread,
Feb 27, 2015, 4:56:18 AM2/27/15
to akka...@googlegroups.com
Hi - is there any documentation (even in draft form) about custom directives for akka-http? Or has anyone any code examples?
Thanks
Tim

Giovanni Alberto Caporaletti

unread,
Feb 27, 2015, 6:14:55 AM2/27/15
to akka...@googlegroups.com
Hi,
I just started to write one to check basic authentication with an external service, because the current implementation forces you to know the cleartext password to compare it with the provided one.

This is a basic test I made for the time being.  I was wondering if there is a better way of integrating existing flows with the directives, instead of sub-materializing them as I did in this example.


class AuthenticationDirectives(userService: UserService) {

val failure = AuthenticationResult.failWithChallenge(HttpChallenge(scheme = "Basic", realm = "test"))

def authenticated: AuthenticationDirective[User] =
extractFlowMaterializer.flatMap { implicit mat =>
authenticateOrRejectWithChallenge[BasicHttpCredentials, User] {

case Some(BasicHttpCredentials(username, password)) =>
userService.authenticate(username, password)
.map {
case None => failure
case Some(user) => AuthenticationResult.success(user)
}
.runWith(Sink.head)

case None => Future.successful(failure)

}
}

}

Tim Pigden

unread,
Feb 27, 2015, 10:07:18 AM2/27/15
to akka...@googlegroups.com
I'll contribute a code example of my own then. Not particularly elegant but it might help someone else. 
In essence I create a directive with the path, then map and filter it to insert the required rejections then map to get rid of my option. 

// My route already knows the user and the role required. It needs to check the user has the right role within the client

def validateRoles(user: User, role: Role)(optClient: Tuple1[Option[Client]]) = {
(for {
client <- optClient._1
    // returns Int bit map of roles for this (client, user) as option
roles <- authenticationHolder.model.clientUsers.get(ClientUserNames(client.name, user.name)) } yield {
logger.debug(s"client is $client roles $roles looking for $role")
(role & roles) != 0
}).getOrElse(false
)
}

// simply checks the client exists. Note the mucking around with Tuple1 - this seems to be necessary as it's tuples all the way
val clientOf : (Tuple1[String]) => Option[Client] = { ts => authenticationHolder.model.clients.get(ts._1) }

def clientRole(user: User, role: Role) = path( Segment ) // match a string for client name
.tmap[Option[Client]](clientOf) // get the client
.tfilter(validateRoles(user, role)(_), AuthorizationFailedRejection) // filter out non-existent client or no authorisation
.tmap[Client](_._1.get) // turns it into the client itself. Couldn't figure out if I could combine filter and map more elegantly


// not pretty but all I've got time for today

Roland Kuhn

unread,
Feb 27, 2015, 10:18:24 AM2/27/15
to akka-user
Thanks for sharing, Giovanni and Tim!

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



Dr. Roland Kuhn
Akka Tech Lead
Typesafe – Reactive apps on the JVM.
twitter: @rolandkuhn


Reply all
Reply to author
Forward
0 new messages