Skip to content

Instantly share code, notes, and snippets.

@Max-AR
Last active September 22, 2021 05:58
Show Gist options
  • Save Max-AR/3613e81ffe4e6322f8a6c3953cf45373 to your computer and use it in GitHub Desktop.
Save Max-AR/3613e81ffe4e6322f8a6c3953cf45373 to your computer and use it in GitHub Desktop.
Basic auth in play 2.8
// From https://www.rtechservices.io/blog/basic-authentication-play-scala
package filter
import akka.stream.Materializer
import com.google.inject.Inject
import play.api.Logging
import play.api.mvc._
import scala.concurrent.{ExecutionContext, Future}
class BasicAuth @Inject() (implicit val mat: Materializer, ec: ExecutionContext)
extends Filter
with Logging {
private lazy val unauthResult = Results.Unauthorized.withHeaders(
("www-authenticate", "Basic realm=\"default\"")
)
private lazy val credentials: Map[String, String] =
Map(
"oldmate" -> "pleaseChangeMeIAmVeryInsecure",
)
// need the space at the end
private lazy val basicSt = "basic "
//This is needed if you are behind a load balancer or a proxy
private def getUserIPAddress(request: RequestHeader): String = {
request.headers
.get("x-forwarded-for")
.getOrElse(request.remoteAddress)
}
private def logFailedAttempt(requestHeader: RequestHeader): Unit = {
logger.warn(
s"IP address ${getUserIPAddress(requestHeader)} failed to log in, " +
s"requested uri: ${requestHeader.uri}"
)
}
private def decodeBasicAuth(auth: String): Option[(String, String)] = {
if (auth.length() < basicSt.length()) {
return None
}
val basicReqSt = auth.substring(0, basicSt.length())
if (basicReqSt.toLowerCase() != basicSt) {
return None
}
val basicAuthSt = auth.replaceFirst(basicReqSt, "")
val decodedAuthSt =
new String(java.util.Base64.getDecoder.decode(basicAuthSt), "UTF-8")
val usernamePassword = decodedAuthSt.split(":")
if (usernamePassword.length >= 2) {
//account for ":" in passwords
return Some(usernamePassword(0), usernamePassword.splitAt(1)._2.mkString)
}
None
}
def apply(
nextFilter: RequestHeader => Future[Result]
)(requestHeader: RequestHeader): Future[Result] = {
requestHeader.headers
.get("authorization")
.map { basicAuth =>
decodeBasicAuth(basicAuth) match {
case Some((user, pass)) =>
if (credentials.exists(_ == user -> pass)) {
return nextFilter(requestHeader)
}
case _ => ;
}
logFailedAttempt(requestHeader)
return Future.successful(unauthResult)
}
.getOrElse({
logFailedAttempt(requestHeader)
Future.successful(unauthResult)
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment