Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 1 | #include <boost/algorithm/string/predicate.hpp> |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 2 | #include <random> |
Ed Tanous | f927347 | 2017-02-28 16:05:13 -0800 | [diff] [blame] | 3 | #include <unordered_map> |
Ed Tanous | f927347 | 2017-02-28 16:05:13 -0800 | [diff] [blame] | 4 | |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 5 | #include <crow/logging.h> |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 6 | #include <base64.hpp> |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 7 | #include <token_authorization_middleware.hpp> |
Ed Tanous | f927347 | 2017-02-28 16:05:13 -0800 | [diff] [blame] | 8 | |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 9 | namespace crow { |
| 10 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 11 | using random_bytes_engine = |
| 12 | std::independent_bits_engine<std::default_random_engine, CHAR_BIT, |
| 13 | unsigned char>; |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 14 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 15 | TokenAuthorizationMiddleware::TokenAuthorizationMiddleware() |
| 16 | : auth_token2(""){ |
Ed Tanous | f927347 | 2017-02-28 16:05:13 -0800 | [diff] [blame] | 17 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 18 | }; |
| 19 | |
| 20 | void TokenAuthorizationMiddleware::before_handle(crow::request& req, |
| 21 | response& res, context& ctx) { |
Ed Tanous | 9992332 | 2017-03-03 14:21:24 -0800 | [diff] [blame] | 22 | auto return_unauthorized = [&req, &res]() { |
| 23 | res.code = 401; |
| 24 | res.end(); |
| 25 | }; |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 26 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 27 | LOG(DEBUG) << "Token Auth Got route " << req.url; |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 28 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 29 | if (req.url == "/" || boost::starts_with(req.url, "/static/")) { |
| 30 | // TODO this is total hackery to allow the login page to work before the |
| 31 | // user is authenticated. Also, it will be quite slow for all pages instead |
| 32 | // of a one time hit for the whitelist entries. Ideally, this should be |
| 33 | // done |
| 34 | // in the url router handler, with tagged routes for the whitelist entries. |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 35 | // Another option would be to whitelist a minimal |
Ed Tanous | 9b65f1f | 2017-03-07 15:17:13 -0800 | [diff] [blame] | 36 | return; |
| 37 | } |
| 38 | |
Ed Tanous | 9992332 | 2017-03-03 14:21:24 -0800 | [diff] [blame] | 39 | if (req.url == "/login") { |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 40 | if (req.method != HTTPMethod::POST) { |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 41 | return_unauthorized(); |
| 42 | return; |
| 43 | } else { |
| 44 | auto login_credentials = crow::json::load(req.body); |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 45 | if (!login_credentials) { |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 46 | return_unauthorized(); |
| 47 | return; |
| 48 | } |
| 49 | auto username = login_credentials["username"].s(); |
| 50 | auto password = login_credentials["password"].s(); |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 51 | |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 52 | // TODO(ed) pull real passwords from PAM |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 53 | if (username == "dude" && password == "dude") { |
| 54 | // TODO(ed) the RNG should be initialized at start, not every time we |
| 55 | // want a token |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 56 | std::random_device rand; |
| 57 | random_bytes_engine rbe; |
| 58 | std::string token('a', 20); |
| 59 | std::generate(begin(token), end(token), std::ref(rbe)); |
| 60 | std::string encoded_token; |
| 61 | base64::base64_encode(token, encoded_token); |
| 62 | ctx.auth_token = encoded_token; |
| 63 | this->auth_token2 = encoded_token; |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 64 | crow::json::wvalue x; |
| 65 | auto auth_token = ctx.auth_token; |
| 66 | x["token"] = auth_token; |
| 67 | |
| 68 | res.write(json::dump(x)); |
| 69 | res.end(); |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 70 | } else { |
| 71 | return_unauthorized(); |
| 72 | return; |
| 73 | } |
| 74 | } |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 75 | |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 76 | } else if (req.url == "/logout") { |
| 77 | this->auth_token2 = ""; |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 78 | res.code = 200; |
| 79 | res.end(); |
| 80 | } else { // Normal, non login, non static file request |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 81 | // Check to make sure we're logged in |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 82 | if (this->auth_token2.empty()) { |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 83 | return_unauthorized(); |
| 84 | return; |
| 85 | } |
| 86 | // Check for an authorization header, reject if not present |
| 87 | if (req.headers.count("Authorization") != 1) { |
| 88 | return_unauthorized(); |
| 89 | return; |
| 90 | } |
| 91 | |
| 92 | std::string auth_header = req.get_header_value("Authorization"); |
| 93 | // If the user is attempting any kind of auth other than token, reject |
| 94 | if (!boost::starts_with(auth_header, "Token ")) { |
| 95 | return_unauthorized(); |
| 96 | return; |
| 97 | } |
| 98 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 99 | // TODO(ed), use span here instead of constructing a new string |
| 100 | if (auth_header.substr(6) != this->auth_token2) { |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 101 | return_unauthorized(); |
| 102 | return; |
| 103 | } |
Ed Tanous | 1ccd57c | 2017-03-21 13:15:58 -0700 | [diff] [blame] | 104 | // else let the request continue unharmed |
Ed Tanous | 9992332 | 2017-03-03 14:21:24 -0800 | [diff] [blame] | 105 | } |
| 106 | } |
Ed Tanous | f927347 | 2017-02-28 16:05:13 -0800 | [diff] [blame] | 107 | |
Ed Tanous | 8041f31 | 2017-04-03 09:47:01 -0700 | [diff] [blame^] | 108 | void TokenAuthorizationMiddleware::after_handle(request& req, response& res, |
| 109 | context& ctx) {} |
Ed Tanous | c4771fb | 2017-03-13 13:39:49 -0700 | [diff] [blame] | 110 | } |