I am trying to read an msExchMailboxSecurityDescriptor, to find whether it contains a Full Access to another person. The access control entries contain the trustees in the netbios format (DOMAIN\Username).
SecurityDescriptor secDesc = (SecurityDescriptor)userDirectoryEntry.Properties["msExchMailboxSecurityDescriptor"].Value;
AccessControlList usrAcl = (AccessControlList)secDesc.DiscretionaryAcl;
foreach (AccessControlEntry ace in (IEnumerable)usrAcl)
{
var netbiosDn = ace.Trustee.Split('\\')[0];
var netbiosUser = ace.Trustee.Split('\\')[1];
// now, the problem:
UserPrincipal user = UserPrincipal.FindByIdentity(
new PrincipalContext(ContextType.Domain, netbiosDn),
netbiosUser
);
This works until the last line, where I have to connect to the correct AD server and get some user info. Obviously, this fails when there is no server available for that domain, like any of the "NT AUTHORITY" or "BUILTIN" "domains". It does not only fail, it needs quite some time until it does.
How on earth would I distinguish which ones are AD domains, where I can connect to the AD server, and which ones aren't?
Some example users I may find in the Security Descriptor, just for you to get a feel for the problem:
CONTOSO\Alex
CONTOSO\Michael
SUBDOMAIN\Kirk
TRUSTED\George
NTPD\ChiefBrown
NT AUTHORITY\SELF
NT INSTANS\INTERAKTIV
BUILTIN\Администраторы
BUILDING2\Владимир
VORDEFINERT\Administrator
Take a look at SecurityIdentifier.IsWellKnown
You can pass various values, including WellKnownSidType.NTAuthoritySid to determine what kind of SID you have.
(See also this PowerShell code on translating into readable names.)
Related
Our organization stores signing certificates in Active Directory. We are using anonymous bind to search for them at a base DN (e.g. OU=MY ORG,dc=mydc,dc=org). I have been trying to use the Spring LdapTemplate to look them up, but no matter what method I use, I get the cryptic InterruptedNamingException.
Assuming a cert subject of cn=mycert.myorg.com
My code looks like this
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(String.format(LDAP_URL_FORMAT, ldapCertStoreParameters.getServerName(),
ldapCertStoreParameters.getPort()));
contextSource.setBase(ldapCertStoreParameters.getBaseDn());
contextSource.setAnonymousReadOnly(true);
contextSource.afterPropertiesSet();
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
ldapTemplate.setIgnorePartialResultException(true);
ldapTemplate.afterPropertiesSet();
X500Principal principal = x509CertSelector.getSubject();
Object obj = ldapTemplate.lookup(new LdapName(principal.getName()));
The X500 principal's name is the whole dn. cn=mycert.myorg.com,OU=MY ORG,dc=mydc,dc=org
I have also tried the search using just the cn.
We have verified that the DN exists on the server using Apache Directory Studio.
• I would suggest you to please remove the call altogether or set the ‘userSearchBase’ either to an empty String (“”) as per the given example in the below community thread: -
Configure Spring security for Ldap connection
As in the ‘AbstractContextSource’, set the base suffix from which all operations should origin. If a base suffix is set, you will not have to (and, indeed, must not) specify the full distinguished names in any operations performed. Since you specified the full DN for the userDN/filter, you must not specify the base.
AD servers are apparently unable to handle referrals automatically, which causes a ‘PartialResultException’ to be thrown whenever a referral is encountered in a search. To avoid this, set the ‘ignorePartialResultException’ property to true. There is currently no way of manually handling these referrals in the form of ‘ReferralException’, i.e., either you get the exception (and your results are lost) or all referrals are ignored (if the server is unable to handle them properly). Neither is there any simple way to get notified that a ‘PartialResultException’ has been ignored.
For more details regarding the LDAP template search for Active Directory stored certificates, kindly refer to the link below: -
https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/core/LdapTemplate.html
• Also, please try to refer to the below documentation for configuration of Springboot LDAP template configuration through certificates stored in Active Directory: -
https://www.baeldung.com/x-509-authentication-in-spring-security
I want to get incremental changes from Active Directory using C# and for that I am trying to build a solution as mentioned in the following article (using DirSync Control).
https://learn.microsoft.com/en-us/windows/win32/ad/polling-for-changes-using-the-dirsync-control
However, I am facing following problems:
When using following code, I am getting exception that The user has insufficient access rights. The user is part of administrators group.
What more permission needs to be given to that account? And how?
LdapConnection connection = new LdapConnection("adfs.fed.zzz.com");
connection.SessionOptions.ProtocolVersion = 3;
connection.Credential = new System.Net.NetworkCredential("adfsfed\\username", "password");
connection.AuthType = AuthType.Basic;
connection.Bind();
var filter = "(&(objectClass=*))";
var searchRequest = new SearchRequest("", filter, SearchScope.Subtree, properties);
DirSyncRequestControl dirSyncRC = new DirSyncRequestControl(null, DirectorySynchronizationOptions.None);
searchRequest.Controls.Add(dirSyncRC);
var response = connection.SendRequest(searchRequest) as SearchResponse;
If I am using below code, then I am not getting any exception but getting empty result in cookie.
String[] properties = { "objectGUID", "sAMAccountName", "displayName", "mail", "member" };
String filter = "(|(objectClass=group)(objectClass=user))";
DirectorySearcher directorySearcher = new DirectorySearcher(myLdapConnection, filter, properties);
var dSynch = new DirectorySynchronization(System.DirectoryServices.DirectorySynchronizationOptions.None);
directorySearcher.DirectorySynchronization = dSynch;
directorySearcher.SearchScope = System.DirectoryServices.SearchScope.Subtree;
var results = directorySearcher.FindAll();
var cookie = dSynch.GetDirectorySynchronizationCookie();
Considerations:
I have only one Domain Controller
I am system admin. So, I can assign appropriate permissions to the user.
Please help.
• Your user ID will need the "Replicating Directory Changes" permission and should be a member of ‘Domain Administrators’ group to use the DirSync LDAP control extension. But please note that it pretty much can read anything in the directory partition, regardless of standard permissions. Though they cannot change anything.
However - you may have some attributes that are sensitive in your directory. Please refer the powershell script in the below link and execute it with the user ID after giving appropriate permissions using C#. It is a dirsync code that will retrieve even attributes like ‘userAccountControl, userparameters, msexchuseraccountcontrol, pwdlastset, unicodePwd (BLANK, So no hashed domain password is returned), lockouttime, accountexpires, unixuserpassword(Its Hash is returned).
http://dloder.blogspot.com/2012/01/powershell-dirsync-sample.html
Based on the response given by #KartikBhiwapurkar-MT, I figured out the bug.
The error The user has insufficient access rights is completely misleading (User had already Replicating Directory Changes rights and was part of Domain Administrators group). The error was happening in System.DirectoryServices.Protocols is that I was passing out "" as first parameter (distinguishedName)
new SearchRequest("", filter, SearchScope.Subtree, properties);
but it should have been passed as
new SearchRequest("DC=adfs,DC=fed,DC=zzz,DC=com", filter, SearchScope.Subtree, properties);
I was getting empty cookie in System.DirectoryServices because of bug in latest nuget package (6.0.0). At the time of writing this answer, the bug is still open.
Reference to bug
I'm coding on top of some JNI libraries, and I don't really know the details about how they are doing it, but the output of lib is the windows domain user information with sid and sids... They look as shown below
sids: [
"S-1-5-21-2923429462-2395316905-2569861443-1123",
"S-1-5-32-545",
"S-1-5-2",
"S-1-5-5-0-79699478",
"S-1-5-11",
"S-1-1-0",
"S-1-5-15",
"S-1-18-1",
"S-1-5-21-2923429462-2395316905-2569861443-513"
],
sid: "S-1-5-21-2923429462-2395316905-2569861443-1123"
Issue
Can I get the information without a password but only with a user
id?
Is the information changeable?
What are SIDs... I thought there's only one secure identifier.
I'll take a stab at it:
I understand that you're using a Java Native Interface but I'm not sure what other language you're using. If it is with Active Directory, Powershell is perfect for it, though, I'm not sure how it would work with a JNI.
Anyway, here is what I can gather. Each account has a specific Security Identifier, called a SID. There are well-known SIDs for the common accounts (Administrator, for example). Even local account and groups have SIDs, as with any in Active Directory.
If you want to translate a SID to an account, that isn't a problem. If you aren't using Powershell, at least this may give you a starting point:
$SID = New-Object System.Security.Principal.SecurityIdentifier("SID_GOES_HERE")
$user = $SID.Translate([System.Security.Principal.NTAccount])
$user.Value
You could feed each line into these 3 steps by putting it into a function like so:
Function SIDtoUser($SIDint) {
$SID = New-Object System.Security.Principal.SecurityIdentifier($SIDint)
$user = $SID.Translate([System.Security.Principal.NTAccount])
return $user.Value
}
Gather all of the SIDs into an array and run through them like this:
$SIDArray | %{
SIDtoUser($_)
}
I hope this helps. Let me know if I can assist any further.
I'd like to get preferred domain controller name/adress on Mac, joined to Active Directory (MS Windows Server with Domain Controller) programmatically with C/Objective-C. The better solution for now is parsing output of dsconfigad -show commandline utility where are such lines:
Advanced Options - Administrative
Preferred Domain controller = 192.168.XXX.XXX
I already tried Open Directory API, as adviced here, but it fails to access nodes far than full name of domain:
// domainNode: "/Active Directory/MYDOMAIN/mydomain.local"
NSArray *domainSubNodes = [domainNode subnodeNamesAndReturnError:&err];
[domainSubNodes count]; // count is 0
Do I need to perform some kind of authorization to access subnodes of domain and how to perform it?
Is there any posix/BSD functions that can obtain domain controller name from pure C code?
We're using LDAP to authenticate users against a large Active Directory setup. We want to extract the list of all groups from Active Directory so that we can mirror them in a local database, and map users' AD groups to local groups.
However when we run the ldap query to get a list of all groups, Active Directory limits the maximum results for our search.
What is the best strategy to get this information given the limitations on query result size? Can we use some form of query paging?
Thanks in advance!
Active-Directory support pagging control. You must refer to Microsoft official article : Searching the Directory ans especialy Search Size and Page Size
A simple paged results query can be used to do that. The key would be to ensure that the requested page size does not exceed whatever the maximum results size is for your Active Directory instance.
The ADO wrappers for ADSI, for example, automatically page results, an example of which can be found here, though obviously that may or may not work for you depending on your technology stack.
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
You can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for any GroupPrincipal
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
// to get around the 1'000 or so object limit - you need to "go deep" and
// set the page size on the underlying DirectorySearcher to e.g. 500
(searcher.GetUnderlyingSearcher() as DirectorySearcher).PageSize = 500;
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
You can specify any of the properties on the GroupPrincipal and use those as "query-by-example" for your PrincipalSearcher.