My code is to check the logged user and retrieve his data as Image, Name, Department as this application work on network. I tested my code and it worked well at Localhost but when I deployed on the company server it doesn't work.
The authentication is windows .
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchScope = SearchScope.Subtree;
string UserName = Page.User.Identity.Name;
searcher.Filter = string.Format(CultureInfo.InvariantCulture, "(sAMAccountName={0})", UserName.Split('\\')[1]);
SearchResult findUser = searcher.FindOne();
if (findUser != null)
{
DirectoryEntry user = findUser.GetDirectoryEntry();
LoggedUser = user.Properties["displayName"].Value.ToString();
LoggedEmail = user.Properties["mail"].Value.ToString();
}
Related
I am creating a web application that connects to Active Directory and allows users to edit their own details in Active Directory from the app.
Users can see other users details so the app uses windows authentication to only allow editing of a user's own details. Obviously I can't provide every user Admin privileges to allow this so upon setting up the Directory Entry I pass it the credentials for an admin service account.
Upon reaching commit changes I can see that the ADEntry credentials are correct. However, it appears to not be using the passed in credentials and instead uses the windows authentication credentials.
When an admin user runs the app they can change details but when a non-admin user runs the app they get error - Access is denied - upon reaching CommitChanges(). This leads me to believe it is using the windows authentication credentials rather than those supplied in DirectoryEntry(credentials)
Any ideas?
Do I need to use Impersonation?
DirectoryEntry ADEntry()
{
using (DirectoryEntry ADEntry = new DirectoryEntry(myDomain, myAdminServiceUsername, myAdminServicePassword, AuthenticationTypes.Secure))
{
return ADEntry;
}
}
DirectorySearcher ADSearcher()
{
using(DirectorySearcher ADSearcher = new DirectorySearcher(ADEntry()))
{
return ADSearcher;
}
}
SearchResult GetADSearchResult(string userToFind)
{
SearchResult searchResult = new SearchResult();
DirectorySearcher ADS = ADSearcher();
ADS.Filter = "(&(objectClass=user)(sAMAccountname=" + userToFind + "))";
searchResult = ADS.FindOne();
return searchResult;
}
void SetProperty(string userToFind, string propertyToChange, string newPropertyValue)
{
SearchResult searchResult = GetADSearchResult(userToFind);
DirectoryEntry _ADEntry = searchResult.GetDirectoryEntry();
if (_ADEntry.Properties.Contains(propertyToChange))
{
_ADEntry.Properties[propertyToChange].Remove(_ADEntry.Properties[propertyToChange].Value);
}
_ADEntry.Properties[propertyToChange].Insert(0, newPropertyValue);
_ADEntry.CommitChanges();
}
These methods are creating, immediately disposing, and then returning some object instances:
DirectoryEntry ADEntry()
{
using (DirectoryEntry ADEntry = new DirectoryEntry(myDomain, myAdminServiceUsername, myAdminServicePassword, AuthenticationTypes.Secure))
{
return ADEntry;
}
}
DirectorySearcher ADSearcher()
{
using(DirectorySearcher ADSearcher = new DirectorySearcher(ADEntry()))
{
return ADSearcher;
}
}
So this:
...
DirectorySearcher ADS = ADSearcher();
ADS.Filter = "(&(objectClass=user)(sAMAccountname=" + userToFind + "))";
searchResult = ADS.FindOne();
...
...can effectively be translated to this:
var directoryEntry = new DirectoryEntry(myDomain, myAdminServiceUsername, myAdminServicePassword, AuthenticationTypes.Secure);
directoryEntry.Dispose();
var directorySearcher = = new DirectorySearcher(directoryEntry);
directorySearcher.Dispose();
directorySearcher.Filter = "(&(objectClass=user)(sAMAccountname=" + userToFind + "))";
var searchResult = directorySearcher.FindOne();
Unfortunately, I don't have an AD available to test against, and it's possible that this isn't the root cause of your issue. However, I would recommend fixing the code to not use object instances after they have been disposed. The following might be a better approach:
SearchResult searchResult;
using (var directoryEntry = new DirectoryEntry(myDomain, myAdminServiceUsername, myAdminServicePassword, AuthenticationTypes.Secure))
using (var directorySearcher = new DirectorySearcher(directoryEntry))
{
directorySearcher.Filter = "(&(objectClass=user)(sAMAccountname=" + userToFind + "))";
searchResult = directorySearcher.FindOne();
}
// It's OK to use searchResult here, it's not `IDisposable`.
I am new to LDAP related coding and today I am asked to develop a code to check the users authentication against LDAP.
The tutorials I have found online are so simple but our company's Directory is so complicated that I don't know how to write a code for that. Here is the info of the LDAP . I have changed the company name to hide the name.
uri = ldaps://ABC.ad.XYZ.com:636
user_filter = memberOf=CN=TENXAIRFLOWPROD,OU=Security Groups,OU=Normal Users and Groups,OU=Account Management Services,OU=AD Master OU,DC=ABC,DC=ad,DC=XYZ,DC=com
user_name_attr = sAMAccountName
superuser_filter = memberOf=CN=TENXAIRFLOWPROD_ADM,OU=Security Groups,OU=Normal Users and Groups,OU=Account Management Services,OU=AD Master OU,DC=ABC,DC=ad,DC=XYZ,DC=com
bind_user = SCGLOBAL\twiki
bind_password_cmd = python /bns/tenx/airflow/ldap_password.py
basedn = DC=ABC,DC=ad,DC=XYZ,DC=com
search_scope = SUBTREE
Here is a code I have developed but it gives me error:
string username = "myUserName";
string domain = "ldaps://ABC.ad.XYZ.com:636";
string pwd = "myPasword";
try
{
DirectoryEntry entry = new DirectoryEntry(domain, username, pwd);
//Bind to the native AdsObject to force authentication.
object obj = entry.NativeObject;
lblError.Text=("Login Successful");
//search some info of this user if any
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
SearchResult result = search.FindOne();
}
catch (Exception ex)
{
lblError.Text=("Login failed: " + ex.ToString());
}
Could anybody help plz?
Comment: According to the admin , I have been assigned to the group in AD. But how can I make sure I can access it?
It seems like Active Directory. If so, you could just use PrincipalContext.
public bool ValidateCredentials(string domain, string username, string password)
{
using (var context = new PrincipalContext(ContextType.Domain, domain))
{
return context.ValidateCredentials(username, password);
}
}
public bool IsUserInAdGroup(string domain, string username, string adGroupName)
{
bool result = false;
using (var context = new PrincipalContext(ContextType.Domain, domain))
{
var user = UserPrincipal.FindByIdentity(context, username);
if (user != null)
{
var group = GroupPrincipal.FindByIdentity(context, adGroupName);
if (group != null && user.IsMemberOf(group))
result = true;
}
}
return result;
}
Please make sure to reference System.DirectoryServices.AccountManagement.
I need to use the windows credentials to allow my users to log in an intranet application. I am planning to create a table with usernames and roles and compare the username from Environment.UserName with my table. How safe is to relay on this? Is there a better way to achieve this task?
Thank you in advance.
You can do this using active directory authentication:
Bellow is sample code that you can try in your application.
string domainUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
string[] paramsLogin = domainUser.Split('\\');
string domain = paramsLogin[0].ToString();
string LdapPath = "";
string strDomainPath = DomainPath();
LdapPath = string.Format("LDAP://{0}/{1}", DomainName, strDomainPath);
string username = LoginUser.UserName;
string password = LoginUser.Password;
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(LdapPath, domainAndUsername, password);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (result != null)
{
IsLoginSucess = true;
//Do your stuff here
}
// Update the new path to the user in the directory
LdapPath = result.Path;
string _filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
IsLoginSucess = false;
}
If you are developing in a Windows application, take a look at this:
Authenticate user in WinForms (Nothing to do with ASP.Net)
System.Security.Principal.WindowsIdentity.GetCurrent() will give you the current Windows user
If you are developing a Web application, there is built in-support, you would need to have relevant entries in your web.config file
Using windows authentication in asp.net with c#
HttpContext.Current.User.Identity will get you the user identity
I keep getting the error The server could not be contacted. When i'm trying to run my code:
I've searched for a few hours, and i'm still unable contact the server.
DirectorySearcher directorySearcher = new DirectorySearcher();
string path = directorySearcher.SearchRoot.Path;
DirectoryEntry directoryEntry = new DirectoryEntry(path);
PrincipalContext pricipalContext = new PrincipalContext(ContextType.Domain, "LDAP://domain.dk/DC=domain,DC=dk");
//GroupPrincipal group = GroupPrincipal.FindByIdentity(pricipalContext, "(CN=" + department + ")");
GroupPrincipal group = GroupPrincipal.FindByIdentity(pricipalContext, "(CN=" + department + ")");
if (group != null)
{
foreach (Principal principal in group.Members)
{
UserPrincipal tu = principal as UserPrincipal;
DirectoryEntry de = tu.GetUnderlyingObject() as DirectoryEntry;
var store = de.InvokeGet("physicalDeliveryOfficeName").ToString();
var storeNumber = de.InvokeGet("description").ToString();
employees.Add(new AdEmployees() { name = principal.Name, phone = tu.VoiceTelephoneNumber, email = tu.EmailAddress, store = store.ToString(), storeNumber = storeNumber.ToString(), link = GenerateLink(principal.Name) });
}
}
Note: I changed my domain where the AD is located to domain.
The key statement here seems to be "I changed my domain where the AD is located to domain."
Ensure the application server is pointed to the correct DNS server.
Ensure the client is pointed to the correct DNS server.
This connection string looks wrong: PrincipalContext pricipalContext = new PrincipalContext(ContextType.Domain, "LDAP://domain.dk/DC=domain,DC=dk");
Connection string in #3 might work better like this:
PrincipalContext pricipalContext = new PrincipalContext(ContextType.Domain, "DOMAIN", "DC=domain,DC=dk");
I'm using DirectorySearcher to search for a user entry in LDAP server.
DirectoryEntry de = new DirectoryEntry();
de.Path = "LDAP://myserver/OU=People,O=mycompany";
de.AuthenticationType = AuthenticationTypes.None;
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(uid=" + model.UserName + ")";
SearchResult result = deSearch.FindOne();
I'm able to get th intended output in result variable.
However If I try to authenticate the same user by providing password in directory entry, I always get following error.
"The user name or password is incorrect."
DirectoryEntry entry = new DirectoryEntry("LDAP://myserver/OU=People,O=mycompany", username, password);
DirectorySearcher search = new DirectorySearcher(
entry,
"(uid=" + username + ")",
new string[] { "uid" }
);
search.SearchScope = System.DirectoryServices.SearchScope.Subtree;
SearchResult found = search.FindOne(); ->>>>>this is where I get wrong credential error.
The username and password are for the user I want to authenticate.
Can anyone tell me what I'm doing wrong here or how to debug this.
This username, password within this line:
DirectoryEntry("LDAP://myserver/OU=People,O=mycompany", username, password);
should be for an account that has permission for directory lookup. It could be a service account or testing purpose try with your own. This shouldn't be the user/pass of someone who you are trying to authenticate.
If you want to authenticate, you can use following steps using PrincipalContext:
using(var context = new PrincipalContext(ContextType.Domain, "mydomain", "mydomain\serviceAcct", "serviceAcctPass")) {
//Username and password for authentication.
return context.ValidateCredentials(username, password);
}
"serviceAcct" = an account within domain users that has permission for directory lookup.
"serviceAcctPass" = password for that service account.
As I said, for testing you can try with your own user/pass context.
Also, make sure supplied username has either "domain\username" or "username#domain" formatting.
Here we are getting the active directory user details and we can use DomainName and UserRole from web.config file
bool isAdmin = false;
RegisterInput model = new RegisterInput();
NewUserInput usr = new NewUserInput();
SearchResultCollection results;
string mobileNumber = string.Empty;
using (DirectoryEntry domainEntry = new DirectoryEntry("LDAP://" + AppSettings.DomainName))
{
using (DirectorySearcher searcher = new DirectorySearcher(domainEntry, "userPrincipalName=" + userName + "#" + AppSettings.DomainName) { Filter = string.Format("(&(objectClass=user)(samaccountname={0}))", userName) })
{
results = searcher.FindAll();
if (results.Count > 0)
{
usr.FirstName = results[0].GetDirectoryEntry().Properties["givenName"].Value.ToString();
usr.LastName = results[0].GetDirectoryEntry().Properties["sn"].Value?.ToString();
usr.EmailAddress = results[0].GetDirectoryEntry().Properties["mail"].Value?.ToString();
mobileNumber = results[0].GetDirectoryEntry().Properties["mobile"]?.Value?.ToString();
dynamic userRoleList = results[0].GetDirectoryEntry().Properties["memberOf"];
if (userRoleList != null)
{
foreach (var role in userRoleList)
{
string[] split = role.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
bool result = split.Any(x => x.ToLowerInvariant() == AppSettings.UserRole.ToLowerInvariant());
if (result)
{
isAdmin = true;
break;
}
}
}
}
}
}
model.NewUser = usr;