Code Monkey home page Code Monkey logo

deadbolt-2-scala's Introduction

Deadbolt 2 for Play 2

Build Status Maven Repository size

Deadbolt 2 is an authorization library for Play 2, and features APIs for both Java- and Scala-based applications. It allows you to apply constraints to controller actions, and to customize template rendering based on the current user.

This repository contains the Scala API for Deadbolt.

Documentation

You can find documentation and examples for Deadbolt at https://deadbolt-scala.readme.io/.

Get the book!

If you want to explore Deadbolt further, you might want to take a look at the book I'm currently writing on it. You can find it at https://leanpub.com/deadbolt-2.

Deadbolt 2 - Powerful authorization for your Play application

Java API

The Java version of Deadbolt can by found at https://github.com/schaloner/deadbolt-2-java.

2.5.x Migration guide

  • There is no longer a common module shared by the Scala and Java versions of Deadbolt, so there is no more usage of Java types in the API.
  • Types previously found in be.objectify.deadbolt.core.models are now found in be.objectify.deadbolt.scala.models.
  • be.objectify.deadbolt.core.PatternType is now be.objectify.deadbolt.scala.models.PatternType.
  • be.objectify.deadbolt.core.DeadboltAnalyzer has been re-implemented in Scala as be.objectify.deadbolt.scala.StaticConstraintAnalyzer.
  • Instead of an implicit Request, actions now receive an explicit AuthenticatedRequest that contains an Option[Subject].
  • The functions of DeadboltActions now return a Future[Result] in place of an Action[A].

deadbolt-2-scala's People

Contributors

amazingdreams avatar flicken avatar francisdb avatar mkurz avatar scala-steward avatar schaloner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deadbolt-2-scala's Issues

WithAuthRequest in 2.6.x wrapping of RequestHeader leads to multiple issues

I have been migrating a project to 2.6.x (https://github.com/bravegag/play-authenticate-usage-scala) and I believe that the latest 2.6.x Deadbolt2 Scala is causing some issues. It has to do with the newly introduced wrapping of the RequestHeader instead of the former way of enriching it with an AuthenticatedRequest containing inplace all the RequestHeader data.

The issue happens when doing e.g.

class Application @Inject()(deadbolt: DeadboltActions) extends Controller {
  def index = deadbolt.WithAuthRequest()() { authRequest =>
    Future {
      Ok(views.html.index(new MyDeadboltHandler)(authRequest))
    }
  }
}

What comes out of this is an AuthenticatedRequest that aggregates another AuthenticatedRequest that aggregates yet the original RequestHeader see attached.
7HVVo

This causes many issues later in the code because the original request data is hidden away within this nesting. For example, the preferred language is not found and the request body too and then as result, form request binding won't work.

Is there an alternative to using WithAuthRequest()() that's more friendly to pre 2.6 code? Otherwise can we not make an alternative to this approach?

I also posted a question here:
https://stackoverflow.com/questions/56068601/migrating-to-2-6-why-deadbolt2s-withauthrequest-outputing-multiple-nested

Unable to provide custom execution context

On fixing tests i trying to providing custom execution context i found that it's impossible. I made little change in ExecutionContextProvider.scala

    case Failure(ex) =>
      logger.info("No custom execution context found, falling back to scala.concurrent.ExecutionContext.global")
      logger.info("No custom execution context found, falling back to scala.concurrent.ExecutionContext.global", ex)
      scala.concurrent.ExecutionContext.global

and gets

[info] - deadbolt.execution-context - No custom execution context found, falling back to scala.concurrent.ExecutionContext.global
com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Found a circular dependency involving play.api.Application, and circular dependencies are disabled.
  at play.api.DefaultApplication.class(Application.scala:235)
  while locating play.api.DefaultApplication
  while locating play.api.Application

1 error
	at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028)
	at be.objectify.deadbolt.scala.DefaultExecutionContextProvider$$anonfun$1.apply(ExecutionContextProvider.scala:42)

Solution would be injecting injector instead application provider.
I made fixes but they depends on #36

About how to security the view without Await.

What about this:

controller

