OAuth

According to http://oauth.net/core/1.0/, the definition of OAuth is as follows:

"OAuth authentication is the process in which Users grant access to their Protected Resources without sharing their credentials with the Consumer. OAuth uses Tokens generated by the Service Provider instead of the User's credentials in Protected Resources requests. The process uses two Token types:

Request Token: Used by the Consumer to ask the User to authorize access to the Protected Resources. The User-authorized Request Token is exchanged for an Access Token, MUST only be used once, and MUST NOT be used for any other purpose. It is RECOMMENDED that Request Tokens have a limited lifetime.

Access Token: Used by the Consumer to access the Protected Resources on behalf of the User. Access Tokens MAY limit access to certain Protected Resources, and MAY have a limited lifetime. Service Providers SHOULD allow Users to revoke Access Tokens. Only the Access Token SHALL be used to access the Protect Resources.

OAuth Authentication is done in three steps:

The Consumer obtains an unauthorized Request Token.

The User authorizes the Request Token.

The Consumer exchanges the Request Token for an Access Token."

Exactly what and how much of it is accessible is decided solely by the service provider.

There are three versions of OAuth: 1.0, 1.0a, and 2.0. The first one (1.0) has some security issues and is not used anymore by service providers.

Play provides an API for using 1.0 and 1.0a and not for 2.0, since using this is a lot simpler. The API is documented at https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.oauth.package.

Let's build an app to that utilizes a Twitter account to log in using Play's OAuth API.

Initially, we'll need to register the app at https://apps.twitter.com/ using a Twitter account so that we have a valid consumer key and secret combination. After this, we can define the action as follows:

val KEY: ConsumerKey = ConsumerKey("myAppKey", "myAppSecret")
val TWITTER: OAuth = OAuth(ServiceInfo(
    "https://api.twitter.com/oauth/request_token",
    "https://api.twitter.com/oauth/access_token",
    "https://api.twitter.com/oauth/authorize", KEY),
    true)

def authenticate = Action { request =>
    TWITTER.retrieveRequestToken("http://localhost:9000/welcome") match {
      case Right(t) => {
        Redirect(TWITTER.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
      }
      case Left(e) => throw e
    }
  }

OAuth is a Play helper class and has this signature:

OAuth(info: ServiceInfo, use10a: Boolean = true)

The parameter determines the version of OpenID. If it's set to true, it uses OpenID 1.0 or else, 1.0.

It provides these three methods:

  • redirectURL: This fetches the URL string where a user should be redirected to authorize the application through the provider
  • retrieveRequestToken: This fetches the request token from the provider
  • retrieveAccessToken: This exchanges the request token for an access token

In the preceding action definition, we only use the provider to login; we cannot get any user details unless we do not exchange the authorized request token for an access token. To get the access token, we need the request token and oauth_verifier, which is provided by the service provider when granting the request token.

Using the Play OAuth API, redirecting after obtaining a request token adds oauth_verifier to the request query string. So, we should redirect to an action that attempts to obtain the access token and then store it, so that it is easily accessible for future requests. In this example, it's stored in the Session:

def authenticate = Action { request =>
    request.getQueryString("oauth_verifier").map { verifier =>
      val tokenPair = sessionTokenPair(request).get
      TWITTER.retrieveAccessToken(tokenPair, verifier) match {
        case Right(t) => {
          Redirect(routes.Application.welcome()).withSession("token" -> t.token, "secret" -> t.secret)
        }
        case Left(e) => throw e
      }
    }.getOrElse(
        TWITTER.retrieveRequestToken("http://localhost:9000/twitterLogin") match {
      case Right(rt) =>
        Redirect(TWITTER.redirectUrl(rt.token)).withSession("token" -> rt.token, "secret" -> rt.secret)
      case Left(e) => throw e
    })
  }

  private def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
    for {
      token <- request.session.get("token")
      secret <- request.session.get("secret")
    } yield {
      RequestToken(token, secret)
    }
  }

  def welcome = Action.async {
    implicit request =>
      sessionTokenPair match {
        case Some(credentials) => {
          WS.url("https://api.twitter.com/1.1/statuses/home_timeline.json")
            .sign(OAuthCalculator(KEY, credentials))
            .get()
            .map(result => Ok(result.json))
        }
        case _ => Future.successful(Redirect(routes.Application.authenticate()).withNewSession)
      }

  }

On successful login and authorization by the user, we fetch the status on a user's timeline and display it as JSON using the welcome action.

Note

There is no built-in support in Play for authentication using OAuth 2.0, CAS, SAML, or any other protocol. However, developers can choose to use a third-party plugin or library that suits their requirements. Some of them are Silhouette (http://silhouette.mohiva.com/v2.0), deadbolt-2 (https://github.com/schaloner/deadbolt-2), play-pac4j (https://github.com/pac4j/play-pac4j), and so on.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.179.59