Skip to content

Commit d816904

Browse files
committed
Allow for overriding the LdapOptions when using the ILdapConnectionService.
1 parent a9e85b2 commit d816904

File tree

6 files changed

+114
-62
lines changed

6 files changed

+114
-62
lines changed

Visus.DirectoryAuthentication/ILdapConnectionService.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// <copyright file="ILdapConnectionService.cs" company="Visualisierungsinstitut der Universität Stuttgart">
2-
// Copyright © 2021 - 2024 Visualisierungsinstitut der Universität Stuttgart.
2+
// Copyright © 2021 - 2025 Visualisierungsinstitut der Universität Stuttgart.
33
// Licensed under the MIT licence. See LICENCE file for details.
44
// </copyright>
55
// <author>Christoph Müller</author>
66

77
using System.DirectoryServices.Protocols;
8+
using Visus.DirectoryAuthentication.Configuration;
89

910

1011
namespace Visus.DirectoryAuthentication {
@@ -14,6 +15,14 @@ namespace Visus.DirectoryAuthentication {
1415
/// </summary>
1516
public interface ILdapConnectionService {
1617

18+
/// <summary>
19+
/// Connect to the LDAP server configured in <paramref name="options"/>.
20+
/// </summary>
21+
/// <param name="options">The <see cref="LdapOptions" /> specifying the
22+
/// server and the user account used to connect to the server.</param>
23+
/// <returns>A new LDAP connection</returns>
24+
LdapConnection Connect(LdapOptions options);
25+
1726
/// <summary>
1827
/// Connect to the preconfigured LDAP service with the specified
1928
/// credentials.

Visus.DirectoryAuthentication/Services/LdapConnectionService.cs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// <copyright file="LdapConnectionService.cs" company="Visualisierungsinstitut der Universität Stuttgart">
2-
// Copyright © 2021 - 2024 Visualisierungsinstitut der Universität Stuttgart.
2+
// Copyright © 2021 - 2025 Visualisierungsinstitut der Universität Stuttgart.
33
// Licensed under the MIT licence. See LICENCE file for details.
44
// </copyright>
55
// <author>Christoph Müller</author>
@@ -45,14 +45,38 @@ public LdapConnectionService(IOptions<LdapOptions> options,
4545

4646
#region Public methods
4747
/// <inheritdoc />
48-
public LdapConnection Connect(string? username, string? password) {
49-
var retval = this._options.ToConnection(_logger);
48+
public LdapConnection Connect(LdapOptions options)
49+
=> this.Connect(null,
50+
null,
51+
options ?? throw new ArgumentNullException(nameof(options)));
52+
53+
/// <inheritdoc />
54+
public LdapConnection Connect(string? username, string? password)
55+
=> this.Connect(username, password, this._options);
56+
#endregion
57+
58+
#region Private class methods
59+
/// <summary>
60+
/// Gets a regular expression for detecting whether the user name is a
61+
/// UPN.
62+
/// </summary>
63+
/// <returns></returns>
64+
[GeneratedRegex(@".+@.+")]
65+
private static partial Regex GetUpnRegex();
66+
#endregion
67+
68+
#region Private methods
69+
public LdapConnection Connect(string? username,
70+
string? password,
71+
LdapOptions options) {
72+
Debug.Assert(options is not null);
73+
var retval = options.ToConnection(_logger);
5074
Debug.Assert(retval != null);
5175

5276
if ((username != null)
53-
&& !string.IsNullOrWhiteSpace(this._options.DefaultDomain)
77+
&& !string.IsNullOrWhiteSpace(options.DefaultDomain)
5478
&& !GetUpnRegex().IsMatch(username)) {
55-
username = $"{username}@{this._options.DefaultDomain}";
79+
username = $"{username}@{options.DefaultDomain}";
5680
}
5781

5882
this._logger.LogDebug("User name to bind (possibly expanded by the "
@@ -79,21 +103,11 @@ public LdapConnection Connect(string? username, string? password) {
79103
retval.SessionOptions.ProtocolVersion,
80104
retval.AutoBind);
81105

82-
return retval;
83-
}
84-
#endregion
85-
86-
#region Private class methods
87-
/// <summary>
88-
/// Gets a regular expression for detecting whether the user name is a
89-
/// UPN.
90-
/// </summary>
91-
/// <returns></returns>
92-
[GeneratedRegex(@".+@.+")]
93-
private static partial Regex GetUpnRegex();
106+
return retval;
107+
}
94108
#endregion
95109

96-
#region Private fields
110+
#region Private fields
97111
private readonly ILogger _logger;
98112
private readonly LdapOptions _options;
99113
#endregion

Visus.DirectoryAuthentication/Visus.DirectoryAuthentication.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Updated dependencies.</PackageReleaseNotes>
1818
<NeutralLanguage>en</NeutralLanguage>
1919
<UserSecretsId>e07a7441-ba97-46b5-9ce1-391f2c978578</UserSecretsId>
2020
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
21-
<Version>2.2.1</Version>
21+
<Version>2.3.0</Version>
2222
<Nullable>enable</Nullable>
2323
</PropertyGroup>
2424

Visus.LdapAuthentication/ILdapConnectionService.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// <copyright file="ILdapConnectionService.cs" company="Visualisierungsinstitut der Universität Stuttgart">
2-
// Copyright © 2021 - 2024 Visualisierungsinstitut der Universität Stuttgart.
2+
// Copyright © 2021 - 2025 Visualisierungsinstitut der Universität Stuttgart.
33
// Licensed under the MIT licence. See LICENCE file for details.
44
// </copyright>
55
// <author>Christoph Müller</author>
66

77
using Novell.Directory.Ldap;
8+
using Visus.LdapAuthentication.Configuration;
89

910

1011
namespace Visus.LdapAuthentication {
@@ -14,6 +15,14 @@ namespace Visus.LdapAuthentication {
1415
/// </summary>
1516
public interface ILdapConnectionService {
1617

18+
/// <summary>
19+
/// Connect to the LDAP server configured in <paramref name="options"/>.
20+
/// </summary>
21+
/// <param name="options">The <see cref="LdapOptions" /> specifying the
22+
/// server and the user account used to connect to the server.</param>
23+
/// <returns>A new LDAP connection</returns>
24+
LdapConnection Connect(LdapOptions options);
25+
1726
/// <summary>
1827
/// Connect to the preconfigured LDAP service with the specified
1928
/// credentials.

Visus.LdapAuthentication/Services/LdapConnectionService.cs

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// <copyright file="LdapConnectionService.cs" company="Visualisierungsinstitut der Universität Stuttgart">
2-
// Copyright © 2021 - 2024 Visualisierungsinstitut der Universität Stuttgart.
2+
// Copyright © 2021 - 2025 Visualisierungsinstitut der Universität Stuttgart.
33
// Licensed under the MIT licence. See LICENCE file for details.
44
// </copyright>
55
// <author>Christoph Müller</author>
@@ -10,7 +10,6 @@
1010
using System;
1111
using System.Collections.Generic;
1212
using System.Diagnostics;
13-
using System.Net.Http.Headers;
1413
using System.Text.RegularExpressions;
1514
using Visus.LdapAuthentication.Configuration;
1615
using Visus.LdapAuthentication.Properties;
@@ -41,37 +40,19 @@ public LdapConnectionService(IOptions<LdapOptions> options,
4140
?? throw new ArgumentNullException(nameof(logger));
4241
this._options = options?.Value
4342
?? throw new ArgumentNullException(nameof(options));
44-
}
43+
}
4544
#endregion
46-
45+
4746
#region Public methods
4847
/// <inheritdoc />
49-
public LdapConnection Connect(string? username, string? password) {
50-
var retval = this.TryConnect();
51-
52-
if ((username != null)
53-
&& !string.IsNullOrWhiteSpace(this._options.DefaultDomain)
54-
&& !GetUpnRegex().IsMatch(username)) {
55-
username = $"{username}@{this._options.DefaultDomain}";
56-
}
57-
58-
this._logger.LogDebug("User name to bind (possibly expanded by the "
59-
+ "default domain) is {username}.", username);
60-
61-
if ((username == null) && (password == null)) {
62-
this._logger.LogInformation(Resources.InfoBindAnonymous);
63-
retval.Bind(null, null);
64-
this._logger.LogInformation(Resources.InfoBoundAnonymous);
48+
public LdapConnection Connect(LdapOptions options)
49+
=> this.Connect(null,
50+
null,
51+
options ?? throw new ArgumentNullException(nameof(options)));
6552

66-
} else {
67-
this._logger.LogInformation(Resources.InfoBindingAsUser,
68-
username);
69-
retval.Bind(username, password);
70-
this._logger.LogInformation(Resources.InfoBoundAsUser, username);
71-
}
72-
73-
return retval;
74-
}
53+
/// <inheritdoc />
54+
public LdapConnection Connect(string? username, string? password)
55+
=> this.Connect(username, password, this._options);
7556
#endregion
7657

7758
#region Private class methods
@@ -89,18 +70,19 @@ public LdapConnection Connect(string? username, string? password) {
8970
/// Block the <paramref name="server"/> at the specified position for
9071
/// the configured amount of time.
9172
/// </summary>
92-
private void Blacklist(int server) {
93-
Debug.Assert(server < this._options.Servers.Length);
73+
private void Blacklist(int server, LdapOptions options) {
74+
Debug.Assert(options is not null);
75+
Debug.Assert(server < options.Servers.Length);
9476

9577
// Only enter the critical section if a valid timespan was
9678
// specified that actually needs to expire.
97-
if (this._options.BlacklistFailedServersFor > TimeSpan.Zero) {
79+
if (options.BlacklistFailedServersFor > TimeSpan.Zero) {
9880
lock (this._lock) {
9981
var until = DateTimeOffset.UtcNow;
100-
until += this._options.BlacklistFailedServersFor;
82+
until += options.BlacklistFailedServersFor;
10183
this._blacklisted[server] = until;
10284
this._logger.LogWarning(Resources.WarnServerBlacklisted,
103-
this._options.Servers[server], until);
85+
options.Servers[server], until);
10486

10587
// If the currently active server is the blacklisted one,
10688
// make sure that we now select another one in the
@@ -109,7 +91,7 @@ private void Blacklist(int server) {
10991
if (this._currentServer == server) {
11092
do {
11193
++this._currentServer;
112-
this._currentServer %= this._options.Servers.Length;
94+
this._currentServer %= options.Servers.Length;
11395
} while (this.IsBlacklistedUnsafe(this._currentServer)
11496
&& (this._currentServer != server));
11597

@@ -121,6 +103,43 @@ private void Blacklist(int server) {
121103
} /* if (this._options.BlacklistFailedServersFor > TimeSpan.Zero) */
122104
}
123105

106+
/// <summary>
107+
/// Connect to the server specified in <paramref name="options"/>
108+
/// </summary>
109+
/// <param name="username"></param>
110+
/// <param name="password"></param>
111+
/// <param name="options"></param>
112+
/// <returns></returns>
113+
private LdapConnection Connect(string? username,
114+
string? password,
115+
LdapOptions options) {
116+
Debug.Assert(options is not null);
117+
var retval = this.TryConnect(options);
118+
119+
if ((username != null)
120+
&& !string.IsNullOrWhiteSpace(options.DefaultDomain)
121+
&& !GetUpnRegex().IsMatch(username)) {
122+
username = $"{username}@{options.DefaultDomain}";
123+
}
124+
125+
this._logger.LogDebug("User name to bind (possibly expanded by the "
126+
+ "default domain) is {username}.", username);
127+
128+
if ((username == null) && (password == null)) {
129+
this._logger.LogInformation(Resources.InfoBindAnonymous);
130+
retval.Bind(null, null);
131+
this._logger.LogInformation(Resources.InfoBoundAnonymous);
132+
133+
} else {
134+
this._logger.LogInformation(Resources.InfoBindingAsUser,
135+
username);
136+
retval.Bind(username, password);
137+
this._logger.LogInformation(Resources.InfoBoundAsUser, username);
138+
}
139+
140+
return retval;
141+
}
142+
124143
/// <summary>
125144
/// Checks whether <paramref name="server"/> is on the black list, but
126145
/// does not acquire the <see cref="_lock"/> before doing so. Therefore,
@@ -183,19 +202,20 @@ private int SelectRoundRobin() {
183202
/// <summary>
184203
/// Try connecting to any of the configured servers.
185204
/// </summary>
186-
private LdapConnection TryConnect() {
205+
private LdapConnection TryConnect(LdapOptions options) {
206+
Debug.Assert(options is not null);
187207
Exception? error = null;
188208

189-
for (int i = 0; i < this._options.Servers.Length; ++i) {
209+
for (int i = 0; i < options.Servers.Length; ++i) {
190210
var selection = this.Select();
191-
var server = this._options.Servers[selection];
211+
var server = options.Servers[selection];
192212

193213
try {
194214
this._logger.LogInformation(Resources.InfoServerSelected,
195215
server);
196-
return this._options.ToConnection(server, this._logger);
216+
return options.ToConnection(server, this._logger);
197217
} catch (Exception ex) {
198-
this.Blacklist(selection);
218+
this.Blacklist(selection, options);
199219
error = ex;
200220
}
201221
}

Visus.LdapAuthentication/Visus.LdapAuthentication.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<RepositoryUrl>https://github.com/UniStuttgart-VISUS/Visus.LdapAuthentication</RepositoryUrl>
1414
<PackageTags>ldap aspnet authentication net5</PackageTags>
1515
<NeutralLanguage>en</NeutralLanguage>
16-
<Version>2.2.1</Version>
16+
<Version>2.3.0</Version>
1717
<PackageReleaseNotes>Added support for fluent mapping.
1818
Improved performance of group mapping.
1919
Updated dependencies.</PackageReleaseNotes>

0 commit comments

Comments
 (0)