473,396 Members | 1,724 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

What permission do I need to add a user to a group? (C#)

I am trying to determine all the groups which the current user has
permissions to add a member.

Here's my code:

foreach (System.DirectoryServices.SearchResult ADSearchres in
ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
ADChild = ADSearchres.GetDirectoryEntry();
foreach (ActiveDirectoryAccessRule ace in
ADChild.ObjectSecurity.GetAccessRules(true, true,
typeof(SecurityIdentifier)))
{
if
(System.Security.Principal.WindowsIdentity.GetCurr ent().Groups.Contains(ace.IdentityReference))
if (ace.AccessControlType ==
AccessControlType.Allow)
{
ActiveDirectoryRights rights =
ace.ActiveDirectoryRights;
if ((rights &
ActiveDirectoryRights.WriteProperty) ==
ActiveDirectoryRights.WriteProperty)
{
GroupListAddItem(ADChild);
break;
}

}
}

}

I had thougth that "ActiveDirectoryRights.WriteProperty" would have
been the one I wanted. When I do this with a limited access user,
though, it still lists all my groups :(

Suggestions? Help?

Brian Hampson
System Administrator, North America
ALS Laboratory Group, Environmental Division

Jul 23 '06 #1
9 5221
Do you need to look this up for an arbitrary user, or the current user who
is binding to the directory? If the former, there is a much easier way to
accomplish this. AD (and ADAM) have a constructed attribute called
"allowedAttributesEffective" which returns an array of strings listing all
the attributes on a given object that can be modified by the security
context that executed the search.

Essentially, you would just add "allowedAttributesEffective" to your
PropertiesToLoad and then read the result of it for each object in your
search results. If it contains the string "member", then you can change
group memberships.

If you must do this via the security descriptor, it is both slower and more
complex. A user might have rights to modify the membership via a variety of
different types of ACEs such as a property write ACE, a control access right
ACE for the "member" property set, a Full Control ACE, etc. It will be much
harder to get this right. :) If possible, I recommend using the
constructed attribute.

We have a few more details on this type of stuff in our book if you are
interested (ch 7 and 8).

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@75g2000cwc.googlegro ups.com...
>I am trying to determine all the groups which the current user has
permissions to add a member.

Here's my code:

foreach (System.DirectoryServices.SearchResult ADSearchres in
ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
ADChild = ADSearchres.GetDirectoryEntry();
foreach (ActiveDirectoryAccessRule ace in
ADChild.ObjectSecurity.GetAccessRules(true, true,
typeof(SecurityIdentifier)))
{
if
(System.Security.Principal.WindowsIdentity.GetCurr ent().Groups.Contains(ace.IdentityReference))
if (ace.AccessControlType ==
AccessControlType.Allow)
{
ActiveDirectoryRights rights =
ace.ActiveDirectoryRights;
if ((rights &
ActiveDirectoryRights.WriteProperty) ==
ActiveDirectoryRights.WriteProperty)
{
GroupListAddItem(ADChild);
break;
}

}
}

}

I had thougth that "ActiveDirectoryRights.WriteProperty" would have
been the one I wanted. When I do this with a limited access user,
though, it still lists all my groups :(

Suggestions? Help?

Brian Hampson
System Administrator, North America
ALS Laboratory Group, Environmental Division

Jul 23 '06 #2
Bingo! Thanks Joe! It still takes a long time to enumerate all the
groups for people that are Domain Admins, but it's quick and nice for
our HelpDesk staff now :)

Cheers!

Joe Kaplan (MVP - ADSI) wrote:
Do you need to look this up for an arbitrary user, or the current user who
is binding to the directory? If the former, there is a much easier way to
accomplish this. AD (and ADAM) have a constructed attribute called
"allowedAttributesEffective" which returns an array of strings listing all
the attributes on a given object that can be modified by the security
context that executed the search.

Essentially, you would just add "allowedAttributesEffective" to your
PropertiesToLoad and then read the result of it for each object in your
search results. If it contains the string "member", then you can change
group memberships.
Jul 24 '06 #3
Glad that helped. It is a useful trick. :) There is also
allowedChildClassesEffective if you want to know which objects a user can
create as a child of another object. The only thing you can't figure out
easily this way is which objects you can delete. :)

There isn't really any point of running this for a DA. DAs generally are
given full control over all objects and can typically take ownership of any
object that has that ACE removed, so there is no real way to prevent a DA
from modifying just about anything. You should always assume that DAs can
do anything they want to any object in the forest.

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m73g2000cwd.googlegr oups.com...
Bingo! Thanks Joe! It still takes a long time to enumerate all the
groups for people that are Domain Admins, but it's quick and nice for
our HelpDesk staff now :)

Cheers!

Joe Kaplan (MVP - ADSI) wrote:
>Do you need to look this up for an arbitrary user, or the current user
who
is binding to the directory? If the former, there is a much easier way
to
accomplish this. AD (and ADAM) have a constructed attribute called
"allowedAttributesEffective" which returns an array of strings listing
all
the attributes on a given object that can be modified by the security
context that executed the search.

Essentially, you would just add "allowedAttributesEffective" to your
PropertiesToLoad and then read the result of it for each object in your
search results. If it contains the string "member", then you can change
group memberships.

Jul 24 '06 #4
Here's the gist of what I've created (some might call it a monster)

Our environment had a number of domain admins (which we are now working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app that
will:

a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this last
bit of help for)

This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed COM,
reading the GC for email addresses, all fell apart. The last few weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all :)

Now, like I said, my only problem is that my DA's get a list of about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:

ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode) ;
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");

ADSearch.PropertiesToLoad.Add("allowedAttributesEf fective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult ADSearchres
in ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}

Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?

Joe Kaplan (MVP - ADSI) wrote:
There isn't really any point of running this for a DA. DAs generally are
given full control over all objects and can typically take ownership of any
object that has that ACE removed, so there is no real way to prevent a DA
from modifying just about anything. You should always assume that DAs can
do anything they want to any object in the forest.
Jul 24 '06 #5
I was really just trying to suggest that checking permissions for DA's
probably isn't that helpful. If you could, you might consider determining
if the user is a DA and not filtering your list if they are. You can do
this by getting the user's tokenGroups attribute and seeing if the DA group
SID is in there. You can also get this directly from the user's
WindowsIdentity.Groups property (which is probably easier).

In our environment with >150K users and ~80K groups, this performance hit
would really work. :) Neither would showing someone a list of 80K groups
though. :)

It is probably best to avoid doing queries that return
allowedAttributesEffective against many many objects, as that result is
fairly expensive for the DC to produce. However, if you are trying to trim
a list, it is hard not to use it.

A way to get much better perf would be to add your own attribute that
contains the DNs of groups that are allowed to use that particular group and
query against that. Then, of course, you need a way to keep the permissions
delegations in sync with the contents of that attribute, but your UI will be
much snappier and your DCs will be lest beaten up servicing that query.

It is weird that your helpdesk users can't search the GC. That should work
fine. Authenticated Users can typically query the GC, just like the
standard LDAP ports.

The rest of the stuff doesn't surprise me though. The way this kind of
thing is often implemented is using a trusted subsystem design, where your
client calls some server process that does have the credentials to perform
the required operations, but then provides its own authorization layer to
implement a role-based security mechanism. The role-based security
mechanism is often a PITA to build and test, but it can gain you a bunch of
important functionality. Some companies have whole products based on
providing role-based delegation of operations against AD, so you could also
consider buying something. :)

Best of luck with your solution. It sounds like you've made a lot of
progress. We have a book out there that might have helped you with some of
the stuff you are doing if you are interested.

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m73g2000cwd.googlegr oups.com...
Here's the gist of what I've created (some might call it a monster)

Our environment had a number of domain admins (which we are now working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app that
will:

a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this last
bit of help for)

This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed COM,
reading the GC for email addresses, all fell apart. The last few weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all :)

Now, like I said, my only problem is that my DA's get a list of about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:

ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode) ;
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");

ADSearch.PropertiesToLoad.Add("allowedAttributesEf fective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult ADSearchres
in ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}

Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?

Joe Kaplan (MVP - ADSI) wrote:
>There isn't really any point of running this for a DA. DAs generally are
given full control over all objects and can typically take ownership of
any
object that has that ACE removed, so there is no real way to prevent a DA
from modifying just about anything. You should always assume that DAs
can
do anything they want to any object in the forest.

Jul 24 '06 #6
Thanks Joe. I really appreciate all the tips. I had originally
planned on it being a "quick tool" and it has really grown. The reason
I wrote it is because I wanted to learn some AD programming, and make
my life easier. At least I got one of those two :)

The lines that caused the anonymous GC query were:

CDOEXM.IMailboxStore mailbox;
mailbox = (IMailboxStore)userentry.NativeObject;

mailbox.CreateMailbox(MailServerList.SelectedValue .ToString());
userentry.CommitChanges();

//Give Mailbox some properties, like email address.

userentry.Properties["mailNickname"].Add(iFname.Text + "." +
iLName.Text);

userentry.Properties["mail"].Add(ioemailaddress.Text +
emaildomain.Text);
userentry.CommitChanges();

The subsystem apparently makes the query as anon if you aren't an admin
(or something like that) Anon read access to GC and things were happy.

Joe Kaplan (MVP - ADSI) wrote:
I was really just trying to suggest that checking permissions for DA's
probably isn't that helpful. If you could, you might consider determining
if the user is a DA and not filtering your list if they are. You can do
this by getting the user's tokenGroups attribute and seeing if the DA group
SID is in there. You can also get this directly from the user's
WindowsIdentity.Groups property (which is probably easier).

In our environment with >150K users and ~80K groups, this performance hit
would really work. :) Neither would showing someone a list of 80K groups
though. :)

It is probably best to avoid doing queries that return
allowedAttributesEffective against many many objects, as that result is
fairly expensive for the DC to produce. However, if you are trying to trim
a list, it is hard not to use it.

A way to get much better perf would be to add your own attribute that
contains the DNs of groups that are allowed to use that particular group and
query against that. Then, of course, you need a way to keep the permissions
delegations in sync with the contents of that attribute, but your UI will be
much snappier and your DCs will be lest beaten up servicing that query.

It is weird that your helpdesk users can't search the GC. That should work
fine. Authenticated Users can typically query the GC, just like the
standard LDAP ports.

The rest of the stuff doesn't surprise me though. The way this kind of
thing is often implemented is using a trusted subsystem design, where your
client calls some server process that does have the credentials to perform
the required operations, but then provides its own authorization layer to
implement a role-based security mechanism. The role-based security
mechanism is often a PITA to build and test, but it can gain you a bunch of
important functionality. Some companies have whole products based on
providing role-based delegation of operations against AD, so you could also
consider buying something. :)

Best of luck with your solution. It sounds like you've made a lot of
progress. We have a book out there that might have helped you with some of
the stuff you are doing if you are interested.

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m73g2000cwd.googlegr oups.com...
Here's the gist of what I've created (some might call it a monster)

Our environment had a number of domain admins (which we are now working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app that
will:

a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this last
bit of help for)

This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed COM,
reading the GC for email addresses, all fell apart. The last few weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all :)

Now, like I said, my only problem is that my DA's get a list of about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:

ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode) ;
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");

ADSearch.PropertiesToLoad.Add("allowedAttributesEf fective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult ADSearchres
in ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}

Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?

Joe Kaplan (MVP - ADSI) wrote:
There isn't really any point of running this for a DA. DAs generally are
given full control over all objects and can typically take ownership of
any
object that has that ACE removed, so there is no real way to prevent a DA
from modifying just about anything. You should always assume that DAs
can
do anything they want to any object in the forest.
Jul 24 '06 #7
Ah, that is CDOEXM doing that. It is a terrible API and I hate it, but it
is also the only supported method for mailbox-enabling objects in Exchange.
Argh.

But yes, AD in 2003 doesn't allow anonymous queries (GC or LDAP port), so
that would cause a problem. Yet another reason to hate CDOEXM! The crappy
deployment model (install Exchange System Manager?!) and dependence on ADSI
integration (can't be used directly from LDAP) and other weird behaviors
with little value-add increase my loathing as well.

These "little" provisionings apps always do tend to get out of hand, don't
they? :)

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m79g2000cwm.googlegr oups.com...
Thanks Joe. I really appreciate all the tips. I had originally
planned on it being a "quick tool" and it has really grown. The reason
I wrote it is because I wanted to learn some AD programming, and make
my life easier. At least I got one of those two :)

The lines that caused the anonymous GC query were:

CDOEXM.IMailboxStore mailbox;
mailbox = (IMailboxStore)userentry.NativeObject;

mailbox.CreateMailbox(MailServerList.SelectedValue .ToString());
userentry.CommitChanges();

//Give Mailbox some properties, like email address.

userentry.Properties["mailNickname"].Add(iFname.Text + "." +
iLName.Text);

userentry.Properties["mail"].Add(ioemailaddress.Text +
emaildomain.Text);
userentry.CommitChanges();

The subsystem apparently makes the query as anon if you aren't an admin
(or something like that) Anon read access to GC and things were happy.

Joe Kaplan (MVP - ADSI) wrote:
>I was really just trying to suggest that checking permissions for DA's
probably isn't that helpful. If you could, you might consider
determining
if the user is a DA and not filtering your list if they are. You can do
this by getting the user's tokenGroups attribute and seeing if the DA
group
SID is in there. You can also get this directly from the user's
WindowsIdentity.Groups property (which is probably easier).

In our environment with >150K users and ~80K groups, this performance hit
would really work. :) Neither would showing someone a list of 80K
groups
though. :)

It is probably best to avoid doing queries that return
allowedAttributesEffective against many many objects, as that result is
fairly expensive for the DC to produce. However, if you are trying to
trim
a list, it is hard not to use it.

A way to get much better perf would be to add your own attribute that
contains the DNs of groups that are allowed to use that particular group
and
query against that. Then, of course, you need a way to keep the
permissions
delegations in sync with the contents of that attribute, but your UI will
be
much snappier and your DCs will be lest beaten up servicing that query.

It is weird that your helpdesk users can't search the GC. That should
work
fine. Authenticated Users can typically query the GC, just like the
standard LDAP ports.

The rest of the stuff doesn't surprise me though. The way this kind of
thing is often implemented is using a trusted subsystem design, where
your
client calls some server process that does have the credentials to
perform
the required operations, but then provides its own authorization layer to
implement a role-based security mechanism. The role-based security
mechanism is often a PITA to build and test, but it can gain you a bunch
of
important functionality. Some companies have whole products based on
providing role-based delegation of operations against AD, so you could
also
consider buying something. :)

Best of luck with your solution. It sounds like you've made a lot of
progress. We have a book out there that might have helped you with some
of
the stuff you are doing if you are interested.

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m73g2000cwd.googleg roups.com...
Here's the gist of what I've created (some might call it a monster)

Our environment had a number of domain admins (which we are now working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app that
will:

a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this last
bit of help for)

This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed COM,
reading the GC for email addresses, all fell apart. The last few weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all :)

Now, like I said, my only problem is that my DA's get a list of about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:

ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode) ;
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");

ADSearch.PropertiesToLoad.Add("allowedAttributesEf fective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult ADSearchres
in ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}

Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?

Joe Kaplan (MVP - ADSI) wrote:

There isn't really any point of running this for a DA. DAs generally
are
given full control over all objects and can typically take ownership
of
any
object that has that ACE removed, so there is no real way to prevent a
DA
from modifying just about anything. You should always assume that DAs
can
do anything they want to any object in the forest.

Jul 24 '06 #8
You took the words right out of my mouth. Perhaps .Net v4 or 5 will
have nice native implementations for these things that don't make you
jump through a few dozen hoops. 2.0 was a nice step up from 1.1 It's
got to keep getting better!

Thanks for all your tips. I've never been a big book fan, but from
what I've seen it looks like yours might make a nice addition to my
thin collection :)

Cheers!

B.
Joe Kaplan (MVP - ADSI) wrote:
Ah, that is CDOEXM doing that. It is a terrible API and I hate it, but it
is also the only supported method for mailbox-enabling objects in Exchange.
Argh.

But yes, AD in 2003 doesn't allow anonymous queries (GC or LDAP port), so
that would cause a problem. Yet another reason to hate CDOEXM! The crappy
deployment model (install Exchange System Manager?!) and dependence on ADSI
integration (can't be used directly from LDAP) and other weird behaviors
with little value-add increase my loathing as well.

These "little" provisionings apps always do tend to get out of hand, don't
they? :)

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m79g2000cwm.googlegr oups.com...
Thanks Joe. I really appreciate all the tips. I had originally
planned on it being a "quick tool" and it has really grown. The reason
I wrote it is because I wanted to learn some AD programming, and make
my life easier. At least I got one of those two :)

The lines that caused the anonymous GC query were:

CDOEXM.IMailboxStore mailbox;
mailbox = (IMailboxStore)userentry.NativeObject;

mailbox.CreateMailbox(MailServerList.SelectedValue .ToString());
userentry.CommitChanges();

//Give Mailbox some properties, like email address.

userentry.Properties["mailNickname"].Add(iFname.Text + "." +
iLName.Text);

userentry.Properties["mail"].Add(ioemailaddress.Text +
emaildomain.Text);
userentry.CommitChanges();

The subsystem apparently makes the query as anon if you aren't an admin
(or something like that) Anon read access to GC and things were happy.

Joe Kaplan (MVP - ADSI) wrote:
I was really just trying to suggest that checking permissions for DA's
probably isn't that helpful. If you could, you might consider
determining
if the user is a DA and not filtering your list if they are. You can do
this by getting the user's tokenGroups attribute and seeing if the DA
group
SID is in there. You can also get this directly from the user's
WindowsIdentity.Groups property (which is probably easier).

In our environment with >150K users and ~80K groups, this performance hit
would really work. :) Neither would showing someone a list of 80K
groups
though. :)

It is probably best to avoid doing queries that return
allowedAttributesEffective against many many objects, as that result is
fairly expensive for the DC to produce. However, if you are trying to
trim
a list, it is hard not to use it.

A way to get much better perf would be to add your own attribute that
contains the DNs of groups that are allowed to use that particular group
and
query against that. Then, of course, you need a way to keep the
permissions
delegations in sync with the contents of that attribute, but your UI will
be
much snappier and your DCs will be lest beaten up servicing that query.

It is weird that your helpdesk users can't search the GC. That should
work
fine. Authenticated Users can typically query the GC, just like the
standard LDAP ports.

The rest of the stuff doesn't surprise me though. The way this kind of
thing is often implemented is using a trusted subsystem design, where
your
client calls some server process that does have the credentials to
perform
the required operations, but then provides its own authorization layer to
implement a role-based security mechanism. The role-based security
mechanism is often a PITA to build and test, but it can gain you a bunch
of
important functionality. Some companies have whole products based on
providing role-based delegation of operations against AD, so you could
also
consider buying something. :)

Best of luck with your solution. It sounds like you've made a lot of
progress. We have a book out there that might have helped you with some
of
the stuff you are doing if you are interested.

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m73g2000cwd.googlegr oups.com...
Here's the gist of what I've created (some might call it a monster)