val dataFuture: Future[Data] = ???
val subjectWithPermissionsFromCacheOrDBFuture: Future[CaseSubject] = ???
for {
  data <- data
  subject <- subjectWithPermissionFromCacheOrDBFuture
} yield {
  Ok(view(data)(SubjectWrap(subject)))
}

view.scala.html

@(data: Data)(wrap: SubjectWrap)
@wrap.require("superAdmin") {
  @data.name
}

I mean get the subject informations with future in the controller first and render the view with no db connection.

not found: value restrict

Hello,

Im using play 2.6.5 and deadbolt 2.6.1 java.

I am trying to add @restrict() {} but does not work.

im add the import

@import be.objectify.deadbolt.java.views.html.di.{restrict}

but all time say me

Compilation error
not found: value restrict

What am I doing wrong?

Thanks.

proposition: introduce scala dsl

The current deadbolt scala api feels very java-like. however it should be trivially easy to add a lightweight scala dsl for permission building to create a better api.

Instead of:

// subject must have the "foo" AND "bar" roles 
def restrictedFunctionB = actionBuilder.RestrictAction("foo", "bar").defaultHandler() { Ok(accessOk()) }

// subject must have the "foo" OR "bar" roles 
def restrictedFunctionC = actionBuilder.RestrictAction(List(Array("foo"), Array("bar"))).defaultHandler() { Ok(accessOk()) }

