Asp.net search Active Directory from IIS - asp.net

Recently I moved my ASP.NET application from an old server running IIS5 to a new server running IIS7.5.
The application gives me an error:
The (&(objectCategory=person)(sAMAccountName=)) search filter is invalid.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: The (&(objectCategory=person)(sAMAccountName=)) search filter is invalid.
The function that searches AD is:
public static string Get_AD_User_Email(string username)
{
try
{
DirectorySearcher searcher = new DirectorySearcher("(&(objectCategory=person)(sAMAccountName=" + username + "))");
SearchResult result = searcher.FindOne();
if (result != null)
{
DirectoryEntry employee = result.GetDirectoryEntry();
if (employee.Properties["mail"] != null)
{
return employee.Properties["mail"].Value.ToString();
}
else return "NULL";
}
else throw new Exception("ERROR: Problem searching active directory for users.");
}
catch (Exception ex) { throw ex; }
}
The weird thing is that on debug in Visual Studio the website is running, only from IIS it's crashes.
Can someone help me?

The trouble is just that your function Get_AD_User_Email(string username) is called with an empty value for username.

Since:
DirectorySearcher searcher = new DirectorySearcher("(&(objectCategory=person)(sAMAccountName=" + username + "))");
Is returning the exception:
The (&(objectCategory=person)(sAMAccountName=)) search filter is
invalid.
You are passing an empty string to Get_AD_User_Email.
How are you retrieving "username"?

You changed IIS servers, now no username is being passed in by the calling method (as several other answers point out).
I would verify that you have anonymous access disabled on that website in IIS. It's common to find both Windows authentication and anonymous access enabled. When this happens anonymous is preferred and you won't get the username.
Check the value of HttpContext.Current.User. I usually use code like the one below to verify windows authentication:
WindowsIdentity id = (WindowsIdentity)HttpContext.Current.User.Identity;
string username = id.Name;

Try:
objectClass=user
Instead of:
objectCategory=person

Related

Entity Framework .Net core FindAsync Throw System.OverflowException: Arithmetic operation resulted in an overflow

I'm trying to create a web API for authentication that return a token.
I'm using .Net core 1.1, EF 1.1.0 and SQL 2014 express on Windows 10. I follow direction from this website to create required classes.
In the middleware class, there's a function called GetIdentity to check the username and password in database. Here is the code
private async Task<ClaimsIdentity> GetIdentity(string username, string password, MyDBContext db) {
try
{
m_user SignedUser = await db.Users.FindAsync(username);
if (SignedUser == null || !SignedUser.password.Equals(password, StringComparison.Ordinal))
throw new ArgumentException("Invalid username or password");
return await Task.FromResult<ClaimsIdentity>(
new ClaimsIdentity(
new GenericIdentity(username, "Token"),
new Claim[] { }
));
}
catch (Exception ex) {Console.WriteLine(ex.Message); return await Task.FromResult<ClaimsIdentity>(null); }
}
When then program hit
m_user SignedUser = await db.Users.FindAsync(username);
It throws System.OverflowException: Arithmetic operation resulted in an overflow.
I didn't get any luck to find the solution or at least the reason why it failed.
Does anyone know why I got that exception?
Thank you for helping me.
P.S: If you need more information, just let me know
I fixed it. I used wrong connection string. I have to put the port number of SQL database in the connection string.
the wrong one:
Server=serverAddress;Database=dbName;User Id=dbUser;Password=dbPassword;
the right one:
Server=serverAddres,portNumber;Database=dbName;User Id=dbUser;Password=dbPassword;
Default MSSQL port number is 1433.
Hope it can help you out if you get same problem with me.
P.S you might get different exception. I got this exception when I tried to run it on VS Code
Like this one:
Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory[1] An exception occurred in the database while iterating the results of a query.

System.DirectoryServices.AccountManagement PrincipalContext impersonation to create new user

In Sharepoint (or any ASP.NET web application) I want to have a function to create AD users. I'm using System.DirectoryServices.AccountManagement for this task, but I'm getting into trouble. Here is my code:
using (var pc = new PrincipalContext(ContextType.Domain,"DOMAIN","administrator","password"))
{
if (pc.ValidateCredentials("administrator", "password"))
{
UserPrincipal up = new UserPrincipal(pc, username, password, true);
up.Save();
}
}
The user gets created but it is disabled. I know that my administrator:password pair is correct because "if" statement is returning true. Also during creation I receive Exception:
Exception has been thrown by the target of an invocation.
I checked PrincipalContext object and it is connecting to domain controller with "administrator" account. What could be the reason of this error and up.Save() function throwing Exception ?
Can you try the following:
using (var pc = new PrincipalContext(ContextType.Domain,"DOMAIN","administrator","password"))
{
using (var up = new UserPrincipal(pc))
{
up.SamAccountName = textboxUsername.Text; // Username
up.SetPassword(textboxPassword.Text); // Password
up.Enabled = true;
up.ExpirePasswordNow();
up.Save();
}
}
This should at least make sure that the user is created and is enabled. Let me know if it works.

Encountering error 'The Provider encountered an unknown error' while trying WebSecurity.CreateAccount in asp.net webpage

