Does .IsInRole work for SIDS in the sidhistory attribute? - c#

We are migrating to another network and are trying to prepare our code base. Our existing groups and members will be imported to new groups on our new domain, and the existing group SID will be in the SID history of the newly created groups.
We currently use IsInRole to check user membership in groups. Does this method also check the SID history attribute? We have no way of populating the SID History attribute ourselves to test this.

The source code for IsInRole is available. Lines 166 to 169 show how it works:
// CheckTokenMembership will check if the SID is both present and enabled in the access token.
if (!Interop.Advapi32.CheckTokenMembership((_identity.ImpersonationLevel != TokenImpersonationLevel.None ? _identity.AccessToken : token),
sid.BinaryForm,
ref isMember))
This looks for the group's SID in the access token of the user. The token is created when the user is authenticated and includes the SIDs of all security (not distribution) groups (and nested groups) that the user is a member of.
The documentation Using SID History to Preserve Resource Access says:
After migrating an account and maintaining the SID history of the source domain account, when a user logs on to the target domain, both the new SID and the original SID from the SID history attribute are added to the access token of the user and determine the local group memberships of the user. The SIDs of the groups in which the user is a member are then added to the access token, together with the SID history of those groups.
So that sounds like the SID history of both the user and the group are used when building the access token.

Related

Adding guest user to Azure AD group fails with correct permissions set