The API could look like this (even without changing the current api, by adding some dsl builders:

// Foo and Bar are types / enums / case classes ... or just stay string, both would work
// subject must have the "foo" AND "bar" roles 
def restrictedFunctionB = RestrictAction(Foo and Bar) { Ok(accessOk()) }

// subject must have the "foo" OR "bar" roles 
def restrictedFunctionC = RestrictAction(Foo or Bar) { Ok(accessOk()) }

Is it possible to make a Subject's #getPermissions return a Future[List[Permission]]?

This is what the signature for the getPermissions method in Subject.java looks like right now:

List<? extends Permission> getPermissions();

But in my case (and, I imagine, for other people as well) I need to fetch permissions for a given user from the database, which shouldn't block my app. This is how I've implemented this interface in my actual User class (note that I have to block the thread at the end because I need to return a List[java.List] of it doesn't match the interface signature.

  def getPermissions: java.util.List[Permission] = {

    val q = for {
      u <- users if u.id === this.id
      uxug <- users_x_user_groups if uxug.userId === u.id
      ug <- user_groups if ug.id === uxug.userGroupId
      pug <- permissions_x_user_groups if (pug.userGroupId === ug.id || pug.userGroupId === ug.parentGroupId)
      p <- permissions if p.id === pug.permissionId
    } yield (p)

    val f = db.run(q.result)

    Await.result(f, 10.seconds).toList.asJava

  }

Is there some way to be able to return a Future without needing to fork the repo and changing the signature in Subject.java ? I'm not a very experienced Scala dev so it's possible I missed some simple solution.

Action composition not working.

I'm using Play 2.6

I tried as per example:
def someFunctionA = deadbolt.SubjectPresent() { Action { Ok("Ok") } }

play.sbt.PlayExceptions$CompilationException: Compilation error[type mismatch;
found : play.api.mvc.Action[play.api.mvc.AnyContent]
required: play.api.mvc.BodyParser[?]]

Also tried:
def someFunctionA = deadbolt.SubjectPresent()() { Action { Ok("Ok") } }

play.sbt.PlayExceptions$CompilationException: Compilation error[type mismatch;
found : play.api.mvc.Action[play.api.mvc.AnyContent]
required: be.objectify.deadbolt.scala.AuthenticatedRequest[play.api.mvc.AnyContent] => scala.concurrent.Future[play.api.mvc.Result]]

Structural type in DeadboltActionBuilder triggers compiler warnings

I am trying to update to 2.5.0 and I have encountered the following issue:

This method returning a structural type produces the following warning:

reflective access of structural type member method apply should be enabled by making the implicit value scala.language.reflectiveCalls visible. This can be achieved by adding the import clause 'import scala.language.reflectiveCalls' or by setting the compiler option -language:reflectiveCalls. See the Scaladoc for value scala.language.reflectiveCalls for a discussion why the feature should be explicitly enabled.

This seems a bit suspicious (having to resort to reflection is always suspicious...) and I was wondering if there is any reason it cannot be just a normal type (e.g. DeadboltActionBuilderWithHandler) to avoid these complications?

DeadboltActions not working

Hi, Im running into an issue with DeadboltActions. I think it has to do with dependency injection?

Im running Scala 2.11.12 and Deadbolt 2.6.0 with Play 2.7.

Unexpected exception
ProvisionException: Unable to provision, see the following errors:

  1. Error injecting constructor, java.lang.AbstractMethodError: Receiver class be.objectify.deadbolt.scala.DeadboltActions does not define or inherit an implementation of the resolved method abstract play$api$mvc$Results$setter$PreconditionRequired_$eq(Lplay/api/mvc/Results$Status;)V of interface play.api.mvc.Results.
    at be.objectify.deadbolt.scala.DeadboltActions.(DeadboltActions.scala:34)
    at be.objectify.deadbolt.scala.DeadboltModule.bindings(DeadboltModule.scala:30):
    Binding(class be.objectify.deadbolt.scala.DeadboltActions to self) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
    while locating be.objectify.deadbolt.scala.DeadboltActions
    for the 3rd parameter of controllers.HomeController.(HomeController.scala:17)
    while locating controllers.HomeController
    for the 2nd parameter of router.Routes.(Routes.scala:29)
    while locating router.Routes
    while locating play.api.inject.RoutesProvider
    while locating play.api.routing.Router
    for the 3rd parameter of play.api.http.JavaCompatibleHttpRequestHandler.(HttpRequestHandler.scala:305)
    while locating play.api.http.JavaCompatibleHttpRequestHandler
    while locating play.api.http.HttpRequestHandler
    for the 6th parameter of play.api.DefaultApplication.(Application.scala:253)
    at play.api.DefaultApplication.class(Application.scala:252)
    while locating play.api.DefaultApplication
    while locating play.api.Application
    1 error

user present or not using AuthenticatedRequest in templates

Hi,

I try to migrate to 2.5 but I have a blocking question:

I have templates using deadbolt views (e.g. @subjectNotPresentOr(){} {}) rendered sometimes with a subject present, sometimes not. That means I call my template from a Play standard Action.
Hence, I manually have to create an AuthenticatedRequest to pass it to the template.

Is there a better option than this not very pretty workaround? Or a maybeSubject action could be interesting in that use case ?

Thanks a lot.

Cheers.

Authorization before request body validation

When we pass body parser to deadbolt action parsing is invoked before authorization. So when we pass invalid request body and invalid authorization data we get validation error response instead authorization error.

DeadboltHandler.getSubject should be async to support non-blocking service, like it was in previous version

If I use non-blocking async service to get current subject (which returns Future), I need to block it to satisfy the new version (v2.3.3) of the API. Previous version (v2.3.2) was non-blocking. Now I have to block my code like this:

trait UserService {
  def getUser[A](implicit request: Request[A]): Future[Option[User]] = ... // some non-blocking code here
}
class MyDeadboltHandler extends DeadboltHandler {
  override def getSubject[A](request: Request[A]): Option[Subject] =
    Await.result(userService.getUser(request), 1.minute)) // This code is blocking
}

So, were there any purpose for forcing users to block their service calls?

Play 2.6

Play 2.6.x is out, so I was wondering when you'll be able to update to it.

I already tried upgrading my own application but I had some issues which I think came from deadbolt. I'll post these in a minute.

I'd like to help you out with this if you need help.

When getSubject returns None, Pattern generates a NoSuchElementException: None.get

For example in the project deadbolt-2-scala-examples, if I replace the current method getSubject in order to always return None, and try to go to the page /printersEdit ,I get the following trace:

play.api.Application$$anon$1: Execution exception[[NoSuchElementException: None.get]]
at play.api.Application$class.handleError(Application.scala:289) ~[play_2.10.jar:2.1.1]
at play.api.DefaultApplication.handleError(Application.scala:383) [play_2.10.jar:2.1.1]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$17$$anonfun$apply$24.apply(PlayDefaultUpstreamHandler.scala:326) [play_2.10.jar:2.1.1]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$17$$anonfun$apply$24.apply(PlayDefaultUpstreamHandler.scala:324) [play_2.10.jar:2.1.1]
at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.1]
at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.1]
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:313) ~[scala-library.jar:na]
at scala.None$.get(Option.scala:311) ~[scala-library.jar:na]
at be.objectify.deadbolt.scala.DeadboltActions$$anonfun$Pattern$1.apply(DeadboltActions.scala:128) ~[deadbolt-scala_2.10-2.1-RC2.jar:2.1-RC2]
at be.objectify.deadbolt.scala.DeadboltActions$$anonfun$Pattern$1.apply(DeadboltActions.scala:124) ~[deadbolt-scala_2.10-2.1-RC2.jar:2.1-RC2]
at play.api.mvc.ActionBuilder$$anon$1.apply(Action.scala:217) ~[play_2.10.jar:2.1.1]
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$2$$anonfun$apply$5$$anonfun$apply$6.apply(Action.scala:109) ~[play_2.10.jar:2.1.1]

