Skip to content

marsmining/play-zhewbacca

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Play-security library

Play! (v2.5) library to protect REST endpoint by OAuth2 token verification. In order to access to protected endpoint clients should pass an Authorization header with Bearer token in every request. This library implemented in non-blocking way and provides two implementation of token verification.

  • AlwaysPassAuthProvider implementation is useful for Development environment to bypass a security mechanism. This implementation assumes that every token is valid.
  • OAuth2AuthProvider implementation acquires token information from a 3rd-party endpoint and then verifies this info. Also it applies a Circuit Breaker pattern.

Clients of this library don't need to change their code in order to protect endpoints. All necessary security configurations are happening in the separate configuration file.

Users guide

Configure libraries dependencies in your build.sbt:

libraryDependencies += "org.zalando" % "play-zhewbacca" % "0.1.0"

To configure Development environment:

import com.google.inject.AbstractModule
import org.zalando.zhewbacca._
import org.zalando.zhewbacca.metrics.{NoOpPlugableMetrics, PlugableMetrics}

class DevModule extends AbstractModule {

  override def configure(): Unit = {
    bind(classOf[PlugableMetrics]).to(classOf[NoOpPlugableMetrics])
    bind(classOf[AuthProvider]).to(classOf[AlwaysPassAuthProvider])
  }

}

For Production environment use:

import com.google.inject.{ TypeLiteral, AbstractModule }
import org.zalando.zhewbacca._
import org.zalando.zhewbacca.metrics.{NoOpPlugableMetrics, PlugableMetrics}

import scala.concurrent.Future

class ProdModule extends AbstractModule {

  override def configure(): Unit = {
    bind(classOf[AuthProvider]).to(classOf[OAuth2AuthProvider])
    bind(classOf[PlugableMetrics]).to(classOf[NoOpPlugableMetrics])
    bind(new TypeLiteral[(OAuth2Token) => Future[Option[TokenInfo]]]() {}).to(classOf[IAMClient])
  }

}

By default no metrics mechanism is used. User can implement PlugableMetrics to gather some simple metrics. See org.zalando.zhewbacca.IAMClient to learn what can be measured.

You need to include de.zalando.seo.play.security.SecurityFilter into your applications' filters:

package filters

import javax.inject.Inject
import org.zalando.zhewbacca.SecurityFilter
import play.api.http.HttpFilters
import play.api.mvc.EssentialFilter

class MyFilters @Inject() (securityFilter: SecurityFilter) extends HttpFilters {
  val filters: Seq[EssentialFilter] = Seq(securityFilter)
}

and then add play.http.filters = filters.MyFilters line to your application.conf. SecurityFilter rejects any requests to any endpoint which does not have a corresponding rule in the security_rules.conf file.

Example of configuration in application.conf file:

# Full URL for authorization endpoint
authorisation.iam.endpoint = "https://info.services.auth.zalando.com/oauth2/tokeninfo"

# Maximum number of failures before opening the circuit
authorisation.iam.cb.maxFailures = 4

# Duration of time in milliseconds after which to consider a call a failure
authorisation.iam.cb.callTimeout = 2000

# Duration of time in milliseconds after which to attempt to close the circuit
authorisation.iam.cb.resetTimeout = 60000

# IAMClient depends on Play internal WS client so it also has to be configured.
# The maximum time to wait when connecting to the remote host.
# Play's default is 120 seconds
play.ws.timeout.connection = 2000

# The maximum time the request can stay idle when connetion is established but waiting for more data
# Play's default is 120 seconds
play.ws.timeout.idle = 2000

# The total time you accept a request to take. It will be interrupted, whatever if the remote host is still sending data.
# Play's default is none, to allow stream consuming.
play.ws.timeout.request = 2000

play.http.filters = filters.MyFilters

play.modules.enabled += "modules.ProdModule"

By default this library reads security configuration from the conf/security_rules.conf file. You can change the file name by specifying a value for the key authorisation.rules.file in your application.conf file.

# This is an example of production-ready configuration security configuration.
# You can copy it from here and paste right into your `conf/security_rules.conf` file.
rules = [
    # All GET requests to /api/my-resource has to have a valid OAuth2 token for scopes: uid, scop1, scope2, scope3
    {
        method: GET
        pathRegex: "/api/my-resource/.*"
        scopes: ["uid", "scope1", "scope2", "scope3"]
    }

    # POST requests to /api/my-resource require only scope2.write scope
    {
        method: POST
        pathRegex: "/api/my-resource/.*"
        scopes: ["scope2.write"]
    }

    # GET requests to /bar resources allowed to be without OAuth2 token
    {
        method: GET
        pathRegex: /bar
        allowed: true
    }

    # 'Catch All' rule will immidiately reject all requests for all other endpoints
    {
        method: GET
        pathRegex: "/.*"
        allowed: false      // this is an example of inline comment
    }
]

Following example demonstrates how you can get an access to the Token Info object inside your controller:

package controllers

import javax.inject.Inject

import de.zalando.seo.play.security.TokenInfoConverter._
import de.zalando.seo.play.security.TokenInfo

class SeoDescriptionController @Inject() extends Controller {

  def create(uid: String): Action[AnyContent] = Action { request =>
    val tokenInfo: TokenInfo = request.tokenInfo
    // do something with token info. For example, read user's UID: tokenInfo.userUid
  }
}

About

Play! (v2.5) library to protect REST endpoint by OAuth2 token verification

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Scala 100.0%