I'm inviting users to my org through my web app and adding them to groups which will be used to determine which parts of the web app they can use because I've got the groups associated with my different roles.
The invite to the org goes out fine, but when I attempt to add the user to the group, I get a Microsoft.Graph.ServiceException as follows:
'Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
Insufficient privileges seems different from the application permissions I've got with admin consent granted on the app registration:
Directory.ReadWrite.All, and
GroupMember.ReadWrite.All
For the life of me I can't find anything relating to "privileges" in the azure portal as it would involve group management so I have to assume that permissions is what this refers to; only, I don't know what permissions it's looking for in addition to these two.
Per the permissions indicated on MS Docs article on adding members to groups, I'm initializing MS Graph with the permissions:
var initialScopes = new string[]
{
// Directory.ReadWrite.All
Constants.Graph.DirectoryReadWrite,
// GroupMember.ReadWrite.All
Constants.Graph.GroupMemberReadWrite,
// Group.ReadWrite.All
Constants.Graph.GroupReadWrite,
// RoleManagement.ReadWrite.Directory
Constants.Graph.RoleManagementReadWriteDirectory
};
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
// Redacted for brevity
})
.EnableTokenAcquisitionToCallDownstreamApi(options =>
configuration.Bind("AzureAd", options), initialScopes)
.AddMicrosoftGraph(configuration.GetSection("GraphAPI"))
GraphAPI section of my config looks like this:
"GraphAPI": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "GroupMember.ReadWrite.All Group.ReadWrite.All Directory.ReadWrite.All RoleManagement.ReadWrite.Directory"
},
I can't possibly be missing any of the required permissions (indicated per the doc). I've logged out and back in again several times (and also completely cleared all my browsing data for the site) to refresh the token auth token but still no luck.
My code to add the invited user to the groups:
// Determine the ID of the regional group to which the user should be added.
string region = this.Provider.Region switch
{
Region.Redacted => config["Groups:redacted"],
Region.Redacted => config["Groups:redacted"],
_ => config["Groups:redacted"]
};
// Add the user to the regional group and to the group for the user's intended role.
var groups = new List<string>
{
region,
config["Groups:redacted"]
};
foreach (var group in groups)
{
await graphClient.Groups[group].Members.References
.Request()
.AddAsync(directoryObject);
}
Are there any additional permissions I need here? If not, what does the error actual indicate is the problem and how do I correct it?
Given the delegated permissions you're requesting (which should cover all scenarios, including role-assignable groups), the most likely cause for this is that the signed-in user is not authorized to manage the membership of the group in question.
In general, whether a user is allowed to manage a group's membership depends on the type of group, and whether the user is owner of the group or not:
Owned groups:
All member users
Security groups, not role-assignable groups:
Intune Administrator
Knowledge Administrator
Knowledge Manager
Windows 365 Administrator
Microsoft 365 groups, not role-assignable groups:
Exchange Administrator
SharePoint Administrator
Teams Administrator
Security groups and Microsoft 365 groups, not role-assignable groups:
User Administrator
Groups Administrator
Identity Governance Administrator can manage
Role-assignable groups, not security groups nor Microsoft 365 groups:
Privileged Role Administrator
All groups, including role-assignable groups
Global Administrator
(This information is essentially a pivot on what's listed here: https://learn.microsoft.com/en-us/azure/active-directory/roles/permissions-reference, which can also be retrieved from Microsoft Graph by querying GET .../roleManagement/directory/roleDefinitions.)

WindowsIdentity - Difference between Groups and Claims

I'm trying to check whether the User belongs to some groups by using SID-s.
I was using WindowsIdentity.Groups, but then noticed that sometimes it doesn't show that the user belongs to the Administrators group.
After searching a while, I've discovered that instead WindowsIdentity.Claims work fine (includes the admin group in the results as well).
I wasn't able to find proper documentation on Claims.
So, what is the difference between the Groups and Claims in WindowsIdentity, and why groups don't show administrators group while the Claims do?
And finally, can I safely use Claims instead of Groups?
Here's the code I have:
var wi = WindowsIdentity.GetCurrent();
var sidToFind = "S-1-5-32-544"; // Hardcoded the sid of administrators group for demo, but in general this is a parameter of a function on my side
// This will NOT include the sid S-1-5-32-544
var groupSids= wi.Groups
.Where(item => item.Value == sidToFind);
// This will include the sid S-1-5-32-544 and also all the other results that Groups provides.
var claimSids = wi.Claims
.Where(item => item.Value == sidToFind));
There are differencies between groups and claims.
Groups work with WORKGROUP and AD
Claims work with Active Directory Federation Services
Claims is more complex way to check user identity, because claims exists not only for ADFS, you can use or create additional claims token provider
When we call Groups method for WindowsIdentity, we have restriction:
// Ignore disabled, logon ID, and deny-only groups.
The role of claims
In the claims-based identity model, claims play a pivotal role in the
federation process, They are the key component by which the outcome of
all Web-based authentication and authorization requests are
determined. This model enables organizations to securely project
digital identity and entitlement rights, or claims, across security
and enterprise boundaries in a standardized way.
So, if you work only in NTLM - you can safty work with Groups, but if you want work via federation (for example SharePoint, Google, etc) - you must use claims. Claims contains groups, but groups not contain claims.
In order to answer the question why you do not see a certain group, you need to know its properties and location. As I wrote above and gave the link, there are restrictions on getting the list of groups. But here i found this info:
SID
Name
Description
S-1-5-32-544
Administrators
A built-in group. After the initial installation of the operating system, the only member of the group is the Administrator account. When a computer joins a domain, the Domain Admins group is added to the Administrators group. When a server becomes a domain controller, the Enterprise Admins group also is added to the Administrators group.
So, if your local admins group is disabled - you cannot see it when you get it via WindowsIdentity even if the user is included in it.

How can I securely ensure the current user belongs to an Active Directory Group?

I am creating a C# Winform Application which will be used in a corporate domain (Windows Active Directory). The app is to behave as the following:
When a user opens the App, the App checks if the current user is part of an Active Directory group.
If it is, the app then allows the user to use the app.
From google searches, I found several ways how to check if a user is part of an Active Directory group.
For example in the link here => How to check if a user belongs to an AD group?
My concern is the security part of this. What if someone spoofs a username and domain. He won't need to know the password to allow access to the app.
Don't do a look up. The SID of every group the user is a member of (recursively) is part of the user's login token. So you can just use WindowsPrincipal.IsInRole(). If you only have the name of the group, you can give it that:
var currentUser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
currentUser.IsInRole("SomeGroup")
That translates the name into the SID and checks the login token for that SID. That requires a network request. If you can give it the SID of the group instead, then you can save that network request:
var groupSid = new SecurityIdentifier("S-1-5-21-blah");
currentUser.IsInRole(groupSid)

