t2v / play2-auth

Play2.x Authentication and Authorization module
Apache License 2.0
608 stars 142 forks source link

Dynamic authorizations with POSTed parameter are messy #14

Open gakuzzzz opened 12 years ago

gakuzzzz commented 12 years ago

An authorization with the action method's parameters is easy. see also https://github.com/t2v/play20-auth/wiki/Advanced-usage:-----request-parameters

But dynamic authorizations with POSTed parameter are messy.

I want to provide the easy way to do it.

soldiermoth commented 12 years ago

+1

sagarsg commented 10 years ago

Hi,

I am trying to get the dynamic authorizations working. Is there a easy way to do this. I would like to get the Permission from the database instead of hardcoding it.

Now, def home = AsyncStack(AuthorityKey -> Administrator) { implicit request =>

Instead, can we do something like below - def home = AsyncStack(AuthorityKey -> getPermission(user)) { implicit request =>

Thanks in advance.

gakuzzzz commented 10 years ago

Hi,

@vogwheels, Sorry I cannot grasp your problem yet.

Is your home action's Authority changed by access user?

you can use getPermission method in authorize implementation of AuthConfig. If all actions use same authority always, you can define the Authority type as Unit

trait AuthConfigImpl extends AuthConfig {
  type Authority = Unit
  def authorize(user: User, authority: Authority): Future[Boolean] = Future.successful {
    val permission = getPermission(user)
    permission.isAdministrator
  }  
}
def home = AsyncStack(AuthorityKey -> ()) { implicit request =>
samco commented 9 years ago

I solved the POST parameter dynamic authorization problem with a trait extending StackableController.

The trait looks something like this:

trait PostParameterAuthElement
    extends StackableController
    with AuthConfigImpl {
    self: AuthElement =>

    lazy val idForm = Form(
        single(
            "id" -> longNumber
        )
    )

    override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Future[Result]): Future[Result] = {
        implicit val request = req
        idForm.bindFromRequest.fold(
            formWithErrors => {
                Future.successful(BadRequest("ID missing"))
            },
            id => {
                Model.findById(iId) match {
                    case Some(model) if (model.ownerId == loggedIn.id) => super.proceed(request)(f)
                    case Some(model) => authorizationFailed(request)
                    case None => Future.successful(NotFound)
                }
            }
        )
  }
}

So then the controller doesn't have the authorisation stuff in it that the example at https://github.com/t2v/play2-auth#changing-the-authorization-depending-on-the-request-parameters has.

I would need to implement a new trait for each authorisation rule and each model type. I'm pretty new to Scala so I don't know if there's a way for play2 to make this easier.

gakuzzzz commented 9 years ago

Hi all,

Now, I try to create a way of Dynamic authorizations with POSTed parameter #119

Using #119 makes is enable as follows

object FooController extends Controller with AuthConfigImpl with AuthElement {

  type Authority = Long
  def authorize(user: User, authority: Authority) = {
    Future.successful(user.id == authority)
  }

  def postAuth = StackAction(AuthorityFactoryKey[AnyContent] -> postedAuthority) { implicit req =>
    ... you can define any action code.
  }

  private lazy val idForm = Form {
    "id" -> longNumber
  }

  private lazy val postedAuthority: Request[AnyContent] => Either[Result, Authority] = { implicit req =>
    idForm.bindFromRequest.fold(Left.apply, Right.apply)
      .left.map(_ => BadRequest("ID missing"))
      .right.flatMap { id =>
        Model.findById(id).map(_.ownerId).toRight(NotFound)
      }
    }
  }

}

What do you say?

samco commented 9 years ago

This looks good but I am going away for a couple of weeks so won't be able to try it for a while. I will let you know how my testing goes when I get back.

samco commented 9 years ago

I have had a chance to give this a run, it works well for my purposes. Thanks for your work on this.