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#include <userver/storages/secdist/secdist.hpp>
23
24USERVER_NAMESPACE_BEGIN
25
26namespace server::handlers::auth::digest {
27
28using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
29using SecdistConfig = storages::secdist::SecdistConfig;
30using ServerDigestAuthSecret =
31 utils::NonLoggable<class DigestSecretKeyTag, std::string>;
32
33/// Used for data hashing and "nonce" generating.
34class Hasher final {
35 public:
36 /// Constructor from the hash algorithm name from "crypto" namespace
37 /// to be used for hashing and storages::secdist::SecdistConfig containing a
38 /// server secret key `http_server_digest_auth_secret`
39 /// to be used for "nonce" generating.
40 Hasher(std::string_view algorithm, const SecdistConfig& secdist_config);
41
42 /// Returns "nonce" directive value in hexadecimal format.
43 std::string GenerateNonce(std::string_view etag) const;
44
45 /// Returns data hashed according to the specified in constructor
46 /// algorithm.
47 std::string GetHash(std::string_view data) const;
48
49 private:
50 using HashAlgorithm = std::function<std::string(
51 std::string_view, crypto::hash::OutputEncoding)>;
52 HashAlgorithm hash_algorithm_;
53 const SecdistConfig& secdist_config_;
54};
55
56/// Contains information about the user.
57struct UserData final {
58 using HA1 = utils::NonLoggable<class HA1Tag, std::string>;
59
60 UserData(HA1 ha1, std::string nonce, TimePoint timestamp,
61 std::int64_t nonce_count);
62
63 HA1 ha1;
64 std::string nonce;
65 TimePoint timestamp;
66 std::int64_t nonce_count{};
67};
68
69/// @ingroup userver_base_classes
70///
71/// @brief Base class for digest authentication checkers. Implements a
72/// digest-authentication logic.
74 public:
75 /// Assepts digest-authentication settings from
76 /// @ref server::handlers::auth::DigestCheckerSettingsComponent and "realm"
77 /// from handler config in static_config.yaml.
78 AuthCheckerBase(const AuthCheckerSettings& digest_settings,
79 std::string&& realm, const SecdistConfig& secdist_config);
80
81 AuthCheckerBase(const AuthCheckerBase&) = delete;
82 AuthCheckerBase(AuthCheckerBase&&) = delete;
83 AuthCheckerBase& operator=(const AuthCheckerBase&) = delete;
84 AuthCheckerBase& operator=(AuthCheckerBase&&) = delete;
85
86 ~AuthCheckerBase() override;
87
88 /// The main checking function that is called for each request.
90 const http::HttpRequest& request,
91 request::RequestContext& request_context) const final;
92
93 /// Returns "true" if the checker is allowed to write authentication
94 /// information about the user to the RequestContext.
95 [[nodiscard]] bool SupportsUserAuth() const noexcept override { return true; }
96
97 /// The implementation should return std::nullopt if the user is not
98 /// registered. If the user is registered, but he is not in storage, the
99 /// implementation can create him with arbitrary data.
100 virtual std::optional<UserData> FetchUserData(
101 const std::string& username) const = 0;
102
103 /// Sets user authentication data to storage.
104 virtual void SetUserData(const std::string& username,
105 const std::string& nonce, std::int64_t nonce_count,
106 TimePoint nonce_creation_time) const = 0;
107
108 /// Pushes "nonce" not tied to username to "Nonce Pool".
109 virtual void PushUnnamedNonce(std::string nonce) const = 0;
110
111 /// Returns "nonce" creation time from "Nonce Pool" if exists.
113 const std::string& nonce) const = 0;
114
115 /// @cond
116 enum class ValidateResult { kOk, kWrongUserData, kDuplicateRequest };
117 ValidateResult ValidateUserData(const ContextFromClient& client_context,
118 const UserData& user_data) const;
119 /// @endcond
120 private:
121 std::string CalculateDigest(const UserData::HA1& ha1_non_loggable,
122 http::HttpMethod request_method,
123 const ContextFromClient& client_context) const;
124
125 std::string ConstructAuthInfoHeader(const ContextFromClient& client_context,
126 std::string_view etag) const;
127
128 std::string ConstructResponseDirectives(std::string_view nonce,
129 bool stale) const;
130
131 AuthCheckResult StartNewAuthSession(std::string username, std::string&& nonce,
132 bool stale,
133 http::HttpResponse& response) const;
134
135 const std::string qops_;
136 const std::string realm_;
137 const std::string domains_;
138 std::string_view algorithm_;
139 const bool is_session_;
140 const bool is_proxy_;
141 const std::chrono::milliseconds nonce_ttl_;
142
143 const Hasher digest_hasher_;
144
145 const std::string authenticate_header_;
146 const std::string authorization_header_;
147 const std::string authenticate_info_header_;
148 const http::HttpStatus unauthorized_status_;
149};
150
151} // namespace server::handlers::auth::digest
152
153USERVER_NAMESPACE_END