Active Directory Shared Mailbox user permissions

I need to write a C# app that queries Active Directory and returns a list of users that have permission to use a certain Shared Mailbox.
I've spoken to our Support department and they say that each Shared Mailbox has an associated Security Group. And to grant a user access to a Shared Mailbox, they make the user a member of the associated Security Group.
My question is what is the link between a Shared Mailbox and a Security Group in AD? How can I work out which Security Group is associated to which Shared Mailbox?
You can use the msExchMailboxSecurityDescriptor attribute of the Shared Mailbox object in Active Directory which will give you the DACL of the Mailbox. eg How to read msExchMailboxSecurityDescriptor attribute in C#
How can I work out which Security Group is associated to which Shared Mailbox?
There is no direct way other then enumerated each DACL on each Shared Mailbox. Autodiscover will return all the Mailboxes a particular user has access to if the are automapped via the AlternativeMailbox element https://msdn.microsoft.com/en-us/library/ee237925(v=EXCHG.80).aspx.
Cheers
Glen
Edit See the Full assembly names you should be able to work the rest out yourself
byte[] DaclByte = (Byte[])DirectoryEntry.Properties["msExchMailBoxSecurityDescriptor"][0];
System.DirectoryServices.ActiveDirectorySecurity adDACL = new ActiveDirectorySecurity();
adDACL.SetSecurityDescriptorBinaryForm(DaclByte);
System.Security.AccessControl.AuthorizationRuleCollection aclCollection = adDACL.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier));
foreach (System.Security.AccessControl.AuthorizationRule ace in aclCollection)
{
I had a similar requirement. The AD field on the mailbox account that I ended up using was publicDelegates:
mailboxDirectoryEntry.publicDelegates
This contains a list of distinguishedNames of userids or groups that have been granted access via Outlook delegation capabilities.
For this specific question, you could then list the members of the group(s) you obtain from publicDelegates.
Transitive membership can be obtained with the
member:1.2.840.113556.1.4.1941:=
selector on your query. (Very handy if your organization uses nested groups)

Finding user's groups SIDs inside Sharepoint

I need to find out all AD groups SIDs that current user belongs to inside my Sharepoint (2007) webpart.
I wanted to use System.DirectoryServices.AccountManagement namespace:
using (var context = new PrincipalContext( ContextType.Domain ))
{
using (var user = UserPrincipal.FindByIdentity( context, accountName ))
{
var groups = user.GetAuthorizationGroups();
...
}
}
, but I get the following error:
Event ID: 10016
Through the permission settings (application specific) is the SID (S-1-5-20) for user NT AUTHORITY \ NETWORK SERVICE of address localhost (Using LRPC) is not authorized to activate (Local) for the COM Server application with CLSID
{61738644-F196-11D0-9953-00C04FD919C1}
This might be fixed with this http://support.microsoft.com/kb/899965
but this approach requires changing registry values (the ownership of the application, so you can change apps values at dcomcnfg) and later User Permissions at dcomcnfg's COM security, which isn't an option for me.
Is there another way to access Current user's groups SIDs inside Sharepoint?
I really hoped I can find these values in SPContext.Current.Web.CurrentUser.Groups, but apparently not.
You need to go the SharePoint way here and not use System assemblies, but the SharePoint ones.
The SID of each user is in the SPUser.Sid Property. As you want to look for AD groups only you can check the .IsDomainGroup Property of SPUser.
Now all you need to do is check the current user: ´SPContext.Current.Web.CurrentUser(aSPUser` object).
To answer your question how to get all groups a user belongs to, you actually will need to use System.DirectoryServices. A solution for your problem is shown in the following stackoverflow posts:
In C#, how to access Active Directory to get the list of groups that a certain user belongs to?
Querying AD for finding all groups of a user - Missing one group
So in short: SPUser object as well as querying the Active Directory via DirectoryServices

Categories