Azure Active Directory authorization - c#

I'm trying to do user authorization though AAD in azure app with own client side. I have a user named "User" in my AAD with password "pass". When user is trying to connect the app:
try
{
if (false == Utils.DataBaseUtils.CheckLoginCorrect(sceneMessage.Login, sceneMessage.Pwd))
{
WriteToLog("Wrong password");
SendError(handler, "Wrong password");
return;
}
}
catch (Exception e)
{
WriteToLog("Unexpected problem when checking password: "+e.ToString());
SendError(handler, "Unexpected problem when checking password");
return;
}
//authorization using Azure Active Directory
public static bool CheckLoginCorrect(string login, string password)
{
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password)) //validatecredentials return true if log or pass is empty
return false;
using (PrincipalContext adContext = new PrincipalContext(ContextType.Domain, "mydomain156.onmicrosoft.com")) //represent AD
{
return adContext.ValidateCredentials(login, password, ContextOptions.Negotiate);
}
}
Where sceneMessage.Login == "User", sceneMessage.Pwd == "pass".
Here I'm getting error:
System.DirectoryServices.AccountManagement.PrincipalServerDownException:
The server could not be contacted. --->
System.DirectoryServices.Protocols.LdapException: The LDAP server is
unavailable.
Could anybody help, please?

It looks like you're using the AD libraries for traditional on-premise AD. To program against Azure AD, use the Auzre Authentication Library (AAL). Note, last week AAL was renamed to Active Directory Authentication Library.
http://msdn.microsoft.com/en-us/library/jj573266.aspx

Azure Active Directory Authentication Library (ADAL, formerly AAL) is the correct API to use for authenticating users in Azure Active Directory. Version 1 has been released and you can find more information here:
http://www.cloudidentity.com/blog/2013/09/12/active-directory-authentication-library-adal-v1-for-net-general-availability/

Related

Why do I have two login popups in Azure AD B2C using Azure AD account?

I created web application (Angular 5 + MSAL + ASP.NET Core) and connected it to the Azure AD B2C. I needed custom flows while signing, so I have to use custom policy. Auth works fine. Then I had to add another Azure AD provider. The deal is that users from AAD and ADD B2C are signing with different behavior.
in general code is following:
this.clientApplication = new UserAgentApplication(
environment.auth.clientId,
environment.auth.loginAuthority,
this.authCallback.bind(this),
{
validateAuthority: false,
cacheLocation: 'localStorage',
logger: logger
}
);
...
public login(): void {
return this.clientApplication.loginRedirect(environment.auth.scopes);
}
...
public getAccessTokenAsync(): Promise<string> {
return this.clientApplication.acquireTokenSilent(environment.auth.scopes)
.then((accessToken: string) => {
return accessToken;
})
.catch((silentError: object) => {
return this.clientApplication.acquireTokenPopup(environment.auth.scopes)
.then((accessToken: string) => Promise.resolve(accessToken))
.catch((popupError: object) => {
return Promise.resolve('');
});
});
}
Firstly I use login, and when http call happens I use getAccessTokenAsync.
Users from B2C redirected from login, and acquireTokenSilent returns access token.
Users from AD redirected from login, and acquireTokenPopup throws error, but token is saved to local storage, so after refresh it works. (Error: Refused to display 'http...' in a frame because it set 'X-Frame-Options' to 'deny'.)
Any ideas why it works so?

LDAP Queries, Core 2.x, IdSvr, Self Host

Writing a C#, Core 2.1, self-hosted web api to stand up an Identy Sewrver 4 instance...
Trying to use LDAP for (temp) user and role store. Yet, when I run the STS I am working on, I keep getting a "bad password" error when I query LDAP. I am working on my Laptop (in a workgroup), am running a DC in Hyper-V (domain).
I am trying to use System.DirectoryServices.AccountManagement and have a simple search setup as:
// Pass in userName as someone#domain.xyz
// Example: userName = keith#sol3.net
// Domain Controller is found at dc01.sol3.net
public static bool CanSignIn(string userName, string domainName)
{
using (var pc = new PrincipalContext(ContextType.Domain, domainName))
{
UserPrincipal user = null;
try
{
var name = userName.Split('#');
user = UserPrincipal.FindByIdentity(pc, IdentityType.Name, name[0]);
}
catch (Exception ex)
{
Log.Warning(ex, $"Could not find {userName} in Active Directory, Domain: {domainName}!");
}
return user != null;
}
}
I am wondering if:
I need to attach my laptop to the domain?
Using Kestrel is interfering?
Should I run in IIS Express mode?
Should I research how to run under HTTP.SYS?
What path will help here?
TIA
I think you need to manually authenticate using a password in order to query the directory. Using the method you detail in your question there is no way for the calling app to identify itself. If you want the app to run independently of the domain (i.e. not have to run as a domain user on a domain-joined server) then the best way would be to use a raw LdapConnection and bind a username/password NetworkCredential to it.
This example uses a pre-configured service account to query for a user by their primary email address:
var connection = new LdapConnection(ldapServerName);
connection.AuthType = AuthType.Basic;
//Additional connection setup omitted for brevity
connection.Bind(new NetworkCredential(serviceUserName, servicePassword));
var request = new SearchRequest(
baseDistinguishedName,
"(&(objectClass=person)(mail=" + EscapeFilterValue(emailAddress) + "))",
System.DirectoryServices.Protocols.SearchScope.Subtree,
null
);
SearchResponse response = (SearchResponse)_connection.SendRequest(request);

Validate machine user credentials fails when the user has no password

