I'm struggling to return user details from AD using LDAP, after i have authenticated that the user exists.
I am using a simple auth method as follows:
Function AuthenticateUser(path As String, user As String, pass As String) As Boolean
Dim de As New DirectoryEntry(path, user, pass, AuthenticationTypes.Secure)
Try
Dim ds As DirectorySearcher = New DirectorySearcher(de)
Dim result As SearchResult = ds.FindOne()
If result Is Nothing Then Return False
'>>DEBUG OUTPUTS ONLY:
displayName.Text = result.GetDirectoryEntry().Properties.Item("distinguishedName").Value
displayName.Text += result.GetDirectoryEntry().Properties("name").Value
Return True
Catch
Return False
End Try
End Function
the problem is that "distinguishedName" returns "DC=our-domain,DC=co,DC=uk"
and "name" returns just "our-domain", not the name of the user that has just been auth'ed
Note: the displayName.text outputs are purely for debug purposes
I have tried various combos of requests but nothing seems to return USER details.
ETA: to the security police: this is all within a https connection, I'm not sending passwords about in plain text!
1. Dim de As New DirectoryEntry(path, user, pass, AuthenticationTypes.Secure)
2. Try
3. Dim ds As DirectorySearcher = New DirectorySearcher(de)
4. Dim result As SearchResult = ds.FindOne()
Line 1 is basically creating a DirectoryEntry element, that refers to the object at path. The only purpose that the username and password parameters serve is to authorise access to whatever entity path refers to.
As you currently have things, you're binding to the domain, not to the user (but you're authorised to connect to the domain as that user).
You then, in line 3, create a DirectorySearcher. But the constructor you're using just says to root the search at de (which as we've established, is just the domain). You've not done anything yet to search for that particular user within the domain - they could be connecting to perform almost any kind of search imaginable.
What you might want to do is look at the overload of DirectorySearcher that accepts a filter parameter - and provide a filter parameter that restricts the search to just the user. I don't know what form your user parameter is in - if it is, say, in the form of a user principal name (user#domain), you might try specifying a filter of:
Dim ds As DirectorySearcher = New DirectorySearcher(de,"(userPrincipalName=" + user + ")")
If you have just a username, you'd want to search against sAMAccountName. If you have an older style domain name (domain\user), then usually you want to split that on \, discard the domain name, and still search on sAMAccountName.
Some (but not too much!) help on constructing the filter parameters is found in the Filter property documentation.
Related
Unable to get it to return any results. Compiles fine and does not error when it is run, but the results are always empty.
I have got this working if I restrict it to something like DisplayName or given name. But would like it to work no matter if the user puts in forename or surname first and that the user is not restricted to adhering to the DisplayName format of "Surname, Forename"
Dim searchterm As String = RouteData.Values("Search")
Dim domain As New PrincipalContext(ContextType.Domain, "Domain")
Dim user As New CustomUserPrincipal(domain)
Dim search As New PrincipalSearcher()
Dim results As PrincipalSearchResult(Of Principal)
jss.MaxJsonLength = Integer.MaxValue
user.Anr = String.Format("*{0}*", searchterm)
search.QueryFilter = user
CType(search.GetUnderlyingSearcher, DirectoryServices.DirectorySearcher).SizeLimit = 25
results = search.FindAll()
<DirectoryObjectClass("user")>
<DirectoryRdnPrefix("CN")>
Public Class CustomUserPrincipal
Inherits UserPrincipal
Public Sub New(context As PrincipalContext)
MyBase.New(context)
End Sub
<DirectoryProperty("anr")>
Public Property Anr As String
Get
Return CStr(ExtensionGet("anr")(0))
End Get
Set(value As String)
ExtensionSet("anr", value)
End Set
End Property
End Class
I am expecting an object that I can enumerate through and pull out individual UserPrincipals to extract details. But I only get an empty object
I think this is your problem:
user.Anr = String.Format("*{0}*", searchterm)
Specifically, that you're putting asterisks around your search term. According to the documentation, it will expand a search term like (anr=Smith) to something like this:
(|(displayName=smith*)(givenName=smith*)(legacyExchangeDN=smith)(physicalDeliveryOfficeName=smith*)(proxyAddresses=smith*)(Name=smith*)(sAMAccountName=smith*)(sn=smith*))
Notice that it already does a "starts with" type search. Putting your own wildcards in there messes it up.
More specifically, it's the asterisk at the beginning. I tested this in our own AD environment. If I search for (anr=*Gabriel*) or (anr=*Gabriel), I get no results. If I search for (anr=Gabriel*) I get results, but it really has no effect on the results (the results are the same as if I had searched for (anr=Gabriel)).
The solution is to change that line to this:
user.Anr = searchterm
It is not exactly equivalent to the "contains" search you seem to want, but putting a wildcard at the beginning of any search really kills performance anyway. It can no longer use any indexes to complete the search, so it's forced to look at every user account in your domain.
I am trying to query Active directory for a user to get a list of details:
1. First/Last Name
2. Email
3. UserName
4. Domain
I am able to get all except for the domain name. Here is my code:
Dim oroot As DirectoryEntry = New DirectoryEntry("GC://ldap.someCompany.com")
Dim osearcher As DirectorySearcher = New DirectorySearcher(oroot)
Dim result As SearchResult
osearcher.Filter = String.Format("(&(SAMAccountName={0}))", "myUsername")
osearcher.PropertiesToLoad.Add("cn")
osearcher.PropertiesToLoad.Add("SAMAccountName") 'Users login name
osearcher.PropertiesToLoad.Add("givenName") 'Users first name
osearcher.PropertiesToLoad.Add("sn") 'Users sur name
osearcher.PropertiesToLoad.Add("mail") 'Email address
result = osearcher.FindOne
Try
myUser.UserID = result.Properties("cn").Item(0)
myUser.Domain = ""
myUser.EmailAddress = result.Properties("mail").Item(0)
myUser.FirstName = result.Properties("givenName").Item(0)
myUser.LastName = result.Properties("sn").Item(0)
myUser.Domain = result.Properties("displayName").Item(0)
Catch ex As Exception
Return Nothing
End Try
This returns this string: GC://ldap.someCompany.com/CN=FirstName M LastName,OU=Employees,OU=Domain Users,DC=val1,DC=val2,DC=com
So, I have two questions. First, how do I get the domain name of the user? It appears to be in DC= (where I have val1)
Second, is there anyway to speed this search up? Right now, it takes about 10 seconds to run the query.
I am using .net 4.0 and Visual Studio 2010
Thanks for any help
jason
Strart from right and read the DC components, then you have the realm/domain of the account. See RFC2247.
I'm trying to validate a list of email addresses using the following code:
Public Function ValidateEmailAddressField() As Boolean
Dim isValid As Boolean = True
Try
txtServiceEmails.Text = txtServiceEmails.Text.Trim.Replace(",", ";")
Dim validateMailAddress = New MailAddress(txtServiceEmails.Text.Trim)
Return isValid
Catch ex As Exception
isValid = False
Return isValid
End Try
End Function
When I enter "johndoe#amce" or "johndoe#acme, janedoe#acme.org" the code validates true. Is entering an email address without an extension, such as ".com", actually considered a valid email address?
Thanks,
crjunk
In an cooperation environment, a domain does not have to have .com/net/org... 'acme' could be a valid domain, so, the email me#acme could be a valid email address internally.
usually, people use regular expression to valid email address. there are lots of examples.
Yes, it is valid. The domain part of email address must match the requirements for a hostname and depending of local configurations the "extension" may be optative.
A hostname is considered to be a fully qualified domain name (FQDN) if all the labels up to and including the top-level domain name (TLD) are specified. The hostname en.wikipedia.org terminates with the top-level domain org and is thus fully qualified. Depending on the operating system DNS software implementation, an unqualified hostname such as csail or wikipedia may be automatically combined with default domain names configured into the system, in order to determine the fully qualified domain name. As an example, a student at MIT may be able to send mail to "joe#csail" and have it automatically qualified by the mail system to be sent to joe#csail.mit.edu.
Source: Wikipedia
Settled for a Regular Expression Validator solution.
Public Function ValidateEmailAddressField() As Boolean
Dim isValid As Boolean = True
Dim emailExpression As New Regex("^((\s*[a-zA-Z0-9\._%-]+#[a-zA-Z0-9\.-]+\.[a-zA-Z]{2,4}\s*[,;:]){1,100}?)?(\s*[a-zA-Z0-9\._%-]+#[a-zA-Z0-9\.-]+\.[a-zA-Z]{2,4})*$")
Try
txtServiceEmails.Text = txtServiceEmails.Text.Trim.Replace(",", ";")
txtServiceEmails.Text = txtServiceEmails.Text.Trim.Replace(" ", "")
isValid = emailExpression.IsMatch(txtServiceEmails.Text.Trim)
Return isValid
Catch ex As Exception
isValid = False
Return isValid
End Try
End Function
So I managed to get some code rolling for updating the AD from an external sourced. However, I'm a bit confused about how it works.
I have a person with sAMAccount xxxx existing in different OUs.
Now, I only want to update the info in a specific OU, so I put that in my LDAP path. Still, it seem that the info has been updated in different OU's as well?
Could that be possible? Is it because there's only one "Person" object, or do the "GetDirectoryEntry()" not put me where I thought in the tree? Or.. am I only imagine and the weird things I see is becausde of something else.
Some code
DirectoryEntry entry = new DirectoryEntry(LDAP://my.path/ou=myou, dc=my, dc=path);
entry.Username = myUser
entry.Password = myPass
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = #"(&(objectClass=Person)(SamAccountname=" + person.id + "))";
SearchResult result = searcher.FindOne();
try
{
DirectoryEntry user = result.GetDirectoryEntry();
user.Properties["displayName"].Value = person.DisplayName;
user.Properties["givenName"].Value = person.Firstname;
user.CommitChanges();
user.Close();
}
catch (DirectoryServicesCOMException ex)
EDIT: It did update the Person object in all the OU's. So either the Person object is one and the same in the whole AD, whick makes my attempt to update them in only the specific OU pointless, or does the "result.GetDirectoryEntry" ignore the fact that I thought I was working only in my specific OU declared in my LDAP path.
Functionality confirmed, still wonder why I needed a specific test-ou since it's still the same users. Anyway, here we go!
i'm new to ASP.NET,so plz b patient :D
i want to redirect one of my pages to the other one,and i keep the username!
i tried to use session.add and session[],but when i want to insert the username inside the brackets,it says use must int!!!but i thought i should use session["username"]
i used another way(request.querystring[]),but both have problems
here is my code
//first solution
string username="asal";
session.Add(username,username);
Response.Redirect("~/Doctor/DoctorsMainPage.aspx");
//in the other page
Label1.Text= Session["username"].ToString();//this one says use int?!
//i used this one instead of it
Label1.Text= Session[0].ToString();//with this one i get the username in other page,but one i want to pass another string like "id" with session,I can not!
//the second solution
string username="asal";
Response.Redirect("~/Doctor/DoctorsMainPage.aspx?username");
Label1.Text = Request.QueryString["username"];//this one redirect to doctors main page but set the value of username to "" !
session.Add(string, string) where the first string is the name of the variable and the second is the value.
You are adding the value twice.
//first solution
string username="asal";
session.Add("username",username); <-- this is your problem
Response.Redirect("~/Doctor/DoctorsMainPage.aspx");
//in the other page
Label1.Text= Session["username"].ToString();
Now, as for
//the second solution
string username="asal";
Response.Redirect("~/Doctor/DoctorsMainPage.aspx?username");
Label1.Text = Request.QueryString["username"];//this one redirect to doctors main page but set the value of username to "" !
In this case you're creating a url "~/Doctor/DoctorsMainPage.aspx?username"
Ok - so what is username? The code is looking for a param in the query string named username but it's not finding a value.
You need:
Response.Redirect("~/Doctor/DoctorsMainPage.aspx?username="+username);
That will give you "~/Doctor/DoctorsMainPage.aspx?username=asal"
string username = "asal";
Session["username"] = username;
Response.Redirect("~/Doctor/DoctorsMainPage.aspx");
//Other page
Label1.Text = Session["username"].ToString().Trim();
You have to add the session like..
session.Add("username",username); instead session.Add(username,username);
And then you can access the value like..Label1.Text= (String)Session["username"];
Check out this article related to the session State ASP.NET Session State Overview that will help you to understand Session State management.
Seconly querystring should be like, as you have not passing your string parameter and it should be like...
Response.Redirect("~/Doctor/DoctorsMainPage.aspx?username=" + username);