I am new to asp.net. I am trying to create a simple login and register webpage with WebMatrix. But I get the following error when I try to create an account:
The Provider encountered an unknown error.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.Security.MembershipCreateUserException: The Provider encountered an unknown error.
Source Error:
Line 32: db.Execute("INSERT INTO UserData (Email,Name) VALUES (#0,#1)", email, username);
Line 33:
Line 34: WebSecurity.CreateAccount(email,password);
Line 35: Response.Redirect("Homepage.cshtml");
Line 36: }
Source File: c:\Users\admin\Documents\My Web Sites\Login\Register.cshtml Line: 34
Stack Trace:
[MembershipCreateUserException: The Provider encountered an unknown error.]
WebMatrix.WebData.SimpleMembershipProvider.CreateAccount(String userName, String password, Boolean requireConfirmationToken) +1312
WebMatrix.WebData.WebSecurity.CreateAccount(String userName, String password, Boolean requireConfirmationToken) +31
ASP._Page_Register_cshtml.Execute() in c:\Users\admin\Documents\My Web Sites\Login\Register.cshtml:34
System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +207
System.Web.WebPages.WebPage.ExecutePageHierarchy(IEnumerable`1 executors) +68
System.Web.WebPages.WebPage.ExecutePageHierarchy() +156
System.Web.WebPages.StartPage.RunPage() +19
System.Web.WebPages.StartPage.ExecutePageHierarchy() +65
System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +76
System.Web.WebPages.WebPageHttpHandler.ProcessRequestInternal(HttpContextBase httpContext) +119
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.272
Any help is appreciated. Thanks.
I just had the same issue ... I was using
WebSecurity.CreateAccount(model.UserName, model.Password);
and above generated issue ..
then I tried:
WebSecurity.CreateAccountAndUser(model.UserName, model.Password);
and find out that I was missing other required fields of my Users table (UserProfile). Following worked for me:
WebSecurity.CreateAccountAndUser(model.UserName, model.Password, new {RequiredColumn1 = Value1, RequiredColumn2 = Value 2, ...... });
The post is old, but hope this can help others..
Be sure to:
Create the User record first
Invoke WebMatrix to create the User account.
Below is my code which resolved the same issue you're having:
public ActionResult SignUp(SignUpModel model)
{
if (ModelState.IsValid)
{
using (MorphometryContext context = new MorphometryContext())
{
User user = new User
{
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName,
Username = model.UserName
};
context.Users.Add(user);
context.SaveChanges();
}
// Attempt to register the user
try
{
WebSecurity.CreateAccount(model.UserName, model.Password);
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
return View();
}
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Projects");
}
Also, you don't want to Respoonse.Redirect to a .cshtml file. Instead you should return a RedirectToAction and pass in the Action and Controller names.
I've just had this problem - but by your code it might not be the same thing. I was trying to create the membership record before creating the record in my own user table. It has to be the other way round.
So I'd check that your INSERT INTO UserData query was actually working.
In my case; It was because of Culture;
the Membership provider for creating account with CreateUserAndAccount function, first create a user. it is ok for now, and the user successfully added to the Database.
But for creating account, It runs the below query to get userID to create new account for it:
SELECT [userID] from [User] Where (UPPER([userName]) = #0);
Here is where exception thrown because in some culture upper casing the letters is different, for example in turkish, the upper case for 'i' is 'İ'.
I Don't know how to solve this problem for this moment, and I'll try to learn it.
In my case I was creating a user named "admin" and exception throw. I change the user name to "mesut" And it runs successfully.
please make sure if you have a culture specific letters in userName field.(or email in your case), (as soon as I found how to solve it I will post it here)

Unknown username or bad password, LDAP Active Directory

I'm trying to authenticate against AD using application mode (ADAM), but keep getting unknown username or bad password. If I test the login in LDP.exe it logs in no problem, on simple bind. I've trawled through all similar posts with the same issue, but have not resolved it, any suggestions what I should be checking for?
private bool ValidateActiveDirectoryLogin(string Username, string Password)
{
bool Success = false;
System.DirectoryServices.DirectoryEntry Entry = new System.DirectoryServices.DirectoryEntry("LDAP://localhost:389/OU=Users,O=TestDirectory", Username, Password);
System.DirectoryServices.DirectorySearcher Searcher = new System.DirectoryServices.DirectorySearcher(Entry);
Searcher.SearchScope = System.DirectoryServices.SearchScope.Subtree;
try
{
System.DirectoryServices.SearchResult Results = Searcher.FindOne();
Success = (Results != null);
}
catch (Exception ex)
{
Success = false;
throw;
}
return Success;
}
Determine what context your application is hitting AD with. If your ASP.NET application pool identity is one that is low privileged, it won't have enough permissions to query active directory. If you don't want to create a custom user to run the app pool as with appropriate permissions - you could use the LogonUser API to make your ValidateActiveDirectoryLogin call under the security context of that account.
Finally, you should consider using System.DirectoryServices.AccountManagement if you are using .NET 3.5 or above.
You can use code like
bool validCreds = false;
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
validCreds = context.ValidateCredentials( username, password );
}

System.DirectoryServices - The server is not operational

I get an error by a website, on which I use Windows Authentication.
Strange things:
Only occurs if user is not yet saved into database (new unknown user)
Appears only on live system, everything fine on local development environment
This is what I get in a logging mail:
Source : System.DirectoryServices
Message: The server is not operational.
Trace:
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
at Smarthouse.Labs.DataAccess.UserListManager.SaveUser(String windowsUserName)
This is how I implement DirectorySearch:
private void SaveUser(string windowsUserName)
{
string[] domainAndUser = windowsUserName.Split('\\');
string domain = domainAndUser[0];
string username = domainAndUser[1];
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher search = new DirectorySearcher(entry);
try
{
// Bind to the native AdsObject to force authentication.
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("sn");
search.PropertiesToLoad.Add("givenName");
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();
if (result == null)
{
throw new Exception("No results found in Windows authentication.");
}
User userToSave = new User();
userToSave.FirstName = (String) result.Properties["givenName"][0];
userToSave.LastName = (String) result.Properties["sn"][0];
userToSave.Email = (String) result.Properties["mail"][0];
userToSave.Username = windowsUserName;
userToSave.Guid = Guid.NewGuid();
SaveUser(userToSave);
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message, ex);
}
finally
{
//Dispose service and search to prevent leek in memory
entry.Dispose();
search.Dispose();
}
}
If more code examples are needed just tell me.
Your problem is that you're using a "plain" domain name to bind - this won't work in LDAP. Actually, if you try to bind to LDAP://MyDomain, what you're really doing is trying to bind to the server called MyDomain.
You need a valid LDAP bind string - something like LDAP://dc=yourdomain,dc=local or something.
To find out what your default LDAP binding context is, use this code snippet:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://RootDSE");
if (deRoot != null)
{
string defaultNamingContext = deRoot.Properties["defaultNamingContext"].Value.ToString();
}
Once you have that string - use that as your bind string to your LDAP server.
And if you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context -- no domain name needed, uses default domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if(user != null)
{
// do something here....
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
You can use bind strings in the format LDAP://mydomain.com:389. I kept getting "Access is Denied" when trying to use the format LDAP://DC=mydomain,DC=com. Once I switched to the LDAP://mydomain.com:389 format, and bound using the AuthenticationTypes.ServerBind flag when constructing my DirectoryEntry, it worked great. This was in Azure App Service.
To add to marc_s's answer above, I needed to search multiple domains.
So for each Domain I did the following:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://" +"DomainName"+ "/RootDSE");
string defaultNamingContext = "LDAP://" + deRoot.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry mySearchRoot = new DirectoryEntry(defaultNamingContext);
DirectorySearcher myDirectorySearcher = new DirectorySearcher(mySearchRoot);
Similar Error Happened to me (though it happened all the time and not in specific cases like pointed out here) because of a wrong Active Directory connection string. i used the corp instead the prod one .
Use something that works for another app in your organization if exists.

Resources