Cavoke  1.1.0
A Platform for creating and hosting multiplayer turn-based board games
Loading...
Searching...
No Matches
AuthFilter.cc
1#include "AuthFilter.h"
2#include <stdexcept>
3
4using namespace drogon;
5AuthFilter::AuthFilter() {
6 // get config
7 auto app_config = nlohmann::to_nlohmann(drogon::app().getCustomConfig());
8 // check if auth config is present
9 if (app_config.contains(SETTINGS_KEYNAME)) {
10 // if yes, parse it
11 auto config = app_config.at("auth").get<AuthConfig>();
12 // check supported token type and algorithm
13 assert(config.type == "JWT");
14 assert(config.algorithm == "RS256");
15 // initialize JWT token verifier with public key
16 verifier =
17 nlohmann_verifier{jwt::default_clock()}
18 .with_audience(config.audience)
19 .with_issuer(config.issuer)
20 .allow_algorithm(jwt::algorithm::rs256(config.public_key));
21 LOG_INFO << config.type << " auth guard enabled (iss=" << config.issuer
22 << ", aud=" << config.audience << ")";
23 } else {
24 // If no auth config is found, warn the server admin
25 // Any users will be allowed access to guarded methods by
26 // a `user_id` query param
27 LOG_WARN << "No auth guard used...";
28 verifier = {};
29 }
30}
31
32void AuthFilter::doFilter(const HttpRequestPtr &req,
33 FilterCallback &&fcb,
34 FilterChainCallback &&fccb) {
35 try {
36 // if no authentication configured, just get user id parameter
37 if (!verifier.has_value()) {
38 auto user_id = req->getOptionalParameter<std::string>(USER_ID_NAME);
39 if (!user_id.has_value()) {
40 throw std::runtime_error("no user_id query parameter");
41 }
42 req->addCookie(USER_ID_NAME, user_id.value());
43 // add user to db
44 register_user(user_id.value());
45 return fccb();
46 }
47 // get authorization header
48 std::string token =
49 extract_token_from_header(req->getHeader(AUTHORIZATION_HEADER));
50 // decode and verify Bearer token
51 auto decoded = jwt::decode<jwt::traits::nlohmann_json>(token);
52 verifier->verify(decoded);
53 // Pass user id to methods
54 auto subject = decoded.get_subject();
55 req->addCookie(USER_ID_NAME, subject);
56 // add user to db
57 register_user(subject);
58 return fccb();
59 } catch (const std::exception &err) {
60 LOG_WARN << "Auth check failed: " << err.what();
61 // Authentication failed
62 return fcb(cavoke::server::controllers::newStatusCodeResponse(
63 k401Unauthorized));
64 }
65}
66
67std::string AuthFilter::extract_token_from_header(
68 const std::string &auth_header) {
69 if (auth_header.size() < TOKEN_PREFIX.size()) {
70 throw std::invalid_argument("Invalid Bearer token");
71 }
72 return {auth_header.begin() + TOKEN_PREFIX.size(), auth_header.end()};
73}
74
75void AuthFilter::register_user(const std::string &user_id) const {
76 drogon_model::cavoke_orm::Users user;
77 // add user to db if not present
78 drogon::app().getDbClient()->execSqlSync(
79 "insert into users (id) values ($1) on conflict do nothing", user_id);
80}
81
82std::string AuthFilter::get_user_id(const HttpRequestPtr &req) {
83 return req->getCookie(USER_ID_NAME);
84}
85
86const std::string AuthFilter::AUTHORIZATION_HEADER = "Authorization";
87const std::string AuthFilter::TOKEN_PREFIX = "Bearer ";
88const std::string AuthFilter::SETTINGS_KEYNAME = "auth";
89const std::string AuthFilter::USER_ID_NAME = "user_id";
static std::string get_user_id(const HttpRequestPtr &)
Acquires user_id parsed during AuthFilter's execution.
Definition: AuthFilter.cc:82