Commit 4d08f102 authored by Erwan Sevellec's avatar Erwan Sevellec 🔥
Browse files

Merge branch '4263-token-authentication-to-recording-server-api-retrieves-wrong-user' into 'master'

4263 token authentication to recording server api retrieves wrong user

See merge request !29
parents 0b064c50 73e928df
......@@ -15,8 +15,8 @@ class AuthConfig @Inject()(configuration: play.api.Configuration) {
val ldapManagerPassword = getConfStringOpt("authentication.ldap.managerPassword")
val ldapSearchBase = getConfStringOpt("authentication.ldap.searchBase")
val ldapSearchFilter = getConfStringOpt("authentication.ldap.userSearchFilter")
val expectedLogin = getConfString("authentication.login.login")
val expectedPassword = getConfString("authentication.login.password")
val expectedLogin = getConfStringOpt("authentication.login.login").filter(_.nonEmpty)
val expectedPassword = getConfStringOpt("authentication.login.password").filter(_.nonEmpty)
val token = configuration.underlying.getString("authentication.token")
private def getConfString(path: String): String = {
......
......@@ -2,7 +2,7 @@ package controllers
import com.google.inject.Inject
import configuration.AuthConfig
import models.AuthenticatedUser
import models.{AuthenticatedToken, AuthenticatedUser, CredentialsValidation}
import play.api.mvc._
import xivo.service._
......@@ -11,11 +11,11 @@ import scala.util.{Failure, Success}
import scala.concurrent.duration._
class Secured @Inject() (authConfig: AuthConfig, xivoWs: XivoWebService, action: DefaultActionBuilder) {
private def username(request: RequestHeader): Option[AuthenticatedUser] = {
private def username(request: RequestHeader): Option[CredentialsValidation] = {
request.session.get("username") match {
case Some(username) => Some(AuthenticatedUser(username, request.session.get("isSuperAdmin").contains("true")))
case None => request.headers.get("X-Auth-Token") match {
case Some(value) if value == authConfig.token => Some(AuthenticatedUser(authConfig.expectedLogin, true))
case Some(value) if value == authConfig.token => Some(AuthenticatedToken)
case _ => None
}
}
......@@ -25,14 +25,15 @@ class Secured @Inject() (authConfig: AuthConfig, xivoWs: XivoWebService, action:
request.cookies.get("_eid") match {
case Some(cookie) =>
Await.ready(xivoWs.validateCookieAgainstXiVO(cookie), 1200.millis).value.get match {
case Success(XivoCookieResponse) => Some(AuthenticatedUser(authConfig.expectedLogin, false))
case Success(XivoCookieResponse) if authConfig.expectedLogin.isDefined => Some(AuthenticatedUser(authConfig.expectedLogin.get, false))
case Success(XivoCookieResponse) => None
case Failure(e) => None
}
case None => None
}
}
private def allAuthenticationMethod(request: RequestHeader): Option[AuthenticatedUser] =
private def allAuthenticationMethod(request: RequestHeader): Option[CredentialsValidation] =
username(request) orElse authFromWebi(request)
private def onUnauthorized(loginRoute: Option[Call], request: RequestHeader) = {
......@@ -46,7 +47,7 @@ class Secured @Inject() (authConfig: AuthConfig, xivoWs: XivoWebService, action:
action(request => f(request))
}
def WithAuthenticatedUser(loginRoute: Option[Call], f: => AuthenticatedUser => Request[AnyContent] => Result) =
def WithAuthenticatedUser(loginRoute: Option[Call], f: => CredentialsValidation => Request[AnyContent] => Result) =
Security.Authenticated(allAuthenticationMethod, onUnauthorized(loginRoute, _)) {
user => action(request => f(user)(request))
}
......
......@@ -4,10 +4,11 @@ import models.authentication.AuthenticationProvider
sealed trait CredentialsValidation
case class AuthenticatedUser(username: String, superAdmin: Boolean=false) extends CredentialsValidation
case object AuthenticatedToken extends CredentialsValidation
case object InvalidCredentials extends CredentialsValidation
class AuthenticateUser(authenticationProvider: AuthenticationProvider) {
def authenticate(username: String, password: String): Option[AuthenticatedUser] = authenticationProvider.authenticate(username, password)
def authenticate(username: String, password: String): Option[CredentialsValidation] = authenticationProvider.authenticate(username, password)
}
package models.authentication
import models.AuthenticatedUser
import models.CredentialsValidation
import play.api.Logger
abstract class AuthenticationDriver {
val logger = Logger(getClass.getName)
def authenticate(login: String, password: String): Option[AuthenticatedUser]
def authenticate(login: String, password: String): Option[CredentialsValidation]
}
package models.authentication
import com.google.inject.ImplementedBy
import models.AuthenticatedUser
import models.{AuthenticatedUser, CredentialsValidation}
import configuration.AuthConfig
import javax.inject.{Inject, Singleton}
import play.api.libs.ws.WSClient
@ImplementedBy(classOf[AuthenticationProviderImpl])
trait AuthenticationProvider {
type AuthenticationFunction = (String,String) => Option[AuthenticatedUser]
type AuthenticationFunction = (String,String) => Option[CredentialsValidation]
val authenticationFunctions:List[AuthenticationFunction]
......@@ -17,7 +18,7 @@ trait AuthenticationProvider {
authenticationFunctions.view.map(configAuthent => configAuthent(username, password)).find(_.isDefined).flatten
}
def authenticate(username:String, password: String):Option[AuthenticatedUser] = {
def authenticate(username:String, password: String):Option[CredentialsValidation] = {
firstAuthentOk(username, password)
}
......@@ -38,9 +39,11 @@ class AuthenticationProviderImpl @Inject()(authConfig: AuthConfig, wsClient: WSC
config.usersWsPath.flatMap(path => Some(new XivoDriver(config, wsClient)))
}
def getLoginDriver(config: AuthConfig): Option[AuthenticationDriver] = {
Some(new LoginDriver(config))
}
def getLoginDriver(config: AuthConfig): Option[AuthenticationDriver] =
for {
expectedLogin <- config.expectedLogin
expectedPassword <- config.expectedPassword
} yield new LoginDriver(expectedLogin, expectedPassword)
override val authenticationFunctions:List[AuthenticationFunction] = {
List[Option[AuthenticationFunction]](
......
package models.authentication
import configuration.AuthConfig
import models.AuthenticatedUser
class LoginDriver(authConfig: AuthConfig) extends AuthenticationDriver {
class LoginDriver(expectedLogin: String, expectedPassword: String) extends AuthenticationDriver {
override def authenticate(login: String, password: String): Option[AuthenticatedUser] = {
if (login.equals(authConfig.expectedLogin) && password.equals(authConfig.expectedPassword)) {
if (login.equals(expectedLogin) && password.equals(expectedPassword)) {
logger.info(s"Login successful for $login")
Some(AuthenticatedUser(login, superAdmin = true))
}
......
package models.authentication
import configuration.AuthConfig
import models.{AuthenticatedUser, CredentialsValidation, InvalidCredentials}
import models.{AuthenticatedToken, AuthenticatedUser, CredentialsValidation, InvalidCredentials}
import play.api.http.Status.NO_CONTENT
import play.api.libs.json.Json
import play.api.libs.ws._
......@@ -15,12 +15,15 @@ case class LoginResult()
class XivoDriver(authConfig: AuthConfig, wsClient: WSClient) extends AuthenticationDriver {
val realDriver = new RealXivoDriver(new RestapiConnector(authConfig.usersWsPath.get, authConfig.usersWsToken, wsClient))
override def authenticate(login: String, password: String): Option[AuthenticatedUser] = realDriver.authenticate(login, password)
override def authenticate(login: String, password: String): Option[CredentialsValidation] = realDriver.authenticate(login, password)
}
protected class RealXivoDriver(val connector: RestapiConnector) extends AuthenticationDriver {
override def authenticate(login: String, password: String): Option[AuthenticatedUser] = {
override def authenticate(login: String, password: String): Option[CredentialsValidation] = {
connector.validateUser(login: String, password: String) match {
case Success(AuthenticatedToken) =>
logger.info(s"Login successful for $login")
Some(AuthenticatedToken)
case Success(res: AuthenticatedUser) =>
logger.info(s"Login successful for $login")
Some(res)
......
val appName = "play-authentication"
val appVersion = "2021.07.00-play2.8"
val appVersion = "2021.07.09-play2.8"
val appOrganisation = "solutions.xivo"
lazy val main = Project(appName, file("."))
......
......@@ -49,8 +49,4 @@ play.i18n.langs=["fr", "en"]
# default values
authentication {
token="kIv7r42Fv4rRZohiCNDh"
login {
login = "avencall"
password = "superpass"
}
}
......@@ -11,17 +11,19 @@ class LoginDriverSpec extends PlaySpecification {
.configure(TestConfig.testConfig)
.build()
val authConfig = new AuthConfig(app.configuration)
"The LoginDriver" should {
"return a User if the login and the password are correct" in {
running(app) {
val driver = new LoginDriver(new AuthConfig(app.configuration))
val driver = new LoginDriver(authConfig.expectedLogin.get, authConfig.expectedPassword.get)
driver.authenticate("john", "doe") shouldEqual Some(AuthenticatedUser("john", true))
}
}
"return None otherwise" in {
running(app) {
val driver = new LoginDriver(new AuthConfig(app.configuration))
val driver = new LoginDriver(authConfig.expectedLogin.get, authConfig.expectedPassword.get)
driver.authenticate("john", "lennon") shouldEqual None
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment