I am using Active Directory to authenticate a user logging into an ASP.NET web site on a corporate intranet. I am getting an error of "handle is invalid" on the following line of code:
Dim entry As DirectoryEntry = New DirectoryEntry(path, domainAndUsername, Password)
Here is my code I am using to authenticate.
Dim entry As DirectoryEntry = New DirectoryEntry(path, domainAndUsername, Password)
Try
'Bind to the native AdsObject to force authentication.
Dim obj As Object = entry.NativeObject
Dim search As DirectorySearcher = New DirectorySearcher(entry)
search.Filter = "(SAMAccountName=" & Username & ")"
search.PropertiesToLoad.Add("cn")
Dim result As SearchResult = search.FindOne()
If (result Is Nothing) Then
Return False
End If
'Update the new path to the user in the directory.
'_path = result.Path
'_filterAttribute = CType(result.Properties("cn")(0), String)
Catch ex As Exception
Throw New Exception("Error authenticating user. " & ex.Message)
End Try
How do I track down this exception? Visual Studio says it is a CryptographicException
Thanks
Assuming you are on .NET 3.5.... and thinking the code translates well to VB you could use built-in method.
public bool isValidUser(string password,string username,string domain)
{
var isValid = false;
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
{
isValid = pc.ValidateCredentials(username, password);
}
return isValid;
}
I know it does not answer question as such, but could avoid getting the exception in the first place
Related
I have a login form that checks for roles and when the credentials are met, the user is directed to a specific page. My issue is that when the username or password is incorrect, my logic fails to prompt the user via a label that I have in the design. I even tried implementing it via a Try/Catch and still the same result.
The Design:
<div><asp:Label ID="lblinfo" runat="server" Width="374px" CssClass="blktext"></asp:Label></div>
The code in behind the (button event-handler):
Try
Dim con As New SqlConnection(GetConnectionString())
con.Open()
Dim cmd As New SqlCommand("Check_Users", con)
cmd.CommandType = CommandType.StoredProcedure
Dim p1 As New SqlParameter("Login_name", username.Text)
Dim p2 As New SqlParameter("Login_Pwd", password.Text)
cmd.Parameters.Add(p1)
cmd.Parameters.Add(p2)
Dim rd As SqlDataReader = cmd.ExecuteReader()
'check the Role of the user logging in'
While (rd.Read())
Session("numrecord") = rd.GetValue(0).ToString()
rd.GetValue(11).ToString()
If rd.HasRows Then
If rd.GetValue(11).ToString() = 1 Then
rd.Read()
lblinfo.Text = "You are Authorized."
FormsAuthentication.RedirectFromLoginPage(username.Text, True)
Response.Redirect("securepages/SecurePage.aspx")
Else
lblprompt.Text = "Invalid username or password."
End If
If rd.GetValue(11).ToString() = 2 Then
rd.Read()
FormsAuthentication.RedirectFromLoginPage(username.Text, True)
Response.Redirect("securepages/newShipment.aspx")
Else
lblprompt.Text = "Invalid username or password."
End If
End If
End While
Catch ex As Exception
lblprompt.Text = "Invalid username or password."
End Try
Could I get some help as to what am failing to do here?
At the very least, please write a basic POCO object to encapsulate the values from the data layer.
Use your datareader to POPULATE the Poco object, and insert some basic logic on the Poco object.
Use the datareader quickly, then get rid of it.
Then you could actually reuse the object and your logic.
Something like this.
Then (in the presentation layer) ~respond to the values in the Poco with the redirects and such.
public enum RedirectTypeEnum
{
Unknown = 0,
SecurePage = 1,
NewShipment = 2,
}
public class LoginAttemptResult
{
public LoginAttemptResult()
{
this.NumRecord = 0;
this.ResultNumberAkaColumn11 = 0;
}
public int NumRecord { get; set; }
public int ResultNumberAkaColumn11 { get; set; }
public RedirectTypeEnum RedirectType
{
get
{
RedirectTypeEnum returnValue = RedirectTypeEnum.Unknown;
if (this.ResultNumberAkaColumn11 == 1)
{
returnValue = RedirectTypeEnum.SecurePage;
}
if (this.ResultNumberAkaColumn11 == 2)
{
returnValue = RedirectTypeEnum.NewShipment;
}
return returnValue;
}
}
public bool IsAuthorized
{
get
{
if (this.ResultNumberAkaColumn11 == 1)
{
return true;
}
if (this.ResultNumberAkaColumn11 == 2)
{
return false; /* ?? */
}
return false;
}
}
}
Then you'll have one place where you populate this object, and someone can see clearly what the biz logic is by looking at the POCO object.
One issue that I see is that you are response.redirect'ing in a Try...Catch block. Unless you put , False (which allows the code to finish executing instead of aborting) after the URL, you will throw a Thread is aborting error every time it attempts to redirect.
As for the message not showing, you show how lblinfo is created, but what about lblprompt? Perhaps you have its visible property set to false? If this is the case, make sure to change it to true in the code. Also, make sure you are not clearing its value on events such as page_load.
I have also cleaned up the code a little bit and implemented a datatable object instead of the reader:
Try
Dim cmd As New SqlCommand("Check_Users", New SqlConnection(GetConnectionString()))
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(New SqlParameter("Login_name", username.Text))
cmd.Parameters.Add(New SqlParameter("Login_Pwd", password.Text))
Dim sqlDataAdapter As New SqlClient.SqlDataAdapter(cmd)
Dim dtResults As New DataTable
sqlDataAdapter.Fill(dtResults)
lblprompt.Text = "Invalid username or password."
'check the Role of the user logging in'
If dtResults.Rows.Count > 0 Then
With dtResults.Rows(0)
Session("numrecord") = .Item(0).ToString()
If .Item(11).ToString() = 1 Then
lblprompt.Text = ""
FormsAuthentication.RedirectFromLoginPage(username.Text, True)
Response.Redirect("securepages/SecurePage.aspx", False)
ElseIf .Item(11).ToString() = 2 Then
lblprompt.Text = ""
FormsAuthentication.RedirectFromLoginPage(username.Text, True)
Response.Redirect("securepages/newShipment.aspx", False)
End If
End With
End If
Catch ex As Exception
lblprompt.Text = "An error has occurred." & ex.Message
End Try
All --
I am able to retieve the FullName value
I am trying to retrieve an email address from Active Directory but using the following code in my ASP.Net Web Forms project that is using Windows Authentication:
Dim wi As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
Dim a As String() = wi.Name.Split(New Char() {"\"c}) '' Context.User.Identity.Name.Split('\')
Dim ADEntry As System.DirectoryServices.DirectoryEntry = New System.DirectoryServices.DirectoryEntry(Convert.ToString("WinNT://" + a(0) + "/" + a(1)))
Dim Name As String = ADEntry.Properties("FullName").Value.ToString()
Dim Email As String = ADEntry.Properties("mail").Value.ToString()
when I get to the line of code where I'm try to retrieve the email address I get an "Object reference not set to an instance of an object." error. I have tried using EmailAddress, E-Mail. I think the problem is that I am simply using the wrong keyword. I am able to retrieve the FullName value.
Thanks to Davide Piras who send me this link, I found a suitable solution:
Dim wi As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
Dim a As String() = wi.Name.Split(New Char() {"\"c}) '' Context.User.Identity.Name.Split('\')
Dim dc As PrincipalContext = New PrincipalContext(ContextType.Domain, "DomainName")
Dim adUser As UserPrincipal = UserPrincipal.FindByIdentity(dc, a(1))
Dim Email As String = adUser.EmailAddress
This code works for me..
Reference to System.DirectoryServices.AccountManagement
static string GetADUserEmailAddress(string username)
{
using (var pctx = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal up = UserPrincipal.FindByIdentity(pctx, username))
{
return up != null && !String.IsNullOrEmpty(up.EmailAddress) ? up.EmailAddress : string.Empty;
}
}
}
to use it:
lblEmail.Text = GetADUserEmailAddress(Request.ServerVariables["AUTH_USER"]);
I got the following error
{"The specified domain either does not exist or could not be
contacted. "}
at the line
Dim adResults = adSearch.FindOne.Path
Can anyone suggest why it is ? Seeing the below code
Dim ID As FormsIdentity = DirectCast(User.Identity, FormsIdentity)
Dim ticket As FormsAuthenticationTicket = ID.Ticket
Dim adTicketID As String = ticket.Name
Dim adSearch As New DirectorySearcher
adSearch.Filter = ("(userPrincipalName=" & adTicketID & ")")
Dim adResults = adSearch.FindOne.Path
Dim adResultsDirectory As New DirectoryEntry(adResults)
Dim found As Boolean = False
For Each entry In adResultsDirectory.Properties("memberOf")
Response.Write(entry)
Response.Write("<br/>")
If entry = "CN=GroupName,CN=UserGroup,DC=my,DC=domain,DC=com" Then
found = True
End If
Next
If Not (found) Then
Response.Redirect("login.aspx")
End If
Where is your domain specified?
First parameter for DirectoryEntry should be your AD server, something like this: LDAP://adserver.
Here is the code that I am using for checking whether user is authenticated in AD:
Dim dsDirectoryEntry As New DirectoryEntry("LDAP://" & domain, userName, password)
Dim dsSearch As New DirectorySearcher(dsDirectoryEntry)
Dim dsResults As SearchResult = dsSearch.FindOne()
If dsResults IsNot Nothing Then
Return True
Else
Return False
End If
Domain I am reading from configuration, userName and password are from login form input.
I am trying to convert the calendar code of C#.NET provided on google site to VB.NET and facing some conversion issues. Please help me.
Code in C#.net:
static void RetrieveAcls(CalendarService service)
{
FeedQuery query = new FeedQuery();
query.Uri = new Uri("http://www.google.com/calendar/feeds/testingforfinals#gmail.com");
AtomFeed calFeed = service.Query(query);
Console.WriteLine();
Console.WriteLine("Sharing permissions for your calendars:");
// Retrieve the meta-feed of all calendars.
foreach (AtomEntry calendarEntry in calFeed.Entries)
{
Console.WriteLine("Calendar: {0}", calendarEntry.Title.Text);
AtomLink link = calendarEntry.Links.FindService(
AclNameTable.LINK_REL_ACCESS_CONTROL_LIST, null);
// For each calendar, retrieve its ACL feed.
if (link != null)
{
AclFeed feed = service.Query(new AclQuery(link.HRef.ToString()));
foreach (AclEntry aclEntry in feed.Entries)
{
Console.WriteLine("\tScope: Type={0} ({1})", aclEntry.Scope.Type,
aclEntry.Scope.Value);
Console.WriteLine("\tRole: {0}", aclEntry.Role.Value);
}
}
}
}
My code in VB.NET:
Public Sub RetrieveAcls(ByVal service As CalendarService)
Dim query As New FeedQuery
query.Uri = New Uri("http://www.google.com/calendar/feeds/testingforfinals#gmail.com")
Dim calFeed As New AtomFeed(service.Query(query))
Console.WriteLine()
Console.WriteLine("Sharing permissions for your calendars:")
Dim calendarEntry As New AtomEntry
Dim link As New AtomLink
Dim aclEntry As New AclEntry
For Each calendarEntry In calFeed.Entries
Console.WriteLine("Calendar: {0}", calendarEntry.Title.Text)
link = calendarEntry.Links.FindService(AclNameTable.LINK_REL_ACCESS_CONTROL_LIST, "")
If (link Is Nothing) Then
Dim feed As AclFeed()
feed = New AclFeed(query, service)
feed = service.Query(New AclQuery(link.HRef.ToString()))
For Each aclEntry In feed.Entries
Console.WriteLine("\tScope: Type={0} ({1})", aclEntry.Scope.Type, aclEntry.Scope.Value)
Console.WriteLine("\tRole: {0}", aclEntry.Role.Value)
Next
End If
Next
End Sub
Am facing error at "query" in "feed = New AclFeed(query, service)" which says Value of type Google.GData.Client.FeedQuery cannot be converted to 'System.Uri'... This issue is resolved... One more last issue is as per below...
Dim myQuery As New EventQuery(feedURI)
Dim myResultsFeed As New EventFeed(service.Query(myQuery))
I am getting error on "myResultsFeed" as "Argument not specified for parameter 'iService' of 'Public Sub New(uriBase As System.Uri, iService As Google.GData.Client.IService)'." and another error on "service.Query(myQuery)) as "Value of type 'Google.GData.Calendar.EventFeed' cannot be converted to 'System.Uri'."
static void DateRangeQuery(CalendarService service, DateTime startTime, DateTime endTime)
{
EventQuery myQuery = new EventQuery(feedUri);
myQuery.StartTime = startTime;
myQuery.EndTime = endTime;
EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;
Console.WriteLine("Matching events from {0} to {1}:",
startTime.ToShortDateString(),
endTime.ToShortDateString());
Console.WriteLine();
for (int i = 0; i < myResultsFeed.Entries.Count; i++)
{
Console.WriteLine(myResultsFeed.Entries[i].Title.Text);
}
Console.WriteLine();
}
Well you've converted this:
AclFeed feed = service.Query(new AclQuery(link.HRef.ToString()));
to this:
Dim feed As AclFeed()
feed = New AclFeed(query, service)
feed = service.Query(New AclQuery(link.HRef.ToString()))
They're not the same at all! Your second line is calling a constructor for no obvious reason.
Just this would be fine:
Dim feed As AclFeed = service.Query(New AclQuery(link.HRef.ToString()))
It's also not clear why you've got lines like this:
Dim calendarEntry As New AtomEntry
Why are you calling the parameterless constructor for AtomEntry? Why are you declaring the variable outside the ForEach loop at all? Just use:
For Each calendarEntry As AtomEntry In calFeed.Entries
EDIT: For the other issue, I think you just need:
Dim myEventFeed As CType(service.Query(myQuery), EventFeed)
If you could provide the full method, that would help.
I'm not sure if it works, but this is the direct c#->VB.Net-Translation from developerfusion, the syntax seems to be correct. Only as a hint for your next problems ;)
Shared Sub RetrieveAcls(ByVal service As CalendarService)
Dim query As New FeedQuery()
query.Uri = New Uri("http://www.google.com/calendar/feeds/testingforfinals#gmail.com")
Dim calFeed As AtomFeed = service.Query(query)
Console.WriteLine()
Console.WriteLine("Sharing permissions for your calendars:")
' Retrieve the meta-feed of all calendars.
For Each calendarEntry As AtomEntry In calFeed.Entries
Console.WriteLine("Calendar: {0}", calendarEntry.Title.Text)
Dim link As AtomLink = calendarEntry.Links.FindService(AclNameTable.LINK_REL_ACCESS_CONTROL_LIST, Nothing)
' For each calendar, retrieve its ACL feed.
If Not link Is Nothing Then
Dim feed As AclFeed = service.Query(New AclQuery(link.HRef.ToString()))
For Each aclEntry As AclEntry In feed.Entries
Console.WriteLine(vbTab & "Scope: Type={0} ({1})", aclEntry.Scope.Type, aclEntry.Scope.Value)
Console.WriteLine(vbTab & "Role: {0}", aclEntry.Role.Value)
Next
End If
Next
End Sub
I am using Windows Authentication in asp.net every thing is ok in local but when deploying on different system of same domain then its working getting error in this line SearchResult userObject = adSearcher.FindOne();
Error
system.runtime.interopservice.comException
My code is
WindowsIdentity winId = id as WindowsIdentity;
if (id == null)
{
Console.WriteLine("Identity is not a windows identity");
return;
}
string userInQuestion = winId.Name.Split('\\')[1];
string myDomain = winId.Name.Split('\\')[0];
DirectoryEntry entry = new DirectoryEntry("LDAP://" + myDomain);
DirectorySearcher adSearcher = new DirectorySearcher(entry);
adSearcher.SearchScope = SearchScope.Subtree;
adSearcher.Filter = "(&(objectClass=user)(samaccountname=" + userInQuestion + "))";
SearchResult userObject = adSearcher.FindOne();
StringBuilder data =new StringBuilder();
Error page:
link text
From your error page, it's failing on the directory Bind. Does the app pool on the new machine have authority to query AD?
Dim Connection As New ADODB.Connection
Connection.Open(ConnectionString)
Dim Insname As String
Dim postname As String