Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
oauth_dpop.h
1#ifndef SOURCEMETA_CORE_OAUTH_DPOP_H_
2#define SOURCEMETA_CORE_OAUTH_DPOP_H_
3
4#ifndef SOURCEMETA_CORE_OAUTH_EXPORT
5#include <sourcemeta/core/oauth_export.h>
6#endif
7
8#include <sourcemeta/core/jose_algorithm.h>
9#include <sourcemeta/core/jose_jwk_private.h>
10
11#include <sourcemeta/core/json.h>
12
13#include <array> // std::array
14#include <chrono> // std::chrono::seconds, std::chrono::system_clock
15#include <cstddef> // std::size_t
16#include <cstdint> // std::uint8_t
17#include <map> // std::map
18#include <mutex> // std::mutex
19#include <optional> // std::optional
20#include <span> // std::span
21#include <string> // std::string
22#include <string_view> // std::string_view
23#include <vector> // std::vector
24
25namespace sourcemeta::core {
26
30inline constexpr std::string_view OAUTH_TOKEN_TYPE_DPOP{"DPoP"};
31
56class SOURCEMETA_CORE_OAUTH_EXPORT OAuthDPoPProofer {
57public:
61
65 auto operator=(const OAuthDPoPProofer &) -> OAuthDPoPProofer & = delete;
67 auto operator=(OAuthDPoPProofer &&) -> OAuthDPoPProofer & = delete;
68 ~OAuthDPoPProofer() = default;
69
77 [[nodiscard]] auto
78 proof(const std::string_view server, const std::string_view method,
79 const std::string_view url, const std::string_view access_token,
80 const std::chrono::system_clock::time_point now, std::string &sink)
81 -> bool;
82
86 auto observe(const std::string_view server, const std::string_view nonce)
87 -> void;
88
93 [[nodiscard]] auto thumbprint() const -> std::optional<std::string>;
94
95private:
96 JWKPrivate key_;
97 JWSAlgorithm algorithm_;
98#if defined(_MSC_VER)
99#pragma warning(push)
100#pragma warning(disable : 4251)
101#endif
102 mutable std::mutex mutex_;
103 std::map<std::string, std::string, std::less<>> nonces_;
104#if defined(_MSC_VER)
105#pragma warning(pop)
106#endif
107};
108
124[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto
125oauth_dpop_confirmation(const std::string_view thumbprint) -> JSON;
126
140[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto
141oauth_dpop_proof_thumbprint(const std::string_view proof)
142 -> std::optional<std::string>;
143
182
191 std::size_t proof_count{1};
194 std::span<const JWSAlgorithm> allowed_algorithms{};
196 std::chrono::seconds past_window{std::chrono::seconds{300}};
199 std::chrono::seconds future_window{std::chrono::seconds{5}};
202 std::optional<std::string_view> expected_nonce{std::nullopt};
206 std::optional<std::string_view> access_token{std::nullopt};
209 std::optional<std::string_view> bound_thumbprint{std::nullopt};
210};
211
231[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto oauth_dpop_verify(
232 const std::string_view proof, const std::string_view method,
233 const std::string_view url, const std::chrono::system_clock::time_point now,
234 const OAuthDPoPVerifyOptions &options) -> std::optional<OAuthDPoPError>;
235
262class SOURCEMETA_CORE_OAUTH_EXPORT OAuthDPoPReplayStore {
263public:
265 static constexpr std::size_t DEFAULT_CAPACITY{131072};
266
270 const std::size_t capacity = DEFAULT_CAPACITY) noexcept
271 : capacity_{capacity == 0 ? DEFAULT_CAPACITY : capacity} {}
272
275 auto operator=(const OAuthDPoPReplayStore &)
276 -> OAuthDPoPReplayStore & = delete;
278 auto operator=(OAuthDPoPReplayStore &&) -> OAuthDPoPReplayStore & = delete;
279 ~OAuthDPoPReplayStore() = default;
280
290 [[nodiscard]] auto
291 check_and_insert(const std::string_view identifier,
292 const std::string_view target,
293 const std::chrono::system_clock::time_point now,
294 const std::chrono::seconds window,
295 const bool normalize_target = true) -> bool;
296
300 [[nodiscard]] auto size(const std::chrono::system_clock::time_point now) const
301 -> std::size_t;
302
303private:
304 struct Entry {
305 std::array<std::uint8_t, 32> digest;
306 std::chrono::system_clock::time_point expiry;
307 };
308
309 std::size_t capacity_;
310#if defined(_MSC_VER)
311#pragma warning(push)
312#pragma warning(disable : 4251)
313#endif
314 mutable std::mutex mutex_;
315 std::vector<Entry> entries_;
316#if defined(_MSC_VER)
317#pragma warning(pop)
318#endif
319};
320
333[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto
334oauth_is_valid_dpop_nonce(const std::string_view value) noexcept -> bool;
335
336} // namespace sourcemeta::core
337
338#endif
Definition crypto_sign.h:33
Definition jose_jwk_private.h:35
JWSAlgorithm
Definition jose_algorithm.h:21
@ Signature
The named key was found but its signature did not verify.
Definition jose_verify.h:214
Definition json_value.h:39
std::optional< std::string_view > access_token
Definition oauth_dpop.h:206
std::span< const JWSAlgorithm > allowed_algorithms
Definition oauth_dpop.h:194
std::optional< std::string_view > expected_nonce
Definition oauth_dpop.h:202
auto check_and_insert(const std::string_view identifier, const std::string_view target, const std::chrono::system_clock::time_point now, const std::chrono::seconds window, const bool normalize_target=true) -> bool
auto proof(const std::string_view server, const std::string_view method, const std::string_view url, const std::string_view access_token, const std::chrono::system_clock::time_point now, std::string &sink) -> bool
OAuthDPoPProofer(JWKPrivate key, const JWSAlgorithm algorithm)
OAuthDPoPProofer(const OAuthDPoPProofer &)=delete
std::chrono::seconds past_window
How far in the past a creation time may be (RFC 9449 Section 11.1).
Definition oauth_dpop.h:196
std::chrono::seconds future_window
Definition oauth_dpop.h:199
std::optional< std::string_view > bound_thumbprint
Definition oauth_dpop.h:209
OAuthDPoPReplayStore(const OAuthDPoPReplayStore &)=delete
A store owns a mutex, so it is neither copied nor moved.
std::size_t proof_count
Definition oauth_dpop.h:191
auto observe(const std::string_view server, const std::string_view nonce) -> void
auto thumbprint() const -> std::optional< std::string >
static constexpr std::size_t DEFAULT_CAPACITY
The default maximum number of live entries a store retains.
Definition oauth_dpop.h:265
OAuthDPoPReplayStore(const std::size_t capacity=DEFAULT_CAPACITY) noexcept
Definition oauth_dpop.h:269
auto size(const std::chrono::system_clock::time_point now) const -> std::size_t
OAuthDPoPError
Definition oauth_dpop.h:148
SOURCEMETA_CORE_OAUTH_EXPORT auto oauth_is_valid_dpop_nonce(const std::string_view value) noexcept -> bool
SOURCEMETA_CORE_OAUTH_EXPORT auto oauth_dpop_verify(const std::string_view proof, const std::string_view method, const std::string_view url, const std::chrono::system_clock::time_point now, const OAuthDPoPVerifyOptions &options) -> std::optional< OAuthDPoPError >
SOURCEMETA_CORE_OAUTH_EXPORT auto oauth_dpop_confirmation(const std::string_view thumbprint) -> JSON
constexpr std::string_view OAUTH_TOKEN_TYPE_DPOP
Definition oauth_dpop.h:30
SOURCEMETA_CORE_OAUTH_EXPORT auto oauth_dpop_proof_thumbprint(const std::string_view proof) -> std::optional< std::string >
@ MissingClaim
A required header parameter or claim was absent (check 3).
Definition oauth_dpop.h:154
@ MethodMismatch
The method claim did not match the request method (check 8).
Definition oauth_dpop.h:165
@ KeyMismatch
Definition oauth_dpop.h:180
@ MissingNonce
Definition oauth_dpop.h:170
@ AccessTokenMismatch
Definition oauth_dpop.h:177
@ NonceMismatch
The nonce claim did not match the nonce the server issued (check 10).
Definition oauth_dpop.h:172
@ ProofCount
More or fewer than one DPoP header field was present (check 1).
Definition oauth_dpop.h:150
@ UnexpectedType
The token type header parameter was not dpop+jwt (check 4).
Definition oauth_dpop.h:156
@ TargetMismatch
The target claim did not match the request target (check 9).
Definition oauth_dpop.h:167
@ Malformed
The assertion was not a well-formed JSON Web Token.
Definition oauth_assertion.h:131
@ Expired
The assertion has expired (RFC 7523 Section 3 check 4).
Definition oauth_assertion.h:147
@ UnsupportedAlgorithm
The algorithm was absent or outside the accepted set (RFC 7523 Section 5).
Definition oauth_assertion.h:133
Definition oauth_dpop.h:188