Our environment had a number of domain admins (which we are now working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app that
will:

a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this last
bit of help for)

This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed COM,
reading the GC for email addresses, all fell apart. The last few weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all :)

Now, like I said, my only problem is that my DA's get a list of about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:

ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode) ;
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");

ADSearch.PropertiesToLoad.Add("allowedAttributesEf fective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult ADSearchres
in ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}

Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?

Joe Kaplan (MVP - ADSI) wrote:

There isn't really any point of running this for a DA. DAs generally
are
given full control over all objects and can typically take ownership
of
any
object that has that ACE removed, so there is no real way to prevent a
DA
from modifying just about anything. You should always assume that DAs
can
do anything they want to any object in the forest.
Jul 24 '06 #9
Look for something they are calling the "Principal API" in the Orcas release
timeframe. They actually showed it at Tech Ed 3 years ago, but then moved
the release back.

The idea behind it is to provide wrappers around objects like Users and
Groups, but with a focus on provisioning and lifecycle instead of
authorization (like the current IPrincipal class). I think that may in fact
be called .NET 4.0 or 5.0 by then. :)

Whether or not Exchange provisioning will still suck or not will depend a
great deal on the Exchange team (and the version of Exchange you use), but I
don't have high hopes...

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11*********************@b28g2000cwb.googlegro ups.com...
You took the words right out of my mouth. Perhaps .Net v4 or 5 will
have nice native implementations for these things that don't make you
jump through a few dozen hoops. 2.0 was a nice step up from 1.1 It's
got to keep getting better!

Thanks for all your tips. I've never been a big book fan, but from
what I've seen it looks like yours might make a nice addition to my
thin collection :)

Cheers!

B.
Joe Kaplan (MVP - ADSI) wrote:
>Ah, that is CDOEXM doing that. It is a terrible API and I hate it, but
it
is also the only supported method for mailbox-enabling objects in
Exchange.
Argh.

But yes, AD in 2003 doesn't allow anonymous queries (GC or LDAP port), so
that would cause a problem. Yet another reason to hate CDOEXM! The
crappy
deployment model (install Exchange System Manager?!) and dependence on
ADSI
integration (can't be used directly from LDAP) and other weird behaviors
with little value-add increase my loathing as well.

These "little" provisionings apps always do tend to get out of hand,
don't
they? :)

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m79g2000cwm.googleg roups.com...
Thanks Joe. I really appreciate all the tips. I had originally
planned on it being a "quick tool" and it has really grown. The reason
I wrote it is because I wanted to learn some AD programming, and make
my life easier. At least I got one of those two :)

The lines that caused the anonymous GC query were:

CDOEXM.IMailboxStore mailbox;
mailbox = (IMailboxStore)userentry.NativeObject;

mailbox.CreateMailbox(MailServerList.SelectedValue .ToString());
userentry.CommitChanges();

//Give Mailbox some properties, like email address.

userentry.Properties["mailNickname"].Add(iFname.Text + "." +
iLName.Text);

userentry.Properties["mail"].Add(ioemailaddress.Text +
emaildomain.Text);
userentry.CommitChanges();

The subsystem apparently makes the query as anon if you aren't an admin
(or something like that) Anon read access to GC and things were happy.

Joe Kaplan (MVP - ADSI) wrote:
I was really just trying to suggest that checking permissions for DA's
probably isn't that helpful. If you could, you might consider
determining
if the user is a DA and not filtering your list if they are. You can
do
this by getting the user's tokenGroups attribute and seeing if the DA
group
SID is in there. You can also get this directly from the user's
WindowsIdentity.Groups property (which is probably easier).

In our environment with >150K users and ~80K groups, this performance
hit
would really work. :) Neither would showing someone a list of 80K
groups
though. :)

It is probably best to avoid doing queries that return
allowedAttributesEffective against many many objects, as that result
is
fairly expensive for the DC to produce. However, if you are trying to
trim
a list, it is hard not to use it.

A way to get much better perf would be to add your own attribute that
contains the DNs of groups that are allowed to use that particular
group
and
query against that. Then, of course, you need a way to keep the
permissions
delegations in sync with the contents of that attribute, but your UI
will
be
much snappier and your DCs will be lest beaten up servicing that
query.

It is weird that your helpdesk users can't search the GC. That should
work
fine. Authenticated Users can typically query the GC, just like the
standard LDAP ports.

The rest of the stuff doesn't surprise me though. The way this kind
of
thing is often implemented is using a trusted subsystem design, where
your
client calls some server process that does have the credentials to
perform
the required operations, but then provides its own authorization layer
to
implement a role-based security mechanism. The role-based security
mechanism is often a PITA to build and test, but it can gain you a
bunch
of
important functionality. Some companies have whole products based on
providing role-based delegation of operations against AD, so you could
also
consider buying something. :)

Best of luck with your solution. It sounds like you've made a lot of
progress. We have a book out there that might have helped you with
some
of
the stuff you are doing if you are interested.

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
--
"Brian Hampson" <br***********@gmail.comwrote in message
news:11**********************@m73g2000cwd.googleg roups.com...
Here's the gist of what I've created (some might call it a monster)

Our environment had a number of domain admins (which we are now
working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app
that
will:

a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on
OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this
last
bit of help for)

This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed
COM,
reading the GC for email addresses, all fell apart. The last few
weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all :)

Now, like I said, my only problem is that my DA's get a list of
about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:

ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode) ;
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");

ADSearch.PropertiesToLoad.Add("allowedAttributesEf fective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult
ADSearchres
in ADSearch.FindAll())
{

//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}

Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?

Joe Kaplan (MVP - ADSI) wrote:

There isn't really any point of running this for a DA. DAs
generally
are
given full control over all objects and can typically take
ownership
of
any
object that has that ACE removed, so there is no real way to
prevent a
DA
from modifying just about anything. You should always assume that
DAs
can
do anything they want to any object in the forest.


Jul 24 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Wayne Wengert | last post by:
I am using VS.NET 2003, VB.NET, ADO.NET and an Access 2000 database. I want to display a list of all tables in an Access database. I want to put that list of table names in a listbox so the user...
12
by: Russ | last post by:
Hello. My new dev machine is running XP Pro. In the past all equipment has only used Windows 2000. I have had a lot of problems getting my projects up and running on the new machine. The current...
3
by: Chua Wen Ching | last post by:
Hi there, I had applied this security permissions in my class library based on fxcop standards. Before namespace: using System.Runtime.InteropServices; using System.Security.Permissions;
2
by: Chen Zhuo | last post by:
Hi, I need to write some code to test whether a folder has read/write permission. The idea is to try to read sub-directories in this folder, if succeed, then test whether it's read-only. Any...
3
by: A P | last post by:
Do I need to give a read permission for "Everyone" on the WWWroot in order for me to use ASP.NET Code? I notice this when I only add the IUSR account of my machine to have change permission on the...
0
by: junis | last post by:
Dear All, if i want to change permission in Ms Access, i just follow this step 1. click "Tool" -> "Security" -> "User Group Permissions" 2. I choose User in Box User/Group Name then select...
3
by: jsamdirect | last post by:
I am having an issue with a Microsoft Access 2003 database that has forms designed to import data. When trying to do the import I get a message microsoft office access permission denied. This is...
1
by: akkha1234 | last post by:
When I click on the properties of a 2005 sql server database and then permissions. If I select a group and then effective permission, I got an error, saying that "cannot execute as the principal...
1
by: doctorhardik | last post by:
other interesting thing i observe during my work which i describe below: i am using dotproject2.0.4 on fc3. it is working fine. but i want to generate pdf file report during this time i face...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.