Skip to content

Instantly share code, notes, and snippets.

@hhanesand
Last active February 8, 2017 14:33
Show Gist options
  • Save hhanesand/310ff975ee1f1142a84ef11b7b5a3620 to your computer and use it in GitHub Desktop.
Save hhanesand/310ff975ee1f1142a84ef11b7b5a3620 to your computer and use it in GitHub Desktop.
final class AuthenticationController: ResourceRepresentable {
func login(_ request: Request) throws -> ResponseRepresentable {
let type = try request.extract() as SessionType
guard let credentials = request.auth.header?.usernamePassword else {
throw AuthError.noAuthorizationHeader
}
switch type {
case .customer:
try request.userSubject().login(credentials: credentials, persist: true)
case .vendor:
try request.vendorSubject().login(credentials: credentials, persist: true)
case .none:
throw Abort.custom(status: .badRequest, message: "Can not log in with a session type of none.")
}
let modelSubject: JSONConvertible = type == .customer ? try request.customer() : try request.vendor()
return try Response(status: .ok, json: modelSubject.makeJSON())
}
func makeResource() -> Resource<String> {
return Resource(
store: login
)
}
}
extension Authorization {
public var usernamePassword: UsernamePassword? {
guard let range = header.range(of: "Basic ") else {
return nil
}
let authString = header.substring(from: range.upperBound)
let decodedAuthString = authString.base64DecodedString
guard let separatorRange = decodedAuthString.range(of: ":") else {
return nil
}
let username = decodedAuthString.substring(to: separatorRange.lowerBound)
let password = decodedAuthString.substring(from: separatorRange.upperBound)
return UsernamePassword(username: username, password: password)
}
}
extension Request {
var sessionType: SessionType {
if (try? customer()) != nil {
return .customer
} else if (try? vendor()) != nil {
return .vendor
} else {
return .none
}
}
func customer() throws -> Customer {
let subject = try userSubject()
guard let details = subject.authDetails else {
throw AuthError.notAuthenticated
}
guard let customer = details.account as? Customer else {
throw AuthError.invalidAccountType
}
return customer
}
func vendor() throws -> Vendor {
let subject = try vendorSubject()
guard let details = subject.authDetails else {
throw AuthError.notAuthenticated
}
guard let vendor = details.account as? Vendor else {
throw AuthError.invalidAccountType
}
return vendor
}
}
//
// UserAuthMiddleware.swift
// subber-api
//
// Created by Hakon Hanesand on 11/10/16.
//
//
import Turnstile
import HTTP
import Cookies
import Foundation
import Cache
import Auth
import Vapor
private let cookieName = "vapor-user-auth"
private let storageName = "userSubject"
private let cookieTimeout: TimeInterval = 7 * 24 * 60 * 60
extension Request {
func userSubject() throws -> Subject {
guard let subject = storage[storageName] as? Subject else {
throw AuthError.noSubject
}
return subject
}
}
class UserAuthMiddleware: Middleware {
private let turnstile: Turnstile
private let cookieFactory: CookieFactory
public typealias CookieFactory = (String) -> Cookie
init() {
let realm = AuthenticatorRealm<Customer>()
self.turnstile = Turnstile(sessionManager: DatabaseLoginSessionManager(realm: realm), realm: realm)
self.cookieFactory = { value in
return Cookie(
name: cookieName,
value: value,
expires: Date().addingTimeInterval(cookieTimeout),
secure: false,
httpOnly: true
)
}
}
public func respond(to request: Request, chainingTo next: Responder) throws -> Response {
request.storage[storageName] = Subject(
turnstile: turnstile,
sessionID: request.cookies[cookieName]
)
let response = try next.respond(to: request)
let session = try request.userSubject().authDetails?.sessionID
if let session = session, request.cookies[cookieName] != session {
response.cookies.insert(cookieFactory(session))
} else if session == nil && request.cookies[cookieName] != nil {
// If we have a cookie but no session, delete it.
response.cookies[cookieName] = nil
}
return response
}
}
public class UserProtectMiddleware: Middleware {
public func respond(to request: Request, chainingTo next: Responder) throws -> Response {
guard try request.userSubject().authenticated else {
throw Abort.custom(status: .forbidden, message: "No user subject.")
}
return try next.respond(to: request)
}
}
//
// VendorAuthMiddleware.swift
// subber-api
//
// Created by Hakon Hanesand on 11/10/16.
//
//
import Turnstile
import HTTP
import Cookies
import Foundation
import Cache
import Auth
import Vapor
private let cookieName = "vapor-vendor-auth"
private let storageName = "vendorSubject"
private let cookieTimeout: TimeInterval = 7 * 24 * 60 * 60
extension Request {
func vendorSubject() throws -> Subject {
guard let subject = storage[storageName] as? Subject else {
throw AuthError.noSubject
}
return subject
}
}
public class VendorAuthMiddleware: Middleware {
private let turnstile: Turnstile
private let cookieFactory: CookieFactory
public typealias CookieFactory = (String) -> Cookie
init() {
let realm = AuthenticatorRealm<Vendor>()
self.turnstile = Turnstile(sessionManager: DatabaseLoginSessionManager(realm: realm), realm: realm)
self.cookieFactory = { value in
return Cookie(
name: cookieName,
value: value,
expires: Date().addingTimeInterval(cookieTimeout),
secure: false,
httpOnly: true
)
}
}
public func respond(to request: Request, chainingTo next: Responder) throws -> Response {
request.storage[storageName] = Subject(
turnstile: turnstile,
sessionID: request.cookies[cookieName]
)
let response = try next.respond(to: request)
let session = try request.vendorSubject().authDetails?.sessionID
if let session = session, request.cookies[cookieName] != session {
response.cookies.insert(cookieFactory(session))
} else if session == nil && request.cookies[cookieName] != nil {
// If we have a cookie but no session, delete it.
response.cookies[cookieName] = nil
}
return response
}
}
public class VendorProtectMiddleware: Middleware {
public func respond(to request: Request, chainingTo next: Responder) throws -> Response {
guard try request.vendorSubject().authenticated else {
throw Abort.custom(status: .forbidden, message: "No vendor subject.")
}
return try next.respond(to: request)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment