Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for non-blocking DataHandler #18

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,25 @@ case class User(id: Long, name: String, hashedPassword: String)

class MyDataHandler extends DataHandler[User] {

def validateClient(clientId: String, clientSecret: String, grantType: String): Boolean = ???
def validateClient(clientId: String, clientSecret: String, grantType: String): Future[Boolean] = ???

def findUser(username: String, password: String): Option[User] = ???
def findUser(username: String, password: String): Future[Option[User]] = ???

def createAccessToken(authInfo: AuthInfo[User]): AccessToken = ???
def createAccessToken(authInfo: AuthInfo[User]): Future[AccessToken] = ???

def getStoredAccessToken(authInfo: AuthInfo[User]): Option[AccessToken] = ???
def getStoredAccessToken(authInfo: AuthInfo[User]): Future[Option[AccessToken]] = ???

def refreshAccessToken(authInfo: AuthInfo[User], refreshToken: String): AccessToken = ???
def refreshAccessToken(authInfo: AuthInfo[User], refreshToken: String): Future[AccessToken] = ???

def findAuthInfoByCode(code: String): Option[AuthInfo[User]] = ???
def findAuthInfoByCode(code: String): Future[Option[AuthInfo[User]]] = ???

def findAuthInfoByRefreshToken(refreshToken: String): Option[AuthInfo[User]] = ???
def findAuthInfoByRefreshToken(refreshToken: String): Future[Option[AuthInfo[User]]] = ???

def findClientUser(clientId: String, clientSecret: String, scope: Option[String]): Option[User] = ???
def findClientUser(clientId: String, clientSecret: String, scope: Option[String]): Future[Option[User]] = ???

def findAccessToken(token: String): Option[AccessToken] = ???
def findAccessToken(token: String): Future[Option[AccessToken]] = ???

def findAuthInfoByAccessToken(accessToken: AccessToken): Option[AuthInfo[User]] = ???
def findAuthInfoByAccessToken(accessToken: AccessToken): Future[Option[AuthInfo[User]]] = ???

}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package scalaoauth2.provider

import play.api.mvc._
import play.api.libs.json._
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.language.implicitConversions
import scala.concurrent.duration._

/**
* Basic OAuth2 provider trait.
Expand Down Expand Up @@ -110,12 +114,16 @@ trait OAuth2Provider extends OAuth2BaseProvider {
* @return Request is successful then return JSON to client in OAuth 2.0 format.
* Request is failed then return BadRequest or Unauthorized status to client with cause into the JSON.
*/
def issueAccessToken[A, U](dataHandler: DataHandler[U])(implicit request: play.api.mvc.Request[A]): Result = {
TokenEndpoint.handleRequest(request, dataHandler) match {
case Left(e) if e.statusCode == 400 => BadRequest(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e))
case Left(e) if e.statusCode == 401 => Unauthorized(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e))
case Right(r) => Ok(Json.toJson(responseAccessToken(r))).withHeaders("Cache-Control" -> "no-store", "Pragma" -> "no-cache")
def issueAccessToken[A, U](dataHandler: DataHandler[U])(implicit request: play.api.mvc.Request[A], timeout: scala.concurrent.duration.Duration = 60.seconds): Result = {
val futureResult: Future[Result] = TokenEndpoint.handleRequest(request, dataHandler).map { requestResult =>
requestResult match {
case Left(e) if e.statusCode == 400 => BadRequest(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e))
case Left(e) if e.statusCode == 401 => Unauthorized(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e))
case Right(r) => Ok(Json.toJson(responseAccessToken(r))).withHeaders("Cache-Control" -> "no-store", "Pragma" -> "no-cache")
}
}

Await.result(futureResult, timeout)
}

/**
Expand All @@ -128,12 +136,16 @@ trait OAuth2Provider extends OAuth2BaseProvider {
* @return Authentication is successful then the response use your API result.
* Authentication is failed then return BadRequest or Unauthorized status to client with cause into the JSON.
*/
def authorize[A, U](dataHandler: DataHandler[U])(callback: AuthInfo[U] => Result)(implicit request: play.api.mvc.Request[A]): Result = {
ProtectedResource.handleRequest(request, dataHandler) match {
case Left(e) if e.statusCode == 400 => BadRequest.withHeaders(responseOAuthErrorHeader(e))
case Left(e) if e.statusCode == 401 => Unauthorized.withHeaders(responseOAuthErrorHeader(e))
case Right(authInfo) => callback(authInfo)
def authorize[A, U](dataHandler: DataHandler[U])(callback: AuthInfo[U] => Result)(implicit request: play.api.mvc.Request[A], timeout: scala.concurrent.duration.Duration = 60.seconds): Result = {
val futureResult: Future[Result] = ProtectedResource.handleRequest(request, dataHandler).map { requestResult =>
requestResult match {
case Left(e) if e.statusCode == 400 => BadRequest.withHeaders(responseOAuthErrorHeader(e))
case Left(e) if e.statusCode == 401 => Unauthorized.withHeaders(responseOAuthErrorHeader(e))
case Right(authInfo) => callback(authInfo)
}
}

Await.result(futureResult, timeout)
}

}
Expand Down Expand Up @@ -182,10 +194,12 @@ trait OAuth2AsyncProvider extends OAuth2BaseProvider {
* Request is failed then return BadRequest or Unauthorized status to client with cause into the JSON.
*/
def issueAccessToken[A, U](dataHandler: DataHandler[U])(implicit request: play.api.mvc.Request[A]): Future[Result] = {
TokenEndpoint.handleRequest(request, dataHandler) match {
case Left(e) if e.statusCode == 400 => Future.successful(BadRequest(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e)))
case Left(e) if e.statusCode == 401 => Future.successful(Unauthorized(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e)))
case Right(r) => Future.successful(Ok(Json.toJson(responseAccessToken(r))).withHeaders("Cache-Control" -> "no-store", "Pragma" -> "no-cache"))
TokenEndpoint.handleRequest(request, dataHandler).map { requestResult =>
requestResult match {
case Left(e) if e.statusCode == 400 => BadRequest(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e))
case Left(e) if e.statusCode == 401 => Unauthorized(responseOAuthErrorJson(e)).withHeaders(responseOAuthErrorHeader(e))
case Right(r) => Ok(Json.toJson(responseAccessToken(r))).withHeaders("Cache-Control" -> "no-store", "Pragma" -> "no-cache")
}
}
}

