viva-con-agua / play2-oauth-client

Implements an OAuth2 client for Play 2 apps. It allows to use Drops as social provider and tailors the OAuth2 handshake to specific organizational support.

GitHub

play2-oauth-client

A Play2 module implementing a small extension to the silhouette authorization library. Using the modules developers are able to connect to an OAuth2 provider that has been implemented to fit the needs of Viva con Agua.

Implements an OAuth2 client for Play2 apps. It allows to use Drops as social provider and tailors the OAuth2 handshake to specific organizational support. First, a user has to be logged out if and only if, a user has been logged out from Drops. Thus play2-oauth-client implements an additional Object-Event-System (OES) using the nats message broker.

Usage

Resolve the library from Sonatype in your build.sbt:

resolvers += "Sonatype OSS Releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2"

libraryDependencies += "org.vivaconagua" %% "play2-oauth-client" % "0.4.1"

You have to use the lib in a controller. You can simply implement the DropsLoginController trait:

package controllers

import javax.inject.Inject
import com.mohiva.play.silhouette.api.Silhouette
import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository
import com.mohiva.play.silhouette.impl.providers.SocialProviderRegistry
import org.vivaconagua.play2OauthClient.silhouette.CookieEnv
import org.vivaconagua.play2OauthClient.controller.DropsLoginController
import org.vivaconagua.play2OauthClient.silhouette.UserService
import concurrent.ExecutionContext.Implicits.global
import play.api.mvc._
import play.api.libs.ws._
import play.api._
import play.api.cache.CacheApi

class DropsController @Inject()(
                                ws: WSClient,
                                override val conf : Configuration,
                                cc: ControllerComponents,
                                override val silhouette: Silhouette[CookieEnv],
                                override val userService: UserService,
                                override val authInfoRepository: AuthInfoRepository,
                                override val socialProviderRegistry: SocialProviderRegistry,
                                cache: CacheApi
                              ) extends AbstractController(cc) with DropsLoginController {
  override val defaultRedirectUrl = routes.HomeController.index.url // defines the default page a user sees after login 
}

Now you have to add the following routes to your conf/routes file. These routes are needed to redirect the users client in order to fulfill the OAuth2 handshake with the social provider Drops:

GET        /authenticate/:provider  controllers.DropsController.authenticate(provider, route: Option[String], ajax: Option[Boolean])
POST       /authenticate/:provider  controllers.DropsController.authenticate(provider, route: Option[String], ajax: Option[Boolean])

WebApps

Furthermore, if you implement a JavaScript WebApp, you can add the following route to your routes file:

GET        /identity                controllers.DropsController.frontendLogin

If your user has a valid session with Drops, you will receive:

{
  "uuid": "<your-users-uuid>"
}

Otherwise, you will receive a JSON encoded error message using the following format:

{
  "http_error_code": 401,
  "internal_error_code": "401.OAuth2Server",
  "msg": "Currently, there is no authenticated user.",
  "msg_i18n": "error.oauth2.not.authenticated",
  "additional_information": {
    "oauth2_client": "<a microservice identifier>"
  }
}

Auth OES

Since play2-oauth-client has to communicate with your nats message broker and Drops you have to add the following lines to your conf/application.conf:

nats.endpoint="nats://<nats_ip>:<nats_port>" // default port is 4222

ms.name="<your_ms_name>" // example: BLOOB
ms.host="<your_ms_domain>" // example: http://localhost:9000
ms.entrypoint="<your_ms_route>" // the route that you have configured before, example: /authenticate/drops
drops.url.base="<drops_domain>" // example: http://localhost:9100 or https://pool.vivaconagua.org/drops
drops.client_id="<your_ms_id>" // the id that has been configured in drops to identify your microservice
drops.client_secret="<your_ms_secret>" // the secret that has been configured in drops to identify your microservice

play.filters.enabled += org.vivaconagua.play2OauthClient.drops.AuthOESFilter

Example implementation

An example controller using the implemented authentification:

import javax.inject.Inject

import play.api.mvc._
import com.mohiva.play.silhouette.api.Silhouette
import org.vivaconagua.play2OauthClient.silhouette.CookieEnv
import org.vivaconagua.play2OauthClient.silhouette.UserService

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

import play.api.mvc.AnyContent
import play.api.Logger

/**
  * A very small controller that renders a home page.
  */
class HomeController @Inject()(
                                cc: ControllerComponents,
                                silhouette: Silhouette[CookieEnv],
                                userService: UserService
) extends AbstractController(cc) {

  val logger: Logger = Logger(this.getClass())

  def userTest = silhouette.SecuredAction.async { implicit request => {
    Future.successful(Ok("User: " + request.identity))
  }}
}

How it works

Todo

ChangeLog

Version 0.4.1 (2018-07-13)