Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.gu.identity.play
import cats.effect.IO
import cats.syntax.either._
import com.gu.identity.auth._
import com.gu.identity.model.User
import play.api.mvc.{Cookie, RequestHeader}
import scala.concurrent.ExecutionContext
// Class that builds upon functionality of IdapiPlayAuthService
// to make user authentication convenient in the context of a Play application.
// It handles extracting the user credentials from a Play request before authenticating them
// using the underlying IdapiPlayAuthService.
// Target client should be set if this service is being used to authenticate using crypto access tokens
// in addition to SC_GU_U cookies. See comments on UserCredentials.CryptoAccessToken for more context.
class IdapiPlayAuthService(idapiAuthService: IdapiAuthService, targetClient: Option[String]) {
import IdapiPlayAuthService._
// Authenticates the user and returns the respective identity id.
// Use this if only authentication + identity id is required.
// For more information see analogous method in IdentityService.
//
// UserCredentials are returned in addition to identity id as a convenience,
// since business logic may depend on type of credentials extracted from request.
@deprecated(
"this function only looks for idapi credentials in the request, in the future only okta credentials will be supported"
)
def authenticateRequest(request: RequestHeader): IO[(IdapiUserCredentials, String)] =
for {
credentials <- getIdapiUserCredentialsFromRequest(request, targetClient)
identityId <- idapiAuthService.authenticateUser(credentials)
} yield (credentials, identityId)
// Authenticates the user and returns the respective user.
// Use this is authentication + user information (in addition to the identity id) is required.
// For more information see analogous method in IdentityService.
//
// UserCredentials are returned in addition to the user as a convenience,
// since business logic may depend on type of credentials extracted from request.
@deprecated(
"this function only looks for idapi credentials in the request, in the future only okta credentials will be supported"
)
def getUserFromRequest(request: RequestHeader): IO[(IdapiUserCredentials, User)] =
for {
credentials <- getIdapiUserCredentialsFromRequest(request, targetClient)
user <- idapiAuthService.getUserFromCredentials(credentials)
} yield (credentials, user)
// Analogous to the authenticateRequest() method, but only attempts to use the SC_GU_U cookie.
// Returning a Cookie (as modelled by Play) instead of just the cookie value
// can be useful if other properties of the cookie are required by business logic.
def authenticateRequestUsingSCGUUCookie(request: RequestHeader): IO[(Cookie, String)] =
for {
cookie <- getSCGUUCookieFromRequest(request)
identityId <- idapiAuthService.authenticateUser(IdapiUserCredentials.SCGUUCookie(cookie.value))
} yield (cookie, identityId)
// Analogous to the getUserFromRequest() method, but only attempts to use the SC_GU_U cookie.
// Returning a Cookie (as modelled by Play) instead of just the cookie value
// can be useful if other properties of the cookie are required by business logic.
def getUserFromRequestUsingSCGUUCookie(request: RequestHeader): IO[(Cookie, User)] =
for {
cookie <- getSCGUUCookieFromRequest(request)
user <- idapiAuthService.getUserFromCredentials(IdapiUserCredentials.SCGUUCookie(cookie.value))
} yield (cookie, user)
}
object IdapiPlayAuthService {
case class UserCredentialsMissingError(message: String) extends Exception {
override def getMessage: String = message
}
def getSCGUUCookieFromRequest(request: RequestHeader): IO[Cookie] =
IO.fromEither(
Either.fromOption(
request.cookies.get("SC_GU_U"),
UserCredentialsMissingError("SC_GU_U cookie not set")
)
)
def getCryptoAccessTokenFromRequest(
request: RequestHeader,
targetClient: String
): IO[IdapiUserCredentials.CryptoAccessToken] =
IO.fromEither(
Either.fromOption(
request.headers
.get("GU-IdentityToken")
.map(token => IdapiUserCredentials.CryptoAccessToken(token, targetClient)),
UserCredentialsMissingError("GU-IdentityToken header not set")
)
)
def getIdapiUserCredentialsFromRequest(
request: RequestHeader,
targetClient: Option[String]
): IO[IdapiUserCredentials] =
getSCGUUCookieFromRequest(request)
.redeemWith(
// If no SC_GU_U cookie set, attempt to get crypto access token if target client is defined.
err => {
// If target client isn't set, then this indicates authentication with crypto access tokens is not supported.
// In this case just return the original error.
targetClient.fold(IO.raiseError[IdapiUserCredentials](err)) { client =>
// Otherwise attempt to extract a crypto access toke for the target client.
getCryptoAccessTokenFromRequest(request, client)
.handleErrorWith { _ =>
// At this point we know attempts were made to extract both credential types,
// and that both attempts were unsuccessful due to the respective credentials not being present.
IO.raiseError(UserCredentialsMissingError("neither SC_GU_U cookie or GU-IdentityToken header set"))
}
}
},
cookie => IO(IdapiUserCredentials.SCGUUCookie(cookie.value))
)
def unsafeInit[A <: AccessClaims, I <: IdentityClaims](
idapiAuthConfig: IdapiAuthConfig
)(implicit ec: ExecutionContext): IdapiPlayAuthService = {
val idapiAuthService =
IdapiAuthService.unsafeInit(IdapiAuthConfig(idapiAuthConfig.identityApiUri, idapiAuthConfig.accessToken))
new IdapiPlayAuthService(idapiAuthService, idapiAuthConfig.targetClient)
}
}