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(disable : 4251)
100#endif
101 mutable std::mutex mutex_;
102 std::map<std::string, std::string, std::less<>> nonces_;
103#if defined(_MSC_VER)
104#pragma warning(default : 4251)
105#endif
106};
107
123[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto
124oauth_dpop_confirmation(const std::string_view thumbprint) -> JSON;
125
139[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto
140oauth_dpop_proof_thumbprint(const std::string_view proof)
141 -> std::optional<std::string>;
142
181
190 std::size_t proof_count{1};
193 std::span<const JWSAlgorithm> allowed_algorithms{};
195 std::chrono::seconds past_window{std::chrono::seconds{300}};
198 std::chrono::seconds future_window{std::chrono::seconds{5}};
201 std::optional<std::string_view> expected_nonce{std::nullopt};
205 std::optional<std::string_view> access_token{std::nullopt};
208 std::optional<std::string_view> bound_thumbprint{std::nullopt};
209};
210
230[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto oauth_dpop_verify(
231 const std::string_view proof, const std::string_view method,
232 const std::string_view url, const std::chrono::system_clock::time_point now,
233 const OAuthDPoPVerifyOptions &options) -> std::optional<OAuthDPoPError>;
234
261class SOURCEMETA_CORE_OAUTH_EXPORT OAuthDPoPReplayStore {
262public:
264 static constexpr std::size_t DEFAULT_CAPACITY{131072};
265
269 const std::size_t capacity = DEFAULT_CAPACITY) noexcept
270 : capacity_{capacity == 0 ? DEFAULT_CAPACITY : capacity} {}
271
274 auto operator=(const OAuthDPoPReplayStore &)
275 -> OAuthDPoPReplayStore & = delete;
277 auto operator=(OAuthDPoPReplayStore &&) -> OAuthDPoPReplayStore & = delete;
278 ~OAuthDPoPReplayStore() = default;
279
289 [[nodiscard]] auto
290 check_and_insert(const std::string_view identifier,
291 const std::string_view target,
292 const std::chrono::system_clock::time_point now,
293 const std::chrono::seconds window,
294 const bool normalize_target = true) -> bool;
295
299 [[nodiscard]] auto size(const std::chrono::system_clock::time_point now) const
300 -> std::size_t;
301
302private:
303 struct Entry {
304 std::array<std::uint8_t, 32> digest;
305 std::chrono::system_clock::time_point expiry;
306 };
307
308 std::size_t capacity_;
309#if defined(_MSC_VER)
310#pragma warning(disable : 4251)
311#endif
312 mutable std::mutex mutex_;
313 std::vector<Entry> entries_;
314#if defined(_MSC_VER)
315#pragma warning(default : 4251)
316#endif
317};
318
331[[nodiscard]] SOURCEMETA_CORE_OAUTH_EXPORT auto
332oauth_is_valid_dpop_nonce(const std::string_view value) noexcept -> bool;
333
334} // namespace sourcemeta::core
335
336#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:200
Definition json_value.h:39
std::optional< std::string_view > access_token
Definition oauth_dpop.h:205
std::span< const JWSAlgorithm > allowed_algorithms
Definition oauth_dpop.h:193
std::optional< std::string_view > expected_nonce
Definition oauth_dpop.h:201
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:195
std::chrono::seconds future_window
Definition oauth_dpop.h:198
std::optional< std::string_view > bound_thumbprint
Definition oauth_dpop.h:208
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:190
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:264
OAuthDPoPReplayStore(const std::size_t capacity=DEFAULT_CAPACITY) noexcept
Definition oauth_dpop.h:268
auto size(const std::chrono::system_clock::time_point now) const -> std::size_t
OAuthDPoPError
Definition oauth_dpop.h:147
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:153
@ MethodMismatch
The method claim did not match the request method (check 8).
Definition oauth_dpop.h:164
@ KeyMismatch
Definition oauth_dpop.h:179
@ MissingNonce
Definition oauth_dpop.h:169
@ AccessTokenMismatch
Definition oauth_dpop.h:176
@ NonceMismatch
The nonce claim did not match the nonce the server issued (check 10).
Definition oauth_dpop.h:171
@ ProofCount
More or fewer than one DPoP header field was present (check 1).
Definition oauth_dpop.h:149
@ UnexpectedType
The token type header parameter was not dpop+jwt (check 4).
Definition oauth_dpop.h:155
@ TargetMismatch
The target claim did not match the request target (check 9).
Definition oauth_dpop.h:166
@ 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:187