#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { using namespace DB; auto eventTime() { const auto finish_time = std::chrono::system_clock::now(); return std::make_pair(timeInSeconds(finish_time), timeInMicroseconds(finish_time)); } using AuthType = AuthenticationType; using Interface = ClientInfo::Interface; void fillColumnArray(const Strings & data, IColumn & column) { auto & array = typeid_cast(column); size_t size = 0; auto & data_col = array.getData(); for (const auto & name : data) { data_col.insertData(name.data(), name.size()); ++size; } auto & offsets = array.getOffsets(); offsets.push_back(offsets.back() + size); } } namespace DB { SessionLogElement::SessionLogElement(const UUID & auth_id_, Type type_) : auth_id(auth_id_), type(type_) { std::tie(event_time, event_time_microseconds) = eventTime(); } ColumnsDescription SessionLogElement::getColumnsDescription() { auto event_type = std::make_shared( DataTypeEnum8::Values { {"LoginFailure", static_cast(SESSION_LOGIN_FAILURE)}, {"LoginSuccess", static_cast(SESSION_LOGIN_SUCCESS)}, {"Logout", static_cast(SESSION_LOGOUT)} }); #define AUTH_TYPE_NAME_AND_VALUE(v) std::make_pair(AuthenticationTypeInfo::get(v).raw_name, static_cast(v)) auto identified_with_column = std::make_shared( DataTypeEnum8::Values { AUTH_TYPE_NAME_AND_VALUE(AuthType::NO_PASSWORD), AUTH_TYPE_NAME_AND_VALUE(AuthType::PLAINTEXT_PASSWORD), AUTH_TYPE_NAME_AND_VALUE(AuthType::SHA256_PASSWORD), AUTH_TYPE_NAME_AND_VALUE(AuthType::DOUBLE_SHA1_PASSWORD), AUTH_TYPE_NAME_AND_VALUE(AuthType::LDAP), AUTH_TYPE_NAME_AND_VALUE(AuthType::KERBEROS), AUTH_TYPE_NAME_AND_VALUE(AuthType::SSH_KEY), AUTH_TYPE_NAME_AND_VALUE(AuthType::SSL_CERTIFICATE), AUTH_TYPE_NAME_AND_VALUE(AuthType::BCRYPT_PASSWORD), AUTH_TYPE_NAME_AND_VALUE(AuthType::HTTP), }); #undef AUTH_TYPE_NAME_AND_VALUE static_assert(static_cast(AuthenticationType::MAX) == 10); auto interface_type_column = std::make_shared( DataTypeEnum8::Values { {"TCP", static_cast(Interface::TCP)}, {"HTTP", static_cast(Interface::HTTP)}, {"gRPC", static_cast(Interface::GRPC)}, {"MySQL", static_cast(Interface::MYSQL)}, {"PostgreSQL", static_cast(Interface::POSTGRESQL)}, {"Local", static_cast(Interface::LOCAL)}, {"TCP_Interserver", static_cast(Interface::TCP_INTERSERVER)} }); static_assert(magic_enum::enum_count() == 7); auto lc_string_datatype = std::make_shared(std::make_shared()); auto settings_type_column = std::make_shared( std::make_shared( DataTypes({ // setting name lc_string_datatype, // value std::make_shared() }))); return ColumnsDescription { {"hostname", lc_string_datatype, "Hostname of the server executing the query."}, {"type", std::move(event_type), "Login/logout result. Possible values: " "LoginFailure — Login error. " "LoginSuccess — Successful login. " "Logout — Logout from the system."}, {"auth_id", std::make_shared(), "Authentication ID, which is a UUID that is automatically generated each time user logins."}, {"session_id", std::make_shared(), "Session ID that is passed by client via HTTP interface."}, {"event_date", std::make_shared(), "Login/logout date."}, {"event_time", std::make_shared(), "Login/logout time."}, {"event_time_microseconds", std::make_shared(6), "Login/logout starting time with microseconds precision."}, {"user", std::make_shared(std::make_shared()), "User name."}, {"auth_type", std::make_shared(std::move(identified_with_column)), "The authentication type."}, {"profiles", std::make_shared(lc_string_datatype), "The list of profiles set for all roles and/or users."}, {"roles", std::make_shared(lc_string_datatype), "The list of roles to which the profile is applied."}, {"settings", std::move(settings_type_column), "Settings that were changed when the client logged in/out."}, {"client_address", DataTypeFactory::instance().get("IPv6"), "The IP address that was used to log in/out."}, {"client_port", std::make_shared(), "The client port that was used to log in/out."}, {"interface", std::move(interface_type_column), "The interface from which the login was initiated."}, {"client_hostname", std::make_shared(), "The hostname of the client machine where the clickhouse-client or another TCP client is run."}, {"client_name", std::make_shared(), "The clickhouse-client or another TCP client name."}, {"client_revision", std::make_shared(), "Revision of the clickhouse-client or another TCP client."}, {"client_version_major", std::make_shared(), "The major version of the clickhouse-client or another TCP client."}, {"client_version_minor", std::make_shared(), "The minor version of the clickhouse-client or another TCP client."}, {"client_version_patch", std::make_shared(), "Patch component of the clickhouse-client or another TCP client version."}, {"failure_reason", std::make_shared(), "The exception message containing the reason for the login/logout failure."}, }; } void SessionLogElement::appendToBlock(MutableColumns & columns) const { assert(type >= SESSION_LOGIN_FAILURE && type <= SESSION_LOGOUT); assert(user_identified_with >= AuthenticationType::NO_PASSWORD && user_identified_with <= AuthenticationType::MAX); size_t i = 0; columns[i++]->insert(getFQDNOrHostName()); columns[i++]->insert(type); columns[i++]->insert(auth_id); columns[i++]->insert(session_id); columns[i++]->insert(static_cast(DateLUT::instance().toDayNum(event_time).toUnderType())); columns[i++]->insert(event_time); columns[i++]->insert(event_time_microseconds); assert((user && user_identified_with) || client_info.interface == ClientInfo::Interface::TCP_INTERSERVER); columns[i++]->insert(user ? Field(*user) : Field()); columns[i++]->insert(user_identified_with ? Field(*user_identified_with) : Field()); fillColumnArray(profiles, *columns[i++]); fillColumnArray(roles, *columns[i++]); { auto & settings_array_col = assert_cast(*columns[i++]); auto & settings_tuple_col = assert_cast(settings_array_col.getData()); auto & names_col = *settings_tuple_col.getColumnPtr(0)->assumeMutable(); auto & values_col = assert_cast(*settings_tuple_col.getColumnPtr(1)->assumeMutable()); for (const auto & kv : settings) { names_col.insert(kv.first); values_col.insert(kv.second); } auto & offsets = settings_array_col.getOffsets(); offsets.push_back(settings_tuple_col.size()); } columns[i++]->insertData(IPv6ToBinary(client_info.current_address.host()).data(), 16); columns[i++]->insert(client_info.current_address.port()); columns[i++]->insert(client_info.interface); columns[i++]->insertData(client_info.client_hostname.data(), client_info.client_hostname.length()); columns[i++]->insertData(client_info.client_name.data(), client_info.client_name.length()); columns[i++]->insert(client_info.client_tcp_protocol_version); columns[i++]->insert(client_info.client_version_major); columns[i++]->insert(client_info.client_version_minor); columns[i++]->insert(client_info.client_version_patch); columns[i++]->insertData(auth_failure_reason.data(), auth_failure_reason.length()); } void SessionLog::addLoginSuccess(const UUID & auth_id, const String & session_id, const Settings & settings, const ContextAccessPtr & access, const ClientInfo & client_info, const UserPtr & login_user) { DB::SessionLogElement log_entry(auth_id, SESSION_LOGIN_SUCCESS); log_entry.client_info = client_info; if (login_user) { log_entry.user = login_user->getName(); log_entry.user_identified_with = login_user->auth_data.getType(); } log_entry.external_auth_server = login_user ? login_user->auth_data.getLDAPServerName() : ""; log_entry.session_id = session_id; if (const auto roles_info = access->getRolesInfo()) log_entry.roles = roles_info->getCurrentRolesNames(); if (const auto profile_info = access->getDefaultProfileInfo()) log_entry.profiles = profile_info->getProfileNames(); for (const auto & s : settings.allChanged()) log_entry.settings.emplace_back(s.getName(), s.getValueString()); add(std::move(log_entry)); } void SessionLog::addLoginFailure( const UUID & auth_id, const ClientInfo & info, const std::optional & user, const Exception & reason) { SessionLogElement log_entry(auth_id, SESSION_LOGIN_FAILURE); log_entry.user = user; log_entry.auth_failure_reason = reason.message(); log_entry.client_info = info; log_entry.user_identified_with = AuthenticationType::NO_PASSWORD; add(std::move(log_entry)); } void SessionLog::addLogOut(const UUID & auth_id, const UserPtr & login_user, const ClientInfo & client_info) { auto log_entry = SessionLogElement(auth_id, SESSION_LOGOUT); if (login_user) { log_entry.user = login_user->getName(); log_entry.user_identified_with = login_user->auth_data.getType(); } log_entry.external_auth_server = login_user ? login_user->auth_data.getLDAPServerName() : ""; log_entry.client_info = client_info; add(std::move(log_entry)); } }