jacobus / s4

Spray Slick Starter Stack

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add authorization

opened this issue · comments

One thing is missing that most real world applications will need: an authorization mechanism.
Maybe checked against a User table with slick?

commented

Hi Marcel,

That's very true. I'll try to add something when I get the time. In the
meantime, this should help, it's a free standing test and authorisation
example in one, and should give a little insight on authorisation. It's not
pretty though, but a start:

import org.specs2.Specification
import spray.testkit.Specs2RouteTest
import spray.http._
import StatusCodes._
import spray.testkit.Specs2RouteTest
import spray.json.DefaultJsonProtocol
import spray.httpx.marshalling._
import MediaTypes.application/json
import org.specs2.runner.JUnitRunner
import spray.http.HttpHeaders.
Authorization
import spray.routing.AuthenticationRequiredRejection
import spray.routing.AuthenticationFailedRejection
import spray.routing.authentication.{ UserPass, ContextAuthenticator,
BasicAuth }
import spray.routing.Directives
import spray.routing.authentication.
UserPassAuthenticator
import spray.routing.authentication.BasicUserContext
import scala.concurrent.Promise
import scala.concurrent.Future
import spray.routing.RequestContext

class CustomAuthSpec2 extends Specification with Directives with
Specs2RouteTest {

def actorRefFactory = system

def is = {
var string2NR = () // shadow implicit conversion from Spray Directives
trait
sequential ^
"Access Control" ^
"Check Bob the Builder" ! bobAccessSucceed ^
"Check Mary had a little lamb" ! maryAccessSucceed ^
"Check Nancy Pancy" ! nancyAccessSucceed ^

  end

}

case class Company(id: Long, name: String)

val companies = List(Company(1, "Sobersoft"), Company(2, "Beersoft"),
Company(3, "Nuttylot"), Company(4, "The Pie Factory"))

companies.find(_.id == 1).get.name

case class CompanyUser(name: String, password: String, companyIds:
List[Long])

val companyUsers = List(CompanyUser("Bob", "TheBuilder", List(1, 2)),
CompanyUser("Mary", "LittleLamb", List(2, 3)), CompanyUser("Nancy",
"Pancy", List(4)))

def createCompanyUser(userPass: UserPass): CompanyUser = {
companyUsers.filter(c => c.name == userPass.user && c.password ==
userPass.pass) match {
case companyUser :: _ => companyUser
case _ => CompanyUser(userPass.user, userPass.pass, Nil)
}
}

object SimpleUserPassAuthenticator extends
UserPassAuthenticator[BasicUserContext] {

def apply(userPass: Option[UserPass]) = Promise.successful(
  userPass match {
    case Some(UserPass(user, pass)) => {
      companyUsers.find(c => c.name == user).flatMap {
        case x => {
          if (x.password == pass) Some(BasicUserContext(user)) else None

        }
      }
    }
    case _ => None
  }).future

def apply(userPass: Option[(String, String)]) = userPass.flatMap {
  case (user, pass) => {
    companyUsers.find(c => c.name == user).map { case x => if

(x.password == pass) BasicUserContext(user) }
}
}
}

object CustomUserPassAuthenticator extends
UserPassAuthenticator[CompanyUser] {

def apply(userPass: Option[UserPass]) = Promise.successful(
  userPass match {
    case Some(UserPass(user, pass)) => {
      companyUsers.find(c => c.name == user).flatMap {
        case x => {
          if (x.password == pass) Some(createCompanyUser(UserPass(user,

pass))) else None

        }
      }
    }
    case _ => None
  }).future

def apply(userPass: Option[(String, String)]) = userPass.flatMap {
  case (user, pass) => {
    companyUsers.find(c => c.name == user).map { case x => if

(x.password == pass) BasicUserContext(user) }

  }
}

}

val companyRoute = {
get {
path("company" / LongNumber) {
(companyId: Long) =>
authenticate(BasicAuth(CustomUserPassAuthenticator, "company")) {
user =>
authorize(user.companyIds.contains(companyId)) { ctx =>
println("Hi " + user.name + " welcome to " +
companies.find(.id == companyId).get.name)
ctx.complete("Welcome to Company " + companies.find(
.id ==
companyId).get.name)

        }
      }
  }
}

}

def bobAccessSucceed = {
Get("/company/2") ~>
addHeader(Authorization(BasicHttpCredentials("Bob", "TheBuilder"))) ~>
companyRoute ~> check {
entityAs[String] must contain("Company")
}
}

def maryAccessSucceed = {
Get("/company/3") ~>
addHeader(Authorization(BasicHttpCredentials("Mary", "LittleLamb"))) ~>
companyRoute ~> check {

  entityAs[String] must contain("Company")
}

}
def nancyAccessSucceed = {
Get("/company/4") ~>
addHeader(Authorization(BasicHttpCredentials("Nancy", "Pancy"))) ~>
companyRoute ~> check {

  entityAs[String] must contain("Company")
}

}
}

Best regards,
Jacobus

On Mon, Aug 19, 2013 at 2:50 PM, Marcel Klemenz notifications@github.comwrote:

One thing is missing that most real world applications will need: an
authorization mechanism.
Maybe checked against a User table with slick?


Reply to this email directly or view it on GitHubhttps://github.com//issues/1
.

commented

Basic HTTP authorisation added. Hope this helps :-p