Skip to content

Instantly share code, notes, and snippets.

@joost-de-vries
Created December 1, 2017 07:54
Show Gist options
  • Save joost-de-vries/946d29ff82510c1fec9c0e04fa848806 to your computer and use it in GitHub Desktop.
Save joost-de-vries/946d29ff82510c1fec9c0e04fa848806 to your computer and use it in GitHub Desktop.
object Authentication {
def createHeader(userId: String, password: String): (String, String) = {
val concatenated = new String(Base64.encodeBase64(s"$userId:$password".getBytes("UTF-8")))
(AUTHORIZATION, s"Basic $concatenated")
}
def decodeBasicAuth(authHeader: String): Option[(String, String)] = {
val encoded = authHeader.replaceFirst("Basic ", "")
val decoded = new String(Base64.decodeBase64(encoded.getBytes("UTF-8")))
decoded.split(":").toList match {
case u :: p :: Nil => Some((u, p))
case _ => None
}
}
def decodeBasicAuth[A](implicit request: Request[A]): Option[(String, String)] =
for {
authHeader <- request.headers.get(AUTHORIZATION)
(clientId, clientSecret) <- decodeBasicAuth(authHeader)
} yield (clientId, clientSecret)
def onlyAccessibleBy[A](clientsToSecrets: Map[String, String], actionBuilder: ActionBuilder[Request, AnyContent])(
action: Action[A]): Action[A] =
actionBuilder.async(action.parser) { request =>
request.headers
.get(AUTHORIZATION)
.flatMap { authorization =>
authorization.split(" ").drop(1).headOption.filter { encoded =>
new String(org.apache.commons.codec.binary.Base64.decodeBase64(encoded.getBytes("UTF-8")))
.split(":")
.toList match {
case u :: p :: Nil
if clientsToSecrets.get(u).map(expectedSecret => expectedSecret == p).getOrElse(false) =>
true
case _ => false
}
}
}
.map(_ => action(request))
.getOrElse {
Future.successful(Unauthorized.withHeaders(WWW_AUTHENTICATE -> """Basic realm="Secured Area""""))
}
}
def unauthorizedResponse: Result =
Results.Unauthorized.withHeaders(WWW_AUTHENTICATE -> "Basic realm=\"Access to app\"")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment