For a work project, we have a central application named APC that handles user management for our internal applications; it allows for standard CRUD operations on users, applications, permissions, and roles.
This application currently uses Active Directory for authentication, using Windows Identity to handle claims. It provides a DLL containing a custom authorization attribute that we use in internal applications.
The business wants APC to be able to handle non-domain authentication (username and password) and they would also like to be able to support mobile devices. To that end, we've decided to make our application directly handle authentication as well by making it an OAuth provider; we'll expand our user persistence to handle usernames and passwords in addition to domain logins, and provide bearer tokens to support multiple application types.
Through my research, I've found good articles for using OWIN to create an OAuth provider with basic authentication, such as this one. I've also found Microsoft's Active Directory Authentication Library (ADAL), which apparently will handle the OAuth portion. However, I'm not sure how to marry the two authentication types in our provider. (This is compounded by the fact that while I understand authentication, I'm not that familiar with how .NET applications work with Active Directory. Generally, it's a tag in web.config, and it just works - I don't really know how to tap into that pipeline.)
How can I authenticate using Active Directory with a username and password combination as a fallback?
Here's what I've got so far, for reference. It's not much, unfortunately:
public override async Task GrantResourceOwnerCredentials( OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); // TODO: Revisit.
/* The authentication portion goes here.
/* Check Active directory first. If that does not succeed, attempt basic authentication.
*/
// Using Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext().AcquireToken can't work, as I need to generate my token based on the AD credentials.
/* If AD fails, fall back to basic auth if it has been provided.
*/
// If auth fails, set context error.
if (false) // TODO: Revisit.
{
context.SetError("invalid_grant", "Authentication failed.");
}
// add user and app guid claims
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ApcClaimTypes.User, userGuid)); // TODO: Revisit.
identity.AddClaim(new Claim(ApcClaimTypes.Application, appGuid)); // TODO: Revisit.
// build claims from apc
var apcClaims = new List<Claim>();
// get privileges
apcClaims.AddRange(_appService.GetPrivileges(uid, aid)
.Select(p => new Claim(ApcClaimTypes.Privilege, p.PrivilegeCode)));
// get roles
apcClaims.AddRange(_appService.GetRoles(uid, aid)
.Select(r => new Claim(ClaimTypes.Role, r.RoleCode)));
identity.AddClaims(apcClaims);
context.Validated(identity);
}