feat: BAC-39 Authentication #114
Submodule knockoutwhistfrontend updated: 6b8488e7a4...240be41dc7
@@ -1,7 +1,5 @@
|
||||
package controllers
|
||||
|
||||
import auth.AuthAction
|
||||
import com.typesafe.config.Config
|
||||
import logic.user.{SessionManager, UserManager}
|
||||
import model.users.User
|
||||
import play.api.Configuration
|
||||
@@ -22,7 +20,7 @@ class OpenIDController @Inject()(
|
||||
val config: Configuration
|
||||
)(implicit ec: ExecutionContext) extends BaseController {
|
||||
|
||||
def loginWithProvider(provider: String) = Action.async { implicit request =>
|
||||
def loginWithProvider(provider: String): Action[AnyContent] = Action.async { implicit request =>
|
||||
val state = openIDService.generateState()
|
||||
val nonce = openIDService.generateNonce()
|
||||
|
||||
@@ -40,7 +38,7 @@ class OpenIDController @Inject()(
|
||||
}
|
||||
}
|
||||
|
||||
def callback(provider: String) = Action.async { implicit request =>
|
||||
def callback(provider: String): Action[AnyContent] = Action.async { implicit request =>
|
||||
val sessionState = request.session.get("oauth_state")
|
||||
val sessionNonce = request.session.get("oauth_nonce")
|
||||
val sessionProvider = request.session.get("oauth_provider")
|
||||
@@ -63,7 +61,7 @@ class OpenIDController @Inject()(
|
||||
openIDService.getUserInfo(provider, tokenResponse.accessToken).map {
|
||||
case Some(userInfo) =>
|
||||
// Store user info in session for username selection
|
||||
Redirect(config.get[String]("app.url") + "/select-username")
|
||||
Redirect(config.get[String]("openid.selectUserRoute"))
|
||||
.withSession(
|
||||
"oauth_user_info" -> Json.toJson(userInfo).toString(),
|
||||
"oauth_provider" -> provider,
|
||||
@@ -81,7 +79,7 @@ class OpenIDController @Inject()(
|
||||
}
|
||||
}
|
||||
|
||||
def selectUsername() = Action.async { implicit request =>
|
||||
def selectUsername(): Action[AnyContent] = Action.async { implicit request =>
|
||||
request.session.get("oauth_user_info") match {
|
||||
case Some(userInfoJson) =>
|
||||
val userInfo = Json.parse(userInfoJson).as[OpenIDUserInfo]
|
||||
@@ -90,14 +88,15 @@ class OpenIDController @Inject()(
|
||||
"email" -> userInfo.email,
|
||||
"name" -> userInfo.name,
|
||||
"picture" -> userInfo.picture,
|
||||
"provider" -> userInfo.provider
|
||||
"provider" -> userInfo.provider,
|
||||
"providerName" -> userInfo.providerName
|
||||
)))
|
||||
case None =>
|
||||
Future.successful(Redirect("/login").flashing("error" -> "No authentication information found"))
|
||||
}
|
||||
}
|
||||
|
||||
def submitUsername() = Action.async { implicit request =>
|
||||
def submitUsername(): Action[AnyContent] = Action.async { implicit request =>
|
||||
val username = request.body.asJson.flatMap(json => (json \ "username").asOpt[String])
|
||||
.orElse(request.body.asFormUrlEncoded.flatMap(_.get("username").flatMap(_.headOption)))
|
||||
val userInfoJson = request.session.get("oauth_user_info")
|
||||
|
||||
@@ -19,6 +19,12 @@ class StubUserManager @Inject()(config: Config) extends UserManager {
|
||||
name = "Janis",
|
||||
passwordHash = UserHash.hashPW("password123")
|
||||
),
|
||||
"Leon" -> User(
|
||||
internalId = 2L,
|
||||
id = java.util.UUID.randomUUID(),
|
||||
name = "Jakob",
|
||||
passwordHash = UserHash.hashPW("password123")
|
||||
),
|
||||
"Jakob" -> User(
|
||||
internalId = 2L,
|
||||
id = java.util.UUID.fromString("323e4567-e89b-12d3-a456-426614174000"),
|
||||
|
||||
@@ -26,8 +26,11 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e
|
||||
else canInteract = Some(InteractionType.Card)
|
||||
case _ =>
|
||||
}
|
||||
|
||||
lock.lock()
|
||||
websocketActor.foreach(_.solveRequests())
|
||||
websocketActor.foreach(_.transmitEventToClient(event))
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
override def id: UUID = user.id
|
||||
|
||||
@@ -19,7 +19,8 @@ case class OpenIDUserInfo(
|
||||
email: Option[String],
|
||||
name: Option[String],
|
||||
picture: Option[String],
|
||||
provider: String
|
||||
provider: String,
|
||||
providerName: String
|
||||
)
|
||||
|
||||
object OpenIDUserInfo {
|
||||
@@ -51,7 +52,7 @@ class OpenIDConnectService@Inject(ws: WSClient, config: Configuration)(implicit
|
||||
|
||||
private val providers = Map(
|
||||
"discord" -> OpenIDProvider(
|
||||
name = "discord",
|
||||
name = "Discord",
|
||||
clientId = config.get[String]("openid.discord.clientId"),
|
||||
clientSecret = config.get[String]("openid.discord.clientSecret"),
|
||||
redirectUri = config.get[String]("openid.discord.redirectUri"),
|
||||
@@ -61,7 +62,7 @@ class OpenIDConnectService@Inject(ws: WSClient, config: Configuration)(implicit
|
||||
scopes = Set("identify", "email")
|
||||
),
|
||||
"keycloak" -> OpenIDProvider(
|
||||
name = "keycloak",
|
||||
name = "Identity",
|
||||
clientId = config.get[String]("openid.keycloak.clientId"),
|
||||
clientSecret = config.get[String]("openid.keycloak.clientSecret"),
|
||||
redirectUri = config.get[String]("openid.keycloak.redirectUri"),
|
||||
@@ -74,7 +75,9 @@ class OpenIDConnectService@Inject(ws: WSClient, config: Configuration)(implicit
|
||||
|
||||
def getAuthorizationUrl(providerName: String, state: String, nonce: String): Option[String] = {
|
||||
providers.get(providerName).map { provider =>
|
||||
val authRequest = new AuthenticationRequest.Builder(
|
||||
val authRequest = if (provider.scopes.contains("openid")) {
|
||||
// Use OpenID Connect AuthenticationRequest for OpenID providers
|
||||
new AuthenticationRequest.Builder(
|
||||
new ResponseType(ResponseType.Value.CODE),
|
||||
new com.nimbusds.oauth2.sdk.Scope(provider.scopes.mkString(" ")),
|
||||
new com.nimbusds.oauth2.sdk.id.ClientID(provider.clientId),
|
||||
@@ -84,6 +87,18 @@ class OpenIDConnectService@Inject(ws: WSClient, config: Configuration)(implicit
|
||||
.nonce(new Nonce(nonce))
|
||||
.endpointURI(URI.create(provider.authorizationEndpoint))
|
||||
.build()
|
||||
} else {
|
||||
// Use standard OAuth2 AuthorizationRequest for non-OpenID providers (like Discord)
|
||||
new AuthorizationRequest.Builder(
|
||||
new ResponseType(ResponseType.Value.CODE),
|
||||
new com.nimbusds.oauth2.sdk.id.ClientID(provider.clientId)
|
||||
)
|
||||
.scope(new com.nimbusds.oauth2.sdk.Scope(provider.scopes.mkString(" ")))
|
||||
.state(new com.nimbusds.oauth2.sdk.id.State(state))
|
||||
.redirectionURI(URI.create(provider.redirectUri))
|
||||
.endpointURI(URI.create(provider.authorizationEndpoint))
|
||||
.build()
|
||||
}
|
||||
|
||||
authRequest.toURI.toString
|
||||
}
|
||||
@@ -139,7 +154,8 @@ class OpenIDConnectService@Inject(ws: WSClient, config: Configuration)(implicit
|
||||
email = (json \ "email").asOpt[String],
|
||||
name = (json \ "name").asOpt[String].orElse((json \ "login").asOpt[String]),
|
||||
picture = (json \ "picture").asOpt[String].orElse((json \ "avatar_url").asOpt[String]),
|
||||
provider = providerName
|
||||
provider = providerName,
|
||||
providerName = provider.name
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -25,11 +25,13 @@ play.filters.cors {
|
||||
|
||||
# Local Development OpenID Connect Configuration
|
||||
openid {
|
||||
selectUserRoute="http://localhost:5173/select-username"
|
||||
|
||||
discord {
|
||||
clientId = ${?DISCORD_CLIENT_ID}
|
||||
clientId = "your-discord-client-id"
|
||||
clientId = "1462555597118509126"
|
||||
clientSecret = ${?DISCORD_CLIENT_SECRET}
|
||||
clientSecret = "your-discord-client-secret"
|
||||
clientSecret = "xZZrdd7_tNpfJgnk-6phSG53DSTy-eMK"
|
||||
redirectUri = ${?DISCORD_REDIRECT_URI}
|
||||
redirectUri = "http://localhost:9000/auth/discord/callback"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ play.filters.cors {
|
||||
# OpenID Connect Configuration
|
||||
openid {
|
||||
|
||||
selectUserRoute="https://knockout.janis-eccarius.de/select-user"
|
||||
selectUserRoute="https://knockout.janis-eccarius.de/select-username"
|
||||
|
||||
discord {
|
||||
clientId = ${?DISCORD_CLIENT_ID}
|
||||
|
||||
@@ -11,3 +11,23 @@ play.filters.cors {
|
||||
allowedHttpMethods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||
allowedHttpHeaders = ["Accept", "Content-Type", "Origin", "X-Requested-With"]
|
||||
}
|
||||
|
||||
openid {
|
||||
|
||||
selectUserRoute="https://st.knockout.janis-eccarius.de/select-username"
|
||||
|
||||
discord {
|
||||
clientId = ${?DISCORD_CLIENT_ID}
|
||||
clientSecret = ${?DISCORD_CLIENT_SECRET}
|
||||
redirectUri = ${?DISCORD_REDIRECT_URI}
|
||||
redirectUri = "https://st.knockout.janis-eccarius.de/auth/discord/callback"
|
||||
}
|
||||
|
||||
keycloak {
|
||||
clientId = "your-keycloak-client-id"
|
||||
clientSecret = "your-keycloak-client-secret"
|
||||
redirectUri = "https://st.knockout.janis-eccarius.de/api/auth/keycloak/callback"
|
||||
authUrl = ${?KEYCLOAK_AUTH_URL}
|
||||
authUrl = "https://identity.janis-eccarius.de/realms/master"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user