1 module vibeauth.router.basic; 2 3 import vibe.http.router; 4 import vibe.data.json; 5 import vibeauth.users; 6 import std.algorithm.searching, std.base64, std..string, std.stdio; 7 import vibeauth.router.baseAuthRouter; 8 9 /// Basic auth credential pair 10 struct BasicAuthCredentials { 11 /// 12 string username; 13 14 /// 15 string password; 16 } 17 18 /// Basic auth handler. It's not safe to use it without https. 19 class BasicAuth(string realm): BaseAuthRouter { 20 21 /// 22 this(UserCollection collection) { 23 super(collection); 24 } 25 26 override { 27 /// Auth handler that will fail if a successfull auth was not performed. 28 /// This handler is usefull for routes that want to hide information to the 29 /// public. 30 void mandatoryAuth(HTTPServerRequest req, HTTPServerResponse res) { 31 auto pauth = "Authorization" in req.headers; 32 33 setAccessControl(res); 34 35 if(pauth && (*pauth).startsWith("Basic ")) { 36 auto auth = parseBasicAuth((*pauth)[6 .. $]); 37 38 if(auth.username in collection && collection[auth.username].isValidPassword(auth.password)) { 39 req.username = auth.username; 40 return; 41 } else { 42 respondUnauthorized(res); 43 } 44 } else { 45 respondUnauthorized(res); 46 } 47 } 48 49 /// Auth handler that fails only if the auth fields are present and are not valid. 50 /// This handler is usefull when a route should return different data when the user is 51 /// logged in 52 void permisiveAuth(HTTPServerRequest req, HTTPServerResponse res) { 53 auto pauth = "Authorization" in req.headers; 54 55 setAccessControl(res); 56 57 if(pauth && (*pauth).startsWith("Basic ")) { 58 auto auth = parseBasicAuth((*pauth)[6 .. $]); 59 60 if(auth.username in collection && collection[auth.username].isValidPassword(auth.password)) { 61 req.username = auth.username; 62 return; 63 } else { 64 respondUnauthorized(res); 65 } 66 } 67 } 68 } 69 70 private { 71 /// Parse user input 72 BasicAuthCredentials parseBasicAuth(string data) { 73 string decodedData = cast(string)Base64.decode(data); 74 auto idx = decodedData.indexOf(":"); 75 enforceBadRequest(idx >= 0, "Invalid auth string format!"); 76 77 return BasicAuthCredentials(decodedData[0 .. idx], decodedData[idx+1 .. $]); 78 } 79 80 /// Respond with auth error 81 void respondUnauthorized(HTTPServerResponse res, string message = "Authorization required") { 82 res.statusCode = HTTPStatus.unauthorized; 83 res.contentType = "text/plain"; 84 res.headers["WWW-Authenticate"] = "Basic realm=\""~realm~"\""; 85 res.bodyWriter.write(message); 86 } 87 } 88 }