Skip to content

Commit

Permalink
OAuth2AsyncProvider become default provider #41
Browse files Browse the repository at this point in the history
  • Loading branch information
tsuyoshizawa committed Nov 14, 2014
1 parent bf75f4b commit 664bab1
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 61 deletions.
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,13 @@ For more details, refer to Scaladoc of ```DataHandler```.
```DataHandler``` returns ```AuthInfo``` as authorized information.
```AuthInfo``` is made up of the following fields.

```
case class AuthInfo[User](user: User, clientId: Option[String], scope: Option[String], redirectUri: Option[String])
```scala
case class AuthInfo[User](
user: User,
clientId: Option[String],
scope: Option[String],
redirectUri: Option[String]
)
```

- user
Expand All @@ -113,17 +118,27 @@ You should follow three steps below to work with Playframework.
* Access to an authorized resource

First, define your own controller with mixining ```OAuth2Provider``` trait provided by this library to issue access token.
Asynchronous result is used in your controller then you can use ```OAuth2AsyncProvider```, which supports returning ```Future[Result]```.

```scala
import scalaoauth2.provider._
object OAuth2Controller extends Controller with OAuth2Provider {
def accessToken = Action { implicit request =>
def accessToken = Action.async { implicit request =>
issueAccessToken(new MyDataHandler())
}
}
```

NOTE: If your controller supports returning synchronous result, use ```await``` method which is package object of scalaoauth2.provider.

```scala
import scalaoauth2.provider._
object OAuth2Controller extends Controller with OAuth2Provider {
def accessToken = Action { implicit request =>
await(issueAccessToken(new MyDataHandler()))
}
}
```

Then, assign a route to the controller that OAuth clients will access to.

```
Expand All @@ -135,7 +150,7 @@ Finally, you can access to an authorized resource like this:
```scala
import scalaoauth2.provider._
object MyController extends Controller with OAuth2Provider {
def list = Action { implicit request =>
def list = Action.async { implicit request =>
authorize(new MyDataHandler()) { authInfo =>
val user = authInfo.user // User is defined on your system
// access resource for the user
Expand All @@ -160,7 +175,7 @@ class MyTokenEndpoint extends TokenEndpoint {
}

override val handlers = Map(
"password" -> passwordNoCred
OAuthGrantType.PASSWORD -> passwordNoCred
)
}
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package scalaoauth2.provider

import play.api.mvc._
import play.api.libs.json._
import scala.concurrent.Await
import scala.concurrent.Future
import play.api.mvc._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.language.implicitConversions
import scala.concurrent.duration._

/**
* Basic OAuth2 provider trait.
Expand Down Expand Up @@ -83,7 +82,7 @@ trait OAuth2BaseProvider extends Results {
* <h3>Create controller for issue access token</h3>
* <code>
* object OAuth2Controller extends Controller with OAuth2Provider {
* def accessToken = Action { implicit request =>
* def accessToken = Action.async { implicit request =>
* issueAccessToken(new MyDataHandler())
* }
* }
Expand All @@ -98,7 +97,7 @@ trait OAuth2BaseProvider extends Results {
* <code>
* import scalaoauth2.provider._
* object BookController extends Controller with OAuthProvider {
* def list = Action { implicit request =>
* def list = Action.async { implicit request =>
* authorize(new MyDataHandler()) { authInfo =>
* val user = authInfo.user // User is defined on your system
* // access resource for the user
Expand All @@ -118,14 +117,12 @@ 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](handler: AuthorizationHandler[U], timeout: Duration = 60.seconds)(implicit request: Request[A]): Result = {
val f = tokenEndpoint.handleRequest(request, handler).map {
def issueAccessToken[A, U](handler: AuthorizationHandler[U])(implicit request: Request[A]): Future[Result] = {
tokenEndpoint.handleRequest(request, handler).map {
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(f, timeout)
}

/**
Expand All @@ -138,14 +135,12 @@ 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](handler: ProtectedResourceHandler[U], timeout: Duration = 60.seconds)(callback: AuthInfo[U] => Result)(implicit request: Request[A]): Result = {
val f = protectedResource.handleRequest(request, handler).map {
case Left(e) if e.statusCode == 400 => BadRequest.withHeaders(responseOAuthErrorHeader(e))
case Left(e) if e.statusCode == 401 => Unauthorized.withHeaders(responseOAuthErrorHeader(e))
def authorize[A, U](handler: ProtectedResourceHandler[U])(callback: AuthInfo[U] => Future[Result])(implicit request: Request[A]): Future[Result] = {
protectedResource.handleRequest(request, handler).flatMap {
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)
}

Await.result(f, timeout)
}

}
Expand Down Expand Up @@ -180,41 +175,5 @@ trait OAuth2Provider extends OAuth2BaseProvider {
* }
* </code>
*/
trait OAuth2AsyncProvider extends OAuth2BaseProvider {

/**
* Issue access token in AuthorizationHandler process and return the response to client.
*
* @param handler Implemented AuthorizationHandler for register access token to your system.
* @param request Playframework is provided HTTP request interface.
* @tparam A play.api.mvc.Request has type.
* @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](handler: AuthorizationHandler[U])(implicit request: Request[A]): Future[Result] = {
tokenEndpoint.handleRequest(request, handler).map {
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")
}
}

/**
* Authorize to already created access token in ProtectedResourceHandler process and return the response to client.
*
* @param handler Implemented ProtectedResourceHandler for authenticate to your system.
* @param callback Callback is called when authentication is successful.
* @param request Playframework is provided HTTP request interface.
* @tparam A play.api.mvc.Request has type.
* @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](handler: ProtectedResourceHandler[U])(callback: AuthInfo[U] => Future[Result])(implicit request: Request[A]): Future[Result] = {
protectedResource.handleRequest(request, handler).flatMap {
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)
}
}

}
@deprecated("Use OAuth2Provider", "0.12.0")
trait OAuth2AsyncProvider extends OAuth2Provider
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package scalaoauth2

import play.api.mvc.Result

import scala.concurrent.duration._
import scala.concurrent.{Await, Future}

package object provider {

/**
* Support synchronous Result for Playframework
*
* <h3>Create controller for issue access token</h3>
* <code>
* import scalaoauth2.provider._
* object OAuth2Controller extends Controller with OAuth2Provider {
* def accessToken = Action { implicit request =>
* await(issueAccessToken(new MyDataHandler()))
* }
* }
* </code>
*
* <h3>Register routes</h3>
* <code>
* POST /oauth2/access_token controllers.OAuth2Controller.accessToken
* </code>
*
* <h3>Authorized</h3>
* <code>
* import scalaoauth2.provider._
* object BookController extends Controller with OAuthProvider {
* def list = Action { implicit request =>
* await(authorize(new MyDataHandler()) { authInfo =>
* val user = authInfo.user // User is defined on your system
* // access resource for the user
* Future.successful(Ok)
* })
* }
* }
* </code>
* @param f callback
* @param timeout maximum wait time
* @return Await and return the result.
*/
def await(f: Future[Result], timeout: Duration = 60.seconds): Result = Await.result(f, timeout)

}
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Keys._
object ScalaOAuth2Build extends Build {

lazy val _organization = "com.nulab-inc"
lazy val _version = "0.11.0"
lazy val _version = "0.12.0-SNAPSHOT"
lazy val _playVersion = "2.3.4"

val _scalaVersion = "2.10.4"
Expand Down

0 comments on commit 664bab1

Please sign in to comment.