AXIAM C++ SDK 1.0.0-alpha8
Authentication, authorization, JWKS & route guards (REST + mTLS)
Loading...
Searching...
No Matches
guard.hpp
Go to the documentation of this file.
1// §10 route-guard interface + §11 declarative authorization helpers.
2//
3// Framework-agnostic: the host adapter (Crow / Pistache / any HTTP server) pulls
4// the raw credential out of the request; turning it into an AxiamUser is the job
5// of axiam::TokenAuthenticator in <axiam/authenticator.hpp>, which is the
6// supported §10 verification path (signature + exp + nbf + tenant binding, fail
7// closed). Do NOT build an AxiamUser straight from
8// JwksVerifier::verify_signature_only_unchecked — that primitive validates the
9// signature only, so a guard fed from it accepts expired and cross-tenant tokens.
10//
11// The helpers here run strictly AFTER that identity exists and compose on top of
12// the client's check_access surface; they never re-implement token verification.
13#pragma once
14
15#include <functional>
16#include <initializer_list>
17#include <optional>
18#include <string>
19#include <vector>
20
21#include "axiam/client.hpp"
22#include "axiam/errors.hpp"
23
24namespace axiam {
25
27struct AxiamUser {
28 std::string user_id;
29 std::string tenant_id;
30 std::vector<std::string> roles;
31
32 bool has_role(const std::string& role) const {
33 for (const auto& r : roles) {
34 if (r == role) return true;
35 }
36 return false;
37 }
38};
39
42inline const AxiamUser& require_auth(const std::optional<AxiamUser>& user) {
43 if (!user.has_value()) {
44 throw AuthError("authentication_failed");
45 }
46 return *user;
47}
48
52inline void require_role(const std::optional<AxiamUser>& user,
53 std::initializer_list<std::string> any_of) {
54 const AxiamUser& u = require_auth(user);
55 for (const auto& role : any_of) {
56 if (u.has_role(role)) return;
57 }
58 throw AuthzError("authorization_denied: missing required role");
59}
60
69inline void require_access(Client& client, const std::optional<AxiamUser>& user,
70 const std::string& action, const std::string& resource_id,
71 std::optional<std::string> scope = std::nullopt) {
72 const AxiamUser& u = require_auth(user);
73 if (resource_id.empty()) {
74 // §11.3: unresolvable resource id is a programming error (400).
75 throw std::invalid_argument("invalid_request: unresolved resource id");
76 }
77 AccessDecision decision;
78 try {
79 decision = client.check_access(action, resource_id, std::move(scope), u.user_id);
80 } catch (const AuthzError&) {
81 throw; // server said 403/409 → denied
82 } catch (const NetworkError&) {
83 // §11.5: fail closed on transport failure; never allow.
84 throw AuthzError("authz_unavailable");
85 }
86 if (!decision.allowed) {
87 throw AuthzError("authorization_denied");
88 }
89}
90
93template <typename Request>
94void require_access(Client& client, const std::optional<AxiamUser>& user,
95 const std::string& action,
96 const std::function<std::string(const Request&)>& resolver,
97 const Request& request, std::optional<std::string> scope = std::nullopt) {
98 require_access(client, user, action, resolver(request), std::move(scope));
99}
100
104template <typename Request>
106public:
107 using Authenticator = std::function<std::optional<AxiamUser>(const Request&)>;
108
109 explicit AxiamGuard(Authenticator auth) : auth_(std::move(auth)) {}
110
111 AxiamUser operator()(const Request& request) const {
112 auto user = auth_(request);
113 return require_auth(user);
114 }
115
116private:
117 Authenticator auth_;
118};
119
120} // namespace axiam
121
125#define AXIAM_REQUIRE_ACCESS(client, user, action, resource) \
126 ::axiam::require_access((client), (user), (action), (resource))
127
128#define AXIAM_REQUIRE_AUTH(user) ::axiam::require_auth((user))
Authentication failure: wrong credentials, expired session, MFA failure, or a 401 on the refresh call...
Definition errors.hpp:19
Authorization failure: authenticated but not permitted.
Definition errors.hpp:26
§10 guard functor: a callable that turns a request into an AxiamUser using a caller-supplied authenti...
Definition guard.hpp:105
AxiamUser operator()(const Request &request) const
Definition guard.hpp:111
std::function< std::optional< AxiamUser >(const Request &)> Authenticator
Definition guard.hpp:107
AxiamGuard(Authenticator auth)
Definition guard.hpp:109
Definition client.hpp:24
AccessDecision check_access(const std::string &action, const std::string &resource_id, std::optional< std::string > scope=std::nullopt, std::optional< std::string > subject_id=std::nullopt)
Transport-level failure: connection refused, timeout, TLS error, DNS failure, malformed request (400)...
Definition errors.hpp:47
Definition authenticator.hpp:40
void require_access(Client &client, const std::optional< AxiamUser > &user, const std::string &action, const std::string &resource_id, std::optional< std::string > scope=std::nullopt)
§11 require_access — authorize the REQUEST's user (subject propagation: subject_id = user....
Definition guard.hpp:69
void require_role(const std::optional< AxiamUser > &user, std::initializer_list< std::string > any_of)
§11 require_role — local check against the verified token's roles.
Definition guard.hpp:52
const AxiamUser & require_auth(const std::optional< AxiamUser > &user)
§11 require_auth — endpoint requires an authenticated identity.
Definition guard.hpp:42
Result of an access check (CheckAccessResponse).
Definition types.hpp:86
bool allowed
Definition types.hpp:87
Authenticated identity injected by the §10 guard into the request context.
Definition guard.hpp:27
std::vector< std::string > roles
Definition guard.hpp:30
std::string tenant_id
Definition guard.hpp:29
bool has_role(const std::string &role) const
Definition guard.hpp:32
std::string user_id
Definition guard.hpp:28