Expand All @@ -200,11 +214,13 @@ trait OAuth2AsyncProvider extends OAuth2BaseProvider {
* Authentication is failed then return BadRequest or Unauthorized status to client with cause into the JSON.
*/
def authorize[A, U](dataHandler: DataHandler[U])(callback: AuthInfo[U] => Future[Result])(implicit request: play.api.mvc.Request[A]): Future[Result] = {
ProtectedResource.handleRequest(request, dataHandler) match {
case Left(e) if e.statusCode == 400 => Future.successful(BadRequest.withHeaders(responseOAuthErrorHeader(e)))
case Left(e) if e.statusCode == 401 => Future.successful(Unauthorized.withHeaders(responseOAuthErrorHeader(e)))
case Right(authInfo) => callback(authInfo)
ProtectedResource.handleRequest(request, dataHandler).flatMap { requestResult =>
requestResult match {
case Left(e) if e.statusCode == 400 => Future.successful(BadRequest.withHeaders(responseOAuthErrorHeader(e)))
case Left(e) if e.statusCode == 401 => Future.successful(Unauthorized.withHeaders(responseOAuthErrorHeader(e)))
case Right(authInfo) => callback(authInfo)
}
}
}

}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package scalaoauth2.provider

import java.util.Date
import scala.concurrent.Future

case class AccessTokenRequest[U](clientId: String, clientSecret: String, user: U)

Expand Down Expand Up @@ -84,7 +85,7 @@ trait DataHandler[U] {
* @param grantType Client send this value which is registered by application.
* @return true if request is a regular client, false if request is a illegal client.
*/
def validateClient(clientId: String, clientSecret: String, grantType: String): Boolean
def validateClient(clientId: String, clientSecret: String, grantType: String): Future[Boolean]

/**
* Find userId with username and password these are used on your system.
Expand All @@ -94,15 +95,15 @@ trait DataHandler[U] {
* @param password Client send this value which is used on your system.
* @return Including UserId to Option if could find the user, None if couldn't find.
*/
def findUser(username: String, password: String): Option[U]
def findUser(username: String, password: String): Future[Option[U]]

/**
* Creates a new access token by authorized information.
*
* @param authInfo This value is already authorized by system.
* @return Access token returns to client.
*/
def createAccessToken(authInfo: AuthInfo[U]): AccessToken
def createAccessToken(authInfo: AuthInfo[U]): Future[AccessToken]

/**
* Returns stored access token by authorized information.
Expand All @@ -112,15 +113,15 @@ trait DataHandler[U] {
* @param authInfo This value is already authorized by system.
* @return Access token returns to client.
*/
def getStoredAccessToken(authInfo: AuthInfo[U]): Option[AccessToken]
def getStoredAccessToken(authInfo: AuthInfo[U]): Future[Option[AccessToken]]

/**
* Creates a new access token by refreshToken.
*
* @param authInfo This value is already authorized by system.
* @return Access token returns to client.
*/
def refreshAccessToken(authInfo: AuthInfo[U], refreshToken: String): AccessToken
def refreshAccessToken(authInfo: AuthInfo[U], refreshToken: String): Future[AccessToken]

/**
* Find authorized information by authorization code.
Expand All @@ -130,7 +131,7 @@ trait DataHandler[U] {
* @param code Client send authorization code which is registered by system.
* @return Return authorized information that matched the code.
*/
def findAuthInfoByCode(code: String): Option[AuthInfo[U]]
def findAuthInfoByCode(code: String): Future[Option[AuthInfo[U]]]

/**
* Find authorized information by refresh token.
Expand All @@ -140,7 +141,7 @@ trait DataHandler[U] {
* @param refreshToken Client send refresh token which is created by system.
* @return Return authorized information that matched the refresh token.
*/
def findAuthInfoByRefreshToken(refreshToken: String): Option[AuthInfo[U]]
def findAuthInfoByRefreshToken(refreshToken: String): Future[Option[AuthInfo[U]]]

/**
* Find userId by clientId and clientSecret.
Expand All @@ -151,23 +152,23 @@ trait DataHandler[U] {
* @param clientSecret Client send this value which is registered by application.
* @return Return user that matched both values.
*/
def findClientUser(clientId: String, clientSecret: String, scope: Option[String]): Option[U]
def findClientUser(clientId: String, clientSecret: String, scope: Option[String]): Future[Option[U]]

/**
* Find AccessToken object by access token code.
*
* @param token Client send access token which is created by system.
* @return Return access token that matched the token.
*/
def findAccessToken(token: String): Option[AccessToken]
def findAccessToken(token: String): Future[Option[AccessToken]]

/**
* Find authorized information by access token.
*
* @param accessToken This value is AccessToken.
* @return Return authorized information if the parameter is available.
*/
def findAuthInfoByAccessToken(accessToken: AccessToken): Option[AuthInfo[U]]
def findAuthInfoByAccessToken(accessToken: AccessToken): Future[Option[AuthInfo[U]]]

/**
* Check expiration.
Expand Down
Loading