
com.mle.play.controllers.OAuthControl.scala Maven / Gradle / Ivy
The newest version!
package com.mle.play.controllers
import java.math.BigInteger
import java.security.SecureRandom
import com.mle.oauth.GoogleOAuth.{CODE, STATE}
import com.mle.oauth.{GoogleOAuth, GoogleOAuthReader}
import com.mle.play.json.JsonMessages
import com.mle.util.Log
import play.api.mvc._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
/**
* A [[Controller]] to handle the Google OAuth2 authentication flow.
*
* 1) User is sent to initiate()
* 2) initiate() sends (redirects) user to Google
* 3) Google redirects user to redirResponse() after consent
* 4) redirResponse() extracts email, authenticates
*
* @author Michael
*/
trait OAuthControl extends Controller with Log {
val messageKey = "message"
val logoutMessage = "You have successfully signed out."
val creds = GoogleOAuthReader.load
val oauth = new GoogleOAuth(creds.clientId, creds.clientSecret)
def isAuthorized(email: String): Boolean
def startOAuth: Call
def oAuthRedir: Call
def onOAuthSuccess: Call
def ejectCall: Call
def redirURL(implicit req: RequestHeader) = oAuthRedir.absoluteURL(req.secure)
def discover() = oauth.discover()
def initiate = Action.async(implicit request => {
discover().map(conf => {
val state = new BigInteger(130, new SecureRandom()).toString(32)
log debug s"Redirecting user to Google OAuth..."
Redirect(oauth.authRequestUri(conf.authorizationEndpoint, redirURL, state))
.withSession(STATE -> state)
})
})
def redirResponse = Action.async(implicit request => {
request.getQueryString(CODE).fold(fut(noConsentFailure))(code => {
val requestState = request.getQueryString(STATE)
val sessionState = request.session.get(STATE)
val isStateOk = requestState.exists(rs => sessionState.contains(rs))
if (isStateOk) {
discover().flatMap(conf => {
// exchanges code for token, which contains the user's email address
oauth.resolveEmail(conf.tokenEndpoint, code, redirURL).map(email => {
if (isAuthorized(email)) {
log info s"User: $email logged in."
Redirect(onOAuthSuccess).withSession(sessionUserKey -> email)
} else {
log warn s"User: $email authenticated successfully but is not authorized."
onOAuthUnauthorized(email)
}
})
})
} else {
val msg = "Invalid state parameter in OAuth callback."
log warn msg
fut(fail(msg))
}
})
})
def sessionUserKey = Security.username
// protected override def onUnauthorized(implicit headers: RequestHeader): Result = Redirect(initiateOAuth)
def onOAuthUnauthorized(email: String) = ejectWith(unauthorizedMessage(email)) //fail(unauthorizedMessage(email))
protected def ejectWith(message: String) = Redirect(ejectCall).flashing(messageKey -> message)
def unauthorizedMessage(email: String) = s"Hi $email, you're not authorized."
def noConsentFailure = {
val msg = "The user did not consent to the OAuth request."
log info msg
fail(msg)
}
def fail(msg: String) = Unauthorized(JsonMessages failure msg)
def fut[T](item: T) = Future successful item
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy