"An operations error occurred"

A

Andy

Hi,

I'm having a problem querying active directory. It happens so far
only on one computer under a particular user account. Things seem to
work fine for that user on another computer, and if I logon to her
computer the query works fine as well. here is the C# code I'm using
to do the query:

private static DirectoryEntry GetUserEntry( WindowsIdentity
ident ) {
string directoryServer;
DirectorySearcher searcher;
DirectoryEntry domainEntry, result;
SearchResult results;
string userName;

result = null;

using ( domainEntry = new DirectoryEntry( "LDAP://rootdse" ) ) {
directoryServer = domainEntry.Invoke(
"GET",
"defaultNamingContext"
).ToString();
}

if ( string.IsNullOrEmpty( directoryServer ) ) {
throw new InvalidOperationException(
Properties.Resources.CannotDetermineDirectoryServer
);
}

if ( directoryServer.StartsWith( @"\\" ) ) {
directoryServer = directoryServer.Substring( 2 );
}

using ( domainEntry = new DirectoryEntry(
string.Format( "LDAP://{0}", directoryServer ) ) ) {

userName = ident.Name;
if ( userName.IndexOf( @"\" ) > -1 ) {
userName =
userName.Substring( userName.IndexOf( @"\" ) + 1 );
}

using (
searcher = new DirectorySearcher(
domainEntry,
string.Format( "SAMAccountName={0}", userName )
)
) {

results = searcher.FindOne();
result = results.GetDirectoryEntry();
}
}

return result;
}

The initial part seems to succeed (querying for the rootdse), but
finding the SAMAccount is failing for some reason. Any ideas? Here's
the exception:

System.Runtime.InteropServices.COMException (0x80072020): An
operations error occurred.

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 MyCompan.Application.UserInfo.GetUserEntry(WindowsIdentity
ident)
 
J

Joe Kaplan

This happens when you bind to AD as the anonymous user. That usually
happens as a result of supplying default credentials in your DirectoryEntry
(null, null) and being logged in a non-domain user. Are you sure the user
having this problem is logged in with a domain account?

There are also a few things you can do if you want to tighten up this code a
bit, but I'll hold off on commenting there unless you like additional
advice. :)

Joe K.
 
A

Andy

This happens when you bind to AD as the anonymous user. That usually
happens as a result of supplying default credentials in your DirectoryEntry
(null, null) and being logged in a non-domain user. Are you sure the user
having this problem is logged in with a domain account?

Yes, she's definitely using a domain account. There's no local
account with her username, and the domain dropdown shows the domain,
not the computer name.
There are also a few things you can do if you want to tighten up this code a
bit, but I'll hold off on commenting there unless you like additional
advice. :)

As long as you can also help provide a solution to my issue, make any
comments you like.
 
J

Joe Kaplan

The bind operation should work as long as she is logged in as a domain user.
Is there any chance she is logged in with a user from a different domain
than the domain the machine is in or anything unusual like that?

Regarding the code, there are a couple of things. For one, you don't ever
need to Invoke the Get method on IADs. You could do this instead:

string namingContext = (string)
domainEntry.Properties["defaultNamingContext"].Value;

In general, you should only ever need to use reflection (Invoke, etc.) on
the interface members on IADsUser and such.

More importantly though, there is a handy shortcut you can do for this type
of operation that should allow you to skip some of the extra work of using
the DirectorySearcher. You can bind to objects in AD directly by using the
SID DN syntax, which looks like this:
<SID=S-1-5-xxxxx>

Thus, the LDAP path for such a DN might look like:
LDAP://domain/<SID=S-1-5-xxxx>

You can format that path by grabbing the domain from the prefix on the
username and the SID value by calling ToString on the User property of the
WindowsIdentity object. That all assume .NET 2.0 on the client though since
the User property is new in .NET 2.0.

Note that the SID DN syntax that takes the SDDL format of the SID requires
Win2K3 AD. If you have Win2K AD, you can still do this, but you need to
supply the SID as a hex string instead. Let me know if you need to see
that.

Joe K.
 
A

Andy

The bind operation should work as long as she is logged in as a domain user.
Is there any chance she is logged in with a user from a different domain
than the domain the machine is in or anything unusual like that?

No, she's definately logging in as the proper user. That's only one
domain here.
Regarding the code, there are a couple of things. For one, you don't ever
need to Invoke the Get method on IADs. You could do this instead:

string namingContext = (string)
domainEntry.Properties["defaultNamingContext"].Value;

In general, you should only ever need to use reflection (Invoke, etc.) on
the interface members on IADsUser and such.

More importantly though, there is a handy shortcut you can do for this type
of operation that should allow you to skip some of the extra work of using
the DirectorySearcher. You can bind to objects in AD directly by using the
SID DN syntax, which looks like this:
<SID=S-1-5-xxxxx>

Thus, the LDAP path for such a DN might look like:
LDAP://domain/<SID=S-1-5-xxxx>

You can format that path by grabbing the domain from the prefix on the
username and the SID value by calling ToString on the User property of the
WindowsIdentity object. That all assume .NET 2.0 on the client though since
the User property is new in .NET 2.0.

Well, I couldn't get this working at all with ldap://domain/<SID=>,
but I found on MSDN that I can do ldap://<SID=>. That gets me a bound
object, but I can't read anything I need, like givenName, sn,
SAMAccountName, or email.

Andy
 
J

Joe Kaplan

Regarding the failed logon, it should definitely work consistently with
every user if the environment is the same. The only thing I can think at
this point would be to have the AD admins tell you what the logon failure on
the AD side was that got audited when this search attempt failed. However,
that might be very difficult to get out of them.

You could also try sniffing the wire traffic to see what type of
authentication information is being passed to the server in the bind
operation. There might be some sort of issue with DNS on her particular
workstation that is causing something low level to fail such as Kerberos or
something like that. It is hard to say.

The binding string with LDAP://domain/<SID=S-1-5-xxxx> and
LDAP://<SID=S-1-5-xxxx> should both work the same way. It may be the case
that there is a name resolution issue in the environment that prevents the
NetBIOS style domain name from being used. If there is only one domain,
then the serverless binding style should be fine. It is also possible to
convert the NetBIOS style name to a DNS name if needed, but that adds
complexity. There is no point in doing that if there is no chance of
ambiguity with the domain name.

Also, the returned object should allow you to read the same attributes that
you can see from finding the object via a search. Can you show a code
sample that demonstrates what isn't working here and how you got there?

Joe K.
--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Andy said:
The bind operation should work as long as she is logged in as a domain
user.
Is there any chance she is logged in with a user from a different domain
than the domain the machine is in or anything unusual like that?

No, she's definately logging in as the proper user. That's only one
domain here.
Regarding the code, there are a couple of things. For one, you don't
ever
need to Invoke the Get method on IADs. You could do this instead:

string namingContext = (string)
domainEntry.Properties["defaultNamingContext"].Value;

In general, you should only ever need to use reflection (Invoke, etc.) on
the interface members on IADsUser and such.

More importantly though, there is a handy shortcut you can do for this
type
of operation that should allow you to skip some of the extra work of
using
the DirectorySearcher. You can bind to objects in AD directly by using
the
SID DN syntax, which looks like this:
<SID=S-1-5-xxxxx>

Thus, the LDAP path for such a DN might look like:
LDAP://domain/<SID=S-1-5-xxxx>

You can format that path by grabbing the domain from the prefix on the
username and the SID value by calling ToString on the User property of
the
WindowsIdentity object. That all assume .NET 2.0 on the client though
since
the User property is new in .NET 2.0.

Well, I couldn't get this working at all with ldap://domain/<SID=>,
but I found on MSDN that I can do ldap://<SID=>. That gets me a bound
object, but I can't read anything I need, like givenName, sn,
SAMAccountName, or email.

Andy
 
A

Andy

Regarding the failed logon, it should definitely work consistently with
every user if the environment is the same. The only thing I can think at
this point would be to have the AD admins tell you what the logon failure on
the AD side was that got audited when this search attempt failed. However,
that might be very difficult to get out of them.

We're a smaller company, so its just the IT guy (who is my manager)
and me. We're both domain admins, so if you tell me where to look, I
can check there.
You could also try sniffing the wire traffic to see what type of
authentication information is being passed to the server in the bind
operation. There might be some sort of issue with DNS on her particular
workstation that is causing something low level to fail such as Kerberos or
something like that. It is hard to say.

The default naming context comes back as
DC=domainname,DC=company,DC=us. I also tried hardcoding just
domainname for ldap://domainname/ said:
The binding string with LDAP://domain/<SID=S-1-5-xxxx> and
LDAP://<SID=S-1-5-xxxx> should both work the same way. It may be the case
that there is a name resolution issue in the environment that prevents the
NetBIOS style domain name from being used. If there is only one domain,
then the serverless binding style should be fine. It is also possible to
convert the NetBIOS style name to a DNS name if needed, but that adds
complexity. There is no point in doing that if there is no chance of
ambiguity with the domain name.

Hmm... that's odd it's not working. I should point out we have two
physical locations, with a DC at each one. We have an always on T1
link though, but when I make changes to the directory (just moving
computers around really) I noticed it's better to do it at the closer
server so that the workstation gets the update without waiting for the
two to sync.
Also, the returned object should allow you to read the same attributes that
you can see from finding the object via a search. Can you show a code
sample that demonstrates what isn't working here and how you got there?

Sure.

private void LoadSelf( WindowsIdentity ident ) {
DirectoryEntry adEntry;

adEntry = GetUserEntry( ident );

// I get a NullReferenceException, because .Value is
returning null for all of these properties, although adEntry.IsBound
returns true.
FirstName =
adEntry.Properties[ "givenName" ].Value.ToString();
LastName = adEntry.Properties[ "sn" ].Value.ToString();
LoginName = ident.Name;
Email =
adEntry.Properties[ "SAMAccountName" ].Value.ToString();
Email += "@company.com";
}

/// <summary>Loads the user
/// with data from ActiveDirectory.</summary>
/// <param name="ident">The <see cref="WindowsIdentity"/>
/// representing the user to load.</param>
/// <returns>A <see cref="DirectoryEntry"/>.</returns>
private static DirectoryEntry GetUserEntry( WindowsIdentity ident )
{
string directoryServer, query;
DirectoryEntry domainEntry;

using ( domainEntry = new DirectoryEntry( "LDAP://rootdse" ) ) {
directoryServer = domainEntry.Properties[
"defaultNamingContext"
].Value.ToString();
}

if ( string.IsNullOrEmpty( directoryServer ) ) {
throw new InvalidOperationException(
Properties.Resources.CannotDetermineDirectoryServer
);
}
if ( directoryServer.StartsWith( @"\\" ) ) {
directoryServer = directoryServer.Substring( 2 );
}

query = string.Format(
"LDAP://<SID={0}>",
ident.User.AccountDomainSid.ToString()
);

return new DirectoryEntry( query );
}
 
J

Joe Kaplan

Below inline:

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Andy said:
On Mar 25, 11:38 am, "Joe Kaplan"
We're a smaller company, so its just the IT guy (who is my manager)
and me. We're both domain admins, so if you tell me where to look, I
can check there.

There should be some sort of logon audit on the DC that occurs when this
operation is executed, so that would be in the security event log if you are
auditing your logons (which you hopefully are). They can be a mess to go
through since the DC is frequently processing LOTS of authentications, but
hopefully you can find a way to line it up.
The default naming context comes back as
DC=domainname,DC=company,DC=us. I also tried hardcoding just
domainname for ldap://domainname/<SID>.
Remember here that the domain name would either be the NetBIOS name of the
domain (which you can get from the prefix on the user name from the
WindowsIdentity.Name property) or the DNS domain name of the domain. I
wanted to make sure there wasn't any confusion over using the distinguished
name of the naming context root of your domain which looks like
DC=xxx,DC=yyyy. The LDAP path syntax basically goes like this:

<provider>://<server (optional)>/<object name>

When you don't supply a server part, that is called a "serverless" bind.
When a serverless bind is done, the underlying components bootstrap a domain
to use based on the security context of the current thread.
Hmm... that's odd it's not working. I should point out we have two
physical locations, with a DC at each one. We have an always on T1
link though, but when I make changes to the directory (just moving
computers around really) I noticed it's better to do it at the closer
server so that the workstation gets the update without waiting for the
two to sync.

I can't see any reason why this wouldn't work, but the process where you get
the user object via a search operation would. The credentials used are the
same, so they should get the same results.

Are you sure that all of the users in your directory have permissions to
read their own user objects? Normally people do, but in some cases they
might not. However, testing when logged in as an admin may give completely
different results.

Note that in your code below, there is no reason to get the
defaultNamingContext attribute from RootDSE if you don't need to use it for
anything. You can get the dnsHostName attribute as well which will give you
the full DNS name of the domain controller, but since you can use serverless
binds, you should not need that.
Sure.

private void LoadSelf( WindowsIdentity ident ) {
DirectoryEntry adEntry;

adEntry = GetUserEntry( ident );

// I get a NullReferenceException, because .Value is
returning null for all of these properties, although adEntry.IsBound
returns true.
FirstName =
adEntry.Properties[ "givenName" ].Value.ToString();
LastName = adEntry.Properties[ "sn" ].Value.ToString();
LoginName = ident.Name;
Email =
adEntry.Properties[ "SAMAccountName" ].Value.ToString();
Email += "@company.com";
}

/// <summary>Loads the user
/// with data from ActiveDirectory.</summary>
/// <param name="ident">The <see cref="WindowsIdentity"/>
/// representing the user to load.</param>
/// <returns>A <see cref="DirectoryEntry"/>.</returns>
private static DirectoryEntry GetUserEntry( WindowsIdentity ident )
{
string directoryServer, query;
DirectoryEntry domainEntry;

using ( domainEntry = new DirectoryEntry( "LDAP://rootdse" ) ) {
directoryServer = domainEntry.Properties[
"defaultNamingContext"
].Value.ToString();
}

if ( string.IsNullOrEmpty( directoryServer ) ) {
throw new InvalidOperationException(
Properties.Resources.CannotDetermineDirectoryServer
);
}
if ( directoryServer.StartsWith( @"\\" ) ) {
directoryServer = directoryServer.Substring( 2 );
}

query = string.Format(
"LDAP://<SID={0}>",
ident.User.AccountDomainSid.ToString()
);

return new DirectoryEntry( query );
}
 
A

Andy

There should be some sort of logon audit on the DC that occurs when this
operation is executed, so that would be in the security event log if you are
auditing your logons (which you hopefully are). They can be a mess to go
through since the DC is frequently processing LOTS of authentications, but
hopefully you can find a way to line it up.

Ok, I'll start digging.
Remember here that the domain name would either be the NetBIOS name of the
domain (which you can get from the prefix on the user name from the
WindowsIdentity.Name property) or the DNS domain name of the domain. I
wanted to make sure there wasn't any confusion over using the distinguished
name of the naming context root of your domain which looks like
DC=xxx,DC=yyyy. The LDAP path syntax basically goes like this:

<provider>://<server (optional)>/<object name>

When you don't supply a server part, that is called a "serverless" bind.
When a serverless bind is done, the underlying components bootstrap a domain
to use based on the security context of the current thread.

Ok.. I now get the DirectoryEntry IsBound to return true using
but either way I don't get the needed said:
I can't see any reason why this wouldn't work, but the process where you get
the user object via a search operation would. The credentials used are the
same, so they should get the same results.

I'm not sure; I was seaching by SAMAccountName... perhaps I'm not
getting back what I am expecting?
Are you sure that all of the users in your directory have permissions to
read their own user objects? Normally people do, but in some cases they
might not. However, testing when logged in as an admin may give completely
different results.

Well, the application is deployed to about seven other users, and they
have no problems reading their own directory information. I use it to
cache some of the properties in the database. In the case of the
code you recommended, since I'm a domain admin I would assume I should
be able to read any of the users' properties, but that doesn't seem to
be the case.
Note that in your code below, there is no reason to get the
defaultNamingContext attribute from RootDSE if you don't need to use it for
anything. You can get the dnsHostName attribute as well which will give you
the full DNS name of the domain controller, but since you can use serverless
binds, you should not need that.

Right.. I have removed that after posting. If I can get the
information from the DirectoryEntry I need, that will make things
simpler than before, so I'd like to keep the way you recommended.

Thanks for keeping with this.

Andy
 
A

Andy

There should be some sort of logon audit on the DC that occurs when this
operation is executed, so that would be in the security event log if you are
auditing your logons (which you hopefully are). They can be a mess to go
through since the DC is frequently processing LOTS of authentications, but
hopefully you can find a way to line it up.

I had her try the application again and checked the Security log on
the DC. I didn't see anything failing.. I saw her account doing a
network logon, and I did see the anonymous account logging on from the
database server, but no failures. I don't know what would cause her
workstation to logon anonymously.

Just so the application architecture is clear: it's a winforms
application which executes data access code on the server by using
remoting to the database server. IIS is configured to impersonate
users via Windows Authentication. So the reading of Active Directory
actually occurs on the database server running under IIS. This has
never been an issue before, and there are currently seven other users
that use the same application without issue. To be clear her issue is
the one I originally posted about, the Operations error occurred.

Not being able to read the properties givenName, sn, etc. has been
happening consistently running as my user account, which is a domain
admin. I was hoping moving to your suggested code would have the nice
side effect of fixing my original problem.. so if I can get the newer
code working, I'd like to try to see if that resolves the original
problem as well.

Thanks!
Andy
 
J

Joe Kaplan

Ah, that makes a huge difference. I was under the impression that this LDAP
code was executing directly on the user's workstation. Thanks for
explaining the architecture in more detail.

So, it sounds like you have a delegation scenario in place here where the
user authenticates to IIS, ASP.NET impersonates the user and then makes
remote calls to AD and SQL.

Out of curiosity, do you have Kerberos delegation enabled for the app pool
identity that the ASP.NET app runs under? This would be the machine account
of web server if you use Network Service or System as the app pool identity.
If so, perhaps you can tell me whether you have it set to "Kerberos Only"
delegation or "Any protocol" in the delegation settings.

If you have Kerberos only, then my suspicion is that this one user is
failing because she is doing an NTLM authentication to IIS instead of
Kerberos. With Kerberos-only delegation, you have to have Kerberos
authentication end to end for it to work. You can find out if her initial
auth to the IIS machine used Kerb or NTLM by looking at the logon event it
generated in its security event log. It will say whether Ntlmssp or
Kerberos was used. That may be the key to the problem.

Joe K.
 
A

Andy

Ah, that makes a huge difference. I was under the impression that this LDAP
code was executing directly on the user's workstation. Thanks for
explaining the architecture in more detail.

Yes, sorry for not mentioning that earlier. Although I'll give it a
shot running locally too and see what happens.
So, it sounds like you have a delegation scenario in place here where the
user authenticates to IIS, ASP.NET impersonates the user and then makes
remote calls to AD and SQL.

Yes, I've tried to make everything automatic so that the user doesn't
need to logon again.
Out of curiosity, do you have Kerberos delegation enabled for the app pool
identity that the ASP.NET app runs under? This would be the machine account
of web server if you use Network Service or System as the app pool identity.
If so, perhaps you can tell me whether you have it set to "Kerberos Only"
delegation or "Any protocol" in the delegation settings.

The application pool (we have only Win2k3 servers) is running as
Network Service. The web.config enables impersonation. I don't see
where I can set delegation however. The only place I see delegation
settings are on Computer accounts in the directory, and the only ones
I've found that were trusted for delegate were the DCs. But these are
set to Kerberos only.
If you have Kerberos only, then my suspicion is that this one user is
failing because she is doing an NTLM authentication to IIS instead of
Kerberos. With Kerberos-only delegation, you have to have Kerberos
authentication end to end for it to work. You can find out if her initial
auth to the IIS machine used Kerb or NTLM by looking at the logon event it
generated in its security event log. It will say whether Ntlmssp or
Kerberos was used. That may be the key to the problem.

Where would this be set for her user? It only seems to be her
particular account on her workstation; if she logs onto my machine
(which is Vista, her's is XP SP2) it works fine. I can also logon to
her machine and it works fine.. but maybe that's just because I'm a
domain admin as well?

Thanks
Andy
 
A

Andy

Ah, that makes a huge difference. I was under the impression that this LDAP
code was executing directly on the user's workstation. Thanks for
explaining the architecture in more detail.

So, it sounds like you have a delegation scenario in place here where the
user authenticates to IIS, ASP.NET impersonates the user and then makes
remote calls to AD and SQL.

Well, if I change the application to talk directly to the db and AD
from her computer, things seem to work. So I think your delegation
idea sounds like its on the right track. Now I just need to know
where to change settings.

Andy
 
A

Andy

Back to the loading via SID.. it seems that is working now. Instead
of using User.AccountDomainSid.ToString, I changed to User.Value.
User.ToString and User.AccountDomainId.ToString seem to have been
returning the domain, because I was at the root of the directory..
Children contained Domain Controllers, Users, Built In, etc. So the
new way of looking up the records seems to work nicely now.

Andy
 
J

Joe Kaplan

The right for a service account to delegate is configured in AD. The
service account can be either a computer account or a normal user account.
With IIS, the service account is the app pool identity. Since you use
network service locally, the service account from the "network" or off-box
perspective is the AD computer account.

For the AD computer account to be able to delegate the credentials of the
logged on user to a remote service, it must have permissions to delegate (as
shown on the delegation tab). The constraints on the delegation depend on
which settings you have in place. When you use Kerberos only, you have the
option of allowing the account to delegate to any service (potentially very
dangerous), but you can only do that if the original authentication of the
user is done via Kerberos. It is also possible to use constrained
delegation, where you configure the service to only delegate to specific
services. You can also use the "protocol transition", although that must be
combined with constrained delegation. Protocol transition (also called
Kerberos S4U) allows you to have the client authenticate with a protocol
other than Kerberos and still do delegation to a Kerberos-based service.

In general, it can be very difficult to figure out why NTLM or Kerberos gets
used when Windows performs negotiate authentication. The fact that your
account gets Kerb auth on her workstation but she doesn't is strange.
However, given that she DOES seem to get Kerb auth when using Vista would
seem to indicate that it is not her account but something specific to that
machine.

Before making any assumptions here, you want to be sure you are seeing what
you think you are seeing in terms of how the .NET remoting stuff is
authenticating to IIS. Check the security event logs carefully and make
sure you know for sure which SSP was used to authenticate the remoting user.
That info is critical to getting an understanding of the problem.
 
A

Andy

The right for a service account to delegate is configured in AD. The
service account can be either a computer account or a normal user account.
With IIS, the service account is the app pool identity. Since you use
network service locally, the service account from the "network" or off-box
perspective is the AD computer account.

For the AD computer account to be able to delegate the credentials of the
logged on user to a remote service, it must have permissions to delegate (as
shown on the delegation tab). The constraints on the delegation depend on
which settings you have in place. When you use Kerberos only, you have the
option of allowing the account to delegate to any service (potentially very
dangerous), but you can only do that if the original authentication of the
user is done via Kerberos. It is also possible to use constrained
delegation, where you configure the service to only delegate to specific
services. You can also use the "protocol transition", although that must be
combined with constrained delegation. Protocol transition (also called
Kerberos S4U) allows you to have the client authenticate with a protocol
other than Kerberos and still do delegation to a Kerberos-based service.

In general, it can be very difficult to figure out why NTLM or Kerberos gets
used when Windows performs negotiate authentication. The fact that your
account gets Kerb auth on her workstation but she doesn't is strange.
However, given that she DOES seem to get Kerb auth when using Vista would
seem to indicate that it is not her account but something specific to that
machine.

Before making any assumptions here, you want to be sure you are seeing what
you think you are seeing in terms of how the .NET remoting stuff is
authenticating to IIS. Check the security event logs carefully and make
sure you know for sure which SSP was used to authenticate the remoting user.
That info is critical to getting an understanding of the problem.

Well, I did a logon and looked at the logs user her workstation /
user. I see sever Kerbous auths from her workstation, then a few
ANONYMOUS auths from the database / IIS server. The same pattern
occurs when I start the application on my workstation. So nothing odd
there.

I also see Service Request Ticket events coming from her computer as
well, shortly followed by on from the database server. This also
seems to follow the same pattern as my logons.

The ANONYMOUS auths I mentioned above all say they are using NTLM, but
as I said, the same logons seem to appear when under my account as
well, and they are all success audits.

Do you have settings I could change, each one independently so I can
get this tracked down? It's possible I'm just not finding the right
log entries.. but I don't see any failure audits.
 
J

Joe Kaplan

Yes, AccountDomainSid is the prefix on the user's SID, but isn't the user's
SID. So, a search for that object via that SID would actually return the
domain root object (of type domainDNS), not the user's object. That might
explain why you didn't see any user attributes on that object.

One other thing worth asking is if you really need delegation. Could you
instead just access AD and SQL using a service account? Are you delegating
permissions in SQL such that you are applying permissions to individual
users there? You mentioned that you were seeing lots of anonymous
authentications happening on the SQL box which leads me to believe that your
delegation isn't working there either.

If you don't really need delegation, you can just disable impersonation on
IIS. Then, the process account will be used for accessing AD and SQL.

Joe K.
 
A

Andy

Yes, AccountDomainSid is the prefix on the user's SID, but isn't the user's
SID. So, a search for that object via that SID would actually return the
domain root object (of type domainDNS), not the user's object. That might
explain why you didn't see any user attributes on that object.

Ya, I now have your simpler code working. Thanks!
One other thing worth asking is if you really need delegation. Could you
instead just access AD and SQL using a service account? Are you delegating
permissions in SQL such that you are applying permissions to individual
users there? You mentioned that you were seeing lots of anonymous
authentications happening on the SQL box which leads me to believe that your
delegation isn't working there either.

Well, I'm using Windows authentication in Sql, and have Windows groups
tied to database roles, and certain procs, views, or functions can
only be executed if you are in the proper role. In some places I also
use the suser_username() function, although I guess it's strictly not
needed. The other plus is that I don't need to store Sql user names
and passwords in my configuration files.

I'm not seeing LOTS of anonymous auths, but there are some. I'm also
not 100% sure they are related, although I think they are, because the
logs indicate the IP address of the workstation on which I launched
the application.

I'd hate to have to redo everything because of one logon problem; as I
said, this setup works for all my other users. Maybe I should let the
IT guy just flatten the box and start over.
 
J

Joe Kaplan

The anonymous auth is typically when there is either some sort of delegation
problem or a problem with Kerberos auth itself. What happens is that if the
service impersonating the user cannot authenticate via Kerberos for some
reason, it will try to authenticate via NTLM instead. However, it doesn't
have any NTLM credentials it can use for the impersonated user, so it
instead logs in the NT AUTHORITY\ANONYMOUS user.

The first thing I would do there is find out if Kerb auth to SQL itself is
broken or whether the problem is just a function of delegation not working.
Connecting to SQL with a known good client that can do Kerb auth and
checking that audit would be a good way to start. It is possible that you
have an SPN problem in your directory related to SQL. This is especially
likely if you run SQL under an account other than System or Network Service
and did not explicitly set an SPN in AD on the actual account you used.

Is it ok for you to be authenticating to SQL as anonymous? That sort of
begs the question of why try to delegate in the first place.

Joe K.
 
J

Joe Kaplan

Just to summarize on this, can I confirm a few things that I'm still unclear
about:

- Is the IIS app pool account enabled for delegation in AD? If so, what
type of delegation?
- In the case where you see the anonymous user authentications in SQL, did
the authentication that came in to IIS use Kerberos or NTLM?
- Is the problem here just for this one particular user on this one
machine, or do you see it more often?
- With successful auths in SQL, do they all use Kerberos at both the SQL
and IIS tier?

It may be the case that using protocol transition can help you here. If the
problem is that your remoting client sometimes uses NTLM instead of
Kerberos, you can still get Kerberos delegation to work by enabling "allow
to delegate with any protocol" in AD. You will have to specify which
services you want to delegate to (just SQL and AD here unless there are
other things you didn't mention), but that is a good idea anyway.

Joe K.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top