Skip to content

Instantly share code, notes, and snippets.

@Joannis
Created August 3, 2016 16:42
Show Gist options
  • Save Joannis/e690c4cfb103348039ede6b0c26a2362 to your computer and use it in GitHub Desktop.
Save Joannis/e690c4cfb103348039ede6b0c26a2362 to your computer and use it in GitHub Desktop.
import MongoKitten
import HTTP
import Vapor
protocol RolesRepresentable {
var roles: [Role] { get }
}
protocol Role {
var authorizationLevel: AuthorizationLevel { get }
}
struct MongoRole: Role {
static var collection: MongoKitten.Collection!
static func find(forUser userID: ObjectId) throws -> [MongoRole] {
return Array(try MongoRole.collection.find(matching: "user" == ~userID).flatMap {
MongoRole(document: $0)
})
}
init?(document: Document) {
self.data = document
}
let data: Document
var authorizationLevel: AuthorizationLevel {
return .anonymous
// TODO: Change to a real role
}
}
struct MongoUser: Account, RolesRepresentable {
var accountID: String
var roles: [Role] {
do {
return try MongoRole.find(forUser: try ObjectId(accountID)).flatMap {
$0
}
} catch {
return []
}
}
}
extension APIKitten.User: RolesRepresentable {
internal var roles: [Role] {
guard let authDetails = self.authDetails else {
return []
}
guard let mongoUser = authDetails.account as? MongoUser else {
return []
}
return mongoUser.roles
}
var authorizationLevel: [AuthorizationLevel] {
return roles.map {
$0.authorizationLevel
}
}
}
extension Request {
var subject: APIKitten.User? {
get {
return storage["TurnstileSubject"] as? APIKitten.User
}
set {
storage["TurnstileSubject"] = newValue
}
}
}
enum AuthorizationLevel {
case anonymous
}
class AuthenticationMiddleware: Middleware {
let turnstile: Turnstile
let levels: [AuthorizationLevel]
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
let user = APIKitten.User(turnstile: turnstile)
request.subject = user
request.storage["authenticated"] = true
for level in levels where user.authorizationLevel.contains(level) {
return try next.respond(to: request)
}
return try Response(status: .badRequest, json: try JSON(["error": "Insufficient permissions"]))
}
init(_ authorizationLevels: [AuthorizationLevel], turnstile: Turnstile) {
self.turnstile = turnstile
self.levels = authorizationLevels
}
}
class AuthenticationVerifier: Middleware {
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
guard request.storage["authenticated"] as? Bool ?? false else {
// Request is not authenticated by a `Middleware`
return try Response(status: .internalServerError, json: try JSON(["error": "Internal server error"]))
}
return try next.respond(to: request)
}
}
let a = Droplet()
let turnstile = Turnstile(sessionManager: MemorySessionManager(), realm: MemoryRealm())
a.globalMiddleware.append(AuthenticationVerifier())
a.get("test") { req in
return "this will never execute"
}
a.group(AuthenticationMiddleware([.anonymous], turnstile: turnstile)) { app in
app.get("test2") { req in
return "works"
}
}
a.serve()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment