Fellow developers, I'm updating an IIS web application from using Windows Authentication to using Azure Active Directory instead. The setup looks fine: I can successfully authenticate, and I get the user's identity as a ClaimsIdentity.
However, this does not mesh well with my current use of System.Web.Security.WindowsTokenRoleProvider. When doing an IsInRole() check, the role provider detects that the current identity is not a WindowsIdentity and throws a ProviderException:
Method is only supported if the user name parameter matches the user name in the current Windows Identity.
I believe I need to configure the application's role manager to use a ClaimsIdentity-friendly provider. Is there a standard role provider class that plays well with the ClaimsIdentity, or will I need to build a custom role provider?
Edit: I've built my own custom role manager that appears to only need an implementation of GetRolesForUser(string username) method. It solves my problem, but doesn't answer my question :)
The base class of Claims Identity is the System.Security.Claims namespace. Hence it needs to be used in the project.
using System.Security.Claims;
To achieve this, we need to use customize the ClaimsIdentity based on our requirement as shown below.
Below is the code snippet:
string Default_IdentityProvider_ClaimValue = "Some_ClaimsIdentity";
var id = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, users.UserId.ToString(), ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, users.UserName, ClaimValueTypes.String));
id.AddClaim(new Claim(Identity_Provider_ClaimType, Default_IdentityProvider_ClaimValue, ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, users.UserName, ClaimValueTypes.String));```
Related
Is there an example of how to authenticate azure resource using User Managed Identity using c#? I am using the following code to authenticate using system managed identity and it works fine. but not sure about how to pass the user managed identity resource in the following example.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("https://mykeyvaultname.vault.azure.net/secrets/test")
.ConfigureAwait(false);
return new string[] { secret.Value };
Please see the documentation here. This feature is in the 1.2.0-preview version of the library. It only works on Azure VMs and VMSS as of now. You need to set the client id in a connection string, which can either be specified in the constructor or in the env variable (documentation of other connection string options here). In this scenario, the constructor is recommended, so you can use developer identity/ cert for local and switch to the user-assigned identity on Azure.
Update: The library has been updated to support user assigned identity in App Services as well as part of 1.2.0-preview2.
In my current asp.net MVC core application we use OpenId Connect to authenticate with our corporation's identity provider.
However during local development we cannot reach the the provider.
Also we would like to easily change claim values for development and unit testing purposes.
I tried swapping my service binding for IHttpContextAccessor to a DevelopmentHttpContextAccessor that fills up the HttpContext's Identity with the desired claims.
This is a bit of a roundabout way and it also doesn't work as the claims are emptied when I check them in my Service.
What is the standard way of handling this during development and unit testing? What am I missing?
The answer was not faking IHttpContextAccessor, but setting a custom ClaimsPrincipal to the identity property.
In your Startup.Configure you can add a middleware step:
app.Use((httpContext, nextMiddleware) => {
var claims = new[] {
// Your claims here
};
var claimsIdentity = new ClaimsIdentity(claims);
var user = new ClaimsPrincipal(claimsIdentity);
httpContext.User = user;
return nextMiddleware();
});
I have an ASP.NET 3.5 application that I recently extended with multiple membership and role providers to "attach" a second application within this application. I do not have direct access to the IIS configuration, so I can't break this off into a separate application directory.
That said, I have successfully separated the logins; however, after I login, I am able to verify the groups the user belongs to through custom role routines, and I am capable of having identical usernames with different passwords for both "applications."
The problem that I am running into is when I create a user with an identical username to the other membership (which uses web.config roles on directories), I am able to switch URLs manually to the other application, and it picks up the username, and loads the roles for that application. Obviously, this is bad, as it allows a user to create a username of someone who has access to the other application, and cross into the other application with the roles of the other user.
How can I mitigate this? If I am limited to one application to work with, with multiple role and membership providers, and the auth cookie stores the username that is apparently transferable, is there anything I can do?
I realize the situation is not ideal, but these are the imposed limitations at the moment.
Example Authentication (upon validation):
FormsAuthentication.SetAuthCookie(usr.UserName, false);
This cookie needs to be based on the user token I suspect, rather than UserName in order to separate the two providers? Is that possible?
Have you tried specifying the applicationName attribute in your membership connection string?
https://msdn.microsoft.com/en-us/library/6e9y4s5t.aspx?f=255&MSPPError=-2147217396
Perhaps not the answer I'd prefer to go with, but I was able to separate the two by having one application use the username for the auth cookie, and the other use the ProviderUserKey (guid). This way the auth cookie would not be recognized from one "application" to the other.
FormsAuthentication.SetAuthCookie(user.ProviderUserKey.ToString(), false);
This required me to handle things a little oddly, but it simply came down to adding some extension methods, and handling a lot of membership utilities through my own class (which I was doing anyhow).
ex. Extension Method:
public static string GetUserName(this IPrincipal ip)
{
return MNMember.MNMembership.GetUser(new Guid(ip.Identity.Name), false).UserName;
}
Where MNMember is a static class, MNMembership is returning the secondary membership provider, and GetUser is the standard function of membership providers.
var validRoles = new List<string>() { "MNExpired", "MNAdmins", "MNUsers" };
var isValidRole = validRoles.Intersect(uroles).Any();
if (isValidRole)
{
var userIsAdmin = uroles.Contains("MNAdmins");
if (isAdmin && !userIsAdmin)
{
Response.Redirect("/MNLogin.aspx");
}
else if (!userIsAdmin && !uroles.Contains("MNUsers"))
{
Response.Redirect("/MNLogin.aspx");
}...
Where isAdmin is checking to see if a subdirectory shows up in the path.
Seems hacky, but also seems to work.
Edit:Now that I'm not using the username as the token, I should be able to go back to using the web.config for directory security, which means the master page hack should be able to be removed. (theoretically?)
Edit 2:Nope - asp.net uses the username auth cookie to resolve the roles specified in the web.config.
i am using the default template of the ASP.net identity framework for registering users. the problem is i can't remove any users. i got an error "Default Membership Provider must be specified.". i know that i must specify the default membership provider and then use Membership.Delete(..);to simply delete the user. but the problem is that i can't config the membership default provider . i searched a lot but all of the link recommend to use " ASP.NET Configuration" wizard which i can't find in Web-Form project ! here is the code for creating a user:
var manager = new UserManager();
var user = new ApplicationUser() { UserName = UserName.Text };
IdentityResult result = manager.Create(user, Password.Text);
Use
userManager.Delete(user)
MembershipProvider is depricated; wherever you use calls to this class - remove them - they are not going to work as Identity framework and MembershipProvider are incompatible
The System.Security.Principal.WindowsIdentity.Impersonate function takes a System.intptr parameter, which seems awfully useless in my situation (with my limited understanding).
I am developing an intranet application that uses integrated security to authorize users page-by-page against a role associated with their Windows Identity. I have no passwords or anything of the sort. Simply a Windows username. For testing purposes, how could I possibly impersonate a Windows user based on their username? The "impersonate" method jumped out at me as obvious, but it takes an unexpected parameter.
Thanks in advance :)
In a nutshell, no. But you are on the right track. You either have to get the user by simulating a login with LoginUserA ( C Win32 Api ) or set your IIS site to Windows Authentication.
In that case, your Page will have a property named User of type IPrincipal, which you can then use to run as that user. For example ( sorry, C# code ).
IPrincipal p = this.User;
WindowsIdentity id = (WindowsIdentity)p.Identity;
WindowsImpersonationContext wic = id.Impersonate();
try {
// do stuff as that user
}
finally {
wic.Undo();
}
Are you using anything windows-specific from the WindowsPrincipal or is it just a handy way to get auth/auth without having to manage users? If you need to be windows-based, Serapth has the right method. If you are just really using it as a convenient auth/auth store, then you should probably write your code to interface with IPrincipal. You can then inject your own implementations of IPrincipal with the desired values into either the HttpContext.User or Thread.CurrentThread.Principal depending on the nature of your tests and app.
User tokens (the value that the IntPtr in Impersonate represents) represent more than the username. They are a handle into an internal windows context that include information about the user, authentication tokens, current security rights, etc. It's because of this that you can't impersonate without a password. You have to actually "log in" to create a token via the LogonUser method.
What I've done in the past is create a special "Test" user account with a password that I can just keep in code or a config file.
You shouldn't need to impersonate to check role membership. Simply use the constructor for a WindowsIdentity that takes a UPN (userPrincipalName) constructed from the username according to your UPN conventions, then create a WindowsPrincipal from that identity and use IsInRole to check membership in a group. This works on W2K3 and a Windows 2003 domain, but not in other circumstances.
var userIdentity = new WindowsIdentity( username + "#domain" );
var principal = new WindowsPrincipal( userIdentity );
var inRole = principal.IsInRole( "roleName" );
You may also want to consider using either the standard or a custom role provider that will allow you to use the Roles interface to check membership.