How to inject DeadboltActions in a Play Controller that depends on it ?

Let's say I have Play 2.4 Controller like this:

class Application @Inject() (deadbolt: DeadboltActions, myService: MyService) extends Controller {

  def hello = deadbolt.SubjectPresent() {
    Action.async{
      val res = myService.helloWorld
      res.map(s => Ok(s))
    }
  }
}

And I use compile time dependency injection to inject the Application controller:
https://www.playframework.com/documentation/2.4.x/ScalaCompileTimeDependencyInjection

Here is my application loader:

class MyAplicationLoader extends ApplicationLoader {
  def load(context: Context): Application = {
    new MyComponents(context).application
  }
}

class MyComponents(context: Context) extends BuiltInComponentsFromContext(context)  {
  lazy val myService = new MyService()

  // The issue is at here. How do I inject the DeadboltActions to Application controller?
  lazy val applicationController = new controllers.Application(..., myService)

  lazy val assets = new controllers.Assets(httpErrorHandler)
  lazy val router = new Routes(httpErrorHandler, applicationController, assets)
}

As you can see the code, at this line I need to provide the DeadboltActions argument to the Application controller:

lazy val applicationController = new controllers.Application(..., myService)

I don't know how to instantiateDeadboltActions, I checked the DeadboltActions has this signature:

class DeadboltActions(analyzer: be.objectify.deadbolt.scala.ScalaAnalyzer, handlers: be.objectify.deadbolt.scala.cache.HandlerCache)

I can supply HandlerCache argument with MyHandlerCache but don't know about ScalaAnalyzer.

Extending deadbolts AuthenticatedRequest

How could I go about extending the authenticated request?

Usecase: I've got a website that requires knowing the hostname and loads a specific configuration based on the hostname. This information is required on a large part of requests so it would be nice to be able to automatically include this information where necessary.

My proposed solution is to extend the AuthenticatedRequest using Play's native action builders etc. However it is not immediately clear to me how to extend the authenticated request without losing the deadbolt.SubjectPresent deadbolt.Pattern etc functionality. Extending DeadboltActions is not a really good idea because it really hooks stuff together and if you change the interface of the hooks it won't work anymore.

Do you have any ideas?

Library inconsistencies with 2.4.2

Using the latest release together with play seems to result in errors, and library inconsistencies. Is it possible that deadbolt 2.4.2 is built on an old play?

Build.sbt dependencies:

libraryDependencies ++= Seq(
  "com.google.inject" % "guice" % "4.0",
  "javax.inject" % "javax.inject" % "1",
  "org.webjars" %% "webjars-play" % "2.4.0",
  "org.webjars" % "bootstrap" % "3.3.4",
  "org.webjars" % "angularjs" % "1.3.15",
  "org.webjars" % "angular-ui-bootstrap" % "0.13.0",
  "org.mockito" % "mockito-core" % "1.10.19" % "test",
  "be.objectify" %% "deadbolt-scala" % "2.4.2"
)

