| 67 | ContextPtr global_context, |
| 68 | LoggerPtr log); |
| 69 | bool authenticateUserByHTTP( |
| 70 | const HTTPServerRequest & request, |
| 71 | const HTMLForm & params, |
| 72 | HTTPServerResponse & response, |
| 73 | Session & session, |
| 74 | std::unique_ptr<Credentials> & request_credentials, |
| 75 | const HTTPHandlerConnectionConfig & connection_config, |
| 76 | ContextPtr global_context, |
| 77 | LoggerPtr log) |
| 78 | { |
| 79 | /// Get the credentials created by the previous call of authenticateUserByHTTP() while handling the previous HTTP request. |
| 80 | auto current_credentials = std::move(request_credentials); |
| 81 | const auto & config_credentials = connection_config.credentials; |
| 82 | |
| 83 | /// The user and password can be passed by headers (similar to X-Auth-*), |
| 84 | /// which is used by load balancers to pass authentication information. |
| 85 | std::string user = request.get("X-ClickHouse-User", ""); |
| 86 | std::string password = request.get("X-ClickHouse-Key", ""); |
| 87 | std::string quota_key = request.get("X-ClickHouse-Quota", ""); |
| 88 | bool has_auth_headers = !user.empty() || !password.empty(); |
| 89 | |
| 90 | /// The header 'X-ClickHouse-SSL-Certificate-Auth: on' enables checking the common name |
| 91 | /// extracted from the SSL certificate used for this connection instead of checking password. |
| 92 | bool has_ssl_certificate_auth = (request.get("X-ClickHouse-SSL-Certificate-Auth", "") == "on"); |
| 93 | bool has_config_credentials = config_credentials.has_value(); |
| 94 | |
| 95 | /// User name and password can be passed using HTTP Basic auth or query parameters |
| 96 | /// (both methods are insecure). |
| 97 | bool has_http_credentials = request.hasCredentials() && request.get("Authorization") != "never"; |
| 98 | bool has_credentials_in_query_params = params.has("user") || params.has("password"); |
| 99 | |
| 100 | std::string spnego_challenge; |
| 101 | #if USE_SSL |
| 102 | X509Certificate::Subjects certificate_subjects; |
| 103 | |
| 104 | /// Capture the TLS client certificate (if the client presented one) regardless of the selected |
| 105 | /// authentication method, so that session_log records it even when the connection authenticates |
| 106 | /// by another method (headers, basic, query parameters, config) or the login fails. |
| 107 | /// Mirrors the native protocol path in TCPHandler::receiveHello. |
| 108 | std::optional<X509Certificate> peer_certificate; |
| 109 | if (request.havePeerCertificate()) |
| 110 | { |
| 111 | peer_certificate = request.peerCertificate(); |
| 112 | session.setClientCertificate(*peer_certificate); |
| 113 | } |
| 114 | #endif |
| 115 | |
| 116 | if (config_credentials) |
| 117 | { |
| 118 | checkUserNameNotEmptyAndServerHasEnoughMemory(config_credentials->getUserName(), "config authentication", global_context); |
| 119 | } |
| 120 | if (has_ssl_certificate_auth) |
| 121 | { |
| 122 | #if USE_SSL |
| 123 | /// For SSL certificate authentication we extract the user name from the "X-ClickHouse-User" HTTP header. |
| 124 | checkUserNameNotEmptyAndServerHasEnoughMemory(user, "X-ClickHouse HTTP headers", global_context); |
| 125 | |
| 126 | /// It is prohibited to mix different authorization schemes. |
no test coverage detected