| Author | Messages | |
DavidCliffe
Posts:15
 | | 04/16/2007 2:53 AM |
| Hi,
We have a developer under contract
here who has written an app [.NET 2.0] which uses a website form [IIS 6] to get
input from users as to theirAD credentials. I don't have most of the
code being used presently, but I'll try to explain to the best of my limited
knowlege to see if anyone might recognize something simple we're missing.
The solution only partially works.
After geting the domain name,
username/password input, the app issues an LDAP query to try and find the
user. This isa single forest with a few child domains. If the
end user's account is a member of the same domain as the IIS web server, the
application continues and all works well. If the user is in any other
domain, the authentication fails. If the hostname of a DC is hardcoded
somewhere in the app (perhaps in the bind? I'm not sure...just stating
this as second hand info), then authentication is successful from any domain
(but this is not desired).
In IIS, the application pool in
question is running under Network Service (we've tried Local System as a
test). In the "authentication methods" dialog box of the website,
we'veenabled Anonymous Access (the goal is not to use integrated
Windows auth for this); nothing elsehas beenticked. In
Web.Config,authentication mode has been set to "Forms" and I believe the
rest of that file is notcustomized(maybe it's not even used in this
situation anyway?). The website does not run on port
80.
As for AD -againnot
sure if this is evenneeded without integrated authentication,
butIenabled delegation on the IIS server's computer object, and I've
created two SPNs for HTTP on that server [and FQDN] at the port where the
webserver is running. I can always turn these off
again.
So not being much of an IIS guy, and
certainly not a .NET guy (and lately wondering how much of an AD guy
:-D ) .... I'm a bit stumped. I took a network trace at
the IIS server during attempted authentication of a user outside IIS server's
domain. The only LDAP query issued by the IIS[looking for that user]
specified a base DN of only its own domain to the LDAP port of a nearby
DC. I couldn't see any other queries and notably nothing going to a GC
(the aforementioned DC does run a GC as well).
This is what the bind function looks
like in the code:
Public
Function Bind() As Boolean Dim
sRet As String = String.Empty Dim
de As DirectoryEntry de = New
DirectoryEntry(Nothing, msDomain + "\" + msUserName,
msPassword)
Try Dim o
As Object =
de.NativeObject
Dim ds As DirectorySearcher = New
DirectorySearcher(de)
ds.Filter = "samaccountname=" +
msUserName
ds.PropertiesToLoad.Add("cn")
Dim sr As SearchResult =
ds.FindOne
If sr Is Nothing
Then
Throw New
Exception
End If
Return True
Catch
Return False End
Try End Function
Are we doing this properly?
Sorry if not enough info. or codeat present - will work on that if need
be.
Thanks,
DaveC This email was sent to you by Reuters, the global news and information company.
To find out more about Reuters visit www.about.reuters.com
Any views expressed in this message are those of the individual sender,
except where the sender specifically states them to be the views of Reuters Limited.
Reuters Limited is part of the Reuters Group of companies, of which Reuters Group PLC is the ultimate parent company.
Reuters Group PLC - Registered office address: The Reuters Building, South Colonnade, Canary Wharf, London E14 5EP, United Kingdom
Registered No: 3296375
Registered in England and Wales | | | |
| bdesmond
Posts:996
 | | 04/16/2007 2:59 AM |
| Joe K will probably chime in being the man on this, but imo that
code is really crappy.
è Filter
is poorly written
è Exception
tells you nothing
AFAIK you can’t specify a null value for the base here though I may
be wrong. Why don’t you just bind to GC: if you’re looking to hit the global
catalog?
Thanks,
Brian Desmond
brian@briandesmond.com
c - 312.731.3132
From:
ActiveDir-owner@mail.activedir.org [mailto:ActiveDir-owner@mail.activedir.org] On
Behalf Of David Cliffe
Sent: Monday, April 16, 2007 2:53 PM
To: ActiveDir@mail.activedir.org
Subject: [ActiveDir] [OT] Problem with .NET 2.0 code or IIS 6.0 or AD or
??
Hi,
We have a developer under contract here who has written an app [.NET 2.0] which
uses a website form [IIS 6] to get input from users as to theirAD
credentials. I don't have most of the code being used presently, but I'll
try to explain to the best of my limited knowlege to see if anyone might
recognize something simple we're missing. The solution only partially
works.
After geting the domain name, username/password input, the app issues an
LDAP query to try and find the user. This isa single forest with a
few child domains. If the end user's account is a member of the same
domain as the IIS web server, the application continues and all works
well. If the user is in any other domain, the authentication fails.
If the hostname of a DC is hardcoded somewhere in the app (perhaps in the
bind? I'm not sure...just stating this as second hand info), then
authentication is successful from any domain (but this is not desired).
In IIS, the application pool in question is running under Network Service
(we've tried Local System as a test). In the "authentication
methods" dialog box of the website, we'veenabled Anonymous
Access (the goal is not to use integrated Windows auth for this); nothing
elsehas beenticked. In Web.Config,authentication mode
has been set to "Forms" and I believe the rest of that file is
notcustomized(maybe it's not even used in this situation
anyway?). The website does not run on port 80.
As
for AD -againnot sure if this is evenneeded without
integrated authentication, butIenabled delegation on the IIS
server's computer object, and I've created two SPNs for HTTP on that server
[and FQDN] at the port where the webserver is running. I can always turn
these off again.
So not being much of an IIS guy, and certainly not a .NET guy (and lately
wondering how much of an AD guy :-D
) .... I'm a bit stumped. I took a network trace at the IIS server during
attempted authentication of a user outside IIS server's domain. The only
LDAP query issued by the IIS[looking for that user] specified a base DN
of only its own domain to the LDAP port of a nearby DC. I couldn't see
any other queries and notably nothing going to a GC (the aforementioned DC does
run a GC as well).
This is what the bind function looks like in the code:
Public
Function Bind() As Boolean
Dim sRet As String = String.Empty
Dim de As DirectoryEntry
de = New DirectoryEntry(Nothing,
msDomain + "\" + msUserName, msPassword)
Try
Dim o As
Object = de.NativeObject
Dim ds As DirectorySearcher
= New DirectorySearcher(de)
ds.Filter =
"samaccountname=" + msUserName
ds.PropertiesToLoad.Add("cn")
Dim sr As
SearchResult = ds.FindOne
If sr Is
Nothing Then
Throw New Exception
End If
Return True
Catch
Return False
End Try
End Function
Are we doing this properly? Sorry if not enough info. or codeat
present - will work on that if need be.
Thanks,
DaveC
This email was sent to you by Reuters, the global news and information company.
To find out more about Reuters visit www.about.reuters.com
Any views expressed in this message are those of the individual sender,
except where the sender specifically states them to be the views of Reuters
Limited.
Reuters Limited is part of the Reuters Group of companies, of which Reuters
Group PLC is the ultimate parent company. Reuters Group PLC - Registered office
address: The Reuters Building, South Colonnade, Canary Wharf, London E14 5EP,
United Kingdom
Registered No: 3296375
Registered in England and Wales | | | |
| dunnry
Posts:0
 | | 04/16/2007 4:54 AM |
| The issue is with the constructor of the DirectoryEntry. By
specifying "Nothing" as the first parameter, it will try a
"defaultNamingContext" bind in the IIS server's domain. This explains
why only those people are found.
To fix this code, you would need to collect the domain from the user
and put it into the binding path of the DirectoryEntry. This would
then be used as the root for a search.
If you want to fix this right, you will dynamically search the
domain(s) by using the domain from the user credentials. You will
also update this code to not use the user's credentials for the
search. Use a trusted subsystem model instead. Once you find the
user, then check the authentication. Remember that the user could be
locked out, disabled, or otherwise not allowed to search.
Finally, you can download our code from
http://directoryprogramming.net (check the Files section and download
the samples in your language flavor). The code you want is in Ch. 12.
The short story is that anything that uses the DirectoryEntry for
authentication purposes is probably not a great idea in ASP.NET. Bad
things(tm) tend to happen. Use FCB or SSPI binding instead (see the
samples).
On 4/16/07, David Cliffe wrote:
> > > Hi,
> > We have a developer under contract here who has written an app [.NET
> 2.0] which uses a website form [IIS 6] to get input from users as to their
> AD credentials. I don't have most of the code being used presently, but
> I'll try to explain to the best of my limited knowlege to see if anyone
> might recognize something simple we're missing. The solution only partially
> works.
> > After geting the domain name, username /password input, the app issues
> an LDAP query to try and find the user. This is a single forest with a few
> child domains. If the end user's account is a member of the same domain as
> the IIS web server, the application continues and all works well. If the
> user is in any other domain, the authentication fails. If the hostname of a
> DC is hardcoded somewhere in the app (perhaps in the bind? I'm not
> sure...just stating this as second hand info), then authentication is
> successful from any domain (but this is not desired).
> > In IIS, the application pool in question is running under Network
> Service (we've tried Local System as a test). In the "authentication
> methods" dialog box of the website, we've enabled Anonymous Access (the
> goal is not to use integrated Windows auth for this); nothing else has been
> ticked. In Web.Config, authentication mode has been set to "Forms" and I
> believe the rest of that file is not customized (maybe it's not even used in
> this situation anyway?). The website does not run on port 80.
> > As for AD - again not sure if this is even needed without integrated
> authentication, but I enabled delegation on the IIS server's computer
> object, and I've created two SPNs for HTTP on that server [and FQDN] at the
> port where the webserver is running. I can always turn these off again.
> > So not being much of an IIS guy, and certainly not a .NET guy (and
> lately wondering how much of an AD guy :-D ) .... I'm a bit stumped. I
> took a network trace at the IIS server during attempted authentication of a
> user outside IIS server's domain. The only LDAP query issued by the IIS
> [looking for that user] specified a base DN of only its own domain to the
> LDAP port of a nearby DC. I couldn't see any other queries and notably
> nothing going to a GC (the aforementioned DC does run a GC as well).
> > This is what the bind function looks like in the code:
> > Public Function Bind() As Boolean
> Dim sRet As String = String.Empty
> Dim de As DirectoryEntry
> de = New DirectoryEntry(Nothing, msDomain + "\" + msUserName,
> msPassword)
> Try
> Dim o As Object = de.NativeObject
> Dim ds As DirectorySearcher = New DirectorySearcher(de)
> ds.Filter = "samaccountname=" + msUserName
> ds.PropertiesToLoad.Add("cn")
> Dim sr As SearchResult = ds.FindOne
> If sr Is Nothing Then
> Throw New Exception
> End If
> Return True
> Catch
> Return False
> End Try
> End Function
> > Are we doing this properly? Sorry if not enough info. or code at
> present - will work on that if need be.
> > Thanks,
> DaveC
> This email was sent to you by Reuters, the global news and information
> company.
> To find out more about Reuters visit www.about.reuters.com
> > Any views expressed in this message are those of the individual sender,
> except where the sender specifically states them to be the views of Reuters
> Limited.
> > Reuters Limited is part of the Reuters Group of companies, of which Reuters
> Group PLC is the ultimate parent company. Reuters Group PLC - Registered
> office address: The Reuters Building, South Colonnade, Canary Wharf, London
> E14 5EP, United Kingdom
> Registered No: 3296375
> Registered in England and Wales
> > List info : http://www.activedir.org/List.aspx
List FAQ : http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx | | | |
| DavidCliffe
Posts:15
 | | 04/16/2007 5:41 AM |
| Thanks Ryan...I appreciate your time looking at this. I will pass this
info. on and maybe learn a bit myself from it too. If they are not
already aware of your site I'll certainly make that known as well.
Brian, thanks also for your earlier response.
-DaveC -----Original Message-----
From: ActiveDir-owner@mail.activedir.org
[mailto:ActiveDir-owner@mail.activedir.org] On Behalf Of Ryan Dunn
Sent: Monday, April 16, 2007 4:54 PM
To: ActiveDir@mail.activedir.org
Subject: Re: [ActiveDir] [OT] Problem with .NET 2.0 code or IIS 6.0 or
AD or ??
The issue is with the constructor of the DirectoryEntry. By specifying
"Nothing" as the first parameter, it will try a "defaultNamingContext"
bind in the IIS server's domain. This explains why only those people
are found.
To fix this code, you would need to collect the domain from the user and
put it into the binding path of the DirectoryEntry. This would then be
used as the root for a search.
If you want to fix this right, you will dynamically search the
domain(s) by using the domain from the user credentials. You will also
update this code to not use the user's credentials for the search. Use
a trusted subsystem model instead. Once you find the user, then check
the authentication. Remember that the user could be locked out,
disabled, or otherwise not allowed to search.
Finally, you can download our code from
http://directoryprogramming.net (check the Files section and download
the samples in your language flavor). The code you want is in Ch. 12.
The short story is that anything that uses the DirectoryEntry for
authentication purposes is probably not a great idea in ASP.NET. Bad
things(tm) tend to happen. Use FCB or SSPI binding instead (see the
samples).
On 4/16/07, David Cliffe wrote:
> > > Hi,
> > We have a developer under contract here who has written an app
> [.NET 2.0] which uses a website form [IIS 6] to get input from users
> as to their AD credentials. I don't have most of the code being used
> presently, but I'll try to explain to the best of my limited knowlege
> to see if anyone might recognize something simple we're missing. The
> solution only partially works.
> > After geting the domain name, username /password input, the app
> issues an LDAP query to try and find the user. This is a single
> forest with a few child domains. If the end user's account is a
> member of the same domain as the IIS web server, the application
> continues and all works well. If the user is in any other domain, the
> authentication fails. If the hostname of a DC is hardcoded somewhere
> in the app (perhaps in the bind? I'm not sure...just stating this as
> second hand info), then authentication is successful from any domain
(but this is not desired).
> > In IIS, the application pool in question is running under Network
> Service (we've tried Local System as a test). In the "authentication
> methods" dialog box of the website, we've enabled Anonymous Access
> (the goal is not to use integrated Windows auth for this); nothing
> else has been ticked. In Web.Config, authentication mode has been set
> to "Forms" and I believe the rest of that file is not customized
> (maybe it's not even used in this situation anyway?). The website
does not run on port 80.
> > As for AD - again not sure if this is even needed without
> integrated authentication, but I enabled delegation on the IIS
> server's computer object, and I've created two SPNs for HTTP on that
> server [and FQDN] at the port where the webserver is running. I can
always turn these off again.
> > So not being much of an IIS guy, and certainly not a .NET guy (and
> lately wondering how much of an AD guy :-D ) .... I'm a bit stumped.
> I took a network trace at the IIS server during attempted
> authentication of a user outside IIS server's domain. The only LDAP
> query issued by the IIS [looking for that user] specified a base DN of
> only its own domain to the LDAP port of a nearby DC. I couldn't see
> any other queries and notably nothing going to a GC (the
aforementioned DC does run a GC as well).
> > This is what the bind function looks like in the code:
> > Public Function Bind() As Boolean
> Dim sRet As String = String.Empty
> Dim de As DirectoryEntry
> de = New DirectoryEntry(Nothing, msDomain + "\" + msUserName,
> msPassword)
> Try
> Dim o As Object = de.NativeObject
> Dim ds As DirectorySearcher = New DirectorySearcher(de)
> ds.Filter = "samaccountname=" + msUserName
> ds.PropertiesToLoad.Add("cn")
> Dim sr As SearchResult = ds.FindOne
> If sr Is Nothing Then
> Throw New Exception
> End If
> Return True
> Catch
> Return False
> End Try
> End Function
> > Are we doing this properly? Sorry if not enough info. or code at
> present - will work on that if need be.
> > Thanks,
> DaveC
> This email was sent to you by Reuters, the global news and
> information company.
> To find out more about Reuters visit www.about.reuters.com
> > Any views expressed in this message are those of the individual
> sender, except where the sender specifically states them to be the
> views of Reuters Limited.
> > Reuters Limited is part of the Reuters Group of companies, of which
> Reuters Group PLC is the ultimate parent company. Reuters Group PLC -
> Registered office address: The Reuters Building, South Colonnade,
> Canary Wharf, London
> E14 5EP, United Kingdom
> Registered No: 3296375
> Registered in England and Wales
> > List info : http://www.activedir.org/List.aspx
List FAQ : http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx This email was sent to you by Reuters, the global news and information company.
To find out more about Reuters visit www.about.reuters.com
Any views expressed in this message are those of the individual sender,
except where the sender specifically states them to be the views of Reuters Limited.
Reuters Limited is part of the Reuters Group of companies, of which Reuters Group PLC is the ultimate parent company.
Reuters Group PLC - Registered office address: The Reuters Building, South Colonnade, Canary Wharf, London E14 5EP, United Kingdom
Registered No: 3296375
Registered in England and Wales List info : http://www.activedir.org/List.aspx
List FAQ : http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx | | | |
| joe
Posts:112
 | | 04/16/2007 7:33 AM |
| I don't have much to add here as Ryan and Brian basically covered it, but
since my name was invoked, I felt compelled.
To do a forest-wide search, you really need to search the GC.
However, it looks to me like if this is a forms authentication situation and
you are using .NET 2.0, you really should just be using the
ActiveDirectoryMembershipProvider to do this instead. Why write code for
something that is built in?
Also, why do forms auth against AD in the first place when IIS can
authenticate against AD just fine if the server is a domain member? Using
IWA or basic auth (with SSL) "just works" and saves a lot of trouble.
If IWA was an issue for some reason (firewall, etc.), then basic is still
fine if the server is a domain member. I'd like to think you are using SSL
with this anyway, as forms authentication isn't secure without SSL and if
the site is worth having authentication for, it is probably worth being
secure, no?
You don't really need Kerberos delegation unless you need to delegate, which
you don't if you can eliminate the LDAP query in the first place.
So, those are my additional observations. :)
Joe K.
----- Original Message -----
From: "Ryan Dunn"
To:
Sent: Monday, April 16, 2007 3:54 PM
Subject: Re: [ActiveDir] [OT] Problem with .NET 2.0 code or IIS 6.0 or AD or
?? > The issue is with the constructor of the DirectoryEntry. By
> specifying "Nothing" as the first parameter, it will try a
> "defaultNamingContext" bind in the IIS server's domain. This explains
> why only those people are found.
> > To fix this code, you would need to collect the domain from the user
> and put it into the binding path of the DirectoryEntry. This would
> then be used as the root for a search.
> > If you want to fix this right, you will dynamically search the
> domain(s) by using the domain from the user credentials. You will
> also update this code to not use the user's credentials for the
> search. Use a trusted subsystem model instead. Once you find the
> user, then check the authentication. Remember that the user could be
> locked out, disabled, or otherwise not allowed to search.
> > Finally, you can download our code from
> http://directoryprogramming.net (check the Files section and download
> the samples in your language flavor). The code you want is in Ch. 12.
> The short story is that anything that uses the DirectoryEntry for
> authentication purposes is probably not a great idea in ASP.NET. Bad
> things(tm) tend to happen. Use FCB or SSPI binding instead (see the
> samples).
> > On 4/16/07, David Cliffe wrote:
>> >> >> Hi,
>> >> We have a developer under contract here who has written an app [.NET
>> 2.0] which uses a website form [IIS 6] to get input from users as to
>> their
>> AD credentials. I don't have most of the code being used presently, but
>> I'll try to explain to the best of my limited knowlege to see if anyone
>> might recognize something simple we're missing. The solution only
>> partially
>> works.
>> >> After geting the domain name, username /password input, the app
>> issues
>> an LDAP query to try and find the user. This is a single forest with a
>> few
>> child domains. If the end user's account is a member of the same domain
>> as
>> the IIS web server, the application continues and all works well. If the
>> user is in any other domain, the authentication fails. If the hostname
>> of a
>> DC is hardcoded somewhere in the app (perhaps in the bind? I'm not
>> sure...just stating this as second hand info), then authentication is
>> successful from any domain (but this is not desired).
>> >> In IIS, the application pool in question is running under Network
>> Service (we've tried Local System as a test). In the "authentication
>> methods" dialog box of the website, we've enabled Anonymous Access (the
>> goal is not to use integrated Windows auth for this); nothing else has
>> been
>> ticked. In Web.Config, authentication mode has been set to "Forms" and I
>> believe the rest of that file is not customized (maybe it's not even used
>> in
>> this situation anyway?). The website does not run on port 80.
>> >> As for AD - again not sure if this is even needed without integrated
>> authentication, but I enabled delegation on the IIS server's computer
>> object, and I've created two SPNs for HTTP on that server [and FQDN] at
>> the
>> port where the webserver is running. I can always turn these off again.
>> >> So not being much of an IIS guy, and certainly not a .NET guy (and
>> lately wondering how much of an AD guy :-D ) .... I'm a bit stumped. I
>> took a network trace at the IIS server during attempted authentication of
>> a
>> user outside IIS server's domain. The only LDAP query issued by the IIS
>> [looking for that user] specified a base DN of only its own domain to the
>> LDAP port of a nearby DC. I couldn't see any other queries and notably
>> nothing going to a GC (the aforementioned DC does run a GC as well).
>> >> This is what the bind function looks like in the code:
>> >> Public Function Bind() As Boolean
>> Dim sRet As String = String.Empty
>> Dim de As DirectoryEntry
>> de = New DirectoryEntry(Nothing, msDomain + "\" + msUserName,
>> msPassword)
>> Try
>> Dim o As Object = de.NativeObject
>> Dim ds As DirectorySearcher = New DirectorySearcher(de)
>> ds.Filter = "samaccountname=" + msUserName
>> ds.PropertiesToLoad.Add("cn")
>> Dim sr As SearchResult = ds.FindOne
>> If sr Is Nothing Then
>> Throw New Exception
>> End If
>> Return True
>> Catch
>> Return False
>> End Try
>> End Function
>> >> Are we doing this properly? Sorry if not enough info. or code at
>> present - will work on that if need be.
>> >> Thanks,
>> DaveC
>> This email was sent to you by Reuters, the global news and information
>> company.
>> To find out more about Reuters visit www.about.reuters.com
>> >> Any views expressed in this message are those of the individual sender,
>> except where the sender specifically states them to be the views of
>> Reuters
>> Limited.
>> >> Reuters Limited is part of the Reuters Group of companies, of which
>> Reuters
>> Group PLC is the ultimate parent company. Reuters Group PLC - Registered
>> office address: The Reuters Building, South Colonnade, Canary Wharf,
>> London
>> E14 5EP, United Kingdom
>> Registered No: 3296375
>> Registered in England and Wales
>> >> > List info : http://www.activedir.org/List.aspx
> List FAQ : http://www.activedir.org/ListFAQ.aspx
> List archive: http://www.activedir.org/ma/default.aspx
List info : http://www.activedir.org/List.aspx
List FAQ : http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx | | | |
| amulnick
Posts:163
 | | 04/16/2007 10:24 AM |
| Just for my curiousity Ryan, why would you want to search prior to checking the user's credentials? Wouldn't it be better to check the credentials to ensure they're valid, use error checking to trap the error if not valid to re-promptand then search? I play a coder on the internet but only when nobody is looking, so I'm honestly trying to understand the order.
On 4/16/07, Ryan Dunn wrote:
The issue is with the constructor of the DirectoryEntry.Byspecifying "Nothing" as the first parameter, it will try a
"defaultNamingContext" bind in the IIS server's domain.This explainswhy only those people are found.To fix this code, you would need to collect the domain from the userand put it into the binding path of the DirectoryEntry.This would
then be used as the root for a search.If you want to fix this right, you will dynamically search thedomain(s) by using the domain from the user credentials.You willalso update this code to not use the user's credentials for the
search.Use a trusted subsystem model instead.Once you find theuser, then check the authentication.Remember that the user could belocked out, disabled, or otherwise not allowed to search.Finally, you can download our code from
http://directoryprogramming.net (check the Files section and downloadthe samples in your language flavor).The code you want is in Ch. 12.The short story is that anything that uses the DirectoryEntry for
authentication purposes is probably not a great idea in ASP.NET.Badthings(tm) tend to happen.Use FCB or SSPI binding instead (see thesamples).On 4/16/07, David Cliffe <
David.Cliffe@reuters.com> wrote:>>> Hi,>> We have a developer under contract here who has written an app [.NET> 2.0] which uses a website form [IIS 6] to get input from users as to their
> AD credentials.I don't have most of the code being used presently, but> I'll try to explain to the best of my limited knowlege to see if anyone> might recognize something simple we're missing.The solution only partially
> works.>> After geting the domain name, username /password input, the app issues> an LDAP query to try and find the user.This is a single forest with a few> child domains.If the end user's account is a member of the same domain as
> the IIS web server, the application continues and all works well.If the> user is in any other domain, the authentication fails.If the hostname of a> DC is hardcoded somewhere in the app (perhaps in the bind?I'm not
> sure...just stating this as second hand info), then authentication is> successful from any domain (but this is not desired).>> In IIS, the application pool in question is running under Network
> Service (we've tried Local System as a test).In the "authentication> methods" dialog box of the website, we've enabledAnonymous Access (the> goal is not to use integrated Windows auth for this); nothing else has been
> ticked.In Web.Config, authentication mode has been set to "Forms" and I> believe the rest of that file is not customized (maybe it's not even used in> this situation anyway?).The website does not run on port 80.
>> As for AD - again not sure if this is even needed without integrated> authentication, but I enabled delegation on the IIS server's computer> object, and I've created two SPNs for HTTP on that server [and FQDN] at the
> port where the webserver is running.I can always turn these off again.>> So not being much of an IIS guy, and certainly not a .NET guy (and> lately wondering how much of an AD guy:-D ) .... I'm a bit stumped.I
> took a network trace at the IIS server during attempted authentication of a> user outside IIS server's domain.The only LDAP query issued by the IIS> [looking for that user] specified a base DN of only its own domain to the
> LDAP port of a nearby DC.I couldn't see any other queries and notably> nothing going to a GC (the aforementioned DC does run a GC as well).>> This is what the bind function looks like in the code:
>> Public Function Bind() As Boolean> Dim sRet As String = String.Empty> Dim de As DirectoryEntry> de = New DirectoryEntry(Nothing, msDomain + "\" + msUserName,
> msPassword)> Try> Dim o As Object = de.NativeObject> Dim ds As DirectorySearcher = New DirectorySearcher(de)> ds.Filter = "samaccountname=" + msUserName
> ds.PropertiesToLoad.Add("cn")> Dim sr As SearchResult = ds.FindOne> If sr Is Nothing Then> Throw New Exception> End If
> Return True> Catch> Return False> End Try> End Function>> Are we doing this properly?Sorry if not enough info. or code at
> present - will work on that if need be.>> Thanks,> DaveC>This email was sent to you by Reuters, the global news and information> company.>To find out more about Reuters visit
www.about.reuters.com>>Any views expressed in this message are those of the individual sender,> except where the sender specifically states them to be the views of Reuters
> Limited.>>Reuters Limited is part of the Reuters Group of companies, of which Reuters> Group PLC is the ultimate parent company. Reuters Group PLC - Registered> office address: The Reuters Building, South Colonnade, Canary Wharf, London
> E14 5EP, United Kingdom>Registered No: 3296375>Registered in England and Wales>>List info : http://www.activedir.org/List.aspx
List FAQ: http://www.activedir.org/ListFAQ.aspxList archive: http://www.activedir.org/ma/default.aspx | | | |
| amulnick
Posts:163
 | | 04/17/2007 1:21 AM |
| Thanks Ryan (and Joe). That explains it perfectly. I was originally thinking it would be more optimal to only make the search if the user was an actual user and was worried that if I followed that search first and authenticate later scenario, that I might be setting myself up for a DoS if somebody who doesn't even have credentials tried to logon. I see by your explanation that the issue is far deeper than I envisioned and I appreciate the detailed answer. That helps tremendously.
-ajmOn 4/17/07, Ryan Dunn wrote:
Joe did a pretty good job of explaining all the ins and outs of ADSIand ASP.NET (and why the DirectoryEntry is not a good authenticationmechanism).In my attempt at writing something short and sweet I didn't even
bother with the ActiveDirectoryMembershipProvider, which Joe pointedout.As to your question, Al.I agree that it seems to be a bit of ananti-pattern to search first and then try the authentication.I
should have pointed out that the real reason to do this is todetermine the state of the object prior to trying the authentication.Here is the typical flow for authentication (and authorization):1. Check credentials (do authentication)
2. Search to get account and find details (groups, etc.) for authorization.It turns out that this order is actually non-optimal for ADSIauthentication (it might be fine for other kinds, so I am only talking
about ADSI here for now).What happens is that the user might not beable to login for all sorts of reasons other than a bad password.Theerror you get will not tell you however why the authentication in step
1 fails.So, you end up searching the directory anyway to figure outwhy: lockout, disabled, password expired, password must be changed atnext login, etc.In order to produce any optimization of this routine, you have to
actually search first and figure out if the account is in any state tobe authenticated.This way, if you find that the account is disabledfor instance, you don't even bother to authenticate and you notify the
user.You save the extra call for authentication that won't tell youanything anyway.Since you would always have to perform the search toget the user's information in either scenario (i.e. to determine why
they failed authentication, or to get their authorization info), it isbetter to stack it upfront and save the authentication call if youcan.Now, you might argue:"if my user cannot authenticate, then there is
something wrong with their credentials, so tell them 'bad credentials'or something like that."The problem with simply failing atauthentication and not performing analysis with why is that since you
cannot tell if it was a bad password or 'user must change password atnext login', you will message the user in a very confusing manner.Typically, if you get a bad credentials error message, you will say to
yourself, "hmm, I must have used another password".So, your userends up locking themselves out in addition to needing to changepassword at next login since they type in a whole bunch of olderpasswords.I have seen this many times.It is much better to message
them, "you must change your password - go here for more information",than flashing a "bad credentials" message.Long story, I know... but I fought this kind of thing a lot back in the day...
On 4/16/07, Joe Kaplan wrote:> There is a particularly bad pattern in this type of auth routine that is> best avoided when using ADSI or
S.DS which is one reason why Ryan suggests> doing the search via the trusted subsystem design.The problem is that if> you use the user's own credentials to bind to the directory, ADSI will open> a new LDAP connection.It basically does this every time a different set of
> credentials are used.The problem here is that even if these connections> get closed down quickly, the TCP port associated with the connection stay in> TCP "time wait" status for 60 seconds.Under high load, the web server can
> run out of TCP wildcard ports and will basically stop working for a while.> That's bad!>> This is one of the reasons why the ADSI SDK says not to use ADSI for> authentication.Its design works against doing that well.
>> The way the AD membership provider in .NET 2.0 (mentioned in my other reply)> deals with this is by using S.DS.Protocols to do the bind operation and> managing the connection directly (the connection is reused).Then, when it
> does a search in the directory, it uses a fixed account (the trusted> subsystem design that Ryan mentions) for this.That will reuse the existing> ADSI LDAP connection and will scale fine (usually).
>> This does kind of beg two other questions, which is why the AD membership> provider doesn't just use S.DS.Protocols for all of the code (I don't know> the answer to that) and why you need to do a search in the first place.
> After all, if the bind works, the credentials are fine.What else does the> search tell you?:)>> In many systems that use LDAP auth, the common pattern is to look up the> user's DN using a service account first based on the short username provided
> by the end user in the UI and then do the bind using the DN as the username.> This is because many directories only support the LDAP V3 specification> which says that the DN is the username you use for binding.However, AD
> supports additional username formats for binding, so it is more flexible> here and doesn't have that particular limitation.That would be the primary> reason to do a search first though.> > Joe K.>> ----- Original Message -----> From: "Al Mulnick" > To: <
ActiveDir@mail.activedir.org>> Sent: Monday, April 16, 2007 9:24 PM> Subject: Re: [ActiveDir] [OT] Problem with .NET 2.0 code or IIS 6.0 or AD or> ??>>> > Just for my curiousity Ryan, why would you want to search prior to
> > checking> > the user's credentials?Wouldn't it be better to check the credentials to> > ensure they're valid, use error checking to trap the error if not valid to> > re-prompt and then search?
> >> > I play a coder on the internet but only when nobody is looking, so I'm> > honestly trying to understand the order.> >> >>> List info :
http://www.activedir.org/List.aspx> List FAQ: http://www.activedir.org/ListFAQ.aspx> List archive:
http://www.activedir.org/ma/default.aspx>List info : http://www.activedir.org/List.aspxList FAQ: http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx | | | |
| joe
Posts:112
 | | 04/17/2007 12:11 PM |
| There is a particularly bad pattern in this type of auth routine that is
best avoided when using ADSI or S.DS which is one reason why Ryan suggests
doing the search via the trusted subsystem design. The problem is that if
you use the user's own credentials to bind to the directory, ADSI will open
a new LDAP connection. It basically does this every time a different set of
credentials are used. The problem here is that even if these connections
get closed down quickly, the TCP port associated with the connection stay in
TCP "time wait" status for 60 seconds. Under high load, the web server can
run out of TCP wildcard ports and will basically stop working for a while.
That's bad!
This is one of the reasons why the ADSI SDK says not to use ADSI for
authentication. Its design works against doing that well.
The way the AD membership provider in .NET 2.0 (mentioned in my other reply)
deals with this is by using S.DS.Protocols to do the bind operation and
managing the connection directly (the connection is reused). Then, when it
does a search in the directory, it uses a fixed account (the trusted
subsystem design that Ryan mentions) for this. That will reuse the existing
ADSI LDAP connection and will scale fine (usually).
This does kind of beg two other questions, which is why the AD membership
provider doesn't just use S.DS.Protocols for all of the code (I don't know
the answer to that) and why you need to do a search in the first place.
After all, if the bind works, the credentials are fine. What else does the
search tell you? :)
In many systems that use LDAP auth, the common pattern is to look up the
user's DN using a service account first based on the short username provided
by the end user in the UI and then do the bind using the DN as the username.
This is because many directories only support the LDAP V3 specification
which says that the DN is the username you use for binding. However, AD
supports additional username formats for binding, so it is more flexible
here and doesn't have that particular limitation. That would be the primary
reason to do a search first though.
Joe K.
----- Original Message -----
From: "Al Mulnick"
To:
Sent: Monday, April 16, 2007 9:24 PM
Subject: Re: [ActiveDir] [OT] Problem with .NET 2.0 code or IIS 6.0 or AD or
?? > Just for my curiousity Ryan, why would you want to search prior to
> checking
> the user's credentials? Wouldn't it be better to check the credentials to
> ensure they're valid, use error checking to trap the error if not valid to
> re-prompt and then search?
> > I play a coder on the internet but only when nobody is looking, so I'm
> honestly trying to understand the order.
> >
List info : http://www.activedir.org/List.aspx
List FAQ : http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx | | | |
| dunnry
Posts:0
 | | 04/17/2007 12:43 PM |
| Joe did a pretty good job of explaining all the ins and outs of ADSI
and ASP.NET (and why the DirectoryEntry is not a good authentication
mechanism).
In my attempt at writing something short and sweet I didn't even
bother with the ActiveDirectoryMembershipProvider, which Joe pointed
out.
As to your question, Al. I agree that it seems to be a bit of an
anti-pattern to search first and then try the authentication. I
should have pointed out that the real reason to do this is to
determine the state of the object prior to trying the authentication.
Here is the typical flow for authentication (and authorization):
1. Check credentials (do authentication)
2. Search to get account and find details (groups, etc.) for authorization.
It turns out that this order is actually non-optimal for ADSI
authentication (it might be fine for other kinds, so I am only talking
about ADSI here for now). What happens is that the user might not be
able to login for all sorts of reasons other than a bad password. The
error you get will not tell you however why the authentication in step
1 fails. So, you end up searching the directory anyway to figure out
why: lockout, disabled, password expired, password must be changed at
next login, etc.
In order to produce any optimization of this routine, you have to
actually search first and figure out if the account is in any state to
be authenticated. This way, if you find that the account is disabled
for instance, you don't even bother to authenticate and you notify the
user. You save the extra call for authentication that won't tell you
anything anyway. Since you would always have to perform the search to
get the user's information in either scenario (i.e. to determine why
they failed authentication, or to get their authorization info), it is
better to stack it upfront and save the authentication call if you
can.
Now, you might argue: "if my user cannot authenticate, then there is
something wrong with their credentials, so tell them 'bad credentials'
or something like that." The problem with simply failing at
authentication and not performing analysis with why is that since you
cannot tell if it was a bad password or 'user must change password at
next login', you will message the user in a very confusing manner.
Typically, if you get a bad credentials error message, you will say to
yourself, "hmm, I must have used another password". So, your user
ends up locking themselves out in addition to needing to change
password at next login since they type in a whole bunch of older
passwords. I have seen this many times. It is much better to message
them, "you must change your password - go here for more information",
than flashing a "bad credentials" message.
Long story, I know... but I fought this kind of thing a lot back in the day...
On 4/16/07, Joe Kaplan wrote:
> There is a particularly bad pattern in this type of auth routine that is
> best avoided when using ADSI or S.DS which is one reason why Ryan suggests
> doing the search via the trusted subsystem design. The problem is that if
> you use the user's own credentials to bind to the directory, ADSI will open
> a new LDAP connection. It basically does this every time a different set of
> credentials are used. The problem here is that even if these connections
> get closed down quickly, the TCP port associated with the connection stay in
> TCP "time wait" status for 60 seconds. Under high load, the web server can
> run out of TCP wildcard ports and will basically stop working for a while.
> That's bad!
> > This is one of the reasons why the ADSI SDK says not to use ADSI for
> authentication. Its design works against doing that well.
> > The way the AD membership provider in .NET 2.0 (mentioned in my other reply)
> deals with this is by using S.DS.Protocols to do the bind operation and
> managing the connection directly (the connection is reused). Then, when it
> does a search in the directory, it uses a fixed account (the trusted
> subsystem design that Ryan mentions) for this. That will reuse the existing
> ADSI LDAP connection and will scale fine (usually).
> > This does kind of beg two other questions, which is why the AD membership
> provider doesn't just use S.DS.Protocols for all of the code (I don't know
> the answer to that) and why you need to do a search in the first place.
> After all, if the bind works, the credentials are fine. What else does the
> search tell you? :)
> > In many systems that use LDAP auth, the common pattern is to look up the
> user's DN using a service account first based on the short username provided
> by the end user in the UI and then do the bind using the DN as the username.
> This is because many directories only support the LDAP V3 specification
> which says that the DN is the username you use for binding. However, AD
> supports additional username formats for binding, so it is more flexible
> here and doesn't have that particular limitation. That would be the primary
> reason to do a search first though.
> > Joe K.
> > ----- Original Message -----
> From: "Al Mulnick"
> To:
> Sent: Monday, April 16, 2007 9:24 PM
> Subject: Re: [ActiveDir] [OT] Problem with .NET 2.0 code or IIS 6.0 or AD or
> ??
> > > > Just for my curiousity Ryan, why would you want to search prior to
> > checking
> > the user's credentials? Wouldn't it be better to check the credentials to
> > ensure they're valid, use error checking to trap the error if not valid to
> > re-prompt and then search?
> > > > I play a coder on the internet but only when nobody is looking, so I'm
> > honestly trying to understand the order.
> > > > > > List info : http://www.activedir.org/List.aspx
> List FAQ : http://www.activedir.org/ListFAQ.aspx
> List archive: http://www.activedir.org/ma/default.aspx
> List info : http://www.activedir.org/List.aspx
List FAQ : http://www.activedir.org/ListFAQ.aspx
List archive: http://www.activedir.org/ma/default.aspx | | | |
|
|