And the problem:

[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * com.typesafe.play:play_2.11:2.3.9 -> 2.4.0
[warn]  * com.typesafe.play:twirl-api_2.11:1.0.2 -> 1.1.1
[warn] Run 'evicted' to see detailed eviction warnings

java.lang.NoSuchMethodException: play.core.server.NettyServer.mainDevHttpMode(play.core.BuildLink, play.core.BuildDocHandler, int)
    at java.lang.Class.getMethod(Class.java:1786)
    at play.runsupport.Reloader$.startDevMode(Reloader.scala:196)
    at play.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.devModeServer$lzycompute$1(PlayRun.scala:75)
    at play.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.play$PlayRun$class$$anonfun$$anonfun$$anonfun$$devModeServer$1(PlayRun.scala:75)
    at play.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.apply(PlayRun.scala:98)
    at play.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.apply(PlayRun.scala:54)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) java.lang.NoSuchMethodException: play.core.server.NettyServer.mainDevHttpMode(play.core.BuildLink, play.core.BuildDocHandler, int)
[error] Total time: 0 s, completed Dec 18, 2015 4:42:56 PM

Getting the subject from the request within a Composite Action?

I switched my deadbolt action from one that just restricted roles

deadbolt.Restrict(allOfGroup("foo"))() { authRequest =>
  Future {
    Ok(authRequest.subject.map(_.identifier))
  }
}

to another that leverages composite actions

 deadbolt.Composite(
       constraint = constraints.ConstraintTree[A](||(ec),
                                                  List(constraints.Restrict(allOfGroup("foo")),
                                                       constraints.Pattern("killer.undead.zombie",
                                                                           PatternType.REGEX))))(){authRequest =>
  Future {
    Ok(authRequest.subject.map(_.identifier))
  }}

It appears for the composite case the request is never supplied with the subject (First case returns the identifier and the second case doesn't). Am I doing something wrong? In my case I need the identifier for downstream operations.

Please tag releases

Hi @schaloner,

is it possible that you git-tag your releases? It's easier to compare/diff tags to see what has changed between versions. Also for deadbolt-java please ๐Ÿ˜„
Thanks!

Difficulty while using play 2.3.10 for Scala with deadbolt 2.3.2

Hi,

I am using deadbolt-scala , version 2.3.2, with play-framework 2.3.10 (scala version: 2.11.7).

I would like to consult, in order to improve the following code. This is a repeatable issue I have in my code.

And the matter is:

When I use Deadbolt in my play framework controllers, sometimes the authorization check is nested inside the inner request. meaning, that in this part I would like to return Future[Result] and not Action[AnyContent].

Since using deadbolt "dynamic" method to add authorization check returns action[A], I need to use apply[request] to force returning Future[Result].

Also, when the original request asynchronous and has body, the returned type is of type Action[JsValue] , so I need to convert it to Action[AnyContent] using asInstanceOf (in order to use the right apply method that will return the expected Future[Result] type ).

This is not such a nice code, and using asInstanceOf[Request[AnyContent]] is a Scala anti-pattern, please advice me if there is a better way of achieving my goal.

Thanks.

Code Example:

/code

def doRequest() = {
  Action.async(parse.json) {
    request => {
      /** fetch auth_param here **/.flatMap(_ match {
        case Some(fetched_param) =>
          performOperationWhenValid(auth_param) 
        case None =>
          ..... 
      }.recover {
      case e => doRecover(e)
    }
  }
}

def performOperationWhenValid(auth_param:String) = {
  // Authorization check 
  val allow_or_forbid_action = Dynamic(auth_param:String, "",
  new FL_DeadboltHandler(Option(new AuthorizedDynamicResourceHandler))) {
    Action.async {
      request.body.validate[PerformOperationRequest].fold(
      errors =>
      Future.successful(BadRequest(formatErrorMessage(errors)))
      ,
      patch_request =>
      /*** performOperation here after authorization check is passed successfully... ***/
    }
  }
  allow_or_forbid_action.apply(request.asInstanceOf[AnyContent])
}    

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.