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/handlers/auth/digest/types.hpp>
19#include <userver/server/http/http_request.hpp>
20#include <userver/server/http/http_response.hpp>
21#include <userver/server/http/http_status.hpp>
22#include <userver/server/request/request_context.hpp>
23#include <userver/storages/secdist/secdist.hpp>
24
25USERVER_NAMESPACE_BEGIN
26
27namespace server::handlers::auth::digest {
28
29using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
30using SecdistConfig = storages::secdist::SecdistConfig;
31using ServerDigestAuthSecret = utils::NonLoggable<class DigestSecretKeyTag, std::string>;
32
33/// Used for data hashing and "nonce" generating.
34class Hasher final {
35public:
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 /// @overload
50 std::string GetHash(std::initializer_list<std::string_view> data) const;
51
52private:
53 const HashAlgTypes hash_algorithm_;
54 const SecdistConfig& secdist_config_;
55};
56
57/// Contains information about the user.
58struct UserData final {
59 using HA1 = utils::NonLoggable<class HA1Tag, std::string>;
60
61 UserData(HA1 ha1, std::string nonce, TimePoint timestamp, 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.
73class AuthCheckerBase : public auth::AuthCheckerBase {
74public:
75 /// Accepts digest-authentication settings from
76 /// @ref server::handlers::auth::digest::AuthCheckerSettingsComponent and "realm"
77 /// from handler config in static_config.yaml.
79 const AuthCheckerSettings& digest_settings,
80 std::string&& realm,
81 const SecdistConfig& secdist_config
82 );
83
84 AuthCheckerBase(const AuthCheckerBase&) = delete;
85 AuthCheckerBase(AuthCheckerBase&&) = delete;
86 AuthCheckerBase& operator=(const AuthCheckerBase&) = delete;
87 AuthCheckerBase& operator=(AuthCheckerBase&&) = delete;
88
89 ~AuthCheckerBase() override;
90
91 /// The main checking function that is called for each request.
92 [[nodiscard]] AuthCheckResult CheckAuth(const http::HttpRequest& request, request::RequestContext& request_context)
93 const final;
94
95 /// Returns "true" if the checker is allowed to write authentication
96 /// information about the user to the RequestContext.
97 [[nodiscard]] bool SupportsUserAuth() const noexcept override { return true; }
98
99 /// The implementation should return std::nullopt if the user is not
100 /// registered. If the user is registered, but he is not in storage, the
101 /// implementation can create him with arbitrary data.
102 virtual std::optional<UserData> FetchUserData(const std::string& username) const = 0;
103
104 /// Sets user authentication data to storage.
105 virtual void SetUserData(
106 const std::string& username,
107 const std::string& nonce,
108 std::int64_t nonce_count,
109 TimePoint nonce_creation_time
110 ) const = 0;
111
112 /// Pushes "nonce" not tied to username to "Nonce Pool".
113 virtual void PushUnnamedNonce(std::string nonce) const = 0;
114
115 /// Returns "nonce" creation time from "Nonce Pool" if exists.
116 virtual std::optional<TimePoint> GetUnnamedNonceCreationTime(const std::string& nonce) const = 0;
117
118 /// @cond
119 enum class ValidateResult { kOk, kWrongUserData, kDuplicateRequest };
120 ValidateResult ValidateUserData(const ContextFromClient& client_context, const UserData& user_data) const;
121 /// @endcond
122private:
123 std::string CalculateDigest(
124 const UserData::HA1& ha1_non_loggable,
125 http::HttpMethod request_method,
126 const ContextFromClient& client_context
127 ) const;
128
129 std::string ConstructAuthInfoHeader(const ContextFromClient& client_context, std::string_view etag) const;
130
131 std::string ConstructResponseDirectives(std::string_view nonce, bool stale) const;
132
134 StartNewAuthSession(std::string username, std::string&& nonce, bool stale, http::HttpResponse& response) const;
135
136 const std::string qops_;
137 const std::string realm_;
138 const std::string domains_;
139 std::string_view algorithm_;
140 const bool is_session_;
141 const bool is_proxy_;
142 const std::chrono::milliseconds nonce_ttl_;
143
144 const Hasher digest_hasher_;
145
146 const std::string authenticate_header_;
147 const std::string authorization_header_;
148 const std::string authenticate_info_header_;
149 const http::HttpStatus unauthorized_status_;
150};
151
152} // namespace server::handlers::auth::digest
153
154USERVER_NAMESPACE_END