Skip to content

Commit

Permalink
make some adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
Yvand committed Feb 7, 2024
1 parent 74a5abb commit 2fc218b
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 83 deletions.
6 changes: 3 additions & 3 deletions Yvand.LDAPCPSE/TEMPLATE/ADMIN/LDAPCPSE/GlobalSettings.ascx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
var entityPermissionValue = $("#" + inputIdentifierAttributeId).val();
// Set the label control to preview a group's value
var entityPermissionValuePreview = leadingTokenValue + "<" + entityPermissionValue + "_value>";
var entityPermissionValuePreview = leadingTokenValue + "<" + entityPermissionValue + "_from_ldap>";
$("#" + lblResultId).text(entityPermissionValuePreview);
}
};
Expand Down Expand Up @@ -347,7 +347,7 @@
<br />
<sharepoint:encodedliteral runat="server" text="Preview of a user permission's encoded value returned by LDAPCP, based on current settings:" encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<b><span>"<%= UserIdentifierEncodedValuePrefix %><span id="lblUserPermissionValuePreview"></span>"</span></b>
<b><span><%= UserIdentifierEncodedValuePrefix %><span id="lblUserPermissionValuePreview"></span></span></b>
<br />
<br />
<sharepoint:encodedliteral runat="server" text="- &quot;Leading token&quot;: Specify a static or dynnamic token to add to the permission's value. Possible dynamic tokens are &quot;{domain}&quot; and &quot;{fqdn}&quot;" encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
Expand Down Expand Up @@ -431,7 +431,7 @@
<br />
<sharepoint:encodedliteral runat="server" text="Preview of a group permission's encoded value returned by LDAPCP, based on current settings:" encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<b><span>"<%= GroupIdentifierEncodedValuePrefix %><span id="lblGroupPermissionValuePreview"></span>"</span></b>
<b><span><%= GroupIdentifierEncodedValuePrefix %><span id="lblGroupPermissionValuePreview"></span></span></b>
<br />
<br />
<sharepoint:encodedliteral runat="server" text="- &quot;Leading token&quot;: Specify a static or dynnamic token to add to the permission's value. Possible dynamic tokens are &quot;{domain}&quot; and &quot;{fqdn}&quot;" encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,14 @@ public static LdapProviderConfiguration ReturnDefaultConfiguration(string claims
{
LdapProviderConfiguration defaultConfig = new LdapProviderConfiguration();
defaultConfig.ClaimsProviderName = claimsProviderName;
defaultConfig.LdapConnections = new List<DirectoryConnection>
{
new DirectoryConnection
{
UseDefaultADConnection = true,
EnableAugmentation = true,
},
};
defaultConfig.ClaimTypes = LdapProviderSettings.ReturnDefaultClaimTypesConfig(claimsProviderName);
return defaultConfig;
}
Expand Down
176 changes: 96 additions & 80 deletions Yvand.LDAPCPSE/Yvand.LdapClaimsProvider/LdapEntityProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -247,51 +246,54 @@ protected virtual List<string> GetGroupsFromLDAPDirectory(DirectoryConnection ld
stopWatch.Start();
try
{
using (DirectorySearcher searcher = new DirectorySearcher(ldapConnection.LdapEntry))
using (DirectoryEntry directory = ldapConnection.LdapEntry)
{
searcher.ClientTimeout = new TimeSpan(0, 0, this.Settings.Timeout);
searcher.Filter = ldapFilter;
foreach (string memberOfPropertyName in ldapConnection.GroupMembershipLdapAttributes)
using (DirectorySearcher searcher = new DirectorySearcher(directory))
{
searcher.PropertiesToLoad.Add(memberOfPropertyName);
}
searcher.PropertiesToLoad.Add(this.Settings.GroupIdentifierClaimTypeConfig.DirectoryObjectAttribute);
searcher.ClientTimeout = new TimeSpan(0, 0, this.Settings.Timeout);
searcher.Filter = ldapFilter;
foreach (string memberOfPropertyName in ldapConnection.GroupMembershipLdapAttributes)
{
searcher.PropertiesToLoad.Add(memberOfPropertyName);
}
searcher.PropertiesToLoad.Add(this.Settings.GroupIdentifierClaimTypeConfig.DirectoryObjectAttribute);

SearchResult ldapResult;
using (new SPMonitoredScope($"[{ClaimsProviderName}] Get group membership of user \"{currentContext.IncomingEntity.Value}\" {directoryDetails}", 1000))
{
ldapResult = searcher.FindOne();
}
SearchResult ldapResult;
using (new SPMonitoredScope($"[{ClaimsProviderName}] Get group membership of user \"{currentContext.IncomingEntity.Value}\" {directoryDetails}", 1000))
{
ldapResult = searcher.FindOne();
}

if (ldapResult == null)
{
stopWatch.Stop();
return; // User was not found in this LDAP server
}
if (ldapResult == null)
{
stopWatch.Stop();
return; // User was not found in this LDAP server
}

using (new SPMonitoredScope($"[{ClaimsProviderName}] Process LDAP groups of user \"{currentContext.IncomingEntity.Value}\" returned {directoryDetails}", 1000))
{
// Verify if memberOf attribte is present, and how many values it has
int memberOfValuesCount = 0;
ResultPropertyValueCollection groupValueDistinguishedNameList = null;
foreach (string groupMembershipAttributes in ldapConnection.GroupMembershipLdapAttributes)
using (new SPMonitoredScope($"[{ClaimsProviderName}] Process LDAP groups of user \"{currentContext.IncomingEntity.Value}\" returned {directoryDetails}", 1000))
{
if (ldapResult.Properties.Contains(groupMembershipAttributes))
// Verify if memberOf attribte is present, and how many values it has
int memberOfValuesCount = 0;
ResultPropertyValueCollection groupValueDistinguishedNameList = null;
foreach (string groupMembershipAttributes in ldapConnection.GroupMembershipLdapAttributes)
{
memberOfValuesCount = ldapResult.Properties[groupMembershipAttributes].Count;
groupValueDistinguishedNameList = ldapResult.Properties[groupMembershipAttributes];
break;
if (ldapResult.Properties.Contains(groupMembershipAttributes))
{
memberOfValuesCount = ldapResult.Properties[groupMembershipAttributes].Count;
groupValueDistinguishedNameList = ldapResult.Properties[groupMembershipAttributes];
break;
}
}
}
if (groupValueDistinguishedNameList == null) { return; } // No memberof attribute found
if (groupValueDistinguishedNameList == null) { return; } // No memberof attribute found

// Go through each memberOf value
List<string> groupsProcessed = new List<string>();
string memberGroupDistinguishedName;
for (int idx = 0; idx < memberOfValuesCount; idx++)
{
memberGroupDistinguishedName = groupValueDistinguishedNameList[idx].ToString();
groups.AddRange(ProcessGroupAndGetMembersGroupsRecursive(ldapConnection, currentContext, memberGroupDistinguishedName, groupsProcessed));
// Go through each memberOf value
List<string> groupsProcessed = new List<string>();
string memberGroupDistinguishedName;
for (int idx = 0; idx < memberOfValuesCount; idx++)
{
memberGroupDistinguishedName = groupValueDistinguishedNameList[idx].ToString();
groups.AddRange(ProcessGroupAndGetMembersGroupsRecursive(ldapConnection, currentContext, memberGroupDistinguishedName, groupsProcessed));
}
}
}
}
Expand Down Expand Up @@ -482,65 +484,79 @@ protected List<LdapEntityProviderResult> QueryLDAPServers(OperationContext curre
{
Debug.WriteLine($"ldapConnection: Path: {ldapConnection.LdapEntry.Path}, UseDefaultADConnection: {ldapConnection.UseDefaultADConnection}");
Logger.LogDebug($"ldapConnection: Path: {ldapConnection.LdapEntry.Path}, UseDefaultADConnection: {ldapConnection.UseDefaultADConnection}");
DirectoryEntry directory = ldapConnection.LdapEntry;
using (DirectorySearcher ds = new DirectorySearcher(ldapFilter))
using (DirectoryEntry directory = ldapConnection.LdapEntry)
{
ds.SearchRoot = directory;
ds.SizeLimit = currentContext.MaxCount;
ds.ClientTimeout = new TimeSpan(0, 0, this.Settings.Timeout); // Set the timeout in seconds
ds.PropertiesToLoad.Add("objectclass");
ds.PropertiesToLoad.Add("nETBIOSName");
foreach (var ldapAttribute in currentContext.CurrentClaimTypeConfigList.Where(x => !String.IsNullOrWhiteSpace(x.DirectoryObjectAttribute)))
using (DirectorySearcher ds = new DirectorySearcher(ldapFilter))
{
ds.PropertiesToLoad.Add(ldapAttribute.DirectoryObjectAttribute);
if (!String.IsNullOrEmpty(ldapAttribute.DirectoryObjectAttributeForDisplayText))
ds.SearchRoot = directory;
ds.SizeLimit = currentContext.MaxCount;
ds.ClientTimeout = new TimeSpan(0, 0, this.Settings.Timeout); // Set the timeout in seconds
ds.PropertiesToLoad.Add("objectclass");
ds.PropertiesToLoad.Add("nETBIOSName");
foreach (var ldapAttribute in currentContext.CurrentClaimTypeConfigList.Where(x => !String.IsNullOrWhiteSpace(x.DirectoryObjectAttribute)))
{
ds.PropertiesToLoad.Add(ldapAttribute.DirectoryObjectAttributeForDisplayText);
ds.PropertiesToLoad.Add(ldapAttribute.DirectoryObjectAttribute);
if (!String.IsNullOrEmpty(ldapAttribute.DirectoryObjectAttributeForDisplayText))
{
ds.PropertiesToLoad.Add(ldapAttribute.DirectoryObjectAttributeForDisplayText);
}
}
}
// Populate additional attributes that are not part of the filter but are requested in the result
foreach (var metadataAttribute in this.Settings.RuntimeMetadataConfig)
{
if (!ds.PropertiesToLoad.Contains(metadataAttribute.DirectoryObjectAttribute))
// Populate additional attributes that are not part of the filter but are requested in the result
foreach (var metadataAttribute in this.Settings.RuntimeMetadataConfig)
{
ds.PropertiesToLoad.Add(metadataAttribute.DirectoryObjectAttribute);
if (!ds.PropertiesToLoad.Contains(metadataAttribute.DirectoryObjectAttribute))
{
ds.PropertiesToLoad.Add(metadataAttribute.DirectoryObjectAttribute);
}
}
}

string loggMessage = $"[{ClaimsProviderName}] Connecting to \"{ldapConnection.LdapEntry.Path}\" with AuthenticationType \"{ldapConnection.LdapEntry.AuthenticationType}\", authenticating ";
loggMessage += String.IsNullOrWhiteSpace(ldapConnection.LdapEntry.Username) ? "as process identity" : $"with credentials \"{ldapConnection.LdapEntry.Username}\"";
loggMessage += $" and sending a query with filter \"{ds.Filter}\"...";
using (new SPMonitoredScope(loggMessage, 3000)) // threshold of 3 seconds before it's considered too much. If exceeded it is recorded in a higher logging level
{
try
string loggMessage = $"[{ClaimsProviderName}] Connecting to \"{ldapConnection.LdapEntry.Path}\" with AuthenticationType \"{ldapConnection.LdapEntry.AuthenticationType}\", authenticating ";
loggMessage += String.IsNullOrWhiteSpace(ldapConnection.LdapEntry.Username) ? "as process identity" : $"with credentials \"{ldapConnection.LdapEntry.Username}\"";
loggMessage += $" and sending a query with filter \"{ds.Filter}\"...";
using (new SPMonitoredScope(loggMessage, 3000)) // threshold of 3 seconds before it's considered too much. If exceeded it is recorded in a higher logging level
{
Logger.Log(loggMessage, TraceSeverity.Verbose, EventSeverity.Information, TraceCategory.Ldap_Request);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
using (SearchResultCollection directoryResults = ds.FindAll())
try
{
stopWatch.Stop();
Logger.Log($"[{ClaimsProviderName}] Got {directoryResults.Count} result(s) in {stopWatch.ElapsedMilliseconds} ms from \"{directory.Path}\" with input \"{currentContext.Input}\" and LDAP filter \"{ds.Filter}\"", TraceSeverity.Medium, EventSeverity.Information, TraceCategory.Ldap_Request);
if (directoryResults.Count > 0)
Logger.Log(loggMessage, TraceSeverity.Verbose, EventSeverity.Information, TraceCategory.Ldap_Request);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
using (SearchResultCollection directoryResults = ds.FindAll())
{
lock (lockResults)
stopWatch.Stop();
Logger.Log($"[{ClaimsProviderName}] Got {directoryResults.Count} result(s) in {stopWatch.ElapsedMilliseconds} ms from \"{directory.Path}\" with input \"{currentContext.Input}\" and LDAP filter \"{ds.Filter}\"", TraceSeverity.Medium, EventSeverity.Information, TraceCategory.Ldap_Request);
if (directoryResults.Count > 0)
{
foreach (SearchResult item in directoryResults)
lock (lockResults)
{
results.Add(new LdapEntityProviderResult(item.Properties, ldapConnection));
foreach (SearchResult item in directoryResults)
{
results.Add(new LdapEntityProviderResult(item.Properties, ldapConnection));
}
}
}
}
}
}
catch (Exception ex)
{
Logger.LogException(ClaimsProviderName, $"while connecting to \"{directory.Path}\" with LDAP filter \"{ds.Filter}\"", TraceCategory.Ldap_Request, ex);
}
finally
{
if (ds != null) { ds.Dispose(); }
directory.Dispose();
catch (DirectoryServicesCOMException ex)
{
if (ldapConnection.UseDefaultADConnection)
{
// A DirectoryServicesCOMException is frequently thrown here when:
// - Use DirectoryEntry returned by Domain.GetComputerDomain().GetDirectoryEntry()
// - In "check permissions" dialog
// - During Validation (Search works fine)
// And despite that, the validation definitely fails, "check permissions" still works normally
// Anyway, record a custom message to recommend to use a custom LDAP connection instead
Logger.Log($"[{ClaimsProviderName}] A DirectoryServicesCOMException occured while connecting using the default AD connection. It may be resolved by replacing it with a custom LDAP connection with explicit credentials. Error details: \"{ex.ExtendedErrorMessage}\"", TraceSeverity.Unexpected, EventSeverity.Error, TraceCategory.Ldap_Request);
}
else
{
Logger.LogException(ClaimsProviderName, $"while connecting to \"{directory.Path}\" with LDAP filter \"{ds.Filter}\"", TraceCategory.Ldap_Request, ex);
}
}
catch (Exception ex)
{
Logger.LogException(ClaimsProviderName, $"while connecting to \"{directory.Path}\" with LDAP filter \"{ds.Filter}\"", TraceCategory.Ldap_Request, ex);
}
}
}
}
Expand Down

0 comments on commit 2fc218b

Please sign in to comment.