Skip to content

Commit ef60ef3

Browse files
authored
[LDAP] Support ldaps scheme (#5934) (#6779)
1 parent 696b497 commit ef60ef3

32 files changed

+1036
-630
lines changed

ydb/core/driver_lib/run/kikimr_services_initializers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@
116116
#include <ydb/core/scheme/scheme_type_registry.h>
117117

118118
#include <ydb/core/security/ticket_parser.h>
119-
#include <ydb/core/security/ldap_auth_provider.h>
119+
#include <ydb/core/security/ldap_auth_provider/ldap_auth_provider.h>
120120
#include <ydb/core/security/ticket_parser_settings.h>
121121

122122
#include <ydb/core/sys_view/processor/processor.h>

ydb/core/driver_lib/run/ya.make

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ PEERDIR(
9898
ydb/core/scheme
9999
ydb/core/scheme_types
100100
ydb/core/security
101+
ydb/core/security/ldap_auth_provider
101102
ydb/core/statistics
102103
ydb/core/statistics/aggregator
103104
ydb/core/sys_view/processor

ydb/core/grpc_services/rpc_login.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <ydb/core/tx/schemeshard/schemeshard.h>
88
#include <ydb/core/tx/scheme_cache/scheme_cache.h>
99

10-
#include <ydb/core/security/ldap_auth_provider.h>
10+
#include <ydb/core/security/ldap_auth_provider/ldap_auth_provider.h>
1111
#include <ydb/core/security/login_shared_func.h>
1212

1313
namespace NKikimr {

ydb/core/grpc_services/ya.make

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ PEERDIR(
117117
ydb/core/util
118118
ydb/core/ydb_convert
119119
ydb/core/security
120+
ydb/core/security/ldap_auth_provider
120121
ydb/library/aclib
121122
ydb/library/binary_json
122123
ydb/library/dynumber

ydb/core/protos/auth.proto

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ message TLdapAuthentication {
9999
optional TCertRequire CertRequire = 3 [default = DEMAND];
100100
}
101101

102-
optional string Host = 1;
102+
optional string Host = 1; // DEPRECATED: Use Hosts instead it
103103
optional uint32 Port = 2;
104104
required string BaseDn = 3;
105105
required string BindDn = 4;
@@ -108,4 +108,6 @@ message TLdapAuthentication {
108108
optional string SearchAttribute = 7;
109109
optional TUseTls UseTls = 8;
110110
optional string RequestedGroupAttribute = 9;
111+
repeated string Hosts = 10;
112+
optional string Scheme = 11 [default = "ldap"];
111113
}

ydb/core/security/ldap_auth_provider.cpp renamed to ydb/core/security/ldap_auth_provider/ldap_auth_provider.cpp

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <ydb/library/actors/core/actor_bootstrapped.h>
22
#include <ydb/library/actors/core/log.h>
33
#include <ydb/core/base/ticket_parser.h>
4-
#include "ticket_parser_log.h"
4+
#include <ydb/core/security/ticket_parser_log.h>
55
#include "ldap_auth_provider.h"
66
#include "ldap_utils.h"
77

@@ -156,7 +156,7 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
156156
}
157157

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

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

194-
const ui32 port = Settings.GetPort() != 0 ? Settings.GetPort() : NKikimrLdap::GetPort();
195-
196193
int result = 0;
197-
if (Settings.GetUseTls().GetEnable()) {
194+
if (Settings.GetScheme() == NKikimrLdap::LDAPS_SCHEME || Settings.GetUseTls().GetEnable()) {
198195
const TString& caCertificateFile = Settings.GetUseTls().GetCaCertFile();
199196
result = NKikimrLdap::SetOption(*ld, NKikimrLdap::EOption::TLS_CACERTFILE, caCertificateFile.c_str());
200197
if (!NKikimrLdap::IsSuccess(result)) {
@@ -205,10 +202,12 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
205202
}
206203
}
207204

208-
*ld = NKikimrLdap::Init(host, port);
209-
if (*ld == nullptr) {
205+
const ui32 port = Settings.GetPort() != 0 ? Settings.GetPort() : NKikimrLdap::GetPort(Settings.GetScheme());
206+
UrisList = GetUris(port);
207+
result = NKikimrLdap::Init(ld, Settings.GetScheme(), UrisList, port);
208+
if (!NKikimrLdap::IsSuccess(result)) {
210209
return {{TEvLdapAuthProvider::EStatus::UNAVAILABLE,
211-
{.Message = "Could not initialize LDAP connection for host: " + host + ", port: " + ToString(port) + ". " + NKikimrLdap::LdapError(*ld),
210+
{.Message = "Could not initialize LDAP connection for uris: " + UrisList + ". " + NKikimrLdap::LdapError(*ld),
212211
.Retryable = false}}};
213212
}
214213

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

223-
if (Settings.GetUseTls().GetEnable()) {
222+
if (Settings.GetScheme() == NKikimrLdap::LDAPS_SCHEME || Settings.GetUseTls().GetEnable()) {
224223
int requireCert = NKikimrLdap::ConvertRequireCert(Settings.GetUseTls().GetCertRequire());
225224
result = NKikimrLdap::SetOption(*ld, NKikimrLdap::EOption::TLS_REQUIRE_CERT, &requireCert);
226225
if (!NKikimrLdap::IsSuccess(result)) {
@@ -230,21 +229,22 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
230229
.Retryable = NKikimrLdap::IsRetryableError(result)}}};
231230
}
232231
}
232+
233233
return {};
234234
}
235235

236236
TAuthenticateUserResponse AuthenticateUser(const TAuthenticateUserRequest& request) {
237237
char* dn = NKikimrLdap::GetDn(*request.Ld, request.Entry);
238238
if (dn == nullptr) {
239239
return {{TEvLdapAuthProvider::EStatus::UNAUTHORIZED,
240-
{.Message = "Could not get dn for the first entry matching " + FilterCreator.GetFilter(request.Login) + " on server " + Settings.GetHost() + "\n"
240+
{.Message = "Could not get dn for the first entry matching " + FilterCreator.GetFilter(request.Login) + " on server " + UrisList + "\n"
241241
+ NKikimrLdap::LdapError(*request.Ld),
242242
.Retryable = false}}};
243243
}
244244
TEvLdapAuthProvider::TError error;
245245
int result = NKikimrLdap::Bind(*request.Ld, dn, request.Password);
246246
if (!NKikimrLdap::IsSuccess(result)) {
247-
error.Message = "LDAP login failed for user " + TString(dn) + " on server " + Settings.GetHost() + "\n"
247+
error.Message = "LDAP login failed for user " + TString(dn) + " on server " + UrisList + "\n"
248248
+ NKikimrLdap::ErrorToString((result));
249249
error.Retryable = NKikimrLdap::IsRetryableError(result);
250250
}
@@ -266,7 +266,7 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
266266
TSearchUserResponse response;
267267
if (!NKikimrLdap::IsSuccess(result)) {
268268
response.Status = NKikimrLdap::ErrorToStatus(result);
269-
response.Error = {.Message = "Could not search for filter " + searchFilter + " on server " + Settings.GetHost() + "\n"
269+
response.Error = {.Message = "Could not search for filter " + searchFilter + " on server " + UrisList + "\n"
270270
+ NKikimrLdap::ErrorToString(result),
271271
.Retryable = NKikimrLdap::IsRetryableError(result)};
272272
return response;
@@ -275,11 +275,11 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
275275
if (countEntries != 1) {
276276
if (countEntries == 0) {
277277
response.Error = {.Message = "LDAP user " + request.User + " does not exist. "
278-
"LDAP search for filter " + searchFilter + " on server " + Settings.GetHost() + " return no entries",
278+
"LDAP search for filter " + searchFilter + " on server " + UrisList + " return no entries",
279279
.Retryable = false};
280280
} else {
281281
response.Error = {.Message = "LDAP user " + request.User + " is not unique. "
282-
"LDAP search for filter " + searchFilter + " on server " + Settings.GetHost() + " return " + countEntries + " entries",
282+
"LDAP search for filter " + searchFilter + " on server " + UrisList + " return " + countEntries + " entries",
283283
.Retryable = false};
284284
}
285285
response.Status = TEvLdapAuthProvider::EStatus::UNAUTHORIZED;
@@ -290,10 +290,58 @@ class TLdapAuthProvider : public NActors::TActorBootstrapped<TLdapAuthProvider>
290290
return response;
291291
}
292292

293+
TInitializeLdapConnectionResponse CheckRequiredSettingsParameters() const {
294+
if (Settings.GetHosts().empty() && Settings.GetHost().empty()) {
295+
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "List of ldap server hosts is empty", .Retryable = false}};
296+
}
297+
if (Settings.GetBaseDn().empty()) {
298+
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Parameter BaseDn is empty", .Retryable = false}};
299+
}
300+
if (Settings.GetBindDn().empty()) {
301+
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Parameter BindDn is empty", .Retryable = false}};
302+
}
303+
if (Settings.GetBindPassword().empty()) {
304+
return {TEvLdapAuthProvider::EStatus::UNAVAILABLE, {.Message = "Parameter BindPassword is empty", .Retryable = false}};
305+
}
306+
return {TEvLdapAuthProvider::EStatus::SUCCESS, {}};
307+
}
308+
309+
TString GetUris(ui32 port) const {
310+
TStringBuilder uris;
311+
if (Settings.HostsSize() > 0) {
312+
for (const auto& host : Settings.GetHosts()) {
313+
uris << CreateUri(host, port) << " ";
314+
}
315+
uris.remove(uris.size() - 1);
316+
} else {
317+
uris << CreateUri(Settings.GetHost(), port);
318+
}
319+
return uris;
320+
}
321+
322+
TString CreateUri(const TString& endpoint, ui32 port) const {
323+
TStringBuilder uri;
324+
uri << Settings.GetScheme() << "://" << endpoint;
325+
if (!HasEndpointPort(endpoint)) {
326+
uri << ':' << port;
327+
}
328+
return uri;
329+
}
330+
331+
static bool HasEndpointPort(const TString& endpoint) {
332+
size_t colonPos = endpoint.rfind(':');
333+
if (colonPos == TString::npos) {
334+
return false;
335+
}
336+
++colonPos;
337+
return (endpoint.size() - colonPos) > 0;
338+
}
339+
293340
private:
294341
const NKikimrProto::TLdapAuthentication Settings;
295342
const TSearchFilterCreator FilterCreator;
296343
char* RequestedAttributes[2];
344+
TString UrisList;
297345
};
298346

299347
IActor* CreateLdapAuthProvider(const NKikimrProto::TLdapAuthentication& settings) {

ydb/core/security/ldap_auth_provider_linux.cpp renamed to ydb/core/security/ldap_auth_provider/ldap_auth_provider_linux.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <ydb/library/actors/core/actor_bootstrapped.h>
22
#include <ydb/library/actors/core/log.h>
33
#include <ydb/core/base/ticket_parser.h>
4-
#include "ticket_parser_log.h"
4+
#include <ydb/core/security/ticket_parser_log.h>
55
#include "ldap_auth_provider.h"
66

77
#define LDAP_DEPRECATED 1
@@ -38,6 +38,7 @@ int ConvertOption(const EOption& option) {
3838
}
3939

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

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

50-
LDAP* Init(const TString& host, ui32 port) {
51-
return ldap_init(host.c_str(), port);
51+
int Init(LDAP** ld, const TString& scheme, const TString& uris, ui32 port) {
52+
Y_UNUSED(scheme, port);
53+
return ldap_initialize(ld, uris.c_str());
5254
}
5355

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

112-
ui32 GetPort() {
114+
ui32 GetPort(const TString& scheme) {
115+
if (scheme == LDAPS_SCHEME) {
116+
return LDAPS_PORT;
117+
}
113118
return LDAP_PORT;
114119
}
115120

0 commit comments

Comments
 (0)