userver: userver/server/handlers/auth/digest/auth_checker_base.hpp Source File
Loading...
Searching...
No Matches
auth_checker_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/handlers/auth/digest/auth_checker_base.hpp
4/// @brief @copybrief server::handlers::auth::digest::AuthCheckerBase
5
6#include <userver/server/handlers/auth/auth_checker_base.hpp>
7
8#include <chrono>
9#include <functional>
10#include <optional>
11#include <random>
12#include <string_view>
13
14#include <userver/crypto/hash.hpp>
15#include <userver/rcu/rcu_map.hpp>
16#include <userver/server/handlers/auth/digest/auth_checker_settings.hpp>
17#include <userver/server/handlers/auth/digest/directives_parser.hpp>
18#include <userver/server/http/http_request.hpp>
19#include <userver/server/http/http_response.hpp>
20#include <userver/server/http/http_status.hpp>
21#include <userver/server/request/request_context.hpp>
22
23USERVER_NAMESPACE_BEGIN
24
25namespace server::handlers::auth::digest {
26
27using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
28
29/// Used for data hashing and "nonce" generating.
30class Hasher final {
31 public:
32 /// Constructor from the hash algorithm name from "crypto" namespace.
33 /// Subsequently, all methods of the class will use this algorithm for
34 /// hashing.
35 Hasher(std::string_view algorithm);
36
37 /// Returns "nonce" directive value in hexadecimal format.
38 std::string GenerateNonce(std::string_view etag) const;
39
40 /// Returns data hashed according to the specified in constructor
41 /// algorithm.
42 std::string GetHash(std::string_view data) const;
43
44 private:
45 using HashAlgorithm = std::function<std::string(
46 std::string_view, crypto::hash::OutputEncoding)>;
47 HashAlgorithm hash_algorithm_;
48};
49
50/// Contains information about the user.
51struct UserData final {
52 using HA1 = utils::NonLoggable<class HA1Tag, std::string>;
53
54 UserData(HA1 ha1, std::string nonce, TimePoint timestamp,
55 std::int64_t nonce_count);
56
57 HA1 ha1;
58 std::string nonce;
59 TimePoint timestamp;
60 std::int64_t nonce_count{};
61};
62
63/// @ingroup userver_base_classes
64///
65/// @brief Base class for digest authentication checkers. Implements a
66/// digest-authentication logic.
68 public:
69 /// Assepts digest-authentication settings from
70 /// @ref server::handlers::auth::digest::AuthCheckerSettingsComponent and
71 /// "realm" from handler config in static_config.yaml.
72 AuthCheckerBase(const AuthCheckerSettings& digest_settings,
73 std::string&& realm);
74
75 AuthCheckerBase(const AuthCheckerBase&) = delete;
76 AuthCheckerBase(AuthCheckerBase&&) = delete;
77 AuthCheckerBase& operator=(const AuthCheckerBase&) = delete;
78 AuthCheckerBase& operator=(AuthCheckerBase&&) = delete;
79
80 ~AuthCheckerBase() override;
81
82 /// The main checking function that is called for each request.
84 const http::HttpRequest& request,
85 request::RequestContext& request_context) const final;
86
87 /// Returns "true" if the checker is allowed to write authentication
88 /// information about the user to the RequestContext.
89 [[nodiscard]] bool SupportsUserAuth() const noexcept override { return true; }
90
91 /// The implementation should return std::nullopt if the user is not
92 /// registered. If the user is registered, but he is not in storage, the
93 /// implementation can create him with arbitrary data.
94 virtual std::optional<UserData> FetchUserData(
95 const std::string& username) const = 0;
96
97 /// Sets user authentication data to storage.
98 virtual void SetUserData(const std::string& username,
99 const std::string& nonce, std::int64_t nonce_count,
100 TimePoint nonce_creation_time) const = 0;
101
102 /// Pushes "nonce" not tied to username to "Nonce Pool".
103 virtual void PushUnnamedNonce(std::string nonce) const = 0;
104
105 /// Returns "nonce" creation time from "Nonce Pool" if exists.
107 const std::string& nonce) const = 0;
108
109 /// @cond
110 enum class ValidateResult { kOk, kWrongUserData, kDuplicateRequest };
111 ValidateResult ValidateUserData(const ContextFromClient& client_context,
112 const UserData& user_data) const;
113 /// @endcond
114 private:
115 std::string CalculateDigest(const UserData::HA1& ha1_non_loggable,
116 http::HttpMethod request_method,
117 const ContextFromClient& client_context) const;
118
119 std::string ConstructAuthInfoHeader(const ContextFromClient& client_context,
120 std::string_view etag) const;
121
122 std::string ConstructResponseDirectives(std::string_view nonce,
123 bool stale) const;
124
125 AuthCheckResult StartNewAuthSession(std::string username, std::string&& nonce,
126 bool stale,
127 http::HttpResponse& response) const;
128
129 const std::string qops_;
130 const std::string realm_;
131 const std::string domains_;
132 std::string_view algorithm_;
133 const bool is_session_;
134 const bool is_proxy_;
135 const std::chrono::milliseconds nonce_ttl_;
136
137 const Hasher digest_hasher_;
138
139 const std::string authenticate_header_;
140 const std::string authorization_header_;
141 const std::string authenticate_info_header_;
142 const http::HttpStatus unauthorized_status_;
143};
144
145} // namespace server::handlers::auth::digest
146
147USERVER_NAMESPACE_END