From 78071208b6eff8ae7e1c292a8e94b7c86ccd3eec Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 09:31:42 +0100 Subject: [PATCH 01/11] #61 updated: removed ToC from readme --- README.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README.md b/README.md index 04faae2..b5418d5 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,6 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/fa1fb822bc1246508d343880c0b1868c)](https://www.codacy.com/app/dmitrykrivaltsevich/play-zhewbacca?utm_source=github.com&utm_medium=referral&utm_content=zalando-stups/play-zhewbacca&utm_campaign=Badge_Grade) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/zalando-stups/play-zhewbacca/master/LICENSE) - -**[Table of Contents](http://tableofcontent.eu)** - -- [Play-security library](#play-security-library) - - [Core Technical Concepts](#core-technical-concepts) - - [Known alternatives](#known-alternatives) - - [Getting Started](#getting-started) - - [Contributing](#contributing) - - [Contact](#contact) - - [License](#license) - Play! (v2.5 - 2.6) library to protect RESTful resource servers using OAuth2. According to [RFC 6749](https://tools.ietf.org/html/rfc6749#section-7): > The client accesses protected resources by presenting the _access From 037e3ef227f5ef0a37b05529ea468a0dd3aceaa2 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 09:33:45 +0100 Subject: [PATCH 02/11] #61 updated: mentioned supported versions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d0c556..ecea089 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/fa1fb822bc1246508d343880c0b1868c)](https://www.codacy.com/app/dmitrykrivaltsevich/play-zhewbacca?utm_source=github.com&utm_medium=referral&utm_content=zalando-stups/play-zhewbacca&utm_campaign=Badge_Grade) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/zalando-stups/play-zhewbacca/master/LICENSE) -Play! (v2.5 - 2.6) library to protect RESTful resource servers using OAuth2. According to [RFC 6749](https://tools.ietf.org/html/rfc6749#section-7): +Play! library to protect RESTful resource servers using OAuth2. Supported Play! Framework versions are 2.5.x, 2.6.x, 2.7.x. According to [RFC 6749](https://tools.ietf.org/html/rfc6749#section-7): > The client accesses protected resources by presenting the _access token_ to the _resource server_. The resource server MUST _validate_ the From d2c04d37a0e50e435615a356c6d9962cca713797 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 10:30:06 +0100 Subject: [PATCH 03/11] #61 updated: enabled cross-scala compilation in travis build settings updated: changed play version to 2.7.0 updated: now the library is cross-compiled using scala versions 2.11.12, 2.12.8, 2.13.0-M5 updated: spec2 updated to version 4.3.5 to match play 2.7.x updated: set sbt version 1.2.7 updated: changed list of maintainers updated: changed library version in readme --- .travis.yml | 11 ++++++----- MAINTAINERS | 2 -- README.md | 2 +- build.sbt | 12 ++++++------ project/build.properties | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index c808293..a6e37e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,17 @@ language: scala scala: - - 2.11.8 + - 2.11.12 + - 2.12.8 + - 2.13.0-M5 jdk: - oraclejdk8 script: - - sbt clean coverage test + - sbt -Dsbt.log.noformat=true clean +coverage +test after_success: - - sbt coverageReport coveralls + - sbt -Dsbt.log.noformat=true +coverageReport coveralls - bash <(curl -s https://codecov.io/bash) # go faster on travis @@ -17,5 +19,4 @@ sudo: false notifications: email: - - dmitry.krivaltsevich@zalando.de - - cezary.lada.extern@zalando.de \ No newline at end of file + - dmitry.krivaltsevich@zalando.de \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index f4314ee..74d23dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,3 +1 @@ Dmitry Krivaltsevich -William Okuyama -Raymond Chenon \ No newline at end of file diff --git a/README.md b/README.md index ecea089..b1246e7 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ We mainly decided to release this library because we saw the needs of OAuth2 pro Configure libraries dependencies in your `build.sbt`: ```scala -libraryDependencies += "org.zalando" %% "play-zhewbacca" % "0.3.4" +libraryDependencies += "org.zalando" %% "play-zhewbacca" % "2.7.0" ``` To configure Development environment: diff --git a/build.sbt b/build.sbt index d534c2e..ee5976c 100644 --- a/build.sbt +++ b/build.sbt @@ -3,11 +3,13 @@ import sbt.Keys._ import scalariform.formatter.preferences._ +val playFrameworkVersion = "2.7.0" + val commonSettings = Seq( organization := "org.zalando", - version := "0.3.4", + version := playFrameworkVersion, scalaVersion := "2.12.5", - crossScalaVersions := Seq("2.11.12", "2.12.5"), + crossScalaVersions := Seq("2.11.12", "2.12.8", "2.13.0-M5"), scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8"), publishTo := { val nexus = "https://oss.sonatype.org/" @@ -27,12 +29,10 @@ val commonSettings = Seq( ) ) -val playFrameworkVersion = "2.6.12" - lazy val testDependencies = Seq( - "org.specs2" %% "specs2-core" % "4.0.3" % "test", - "org.specs2" %% "specs2-junit" % "4.0.3" % "test" + "org.specs2" %% "specs2-core" % "4.3.5" % "test", + "org.specs2" %% "specs2-junit" % "4.3.5" % "test" ) lazy val playDependencies = diff --git a/project/build.properties b/project/build.properties index b7dd3cb..72f9028 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.0.2 +sbt.version=1.2.7 From 5baeffde7e79ff27b99d49064dfe3d15a61a16b6 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 13:17:01 +0100 Subject: [PATCH 04/11] #61 fixed: java.lang.RuntimeException The global application reference is disabled. Play's global state is deprecated and will be removed in a future release. You should use dependency injection instead. To enable the global application anyway, set play.allowGlobalApplication = true. --- .../zhewbacca/SecurityFilterSpec.scala | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala b/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala index 3c34f5f..4857d39 100644 --- a/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala +++ b/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala @@ -1,9 +1,11 @@ package org.zalando.zhewbacca +import javax.inject.{Inject, Provider} import play.api.inject._ import play.api.inject.guice.GuiceApplicationBuilder import play.api.mvc.Results._ import play.api.mvc._ +import play.api.routing.Router import play.api.test.{FakeRequest, PlaySpecification} import play.api.{Application, Mode} @@ -11,23 +13,11 @@ class SecurityFilterSpec extends PlaySpecification with BodyParsers { val testTokenInfo = TokenInfo("", Scope.Empty, "token type", "user uid", realm = "/employees") - val routes: PartialFunction[(String, String), Handler] = { - // test action returning action type. Shows the usage and makes it possible to test basic behaviour - // security rules described in 'security_filter.conf' file - case ("GET", "/") => Action { request => - import TokenInfoConverter._ - Ok(request.tokenInfo.tokenType) - } - - case ("GET", "/unprotected") => Action { - Ok - } - } - def appWithRoutes: Application = new GuiceApplicationBuilder() .in(Mode.Test) .bindings(bind[AuthProvider] to new AlwaysPassAuthProvider(testTokenInfo)) - .routes(routes) + .overrides( + bind[Router].toProvider[TestRouterProvider]) .configure( "play.http.filters" -> "org.zalando.zhewbacca.TestingFilters", "authorisation.rules.file" -> "security_filter.conf") @@ -48,4 +38,23 @@ class SecurityFilterSpec extends PlaySpecification with BodyParsers { } +} + +class TestRouterProvider @Inject() (components: ControllerComponents) extends Provider[Router] { + + import components.{actionBuilder => Action} + import play.api.routing.sird._ + + override def get(): Router = Router.from { + // test action returning action type. Shows the usage and makes it possible to test basic behaviour + // security rules described in 'security_filter.conf' file + case GET(p"/") => Action { request => + import TokenInfoConverter._ + Ok(request.tokenInfo.tokenType) + } + + case GET(p"/unprotected") => Action { + Ok + } + } } \ No newline at end of file From 2524a38cfb32097336bbd53991a6f3bf6d3a3b77 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 13:20:13 +0100 Subject: [PATCH 05/11] #61 updated: set compiler option to count warnings as errors --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index ee5976c..db4d310 100644 --- a/build.sbt +++ b/build.sbt @@ -8,9 +8,9 @@ val playFrameworkVersion = "2.7.0" val commonSettings = Seq( organization := "org.zalando", version := playFrameworkVersion, - scalaVersion := "2.12.5", + scalaVersion := "2.12.8", crossScalaVersions := Seq("2.11.12", "2.12.8", "2.13.0-M5"), - scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8"), + scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8", "-Xfatal-warnings"), publishTo := { val nexus = "https://oss.sonatype.org/" if (isSnapshot.value) { From 876126a8aa6f62d3760ded16a33e1cebb9373a60 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 13:21:59 +0100 Subject: [PATCH 06/11] #61 updated: dropped usage of deprecated API --- src/main/scala/org/zalando/zhewbacca/SecurityFilter.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/org/zalando/zhewbacca/SecurityFilter.scala b/src/main/scala/org/zalando/zhewbacca/SecurityFilter.scala index ebec27c..2e8fbcf 100644 --- a/src/main/scala/org/zalando/zhewbacca/SecurityFilter.scala +++ b/src/main/scala/org/zalando/zhewbacca/SecurityFilter.scala @@ -23,9 +23,11 @@ class SecurityFilter @Inject() ( implicit val mat: Materializer, implicit val ec: ExecutionContext) extends Filter { + private val logger = Logger(getClass) + override def apply(nextFilter: RequestHeader => Future[Result])(requestHeader: RequestHeader): Future[Result] = { rulesRepository.get(requestHeader).getOrElse { - Logger.debug(s"No security rules found for ${requestHeader.method} ${requestHeader.uri}. Access denied.") + logger.debug(s"No security rules found for ${requestHeader.method} ${requestHeader.uri}. Access denied.") DenyAllRule }.execute(nextFilter, requestHeader) } From b03f731ac9c3ca11870e60150df127147ebadfde Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 13:23:40 +0100 Subject: [PATCH 07/11] #61 updated: dropped usage of deprecated API --- .../zalando/zhewbacca/SecurityRulesRepository.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala b/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala index 523630f..fb39b02 100644 --- a/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala +++ b/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala @@ -21,12 +21,14 @@ class SecurityRulesRepository @Inject() (configuration: Configuration, provider: private val rules: Seq[StrictRule] = load() + private val logger = Logger(getClass) + def get(requestHeader: RequestHeader): Option[StrictRule] = rules.find(_.isApplicableTo(requestHeader)) private def load(): Seq[StrictRule] = { val securityRulesFileName = configuration.getOptional[String]("authorisation.rules.file").getOrElse("security_rules.conf") - Logger.info(s"Configuration file for security rules: $securityRulesFileName") + logger.info(s"Configuration file for security rules: $securityRulesFileName") if (configFileExists(securityRulesFileName)) { ConfigFactory.load(securityRulesFileName) @@ -40,15 +42,15 @@ class SecurityRulesRepository @Inject() (configuration: Configuration, provider: private def toRule(config: Config): StrictRule = { (getHttpMethod(config), config.getString(ConfigKeyPathRegex), getAllowedFlag(config), getScopeNames(config)) match { case (Some(method), pathRegex, Some(true), _) => - Logger.info(s"Explicitly allowed unauthorized requests for method: '$method' and path regex: '$pathRegex'") + logger.info(s"Explicitly allowed unauthorized requests for method: '$method' and path regex: '$pathRegex'") ExplicitlyAllowedRule(method, pathRegex) case (Some(method), pathRegex, Some(false), _) => - Logger.info(s"Explicitly denied all requests for method: '$method' and path regex: '$pathRegex'") + logger.info(s"Explicitly denied all requests for method: '$method' and path regex: '$pathRegex'") ExplicitlyDeniedRule(method, pathRegex) case (Some(method), pathRegex, None, Some(scopeNames)) => - Logger.info(s"Configured required scopes '$scopeNames' for method '$method' and path regex: '$pathRegex'") + logger.info(s"Configured required scopes '$scopeNames' for method '$method' and path regex: '$pathRegex'") ValidateTokenRule(provider, method, pathRegex, Scope(scopeNames)) case _ => From f91c0e472d9d087d0244f8a722243a336d86dfda Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 14:19:23 +0100 Subject: [PATCH 08/11] #61 added: promoted Mikhail Litvin to maintainers --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 74d23dd..55f12c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1 +1,2 @@ Dmitry Krivaltsevich +Mikhail Litvin From 40b8b2d079f89c7fd799a0d7e0ed51b1f9799bc1 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 15:46:33 +0100 Subject: [PATCH 09/11] #61 removed: drop support of scala 2.13.0-M5 for now updated: increased memory to run test on CI --- .travis.yml | 5 ++-- build.sbt | 9 +++--- .../zhewbacca/SecurityRulesRepository.scala | 4 +-- .../org/zalando/zhewbacca/IAMClientSpec.scala | 29 ++++++++++++++----- .../zhewbacca/SecurityFilterSpec.scala | 4 +-- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6e37e4..7d15b26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,15 +3,14 @@ language: scala scala: - 2.11.12 - 2.12.8 - - 2.13.0-M5 jdk: - oraclejdk8 script: - - sbt -Dsbt.log.noformat=true clean +coverage +test + - sbt -mem 4096 -Dsbt.log.noformat=true clean +coverage +test after_success: - - sbt -Dsbt.log.noformat=true +coverageReport coveralls + - sbt +coverageReport coveralls - bash <(curl -s https://codecov.io/bash) # go faster on travis diff --git a/build.sbt b/build.sbt index db4d310..98b8391 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,9 @@ val commonSettings = Seq( organization := "org.zalando", version := playFrameworkVersion, scalaVersion := "2.12.8", - crossScalaVersions := Seq("2.11.12", "2.12.8", "2.13.0-M5"), + // play 2.7.0 started to use scalac version 2.13.0-M5, but + // we cannot use "2.13.0-M5" because of "atmos" library (it does not support scala 2.13 yet) + crossScalaVersions := Seq("2.11.12", "2.12.8"), scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8", "-Xfatal-warnings"), publishTo := { val nexus = "https://oss.sonatype.org/" @@ -104,9 +106,6 @@ pomExtra := ( Dmitry Krivaltsevich - William Okuyama - - - Raymond Chenon + Mikhail Litvin ) diff --git a/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala b/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala index fb39b02..2cac70c 100644 --- a/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala +++ b/src/main/scala/org/zalando/zhewbacca/SecurityRulesRepository.scala @@ -11,6 +11,8 @@ import play.api.mvc.RequestHeader class SecurityRulesRepository @Inject() (configuration: Configuration, provider: AuthProvider) { + private val logger = Logger(getClass) + private val SupportedHttpMethods: Set[String] = Set(GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) private val ConfigKeyMethod = "method" @@ -21,8 +23,6 @@ class SecurityRulesRepository @Inject() (configuration: Configuration, provider: private val rules: Seq[StrictRule] = load() - private val logger = Logger(getClass) - def get(requestHeader: RequestHeader): Option[StrictRule] = rules.find(_.isApplicableTo(requestHeader)) diff --git a/src/test/scala/org/zalando/zhewbacca/IAMClientSpec.scala b/src/test/scala/org/zalando/zhewbacca/IAMClientSpec.scala index 29da6e5..9bd0694 100644 --- a/src/test/scala/org/zalando/zhewbacca/IAMClientSpec.scala +++ b/src/test/scala/org/zalando/zhewbacca/IAMClientSpec.scala @@ -1,12 +1,15 @@ package org.zalando.zhewbacca import akka.actor.ActorSystem +import javax.inject.{Inject, Provider} import org.specs2.mutable.Specification import org.zalando.zhewbacca.metrics.NoOpPluggableMetrics import play.api.http.{DefaultFileMimeTypes, FileMimeTypesConfiguration, Port} +import play.api.inject._ import play.api.inject.guice.GuiceApplicationBuilder import play.api.libs.ws.WSClient import play.api.mvc._ +import play.api.routing.Router import play.api.test.WsTestClient import play.api.{Application, Configuration, Mode} import play.core.server.Server @@ -176,17 +179,14 @@ class IAMClientSpec extends Specification { } def fakeApp(delay: Duration = 0.second, response: Result = Results.Ok): Application = { - val routes: PartialFunction[(String, String), Handler] = { - case ("GET", "/tokeninfo") => Action { - Thread.sleep(delay.toMillis) - response - } - } - new GuiceApplicationBuilder() .in(Mode.Test) - .routes(routes) .configure("play.akka.actor-system" -> s"application_iam_client_${java.util.UUID.randomUUID}") + .bindings( + bind[Duration].toInstance(delay), + bind[Result].toInstance(response)) + .overrides( + bind[Router].toProvider[IAMClientTestRouterProvider]) .build } @@ -210,3 +210,16 @@ class IAMClientSpec extends Specification { new IAMClient(clientConfig, new NoOpPluggableMetrics, client, actorSystem, ExecutionContext.Implicits.global) } } + +class IAMClientTestRouterProvider @Inject() (components: ControllerComponents, delay: Duration, response: Result) extends Provider[Router] { + + import components.{actionBuilder => Action} + import play.api.routing.sird._ + + override def get(): Router = Router.from { + case GET(p"/tokeninfo") => Action { + Thread.sleep(delay.toMillis) + response + } + } +} diff --git a/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala b/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala index 4857d39..12d22ed 100644 --- a/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala +++ b/src/test/scala/org/zalando/zhewbacca/SecurityFilterSpec.scala @@ -17,7 +17,7 @@ class SecurityFilterSpec extends PlaySpecification with BodyParsers { .in(Mode.Test) .bindings(bind[AuthProvider] to new AlwaysPassAuthProvider(testTokenInfo)) .overrides( - bind[Router].toProvider[TestRouterProvider]) + bind[Router].toProvider[SecurityFilterTestRouterProvider]) .configure( "play.http.filters" -> "org.zalando.zhewbacca.TestingFilters", "authorisation.rules.file" -> "security_filter.conf") @@ -40,7 +40,7 @@ class SecurityFilterSpec extends PlaySpecification with BodyParsers { } -class TestRouterProvider @Inject() (components: ControllerComponents) extends Provider[Router] { +class SecurityFilterTestRouterProvider @Inject() (components: ControllerComponents) extends Provider[Router] { import components.{actionBuilder => Action} import play.api.routing.sird._ From 576df202ff06fd1b543a8bc07a0f6de576697697 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 15:51:54 +0100 Subject: [PATCH 10/11] #61 updated: changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3937541..f893c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -## [Unreleased] +## [2.7.0] - 2019-03-28 ### Changed - Rename `PlugableMetrics` trait to `PluggableMetrics`. Rename all occurrences of `Plugable*` to `Pluggable*`. - Add `Duration` support in configuration properties. +- Add support of Play! 2.7.0 ## [0.3.4] - 2018-06-06 ### Changed From 0a04b57113891fcf331a7aedc9e60c7c25742399 Mon Sep 17 00:00:00 2001 From: Dmitry Krivaltsevich Date: Thu, 28 Mar 2019 17:03:25 +0100 Subject: [PATCH 11/11] #61 removed: -mem 4096 causes error on Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7d15b26..9ee8225 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ jdk: - oraclejdk8 script: - - sbt -mem 4096 -Dsbt.log.noformat=true clean +coverage +test + - sbt clean +coverage +test after_success: - sbt +coverageReport coveralls - bash <(curl -s https://codecov.io/bash)