I'm trying to validate a username and its password on a local windows machine.
bool AreUserCredentialsValid(string username, string password)
{
try
{
using(var context = new PrincipalContext(ContextType.Machine))
{
return context.ValidateCredentials(username, password);
}
}
catch
{
return false;
}
}
This works fine for most cases. In one case I get the following error message.
The user cannot login because of an account restriction. Possible reasons are blank passwords not allowed, logon hour restrictions, or a policy.
This message appears only if I login as user A and try to validate the credentials of user A. If I login as user B and try to validate the credentials of user A it works as expected.
I can reproduce this behavoir with the following cmd line.
runas /user:A notepad
How can I validate credentials of a local user in any case without changing system settings or the user? As the user is able to login it should be possible.

change active directory password in sharepoint webpart

I want to change active directory password in my web part in SharePoint but when i change the password, the stored account password in SharePoint does not change and i get this error:
This operation can be performed only on a computer that is joined to a server farm by users who have permissions in SQL Server to read from the configuration database. To connect this server to the server farm, use the SharePoint Products Configuration Wizard, located on the Start menu in Microsoft SharePoint 2010 Products.
This is my code for change password:
public void ChangePassword(string usrDomain, string username, string oldPassword, string newPassword)
{
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, usrDomain, username, oldPassword))
{
UserPrincipal user = new UserPrincipal(ctx);
user = UserPrincipal.FindByIdentity(ctx, username);
user.ChangePassword(oldPassword, newPassword);
user.Save();
}
}
Assuming your AD server is "in the sharepoint farm", you will have to run your code with another account.
Solution is to impersonate with an admin user token who has rights in the AD server :
SPUser AdminUser = SPContext.Current.Web.SiteUsers[#"domain\username"];
using(SPSite oSiteCollection = new SPSite("http://YOURSITE", AdminUser.UserToken))
{
//run your code
}

Why does Active Directory validate last password?

I am working on a simple solution to update a user's password in Active Directory.
I can successfully update the users password. Updating the password works fine. Lets say the user has updated the password from MyPass1 to MyPass2
Now when I run my custom code to validate users credential using:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "MyPass2");
}
//returns true - which is good
Now when I enter some wrong password it validates very nicely:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "wrongPass");
}
//returns false - which is good
Now for some odd reasons, it validates the previous last password which was MyPass1 remember?
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "MyPass1");
}
//returns true - but why? we have updated password to Mypass2
I got this code from:
Validate a username and password against Active Directory?
Is it something to do with last password expiry or is this how the validation supposed to work?
The reason why you are seeing this has to do with special behavior specific to NTLM network authentication.
Calling the ValidateCredentials method on a PrincipalContext instance results in a secure LDAP connection being made, followed by a bind operation being performed on that connection using a ldap_bind_s function call.
The authentication method used when calling ValidateCredentials is AuthType.Negotiate. Using this results in the bind operation being attempted using Kerberos, which (being not NTLM of course) will not exhibit the special behavior described above. However, the bind attempt using Kerberos will fail (the password being wrong and all), which will result in another attempt being made, this time using NTLM.
You have two ways to approach this:
Follow the instructions in the Microsoft KB article I linked to shorten or eliminate the lifetime period of an old password using the OldPasswordAllowedPeriod registry value. Probably not the most ideal solution.
Don't use PrincipleContext class to validate credentials. Now that you know (roughly) how ValidateCredentials works, it shouldn't be too difficult for you to do the process manually. What you'll want to do is create a new LDAP connection (LdapConnection), set its network credentials, set the AuthType explicitly to AuthType.Kerberos, and then call Bind(). You'll get an exception if the credentials are bad.
The following code shows how you can perform credential validation using only Kerberos. The authentication method at use will not fall back to NTLM in the event of failure.
private const int ERROR_LOGON_FAILURE = 0x31;
private bool ValidateCredentials(string username, string password, string domain)
{
NetworkCredential credentials
= new NetworkCredential(username, password, domain);
LdapDirectoryIdentifier id = new LdapDirectoryIdentifier(domain);
using (LdapConnection connection = new LdapConnection(id, credentials, AuthType.Kerberos))
{
connection.SessionOptions.Sealing = true;
connection.SessionOptions.Signing = true;
try
{
connection.Bind();
}
catch (LdapException lEx)
{
if (ERROR_LOGON_FAILURE == lEx.ErrorCode)
{
return false;
}
throw;
}
}
return true;
}
I try to never use exceptions to handle the flow control of my code; however, in this particular instance, the only way to test credentials on a LDAP connection seems to be to attempt a Bind operation, which will throw an exception if the credentials are bad. PrincipalContext takes the same approach.
I've found a way to validate the user's current credentials only. It leverages the fact that ChangePassword does not use cached credentials. By attempting to change the password to its current value, which first validates the password, we can determine if the password is incorrect or there is a policy problem (can't reuse the same password twice).
Note: this will probably only work if your policy has a history requirement of at least not allowing to repeat the most recent password.
var isPasswordValid = PrincipalContext.ValidateCredentials(
userName,
password);
// use ChangePassword to test credentials as it doesn't use caching, unlike ValidateCredentials
if (isPasswordValid)
{
try
{
user.ChangePassword(password, password);
}
catch (PasswordException ex)
{
if (ex.InnerException != null && ex.InnerException.HResult == -2147024810)
{
// Password is wrong - must be using a cached password
isPasswordValid = false;
}
else
{
// Password policy problem - this is expected, as we can't change a password to itself for history reasons
}
}
catch (Exception)
{
// ignored, we only want to check wrong password. Other AD related exceptions should occure in ValidateCredentials
}
}
Depending on the context of how you run this, it may have to do with something called "cached credentials."

Categories

Resources