Skip to content
This repository has been archived by the owner on Sep 12, 2021. It is now read-only.

Add MyRequest #118

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/controllers/ActivateAccountController.scala
Expand Up @@ -8,7 +8,7 @@ import com.mohiva.play.silhouette.impl.providers.CredentialsProvider
import javax.inject.Inject
import play.api.i18n.Messages
import play.api.libs.mailer.Email
import play.api.mvc.{ AnyContent, Request }
import play.api.mvc.AnyContent
import utils.route.Calls

import scala.concurrent.{ ExecutionContext, Future }
Expand All @@ -26,7 +26,7 @@ class ActivateAccountController @Inject() (
* @param email The email address of the user to send the activation mail to.
* @return The result to display.
*/
def send(email: String) = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def send(email: String) = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
val decodedEmail = URLDecoder.decode(email, "UTF-8")
val loginInfo = LoginInfo(CredentialsProvider.ID, decodedEmail)
val result = Redirect(Calls.signin).flashing("info" -> Messages("activation.email.sent", decodedEmail))
Expand Down Expand Up @@ -55,7 +55,7 @@ class ActivateAccountController @Inject() (
* @param token The token to identify a user.
* @return The result to display.
*/
def activate(token: UUID) = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def activate(token: UUID) = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
authTokenService.validate(token).flatMap {
case Some(authToken) => userService.retrieve(authToken.userID).flatMap {
case Some(user) if user.loginInfo.providerID == CredentialsProvider.ID =>
Expand Down
5 changes: 2 additions & 3 deletions app/controllers/ApplicationController.scala
@@ -1,7 +1,6 @@
package controllers

import com.mohiva.play.silhouette.api.LogoutEvent
import com.mohiva.play.silhouette.api.actions._
import com.mohiva.play.silhouette.impl.providers.GoogleTotpInfo
import javax.inject.Inject
import play.api.mvc._
Expand All @@ -22,7 +21,7 @@ class ApplicationController @Inject() (
*
* @return The result to display.
*/
def index = SecuredAction.async { implicit request: SecuredRequest[EnvType, AnyContent] =>
def index = SecuredAction.async { implicit request: MySecuredRequest[AnyContent] =>
authInfoRepository.find[GoogleTotpInfo](request.identity.loginInfo).map { totpInfoOpt =>
Ok(home(request.identity, totpInfoOpt))
}
Expand All @@ -33,7 +32,7 @@ class ApplicationController @Inject() (
*
* @return The result to display.
*/
def signOut = SecuredAction.async { implicit request: SecuredRequest[EnvType, AnyContent] =>
def signOut = SecuredAction.async { implicit request: MySecuredRequest[AnyContent] =>
val result = Redirect(Calls.home)
eventBus.publish(LogoutEvent(request.identity, request))
authenticatorService.discard(request.authenticator, result)
Expand Down
12 changes: 5 additions & 7 deletions app/controllers/ChangePasswordController.scala
@@ -1,14 +1,12 @@
package controllers

import com.mohiva.play.silhouette.api.actions.SecuredRequest
import com.mohiva.play.silhouette.api.exceptions.ProviderException
import com.mohiva.play.silhouette.api.util.{ Credentials, PasswordInfo }
import com.mohiva.play.silhouette.impl.providers.CredentialsProvider
import forms.ChangePasswordForm
import javax.inject.Inject
import play.api.i18n.Messages
import play.api.mvc._
import utils.auth.{ DefaultEnv, WithProvider }
import utils.auth.WithProvider

import scala.concurrent.{ ExecutionContext, Future }

Expand All @@ -25,8 +23,8 @@ class ChangePasswordController @Inject() (
*
* @return The result to display.
*/
def view = SecuredAction(WithProvider[AuthType](CredentialsProvider.ID)) {
implicit request: SecuredRequest[DefaultEnv, AnyContent] =>
def view = SecuredAction(WithProvider(CredentialsProvider.ID)) {
implicit request =>
Ok(changePassword(ChangePasswordForm.form, request.identity))
}

Expand All @@ -35,8 +33,8 @@ class ChangePasswordController @Inject() (
*
* @return The result to display.
*/
def submit = SecuredAction(WithProvider[AuthType](CredentialsProvider.ID)).async {
implicit request: SecuredRequest[DefaultEnv, AnyContent] =>
def submit = SecuredAction(WithProvider(CredentialsProvider.ID)).async {
implicit request =>
ChangePasswordForm.form.bindFromRequest.fold(
form => Future.successful(BadRequest(changePassword(form, request.identity))),
password => {
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/ForgotPasswordController.scala
Expand Up @@ -6,7 +6,7 @@ import forms.ForgotPasswordForm
import javax.inject.Inject
import play.api.i18n.Messages
import play.api.libs.mailer.Email
import play.api.mvc.{ AnyContent, Request }
import play.api.mvc.AnyContent
import utils.route.Calls

import scala.concurrent.{ ExecutionContext, Future }
Expand All @@ -24,7 +24,7 @@ class ForgotPasswordController @Inject() (
*
* @return The result to display.
*/
def view = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def view = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
Future.successful(Ok(forgotPassword(ForgotPasswordForm.form)))
}

Expand All @@ -36,7 +36,7 @@ class ForgotPasswordController @Inject() (
*
* @return The result to display.
*/
def submit = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def submit = SecuredAction.async { implicit request: MyRequest[AnyContent] =>
wsargent marked this conversation as resolved.
Show resolved Hide resolved
ForgotPasswordForm.form.bindFromRequest.fold(
form => Future.successful(BadRequest(forgotPassword(form))),
email => {
Expand Down
118 changes: 118 additions & 0 deletions app/controllers/MyRequest.scala
@@ -0,0 +1,118 @@
package controllers

import org.slf4j.Marker
import play.api.MarkerContext
import play.api.i18n.MessagesApi
import play.api.mvc._
import utils.auth.DefaultEnv

import scala.concurrent.{ExecutionContext, Future}
import scala.language.higherKinds

/**
* Defines our own request with extended features above and beyond what Silhouette provides.
*/
trait MyRequestHeader extends MessagesRequestHeader
with PreferredMessagesProvider
with MarkerContext

/**
* The request implementation with a parsed body (only relevant for POST requests)
*
* @param request the original request
* @param messagesApi the messages API, needed for producing a Messages instance
* @tparam B the type of the body, if any.
*/
class MyRequest[B](
request: Request[B],
messagesApi: MessagesApi
) extends MessagesRequest[B](request, messagesApi) with MyRequestHeader {
// Stubbed out here, but see marker context docs
// https://www.playframework.com/documentation/2.8.x/ScalaLogging#Using-Markers-and-Marker-Contexts
def marker: Option[Marker] = None
}

/**
* A request with identity and authenticator traits.
*/
trait MySecuredRequestHeader extends MyRequestHeader
with SecuredRequestHeader[DefaultEnv]

/**
* Implementation of secured request.
*/
class MySecuredRequest[B](
request: Request[B],
messagesApi: MessagesApi,
val identity: DefaultEnv#I,
val authenticator: DefaultEnv#A,
) extends MyRequest(request, messagesApi) with MySecuredRequestHeader

/**
* A request with optional identity and authenticator traits.
*/
trait MyUserAwareRequestHeader extends MyRequestHeader
with UserAwareRequestHeader[DefaultEnv]

class MyUserAwareRequest[B](
request: Request[B],
messagesApi: MessagesApi,
val identity: Option[DefaultEnv#I],
val authenticator: Option[DefaultEnv#A]
) extends MyRequest(request, messagesApi) with MyUserAwareRequestHeader

/**
* Abstract class to stop defining executionContext in every subclass
*
* @param cc controller components
*/
protected abstract class AbstractActionTransformer[-R[_], +P[_]](cc: SilhouetteControllerComponents) extends ActionTransformer[R, P] {
override protected def executionContext: ExecutionContext =
cc.executionContext
}

/**
* Transforms from a Request into MyRequest.
*
* @param cc controller components
*/
class MyActionTransformer(cc: SilhouetteControllerComponents) extends AbstractActionTransformer[Request, MyRequest](cc) {
override protected def transform[A](request: Request[A]): Future[MyRequest[A]] = {
Future.successful(new MyRequest[A](
messagesApi = cc.messagesApi,
request = request
))
}
}

/**
* Transforms from a SecuredRequest[DefaultEnv] into MySecuredRequest.
*
* @param cc controller components
*/
class MySecuredActionTransformer(cc: SilhouetteControllerComponents) extends AbstractActionTransformer[SecuredEnvRequest, MySecuredRequest](cc) {
override protected def transform[A](request: SecuredEnvRequest[A]): Future[MySecuredRequest[A]] = {
Future.successful(new MySecuredRequest[A](
messagesApi = cc.messagesApi,
identity = request.identity,
authenticator = request.authenticator,
request = request
))
}
}

/**
* Transforms from a UserAwareRequest[DefaultEnv] into MyUserAwareRequest.
*
* @param cc controller components
*/
class MyUserAwareActionTransformer(cc: SilhouetteControllerComponents) extends AbstractActionTransformer[UserAwareEnvRequest, MyUserAwareRequest](cc) {
override protected def transform[A](request: UserAwareEnvRequest[A]): Future[MyUserAwareRequest[A]] = {
Future.successful(new MyUserAwareRequest[A](
messagesApi = cc.messagesApi,
identity = request.identity,
authenticator = request.authenticator,
request = request
))
}
}
6 changes: 3 additions & 3 deletions app/controllers/ResetPasswordController.scala
Expand Up @@ -7,7 +7,7 @@ import com.mohiva.play.silhouette.impl.providers.CredentialsProvider
import forms.ResetPasswordForm
import javax.inject.Inject
import play.api.i18n.Messages
import play.api.mvc.{ AnyContent, Request }
import play.api.mvc.AnyContent
import utils.route.Calls

import scala.concurrent.{ ExecutionContext, Future }
Expand All @@ -26,7 +26,7 @@ class ResetPasswordController @Inject() (
* @param token The token to identify a user.
* @return The result to display.
*/
def view(token: UUID) = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def view(token: UUID) = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
authTokenService.validate(token).map {
case Some(_) => Ok(resetPassword(ResetPasswordForm.form, token))
case None => Redirect(Calls.signin).flashing("error" -> Messages("invalid.reset.link"))
Expand All @@ -39,7 +39,7 @@ class ResetPasswordController @Inject() (
* @param token The token to identify a user.
* @return The result to display.
*/
def submit(token: UUID) = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def submit(token: UUID) = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
authTokenService.validate(token).flatMap {
case Some(authToken) =>
ResetPasswordForm.form.bindFromRequest.fold(
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/SignInController.scala
Expand Up @@ -7,7 +7,7 @@ import com.mohiva.play.silhouette.impl.providers._
import forms.{ SignInForm, TotpForm }
import javax.inject.Inject
import play.api.i18n.Messages
import play.api.mvc.{ AnyContent, Request }
import play.api.mvc.AnyContent
import utils.route.Calls

import scala.concurrent.{ ExecutionContext, Future }
Expand All @@ -27,7 +27,7 @@ class SignInController @Inject() (
*
* @return The result to display.
*/
def view = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def view = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
Future.successful(Ok(signIn(SignInForm.form, socialProviderRegistry)))
}

Expand All @@ -36,7 +36,7 @@ class SignInController @Inject() (
*
* @return The result to display.
*/
def submit = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def submit = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
SignInForm.form.bindFromRequest.fold(
form => Future.successful(BadRequest(signIn(form, socialProviderRegistry))),
data => {
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/SignUpController.scala
Expand Up @@ -9,7 +9,7 @@ import javax.inject.Inject
import models.User
import play.api.i18n.Messages
import play.api.libs.mailer.Email
import play.api.mvc.{ AnyContent, Request }
import play.api.mvc.AnyContent
import utils.route.Calls

import scala.concurrent.{ ExecutionContext, Future }
Expand All @@ -27,7 +27,7 @@ class SignUpController @Inject() (
*
* @return The result to display.
*/
def view = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def view = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
Future.successful(Ok(signUp(SignUpForm.form)))
}

Expand All @@ -36,7 +36,7 @@ class SignUpController @Inject() (
*
* @return The result to display.
*/
def submit = UnsecuredAction.async { implicit request: Request[AnyContent] =>
def submit = UnsecuredAction.async { implicit request: MyRequest[AnyContent] =>
SignUpForm.form.bindFromRequest.fold(
form => Future.successful(BadRequest(signUp(form))),
data => {
Expand Down
39 changes: 26 additions & 13 deletions app/controllers/SilhouetteController.scala
@@ -1,27 +1,44 @@
package controllers

import com.mohiva.play.silhouette.api.actions.{ SecuredActionBuilder, UnsecuredActionBuilder }
import com.mohiva.play.silhouette.api._
import com.mohiva.play.silhouette.api.actions._
import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository
import com.mohiva.play.silhouette.api.services.{ AuthenticatorService, AvatarService }
import com.mohiva.play.silhouette.api.util.{ Clock, PasswordHasherRegistry }
import com.mohiva.play.silhouette.api.{ EventBus, Silhouette }
import com.mohiva.play.silhouette.impl.providers.{ CredentialsProvider, GoogleTotpProvider, SocialProviderRegistry }
import javax.inject.Inject
import models.services.{ AuthTokenService, UserService }
import play.api.Logging
import play.api.http.FileMimeTypes
import play.api.i18n.{ I18nSupport, Langs, MessagesApi }
import play.api.i18n.{ Langs, MessagesApi }
import play.api.libs.mailer.MailerClient
import play.api.mvc._
import utils.auth.DefaultEnv

import scala.concurrent.duration.FiniteDuration

abstract class SilhouetteController(override protected val controllerComponents: SilhouetteControllerComponents)
extends MessagesAbstractController(controllerComponents) with SilhouetteComponents with I18nSupport with Logging {
extends MessagesAbstractController(controllerComponents) with SilhouetteComponents with Logging {

def SecuredAction: SecuredActionBuilder[EnvType, AnyContent] = controllerComponents.silhouette.SecuredAction
def UnsecuredAction: UnsecuredActionBuilder[EnvType, AnyContent] = controllerComponents.silhouette.UnsecuredAction
private val myActionTransformer = new MyActionTransformer(controllerComponents)
private val mySecuredActionTransformer = new MySecuredActionTransformer(controllerComponents)
private val myUserAwareActionTransformer = new MyUserAwareActionTransformer(controllerComponents)

def UnsecuredAction: ActionBuilder[MyRequest, AnyContent] = controllerComponents.silhouette.UnsecuredAction.andThen(myActionTransformer)

def SecuredAction: ActionBuilder[MySecuredRequest, AnyContent] = {
controllerComponents.silhouette.SecuredAction.andThen(mySecuredActionTransformer)
}

def SecuredAction(errorHandler: SecuredErrorHandler): ActionBuilder[MySecuredRequest, AnyContent] = {
controllerComponents.silhouette.SecuredAction(errorHandler).andThen(mySecuredActionTransformer)
}

def SecuredAction(authorization: Authorization[DefaultEnv#I, DefaultEnv#A]): ActionBuilder[MySecuredRequest, AnyContent] = {
controllerComponents.silhouette.SecuredAction(authorization).andThen(mySecuredActionTransformer)
}

def UserAwareAction: ActionBuilder[MyUserAwareRequest, AnyContent] = controllerComponents.silhouette.UserAwareAction.andThen(myUserAwareActionTransformer)

def userService: UserService = controllerComponents.userService
def authInfoRepository: AuthInfoRepository = controllerComponents.authInfoRepository
Expand All @@ -35,16 +52,12 @@ abstract class SilhouetteController(override protected val controllerComponents:
def totpProvider: GoogleTotpProvider = controllerComponents.totpProvider
def avatarService: AvatarService = controllerComponents.avatarService

def silhouette: Silhouette[EnvType] = controllerComponents.silhouette
def authenticatorService: AuthenticatorService[AuthType] = silhouette.env.authenticatorService
def silhouette: Silhouette[DefaultEnv] = controllerComponents.silhouette
def authenticatorService: AuthenticatorService[DefaultEnv#A] = silhouette.env.authenticatorService
def eventBus: EventBus = silhouette.env.eventBus
}

trait SilhouetteComponents {
type EnvType = DefaultEnv
type AuthType = EnvType#A
type IdentityType = EnvType#I

def userService: UserService
def authInfoRepository: AuthInfoRepository
def passwordHasherRegistry: PasswordHasherRegistry
Expand All @@ -57,7 +70,7 @@ trait SilhouetteComponents {
def totpProvider: GoogleTotpProvider
def avatarService: AvatarService

def silhouette: Silhouette[EnvType]
def silhouette: Silhouette[DefaultEnv]
}

trait SilhouetteControllerComponents extends MessagesControllerComponents with SilhouetteComponents
Expand Down