Last active
February 8, 2017 14:33
-
-
Save hhanesand/310ff975ee1f1142a84ef11b7b5a3620 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
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 | |
} | |
} |
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
// | |
// 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) | |
} | |
} | |
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
// | |
// 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