Created
August 3, 2016 16:42
-
-
Save Joannis/e690c4cfb103348039ede6b0c26a2362 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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