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#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