问题
I have a web API that use Individual accounts and issue tokens properly. I modified it to accept social authentication from native application.
Now, I want to add options for internal employees to access that API using their domain credentials rather than creating new username and password.
Employees should call the api/token to get a token, however, they will pass in the body, the domain credential.
Any ideas on how to differentiate between normal username and password and domain credentials, and where to do the changes exactly?
回答1:
I succeeded, but I just want to make sure I didn't put myself in security troubles, and I'm ready for any comment.
First, all what I changed is within the provider file: ApplicationOAuthProvider.cs:
create new private variable to define whether client wants to login using Domain:
private bool DomainUser = false;
Modified the first task responsible of issuing token, so it checks for a new parameter (DomainUser) within the request body:
grant_type=password&username=username&password=password&DomainUser=true
:public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { // Resource owner password credentials does not provide a client ID. if (context.ClientId == null) { DomainUser = context.Parameters["DomainUser"] == "true"; context.Validated(); } return Task.FromResult<object>(null); }
Modified the task that verify the username and password, so first it will check if this is a request for a DomainUser, and authenticate with domain, otherwise, it will continue as usual:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); ApplicationUser user; if (DomainUser && IsValidCredentials(context.UserName, context.Password, "MyDomain")) user=await PrepareDomainUser(context); else user = await userManager.FindAsync(context.UserName, context.Password);
where the function IsValidCredentials will verify the credentials with the domain (You need to add reference to System.DirectoryServices.AccountManagement
):
private static bool IsValidCredentials(string Username, string Password, string Domain)
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain))
{
return pc.ValidateCredentials(Username, Password);
}
}
and the PrepareDomainUser will create, if this is the first time, the application user, without password:
private async Task<ApplicationUser> PrepareDomainUser(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindByEmailAsync(context.UserName);
if (user == null)
{
user = new ApplicationUser() { UserName = context.UserName, Email = context.UserName };
IdentityResult result = await userManager.CreateAsync(user);
}
return user;
}
来源:https://stackoverflow.com/questions/43977557/mix-windows-authentication-and-individual-accounts-in-web-api