All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zalando.zhewbacca.SecurityRulesRepository.scala Maven / Gradle / Ivy

The newest version!
package org.zalando.zhewbacca

import javax.inject.Inject

import com.typesafe.config.{Config, ConfigFactory}
import play.api.mvc.RequestHeader
import play.api.{Configuration, Logger}

import scala.collection.JavaConversions._
import play.api.http.HttpVerbs._

class SecurityRulesRepository @Inject() (configuration: Configuration, provider: AuthProvider) {

  private val SupportedHttpMethods: Set[String] = Set(GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)

  private val ConfigKeyMethod = "method"
  private val ConfigKeyPathRegex = "pathRegex"
  private val ConfigKeyScopes = "scopes"
  private val ConfigKeyAllowed = "allowed"
  private val ConfigKeyRules = "rules"

  private val rules: Seq[StrictRule] = load()

  def get(requestHeader: RequestHeader): Option[StrictRule] =
    rules.find(_.isApplicableTo(requestHeader))

  private def load(): Seq[StrictRule] = {
    val securityRulesFileName = configuration.getString("authorisation.rules.file").getOrElse("security_rules.conf")
    Logger.info(s"Configuration file for security rules: $securityRulesFileName")

    if (configFileExists(securityRulesFileName)) {
      ConfigFactory.load(securityRulesFileName)
        .getConfigList(ConfigKeyRules)
        .map(toRule)
    } else {
      sys.error(s"configuration file $securityRulesFileName for security rules not found")
    }
  }

  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'")
        new ExplicitlyAllowedRule(method, pathRegex)

      case (Some(method), pathRegex, Some(false), _) =>
        Logger.info(s"Explicitly denied all requests for method: '$method' and path regex: '$pathRegex'")
        new ExplicitlyDeniedRule(method, pathRegex)

      case (Some(method), pathRegex, None, Some(scopeNames)) =>
        Logger.info(s"Configured required scopes '$scopeNames' for method '$method' and path regex: '$pathRegex'")
        new ValidateTokenRule(method, pathRegex, Scope(scopeNames)) {
          override val authProvider: AuthProvider = provider
        }

      case _ =>
        sys.error(s"Invalid config: $config")
    }
  }

  private def configFileExists(fileName: String): Boolean =
    Option(Thread.currentThread()
      .getContextClassLoader
      .getResource(fileName))
      .isDefined

  private def getHttpMethod(config: Config): Option[String] = {
    if (SupportedHttpMethods(config.getString(ConfigKeyMethod))) {
      Some(config.getString(ConfigKeyMethod))
    } else {
      None
    }
  }

  private def getAllowedFlag(config: Config): Option[Boolean] = {
    if (config.hasPath(ConfigKeyAllowed)) {
      Some(config.getBoolean(ConfigKeyAllowed))
    } else {
      None
    }
  }

  private def getScopeNames(config: Config): Option[Set[String]] = {
    if (config.hasPath(ConfigKeyScopes)) {
      Some(config.getStringList(ConfigKeyScopes).toSet)
    } else {
      None
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy