userver: userver/server/handlers/auth/digest/auth_checker_base.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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