blob: bf164c807cd03a55003c5be075870f59449ef8f8 [file] [log] [blame]
Ed Tanous1ccd57c2017-03-21 13:15:58 -07001#include <random>
Ed Tanousf9273472017-02-28 16:05:13 -08002#include <unordered_map>
Ed Tanous9140a672017-04-24 17:01:32 -07003#include <boost/algorithm/string/predicate.hpp>
Ed Tanousf9273472017-02-28 16:05:13 -08004
Ed Tanousc4771fb2017-03-13 13:39:49 -07005#include <base64.hpp>
Ed Tanous8041f312017-04-03 09:47:01 -07006#include <token_authorization_middleware.hpp>
Ed Tanous9140a672017-04-24 17:01:32 -07007#include <crow/logging.h>
Ed Tanousf9273472017-02-28 16:05:13 -08008
Ed Tanousc4771fb2017-03-13 13:39:49 -07009namespace crow {
10
Ed Tanous8041f312017-04-03 09:47:01 -070011using random_bytes_engine =
12 std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
13 unsigned char>;
Ed Tanousc4771fb2017-03-13 13:39:49 -070014
Ed Tanous8041f312017-04-03 09:47:01 -070015TokenAuthorizationMiddleware::TokenAuthorizationMiddleware()
16 : auth_token2(""){
Ed Tanousf9273472017-02-28 16:05:13 -080017
Ed Tanous8041f312017-04-03 09:47:01 -070018 };
19
20void TokenAuthorizationMiddleware::before_handle(crow::request& req,
21 response& res, context& ctx) {
Ed Tanous99923322017-03-03 14:21:24 -080022 auto return_unauthorized = [&req, &res]() {
23 res.code = 401;
24 res.end();
25 };
Ed Tanous1ccd57c2017-03-21 13:15:58 -070026
Ed Tanous1e94fa42017-04-03 13:41:19 -070027 auto return_bad_request = [&req, &res]() {
28 res.code = 400;
29 res.end();
30 };
31
Ed Tanousd793bb42017-04-25 08:59:32 -070032 auto return_internal_error = [&req, &res]() {
33 res.code = 500;
34 res.end();
35 };
36
Ed Tanous9140a672017-04-24 17:01:32 -070037 CROW_LOG_DEBUG << "Token Auth Got route " << req.url;
Ed Tanous1ccd57c2017-03-21 13:15:58 -070038
Ed Tanous8041f312017-04-03 09:47:01 -070039 if (req.url == "/" || boost::starts_with(req.url, "/static/")) {
40 // TODO this is total hackery to allow the login page to work before the
41 // user is authenticated. Also, it will be quite slow for all pages instead
42 // of a one time hit for the whitelist entries. Ideally, this should be
43 // done
44 // in the url router handler, with tagged routes for the whitelist entries.
Ed Tanous1ccd57c2017-03-21 13:15:58 -070045 // Another option would be to whitelist a minimal
Ed Tanous9b65f1f2017-03-07 15:17:13 -080046 return;
47 }
48
Ed Tanous99923322017-03-03 14:21:24 -080049 if (req.url == "/login") {
Ed Tanous8041f312017-04-03 09:47:01 -070050 if (req.method != HTTPMethod::POST) {
Ed Tanousc4771fb2017-03-13 13:39:49 -070051 return_unauthorized();
52 return;
53 } else {
54 auto login_credentials = crow::json::load(req.body);
Ed Tanous8041f312017-04-03 09:47:01 -070055 if (!login_credentials) {
Ed Tanous1e94fa42017-04-03 13:41:19 -070056 return_bad_request();
57 return;
58 }
Ed Tanous1ff48782017-04-18 12:45:08 -070059 if (!login_credentials.has("username") ||
60 !login_credentials.has("password")) {
Ed Tanous1e94fa42017-04-03 13:41:19 -070061 return_bad_request();
Ed Tanousc4771fb2017-03-13 13:39:49 -070062 return;
63 }
64 auto username = login_credentials["username"].s();
65 auto password = login_credentials["password"].s();
Ed Tanous8041f312017-04-03 09:47:01 -070066
Ed Tanous1ccd57c2017-03-21 13:15:58 -070067 // TODO(ed) pull real passwords from PAM
Ed Tanous8041f312017-04-03 09:47:01 -070068 if (username == "dude" && password == "dude") {
Ed Tanousd793bb42017-04-25 08:59:32 -070069 crow::json::wvalue x;
70
Ed Tanous8041f312017-04-03 09:47:01 -070071 // TODO(ed) the RNG should be initialized at start, not every time we
72 // want a token
Ed Tanousc4771fb2017-03-13 13:39:49 -070073 std::random_device rand;
74 random_bytes_engine rbe;
75 std::string token('a', 20);
Ed Tanous1ff48782017-04-18 12:45:08 -070076 // TODO(ed) for some reason clang-tidy finds a divide by zero error in
77 // cstdlibc here
Ed Tanous93f987d2017-04-17 17:52:36 -070078 // commented out for now. Needs investigation
79 std::generate(begin(token), end(token), std::ref(rbe)); // NOLINT
Ed Tanousc4771fb2017-03-13 13:39:49 -070080 std::string encoded_token;
81 base64::base64_encode(token, encoded_token);
82 ctx.auth_token = encoded_token;
83 this->auth_token2 = encoded_token;
Ed Tanousd793bb42017-04-25 08:59:32 -070084
Ed Tanous8041f312017-04-03 09:47:01 -070085 auto auth_token = ctx.auth_token;
86 x["token"] = auth_token;
87
88 res.write(json::dump(x));
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070089 res.add_header("Content-Type", "application/json");
Ed Tanous8041f312017-04-03 09:47:01 -070090 res.end();
Ed Tanousc4771fb2017-03-13 13:39:49 -070091 } else {
92 return_unauthorized();
93 return;
94 }
95 }
Ed Tanous8041f312017-04-03 09:47:01 -070096
Ed Tanousc4771fb2017-03-13 13:39:49 -070097 } else if (req.url == "/logout") {
98 this->auth_token2 = "";
Ed Tanous8041f312017-04-03 09:47:01 -070099 res.code = 200;
100 res.end();
101 } else { // Normal, non login, non static file request
Ed Tanousc4771fb2017-03-13 13:39:49 -0700102 // Check to make sure we're logged in
Ed Tanous8041f312017-04-03 09:47:01 -0700103 if (this->auth_token2.empty()) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700104 return_unauthorized();
105 return;
106 }
107 // Check for an authorization header, reject if not present
108 if (req.headers.count("Authorization") != 1) {
109 return_unauthorized();
110 return;
111 }
112
113 std::string auth_header = req.get_header_value("Authorization");
114 // If the user is attempting any kind of auth other than token, reject
115 if (!boost::starts_with(auth_header, "Token ")) {
116 return_unauthorized();
117 return;
118 }
119
Ed Tanous8041f312017-04-03 09:47:01 -0700120 // TODO(ed), use span here instead of constructing a new string
121 if (auth_header.substr(6) != this->auth_token2) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700122 return_unauthorized();
123 return;
124 }
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700125 // else let the request continue unharmed
Ed Tanous99923322017-03-03 14:21:24 -0800126 }
127}
Ed Tanousf9273472017-02-28 16:05:13 -0800128
Ed Tanous8041f312017-04-03 09:47:01 -0700129void TokenAuthorizationMiddleware::after_handle(request& req, response& res,
130 context& ctx) {}
Ed Tanousc4771fb2017-03-13 13:39:49 -0700131}