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