Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LDAP] Support ldaps scheme (#5934) #6779

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ydb/core/driver_lib/run/kikimr_services_initializers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
#include <ydb/core/scheme/scheme_type_registry.h>

#include <ydb/core/security/ticket_parser.h>
#include <ydb/core/security/ldap_auth_provider.h>
#include <ydb/core/security/ldap_auth_provider/ldap_auth_provider.h>
#include <ydb/core/security/ticket_parser_settings.h>

#include <ydb/core/sys_view/processor/processor.h>
Expand Down
1 change: 1 addition & 0 deletions ydb/core/driver_lib/run/ya.make
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ PEERDIR(
ydb/core/scheme
ydb/core/scheme_types
ydb/core/security
ydb/core/security/ldap_auth_provider
ydb/core/statistics
ydb/core/statistics/aggregator
ydb/core/sys_view/processor
Expand Down
2 changes: 1 addition & 1 deletion ydb/core/grpc_services/rpc_login.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <ydb/core/tx/schemeshard/schemeshard.h>
#include <ydb/core/tx/scheme_cache/scheme_cache.h>

#include <ydb/core/security/ldap_auth_provider.h>
#include <ydb/core/security/ldap_auth_provider/ldap_auth_provider.h>
#include <ydb/core/security/login_shared_func.h>

namespace NKikimr {
Expand Down
1 change: 1 addition & 0 deletions ydb/core/grpc_services/ya.make
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ PEERDIR(
ydb/core/util
ydb/core/ydb_convert
ydb/core/security
ydb/core/security/ldap_auth_provider
ydb/library/aclib
ydb/library/binary_json
ydb/library/dynumber
Expand Down
4 changes: 3 additions & 1 deletion ydb/core/protos/auth.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ message TLdapAuthentication {
optional TCertRequire CertRequire = 3 [default = DEMAND];
}

optional string Host = 1;
optional string Host = 1; // DEPRECATED: Use Hosts instead it
optional uint32 Port = 2;
required string BaseDn = 3;
required string BindDn = 4;
Expand All @@ -108,4 +108,6 @@ message TLdapAuthentication {
optional string SearchAttribute = 7;
optional TUseTls UseTls = 8;
optional string RequestedGroupAttribute = 9;
repeated string Hosts = 10;
optional string Scheme = 11 [default = "ldap"];
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <ydb/library/actors/core/actor_bootstrapped.h>
#include <ydb/library/actors/core/log.h>
#include <ydb/core/base/ticket_parser.h>
#include "ticket_parser_log.h"
#include <ydb/core/security/ticket_parser_log.h>
#include "ldap_auth_provider.h"
#include "ldap_utils.h"

Expand Down Expand Up @@ -156,7 +156,7 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
}

int result = 0;
if (Settings.GetUseTls().GetEnable()) {
if (Settings.GetScheme() != NKikimrLdap::LDAPS_SCHEME && Settings.GetUseTls().GetEnable()) {
result = NKikimrLdap::StartTLS(*ld);
if (!NKikimrLdap::IsSuccess(result)) {
TEvLdapAuthProvider::TError error {
Expand All @@ -173,7 +173,7 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
result = NKikimrLdap::Bind(*ld, Settings.GetBindDn(), Settings.GetBindPassword());
if (!NKikimrLdap::IsSuccess(result)) {
TEvLdapAuthProvider::TError error {
.Message = "Could not perform initial LDAP bind for dn " + Settings.GetBindDn() + " on server " + Settings.GetHost() + "\n"
.Message = "Could not perform initial LDAP bind for dn " + Settings.GetBindDn() + " on server " + UrisList + "\n"
+ NKikimrLdap::ErrorToString(result),
.Retryable = NKikimrLdap::IsRetryableError(result)
};
Expand All @@ -186,15 +186,12 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
}

TInitializeLdapConnectionResponse InitializeLDAPConnection(LDAP** ld) {
const TString& host = Settings.GetHost();
if (host.empty()) {
return {{TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Ldap server host is empty", .Retryable = false}}};
if (TInitializeLdapConnectionResponse response = CheckRequiredSettingsParameters(); response.Status != TEvLdapAuthProvider::EStatus::SUCCESS) {
return response;
}

const ui32 port = Settings.GetPort() != 0 ? Settings.GetPort() : NKikimrLdap::GetPort();

int result = 0;
if (Settings.GetUseTls().GetEnable()) {
if (Settings.GetScheme() == NKikimrLdap::LDAPS_SCHEME || Settings.GetUseTls().GetEnable()) {
const TString& caCertificateFile = Settings.GetUseTls().GetCaCertFile();
result = NKikimrLdap::SetOption(*ld, NKikimrLdap::EOption::TLS_CACERTFILE, caCertificateFile.c_str());
if (!NKikimrLdap::IsSuccess(result)) {
Expand All @@ -205,10 +202,12 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
}
}

*ld = NKikimrLdap::Init(host, port);
if (*ld == nullptr) {
const ui32 port = Settings.GetPort() != 0 ? Settings.GetPort() : NKikimrLdap::GetPort(Settings.GetScheme());
UrisList = GetUris(port);
result = NKikimrLdap::Init(ld, Settings.GetScheme(), UrisList, port);
if (!NKikimrLdap::IsSuccess(result)) {
return {{TEvLdapAuthProvider::EStatus::UNAVAILABLE,
{.Message = "Could not initialize LDAP connection for host: " + host + ", port: " + ToString(port) + ". " + NKikimrLdap::LdapError(*ld),
{.Message = "Could not initialize LDAP connection for uris: " + UrisList + ". " + NKikimrLdap::LdapError(*ld),
.Retryable = false}}};
}

Expand All @@ -220,7 +219,7 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
.Retryable = NKikimrLdap::IsRetryableError(result)}}};
}

if (Settings.GetUseTls().GetEnable()) {
if (Settings.GetScheme() == NKikimrLdap::LDAPS_SCHEME || Settings.GetUseTls().GetEnable()) {
int requireCert = NKikimrLdap::ConvertRequireCert(Settings.GetUseTls().GetCertRequire());
result = NKikimrLdap::SetOption(*ld, NKikimrLdap::EOption::TLS_REQUIRE_CERT, &requireCert);
if (!NKikimrLdap::IsSuccess(result)) {
Expand All @@ -230,21 +229,22 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
.Retryable = NKikimrLdap::IsRetryableError(result)}}};
}
}

return {};
}

TAuthenticateUserResponse AuthenticateUser(const TAuthenticateUserRequest& request) {
char* dn = NKikimrLdap::GetDn(*request.Ld, request.Entry);
if (dn == nullptr) {
return {{TEvLdapAuthProvider::EStatus::UNAUTHORIZED,
{.Message = "Could not get dn for the first entry matching " + FilterCreator.GetFilter(request.Login) + " on server " + Settings.GetHost() + "\n"
{.Message = "Could not get dn for the first entry matching " + FilterCreator.GetFilter(request.Login) + " on server " + UrisList + "\n"
+ NKikimrLdap::LdapError(*request.Ld),
.Retryable = false}}};
}
TEvLdapAuthProvider::TError error;
int result = NKikimrLdap::Bind(*request.Ld, dn, request.Password);
if (!NKikimrLdap::IsSuccess(result)) {
error.Message = "LDAP login failed for user " + TString(dn) + " on server " + Settings.GetHost() + "\n"
error.Message = "LDAP login failed for user " + TString(dn) + " on server " + UrisList + "\n"
+ NKikimrLdap::ErrorToString((result));
error.Retryable = NKikimrLdap::IsRetryableError(result);
}
Expand All @@ -266,7 +266,7 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
TSearchUserResponse response;
if (!NKikimrLdap::IsSuccess(result)) {
response.Status = NKikimrLdap::ErrorToStatus(result);
response.Error = {.Message = "Could not search for filter " + searchFilter + " on server " + Settings.GetHost() + "\n"
response.Error = {.Message = "Could not search for filter " + searchFilter + " on server " + UrisList + "\n"
+ NKikimrLdap::ErrorToString(result),
.Retryable = NKikimrLdap::IsRetryableError(result)};
return response;
Expand All @@ -275,11 +275,11 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
if (countEntries != 1) {
if (countEntries == 0) {
response.Error = {.Message = "LDAP user " + request.User + " does not exist. "
"LDAP search for filter " + searchFilter + " on server " + Settings.GetHost() + " return no entries",
"LDAP search for filter " + searchFilter + " on server " + UrisList + " return no entries",
.Retryable = false};
} else {
response.Error = {.Message = "LDAP user " + request.User + " is not unique. "
"LDAP search for filter " + searchFilter + " on server " + Settings.GetHost() + " return " + countEntries + " entries",
"LDAP search for filter " + searchFilter + " on server " + UrisList + " return " + countEntries + " entries",
.Retryable = false};
}
response.Status = TEvLdapAuthProvider::EStatus::UNAUTHORIZED;
Expand All @@ -290,10 +290,58 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
return response;
}

TInitializeLdapConnectionResponse CheckRequiredSettingsParameters() const {
if (Settings.GetHosts().empty() && Settings.GetHost().empty()) {
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "List of ldap server hosts is empty", .Retryable = false}};
}
if (Settings.GetBaseDn().empty()) {
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Parameter BaseDn is empty", .Retryable = false}};
}
if (Settings.GetBindDn().empty()) {
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Parameter BindDn is empty", .Retryable = false}};
}
if (Settings.GetBindPassword().empty()) {
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Parameter BindPassword is empty", .Retryable = false}};
}
return {TEvLdapAuthProvider::EStatus::SUCCESS, {}};
}

TString GetUris(ui32 port) const {
TStringBuilder uris;
if (Settings.HostsSize() > 0) {
for (const auto& host : Settings.GetHosts()) {
uris << CreateUri(host, port) << " ";
}
uris.remove(uris.size() - 1);
} else {
uris << CreateUri(Settings.GetHost(), port);
}
return uris;
}

TString CreateUri(const TString& endpoint, ui32 port) const {
TStringBuilder uri;
uri << Settings.GetScheme() << "://" << endpoint;
if (!HasEndpointPort(endpoint)) {
uri << ':' << port;
}
return uri;
}

static bool HasEndpointPort(const TString& endpoint) {
size_t colonPos = endpoint.rfind(':');
if (colonPos == TString::npos) {
return false;
}
++colonPos;
return (endpoint.size() - colonPos) > 0;
}

private:
const NKikimrProto::TLdapAuthentication Settings;
const TSearchFilterCreator FilterCreator;
char* RequestedAttributes[2];
TString UrisList;
};

IActor* CreateLdapAuthProvider(const NKikimrProto::TLdapAuthentication& settings) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <ydb/library/actors/core/actor_bootstrapped.h>
#include <ydb/library/actors/core/log.h>
#include <ydb/core/base/ticket_parser.h>
#include "ticket_parser_log.h"
#include <ydb/core/security/ticket_parser_log.h>
#include "ldap_auth_provider.h"

#define LDAP_DEPRECATED 1
Expand Down Expand Up @@ -38,6 +38,7 @@ int ConvertOption(const EOption& option) {
}

char* noAttributes[] = {ldapNoAttribute, nullptr};
const TString LDAPS_SCHEME = "ldaps";

int Bind(LDAP* ld, const TString& dn, const TString& password) {
return ldap_simple_bind_s(ld, dn.c_str(), password.c_str());
Expand All @@ -47,8 +48,9 @@ int Unbind(LDAP* ld) {
return ldap_unbind(ld);
}

LDAP* Init(const TString& host, ui32 port) {
return ldap_init(host.c_str(), port);
int Init(LDAP** ld, const TString& scheme, const TString& uris, ui32 port) {
Y_UNUSED(scheme, port);
return ldap_initialize(ld, uris.c_str());
}

int Search(LDAP* ld,
Expand Down Expand Up @@ -109,7 +111,10 @@ std::vector<TString> GetAllValuesOfAttribute(LDAP* ld, LDAPMessage* entry, char*
return response;
}

ui32 GetPort() {
ui32 GetPort(const TString& scheme) {
if (scheme == LDAPS_SCHEME) {
return LDAPS_PORT;
}
return LDAP_PORT;
}

Expand Down
Loading
Loading