Stanford is looking at implementing groups into our LDAP servers, and in particular, looking at using slapo-dynlist. However, it does not behave as I expected it to.
Basically, it uses the credentials of whomever bound to determine the membership list. This means I would have to give access to a privileged attribute to those who wished to use groups, which is exactly what I'm trying to avoid. What I wanted to do, was specifically control the access to the group objects themselves. If an entity has access to the group object, they would then be able to see all current members of the group.
I believe this would mean adding functionality to slapo-dynlist to where it uses the rootdn to perform the internal search instead of the credentials. Would it be possible to have this sort of addition?
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
Stanford is looking at implementing groups into our LDAP servers, and in particular, looking at using slapo-dynlist. However, it does not behave as I expected it to.
Basically, it uses the credentials of whomever bound to determine the membership list. This means I would have to give access to a privileged attribute to those who wished to use groups, which is exactly what I'm trying to avoid. What I wanted to do, was specifically control the access to the group objects themselves. If an entity has access to the group object, they would then be able to see all current members of the group.
I believe this would mean adding functionality to slapo-dynlist to where it uses the rootdn to perform the internal search instead of the credentials. Would it be possible to have this sort of addition?
I'm not quite sure I understood what you mean. Are you going to use it for access control? Or do you want it to return the actual member list during a search? Can you describe further, and possibly post a sample conf+data, or at least a sketch of what you're trying to accomplish? As far as I can tell, slapo-dynlist(5) doesn't cope fine with ACLs as it is now...
p.
Ing. Pierangelo Masarati OpenLDAP Core Team
SysNet s.n.c. Via Dossi, 8 - 27100 Pavia - ITALIA http://www.sys-net.it ------------------------------------------ Office: +39.02.23998309 Mobile: +39.333.4963172 Email: pierangelo.masarati@sys-net.it ------------------------------------------
--On Thursday, January 11, 2007 5:25 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
I'm not quite sure I understood what you mean. Are you going to use it for access control? Or do you want it to return the actual member list during a search? Can you describe further, and possibly post a sample conf+data, or at least a sketch of what you're trying to accomplish? As far as I can tell, slapo-dynlist(5) doesn't cope fine with ACLs as it is now...
My intention is to be able to do something like:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu" by ldapadmins read by <somedn> compare
etc.
And yes, it is to be used for access control. The problem I have right now, is that to instantiate a dynamic group, I have to give <somedn> access to the attribute(s) being used in the filter to create the group, which is exactly what I need to avoid, due to HIPAA concerns.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
--On Friday, January 12, 2007 10:58 AM -0800 Quanah Gibson-Mount quanah@stanford.edu wrote:
--On Thursday, January 11, 2007 5:25 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
I'm not quite sure I understood what you mean. Are you going to use it for access control? Or do you want it to return the actual member list during a search? Can you describe further, and possibly post a sample conf+data, or at least a sketch of what you're trying to accomplish? As far as I can tell, slapo-dynlist(5) doesn't cope fine with ACLs as it is now...
My intention is to be able to do something like:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu"
This should read:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu" attrs=member
actually. ;)
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
My intention is to be able to do something like:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu"
This should read:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu" attrs=member
Try this patch (to HEAD as of now).
p.
Ing. Pierangelo Masarati OpenLDAP Core Team
SysNet s.n.c. Via Dossi, 8 - 27100 Pavia - ITALIA http://www.sys-net.it ------------------------------------------ Office: +39.02.23998309 Mobile: +39.333.4963172 Email: pierangelo.masarati@sys-net.it ------------------------------------------
Pierangelo Masarati wrote:
Quanah Gibson-Mount wrote:
My intention is to be able to do something like:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu"
This should read:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu" attrs=member
Try this patch (to HEAD as of now).
We already use is_auth_check in ACL checking, what is this is_acl_check flag for?
Howard Chu wrote:
Pierangelo Masarati wrote:
Quanah Gibson-Mount wrote:
My intention is to be able to do something like:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu"
This should read:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu" attrs=member
Try this patch (to HEAD as of now).
We already use is_auth_check in ACL checking, what is this is_acl_check flag for?
auth_check means that's an authorization check, which causes ACL_READ to be turned into ACL_AUTH; acl_check means that the acl checking is part of a search that's internal to ACL checking itself, not only for auth purposes, and thus deserves to be performed with rootdn identity. It's different.
p.
Ing. Pierangelo Masarati OpenLDAP Core Team
SysNet s.n.c. Via Dossi, 8 - 27100 Pavia - ITALIA http://www.sys-net.it ------------------------------------------ Office: +39.02.23998309 Mobile: +39.333.4963172 Email: pierangelo.masarati@sys-net.it ------------------------------------------
--On Friday, January 12, 2007 8:49 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Quanah Gibson-Mount wrote:
My intention is to be able to do something like:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu"
This should read:
access to dn.exact="cn=groupa,cn=groups,dc=stanford,dc=edu" attrs=member
Try this patch (to HEAD as of now).
No go... I have:
access to dn.exact="cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" attrs=member by dn.base="uid=cadabra,cn=accounts,dc=stanford,dc=edu" read by * none
(cadabra is my test account)
I get nothing back.
If I change it to:
access to dn.exact="cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" by dn.base="uid=cadabra,cn=accounts,dc=stanford,dc=edu" sasl_ssf=56 read by * none
I can see:
dn: cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu objectClass: groupOfURLs cn: registry-consult memberURL: ldap:///cn=people,dc=stanford,dc=edu??sub?(suprivilegegroup=registr y:consult)
(notice no membership)
If I search this with my normal id (quanah) which has full access, I get the listing + members.
debug level -1 shows:
[snip]
<==slap_sasl2dn: Converted SASL name to uid=cadabra,cn=accounts,dc=stanford,dc=edu slap_sasl_getdn: dn:id converted to uid=cadabra,cn=accounts,dc=stanford,dc=edu SASL Canonicalize [conn=0]: slapAuthcDN="uid=cadabra,cn=accounts,dc=stanford,dc=edu" SASL proxy authorize [conn=0]: authcid="cadabra@stanford.edu" authzid="cadabra@stanford.edu" conn=0 op=3 BIND authcid="cadabra@stanford.edu" authzid="cadabra@stanford.edu" SASL Authorize [conn=0]: proxy authorization allowed authzDN="" send_ldap_sasl: err=0 len=-1 conn=0 op=3 BIND dn="uid=cadabra,cn=accounts,dc=stanford,dc=edu" mech=GSSAPI ssf=56
conn=0 op=4 SRCH base="cn=groups,cn=applications,dc=stanford,dc=edu" scope=2 deref=0 filter="(cn=registry-consult)"
=> access_allowed: search access to "cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" "cn" requested
=> acl_mask: access to entry "cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu", attr "cn" requested => acl_mask: to value by "uid=cadabra,cn=accounts,dc=stanford,dc=edu", (=0) <= check a_dn_pat: uid=cadabra,cn=accounts,dc=stanford,dc=edu <= check a_authz.sai_sasl_ssf: ACL 56 > OP 56 <= acl_mask: [1] applying read(=rscxd) (stop) <= acl_mask: [1] mask: read(=rscxd) => slap_access_allowed: search access granted by read(=rscxd) => access_allowed: search access granted by read(=rscxd) <= test_filter 6 ldap_url_parse_ext(ldap:///cn=people,dc=stanford,dc=edu??sub?(suprivilegegroup=registry:consult))
dnPrettyNormal: <cn=people,dc=stanford,dc=edu>
=> ldap_bv2dn(cn=people,dc=stanford,dc=edu,0) <= ldap_bv2dn(cn=people,dc=stanford,dc=edu)=0 => ldap_dn2bv(272) <= ldap_dn2bv(cn=people,dc=stanford,dc=edu)=0 => ldap_dn2bv(272) <= ldap_dn2bv(cn=people,dc=stanford,dc=edu)=0 <<< dnPrettyNormal: <cn=people,dc=stanford,dc=edu>, <cn=people,dc=stanford,dc=edu> str2filter "(&(!(objectClass=groupOfURLs))(suprivilegegroup=registry:consult))" put_filter: "(&(!(objectClass=groupOfURLs))(suprivilegegroup=registry:consult))" put_filter: AND put_filter_list "(!(objectClass=groupOfURLs))(suprivilegegroup=registry:consult)" put_filter: "(!(objectClass=groupOfURLs))" put_filter: NOT put_filter_list "(objectClass=groupOfURLs)" put_filter: "(objectClass=groupOfURLs)" put_filter: simple put_simple_filter: "objectClass=groupOfURLs" put_filter: "(suprivilegegroup=registry:consult)" put_filter: simple put_simple_filter: "suprivilegegroup=registry:consult" begin get_filter AND begin get_filter_list begin get_filter NOT begin get_filter EQUALITY
search_candidates: base="cn=people,dc=stanford,dc=edu" (0x00000006) scope=2
Most importantly, as you can see here:
=> acl_mask: access to entry "suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu", attr "objectClass" requested => acl_mask: to value by "uid=cadabra,cn=accounts,dc=stanford,dc=edu", (=0)
[snip]
<= acl_mask: no more <who> clauses, returning =0 (stop) => slap_access_allowed: search access denied by =0 => access_allowed: no more rules
It is still using the "cadabra" credentials to find membership in the group, and not the internal rootdn.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
OK, in fact my test example was wrong, please disregard.
p.
Ing. Pierangelo Masarati OpenLDAP Core Team
SysNet s.n.c. Via Dossi, 8 - 27100 Pavia - ITALIA http://www.sys-net.it ------------------------------------------ Office: +39.02.23998309 Mobile: +39.333.4963172 Email: pierangelo.masarati@sys-net.it ------------------------------------------
It seems that your problem is caused by the fact that slapo-dynlist(5) implements compare on dynamically generated data by performing an internal search to collect info that before being used, or anyway accessed, will be subjected to further access control with the identity of the effective user. The reason an internal search is used in that case seems to be essentially related to code reuse, so slapo-dynlist(5) should be redesigned to avoid using internal searches in those circumstances, so that the correct access privilege is assessed (e.g. compare vs. search/read). Using the rootdn to generate the list, and then check access to the list itself may not be correct, because the dynamic list could become a means to circumvent access control to the actual data; think of a case where the effective user has no privileges on the actual data, but has compare, or even read access to the dynamically generated list. Then, if the list were generated as rootdn, the user would be able to compare, or even read, on data that is a derivative of otherwise inaccessible data. I would consider this a violation of data integrity.
The attached patch modifies ACL code such that the access privilege to be used can be specified (e.g. adding a o_acl_priv which is used for all checking if != ACL_NONE. I picked ACL_NONE because it's zero; ACL_INVALID_ACCESS would be more appropriate, but then we'd need to initialize all Operation structures...)
p.
Ing. Pierangelo Masarati OpenLDAP Core Team
SysNet s.n.c. Via Dossi, 8 - 27100 Pavia - ITALIA http://www.sys-net.it ------------------------------------------ Office: +39.02.23998309 Mobile: +39.333.4963172 Email: pierangelo.masarati@sys-net.it ------------------------------------------
--On Saturday, January 13, 2007 11:03 AM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Using the rootdn to generate the list, and then check access to the list itself may not be correct, because the dynamic list could become a means to circumvent access control to the actual data; think of a case where the effective user has no privileges on the actual data, but has compare, or even read access to the dynamically generated list. Then, if the list were generated as rootdn, the user would be able to compare, or even read, on data that is a derivative of otherwise inaccessible data. I would consider this a violation of data integrity.
Well, I think you are not considering the scenario that I have. Let's assume you have an attribute (privgroup) that contains information about all the groups particular people may be in. People can be in many hundreds to thousands of groups. Any person can create a group, and add other people to those groups. Now, you have doctors involved, who do patient studies. So lets say the doctor creates a priv group for an AIDS study they are doing. So some number of people now have privgroup=drnefarious:aids-patients as a value.
So now, we want to implement groups. We can either (a) convert all of the privgroup information into static groups, or (b) convert all of the privgroup information into dynamic groups. Since we already have the information in an attribute, creating dynamic groups seems the best way to do this. Imagine my surprise that doing so meant I'd have to give access to the privgroup attribute to the end user, since that is exactly what I want to avoid for security & legal reasons.
You think of it as a derivative of otherwise inaccessible data, while I think of it as giving them access to large amounts of data they shouldn't have access to, which to me is a violation of data integrity. I want them to only access what specifically I say they can. Just because the dynamic group is extrapolated from another attribute's value, does not mean that the end user should be given wholesale access (compare or read) to every value that attribute has. They get to see, and only see, the memberships of the groups they get access to.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
--On Saturday, January 13, 2007 1:36 PM -0800 Quanah Gibson-Mount quanah@stanford.edu wrote:
--On Saturday, January 13, 2007 11:03 AM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Using the rootdn to generate the list, and then check access to the list itself may not be correct, because the dynamic list could become a means to circumvent access control to the actual data; think of a case where the effective user has no privileges on the actual data, but has compare, or even read access to the dynamically generated list. Then, if the list were generated as rootdn, the user would be able to compare, or even read, on data that is a derivative of otherwise inaccessible data. I would consider this a violation of data integrity.
Oh, and much thanks for the patch. :) I'll give it a try here soon. ;)
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
--On Saturday, January 13, 2007 11:03 AM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Using the rootdn to generate the list, and then check access to the list itself may not be correct, because the dynamic list could become a means to circumvent access control to the actual data; think of a case where the effective user has no privileges on the actual data, but has compare, or even read access to the dynamically generated list. Then, if the list were generated as rootdn, the user would be able to compare, or even read, on data that is a derivative of otherwise inaccessible data. I would consider this a violation of data integrity.
Well, I think you are not considering the scenario that I have. Let's assume you have an attribute (privgroup) that contains information about all the groups particular people may be in. People can be in many hundreds to thousands of groups. Any person can create a group, and add other people to those groups. Now, you have doctors involved, who do patient studies. So lets say the doctor creates a priv group for an AIDS study they are doing. So some number of people now have privgroup=drnefarious:aids-patients as a value.
So now, we want to implement groups. We can either (a) convert all of the privgroup information into static groups, or (b) convert all of the privgroup information into dynamic groups. Since we already have the information in an attribute, creating dynamic groups seems the best way to do this. Imagine my surprise that doing so meant I'd have to give access to the privgroup attribute to the end user, since that is exactly what I want to avoid for security & legal reasons.
You think of it as a derivative of otherwise inaccessible data, while I think of it as giving them access to large amounts of data they shouldn't have access to, which to me is a violation of data integrity. I want them to only access what specifically I say they can. Just because the dynamic group is extrapolated from another attribute's value, does not mean that the end user should be given wholesale access (compare or read) to every value that attribute has. They get to see, and only see, the memberships of the groups they get access to.
You seem to be under the impression that changing the name of a piece of data changes the nature of the data. If you have an attribute that general users should not be able to see, then they also should not be able to see the dynamic group derived from that attribute. Opening it up in any way is only going to open you to the same liability you claim to want to avoid.
--On Saturday, January 13, 2007 1:47 PM -0800 Howard Chu hyc@symas.com wrote:
You seem to be under the impression that changing the name of a piece of data changes the nature of the data. If you have an attribute that general users should not be able to see, then they also should not be able to see the dynamic group derived from that attribute. Opening it up in any way is only going to open you to the same liability you claim to want to avoid.
Please explain to me how they would see dynamic groups I haven't given them access to via acl control.
This:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attrs=privgroup by USER compare
Is much worse than
access to dn.exact="cn=usergroup,cn=groups,dc=stanford,dc=edu" by USER compare
I don't in any way intend to let people see groups they don't have access to *but* if I have to use the user credentials to create groups, that's essentially the position I'm forced into unless I want to make thousands and thousands of ACL's like:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attrs=privgroup val.regex="user-group-a" by * compare
Which is something I definitely want to avoid.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
--On Saturday, January 13, 2007 1:55 PM -0800 Quanah Gibson-Mount quanah@stanford.edu wrote:
--On Saturday, January 13, 2007 1:47 PM -0800 Howard Chu hyc@symas.com wrote:
You seem to be under the impression that changing the name of a piece of data changes the nature of the data. If you have an attribute that general users should not be able to see, then they also should not be able to see the dynamic group derived from that attribute. Opening it up in any way is only going to open you to the same liability you claim to want to avoid.
Please explain to me how they would see dynamic groups I haven't given them access to via acl control.
This:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attrs=privgroup by USER compare
Is much worse than
access to dn.exact="cn=usergroup,cn=groups,dc=stanford,dc=edu" by USER compare
I don't in any way intend to let people see groups they don't have access to *but* if I have to use the user credentials to create groups, that's essentially the position I'm forced into unless I want to make thousands and thousands of ACL's like:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attrs=privgroup val.regex="user-group-a" by * compare
s/*/USER
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
--On Saturday, January 13, 2007 1:47 PM -0800 Howard Chu hyc@symas.com wrote:
You seem to be under the impression that changing the name of a piece of data changes the nature of the data. If you have an attribute that general users should not be able to see, then they also should not be able to see the dynamic group derived from that attribute. Opening it up in any way is only going to open you to the same liability you claim to want to avoid.
Please explain to me how they would see dynamic groups I haven't given them access to via acl control.
Please explain how those dynamic groups have any relevance to them if they are not members of the group.
You asked for the ability to use rootdn privileges to evaluate the membership of a dynamic group because the user on whose behalf you are evaluating may not have access to evaluate the membership.
This makes no sense. If the user doesn't have access to evaluate the membership, then clearly the user doesn't have the values that determine membership in the group - thus the user is not a member, so the actual membership of that group is a moot point.
I don't in any way intend to let people see groups they don't have access to *but* if I have to use the user credentials to create groups, that's essentially the position I'm forced into unless I want to make thousands and thousands of ACL's like:
The only reason to use root privilege to evaluate the group membership is to make the member list visible where it otherwise would not be. If you're claiming that the member list is sensitive information, and should not be visible to non-members, then all this does is break your security.
--On Saturday, January 13, 2007 2:07 PM -0800 Howard Chu hyc@symas.com wrote:
Quanah Gibson-Mount wrote:
--On Saturday, January 13, 2007 1:47 PM -0800 Howard Chu hyc@symas.com wrote:
You seem to be under the impression that changing the name of a piece of data changes the nature of the data. If you have an attribute that general users should not be able to see, then they also should not be able to see the dynamic group derived from that attribute. Opening it up in any way is only going to open you to the same liability you claim to want to avoid.
Please explain to me how they would see dynamic groups I haven't given them access to via acl control.
Please explain how those dynamic groups have any relevance to them if they are not members of the group.
You asked for the ability to use rootdn privileges to evaluate the membership of a dynamic group because the user on whose behalf you are evaluating may not have access to evaluate the membership.
This makes no sense. If the user doesn't have access to evaluate the membership, then clearly the user doesn't have the values that determine membership in the group - thus the user is not a member, so the actual membership of that group is a moot point.
Well, here's an example of why:
I have an application, say "cgi.stanford.edu". cgi.stanford.edu connects to the LDAP servers with "service/cgi@stanford.edu" as its principal. That is mapped to an entry in the "cn=service,cn=applications,dc=stanford,dc=edu" tree. It has no entries in the person tree, and it belongs to no groups. "userA" comes along to access a CGI script that is restricted to only members of a particular group. The CGI servers are now going to query the group to see if "userA" is a member of that group.
Or, in another case.
I have an application, that is perhaps running on "cgi.stanford.edu". It will use my CGI principal's credentials to connecto to the LDAP Servers with "cgi/quanah@stanford.edu" as its principal. That is mapped to an entry in the "cn=cgi,cn=applications,dc=stanford,dc=edu" tree. It has no entries in the person tree, and it belongs to no groups. "userA" comes along to run the script, and I want to see which of the different groups I have they belong to. The script is now going to bind to the LDAP server as itself, and see if "userA" is a member of several different groups.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah,
you don't have to go through many examples --- your problem is clear and well posed. It's the solution: if the user has enough privilege to check membership but, for implementation-related reasons, the software requires higher privileges while gathering data, the solution is not to hack the software raising the privileges of whom does internal data gathering, because that would gather also data the user wouldn't be allowed to check.
The solution rather consists in making the software require as much privilege as actually required for the actual operation, anything more anything less, even during internal operations used to gather the data. The software was using an internal search as is, i.e. requiring "search" on the filter and "read" on the data while actually gathering data for a "compare", and the software was wrong (I guess there are many more places where internal searches are used like that, sigh). The fix is making the software require "compare" in all those phases, since as soon as they're a mere technicalism to gather data for a compare, that's the privilege they should require.
p.
Ing. Pierangelo Masarati OpenLDAP Core Team
SysNet s.n.c. Via Dossi, 8 - 27100 Pavia - ITALIA http://www.sys-net.it ------------------------------------------ Office: +39.02.23998309 Mobile: +39.333.4963172 Email: pierangelo.masarati@sys-net.it ------------------------------------------
--On Saturday, January 13, 2007 11:03 AM +0100 Pierangelo Masarati ando@sys-net.it wrote:
It seems that your problem is caused by the fact that slapo-dynlist(5) implements compare on dynamically generated data by performing an internal search to collect info that before being used, or anyway accessed, will be subjected to further access control with the identity of the effective user. The reason an internal search is used in that case seems to be essentially related to code reuse, so slapo-dynlist(5) should be redesigned to avoid using internal searches in those circumstances, so that the correct access privilege is assessed (e.g. compare vs. search/read). Using the rootdn to generate the list, and then check access to the list itself may not be correct, because the dynamic list could become a means to circumvent access control to the actual data; think of a case where the effective user has no privileges on the actual data, but has compare, or even read access to the dynamically generated list. Then, if the list were generated as rootdn, the user would be able to compare, or even read, on data that is a derivative of otherwise inaccessible data. I would consider this a violation of data integrity.
The attached patch modifies ACL code such that the access privilege to be used can be specified (e.g. adding a o_acl_priv which is used for all checking if != ACL_NONE. I picked ACL_NONE because it's zero; ACL_INVALID_ACCESS would be more appropriate, but then we'd need to initialize all Operation structures...)
This patch also does not work, continuing to use the credentials of the bound user.
=> acl_mask: access to entry "suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu", attr "suPrivilegeGroup" requested => acl_mask: to value by "uid=cadabra,cn=accounts,dc=stanford,dc=edu", (=0) <= check a_set_pat: this/uid & user/uid
dnNormalize:
<suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu> => ldap_bv2dn(suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu,0) <= ldap_bv2dn(suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu)=0 => ldap_dn2bv(272) <= ldap_dn2bv(suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu)=0 <<< dnNormalize: <suRegID=000648cb784048849a1573566ffe0ef8,cn=people,dc=stanford,dc=edu>
dnNormalize: <uid=cadabra,cn=accounts,dc=stanford,dc=edu>
=> ldap_bv2dn(uid=cadabra,cn=accounts,dc=stanford,dc=edu,0) <= ldap_bv2dn(uid=cadabra,cn=accounts,dc=stanford,dc=edu)=0 => ldap_dn2bv(272) <= ldap_dn2bv(uid=cadabra,cn=accounts,dc=stanford,dc=edu)=0 <<< dnNormalize: <uid=cadabra,cn=accounts,dc=stanford,dc=edu> => bdb_entry_get: ndn: "uid=cadabra,cn=accounts,dc=stanford,dc=edu" => bdb_entry_get: oc: "(null)", at: "uid" bdb_dn2entry("uid=cadabra,cn=accounts,dc=stanford,dc=edu") => bdb_entry_get: found entry: "uid=cadabra,cn=accounts,dc=stanford,dc=edu" bdb_entry_get: rc=0 <= acl_mask: no more <who> clauses, returning =0 (stop) => slap_access_allowed: search access denied by =0 => access_allowed: no more rules
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
--On January 16, 2007 6:34:39 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Quanah Gibson-Mount wrote:
This patch also does not work, continuing to use the credentials of the bound user.
What operation are you performing when it gets to evaluate that filter? Can you describe it a little bit further?
ldapsearch -LLL -Q -h ldap-dev1 -b "cn=groups,cn=applications,dc=stanford,dc=edu" cn=registry-consult
Output is:
dn: cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu objectClass: groupOfURLs cn: registry-consult memberURL: ldap:///cn=people,dc=stanford,dc=edu??sub?(suprivilegegroup=registr y:consult)
(but no members). Searching with my admin credentials, I get a full user list.
access to dn.exact="cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" by dn.base="uid=cadabra,cn=accounts,dc=stanford,dc=edu" sasl_ssf=56 read by * none
is the ACL in place (admin group comes before this acl with full read to everything in the tree).
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
--On January 16, 2007 6:34:39 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Quanah Gibson-Mount wrote:
This patch also does not work, continuing to use the credentials of the bound user.
What operation are you performing when it gets to evaluate that filter? Can you describe it a little bit further?
ldapsearch -LLL -Q -h ldap-dev1 -b "cn=groups,cn=applications,dc=stanford,dc=edu" cn=registry-consult
Output is:
dn: cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu objectClass: groupOfURLs cn: registry-consult memberURL: ldap:///cn=people,dc=stanford,dc=edu??sub?(suprivilegegroup=registr y:consult)
(but no members). Searching with my admin credentials, I get a full user list.
access to dn.exact="cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu"
by dn.base="uid=cadabra,cn=accounts,dc=stanford,dc=edu"
sasl_ssf=56 read by * none
is the ACL in place (admin group comes before this acl with full read to everything in the tree).
The last patch I sent you was not addressing this issue. In this case, I believe the software is behaving as expected, according to the discussion in http://www.openldap.org/lists/openldap-devel/200701/msg00056.html. What the patch should give you, is the capability to compare the "member" of the dynlist, assuming the identity you use has "compare" privs on the attributes in the URL's filter. Would this be of help? In any case, could you try it?
p.
--On Tuesday, January 16, 2007 7:48 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
is the ACL in place (admin group comes before this acl with full read to everything in the tree).
The last patch I sent you was not addressing this issue. In this case, I believe the software is behaving as expected, according to the discussion in http://www.openldap.org/lists/openldap-devel/200701/msg00056.html. What the patch should give you, is the capability to compare the "member" of the dynlist, assuming the identity you use has "compare" privs on the attributes in the URL's filter. Would this be of help? In any case, could you try it?
I will try it, but it is not of help.
The problem here, is that we are approaching things from different viewpoints. In your viewpoint, the user requesting access is or should be a member of the group, and therefore, really only needs compare to know if it is or isn't. You've apparently extended that some (?) to allow it to see if others "compare" to be members of the group.
In my viewpoint, the user requesting access is in no way actually associated with the group. It is an external application deciding multiple things. It may (a) be deciding if its users should have access (in which compare is sufficient), or (b) deciding whether or not to *list* the membership of the group.
This secondary approach obviously works just fine for static groups, and to make dynamic groups behave differently means that one cannot depend on "group" behavior as being consistent, which for me is extremely problematic, as my applications should not need to "know" whether or not the group was implemented statically or dynamically. See:
http://www.openldap.org/lists/openldap-devel/200701/msg00054.html http://www.openldap.org/lists/openldap-devel/200701/msg00055.html
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
--On Tuesday, January 16, 2007 11:36 AM -0800 Quanah Gibson-Mount quanah@stanford.edu wrote:
I will try it, but it is not of help.
And this does work:
ldapcompare -Q -h ldap-dev1 "cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" "member:suRegID=ff44e0a6e76a11d1a28c2436000baa77,cn=people,dc=stanford,dc=edu" TRUE
so that fixes half my problem. ;)
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
--On Tuesday, January 16, 2007 11:36 AM -0800 Quanah Gibson-Mount quanah@stanford.edu wrote:
I will try it, but it is not of help.
And this does work:
ldapcompare -Q -h ldap-dev1 "cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" "member:suRegID=ff44e0a6e76a11d1a28c2436000baa77,cn=people,dc=stanford,dc=edu"
TRUE
so that fixes half my problem. ;)
Great. For the listing, honestly I remain on my positions. A possible exception, which would probably solve your problem and at the same time not hinder what access is being applied to data is to design a new access privilege that means something like "disclose to internal operations". This would need to be explicitly added to data that one wants to be accessible by internal operations but not directly by regular ops, like in your case. What I don't like of this access privilege is that it's too generic: it doesn't allow to tell what an internal operation would do with that data. For example, an internal operation may want to modify it, or give it away or so. Note that I have no idea (nor intention: I still remember how much I had to sweat to add "add" and "zap" privileges!) of how to implement it, right now.
p.
Pierangelo Masarati wrote:
Great. For the listing, honestly I remain on my positions. A possible exception, which would probably solve your problem and at the same time not hinder what access is being applied to data is to design a new access privilege that means something like "disclose to internal operations". This would need to be explicitly added to data that one wants to be accessible by internal operations but not directly by regular ops, like in your case. What I don't like of this access privilege is that it's too generic: it doesn't allow to tell what an internal operation would do with that data. For example, an internal operation may want to modify it, or give it away or so. Note that I have no idea (nor intention: I still remember how much I had to sweat to add "add" and "zap" privileges!) of how to implement it, right now.
Another approach may be to view the dyngroup overlay as a proxy, and just configure an identity for it to use. So you can explicitly give it access to whatever attributes it needs to see.
--On Tuesday, January 16, 2007 2:03 PM -0800 Howard Chu hyc@symas.com wrote:
Pierangelo Masarati wrote:
Great. For the listing, honestly I remain on my positions. A possible exception, which would probably solve your problem and at the same time not hinder what access is being applied to data is to design a new access privilege that means something like "disclose to internal operations". This would need to be explicitly added to data that one wants to be accessible by internal operations but not directly by regular ops, like in your case. What I don't like of this access privilege is that it's too generic: it doesn't allow to tell what an internal operation would do with that data. For example, an internal operation may want to modify it, or give it away or so. Note that I have no idea (nor intention: I still remember how much I had to sweat to add "add" and "zap" privileges!) of how to implement it, right now.
Another approach may be to view the dyngroup overlay as a proxy, and just configure an identity for it to use. So you can explicitly give it access to whatever attributes it needs to see.
This would certainly work for me, and is I think, what I was trying to ask for originally, except I said the rootdn, when I should have said a proxy ID. ;) Then I could just add
access to suprivilegroup by dyngroupID compare
and be happy.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
Another approach may be to view the dyngroup overlay as a proxy, and just configure an identity for it to use. So you can explicitly give it access to whatever attributes it needs to see.
This would certainly work for me, and is I think, what I was trying to ask for originally, except I said the rootdn, when I should have said a proxy ID. ;) Then I could just add
access to suprivilegroup by dyngroupID compare
and be happy.
This already you have now in HEAD. I fear you'd rather need to add
access to suprivilegroup by dyngroupID __READ__
and be (un)happy...
p.
--On Thursday, January 18, 2007 7:59 AM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Quanah Gibson-Mount wrote:
Another approach may be to view the dyngroup overlay as a proxy, and just configure an identity for it to use. So you can explicitly give it access to whatever attributes it needs to see.
This would certainly work for me, and is I think, what I was trying to ask for originally, except I said the rootdn, when I should have said a proxy ID. ;) Then I could just add
access to suprivilegroup by dyngroupID compare
and be happy.
This already you have now in HEAD. I fear you'd rather need to add
access to suprivilegroup by dyngroupID __READ__
and be (un)happy...
Why would it need read? The acl's should be something like:
access to group by uid=a read by uid=b compare
access to other group by uid=c read
etc
and then in dynlist, I supply a proxy ID that is used internally to do the comparisons to generate the membership. Then only that proxy ID needs to do any sort of internal lookups. The initial user's credentials are still used with the ACLs to see what, if anything, they can do with the generated information.
Something perhaps like:
overlay dynlist
dynlist-proxyID cn=dynlist
Then in my ACL's as well:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attr=suprivilegegroup by dn.base="cn=dynlist" compare
--Quanah
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
This would certainly work for me, and is I think, what I was trying to ask for originally, except I said the rootdn, when I should have said a proxy ID. ;) Then I could just add
access to suprivilegroup by dyngroupID compare
and be happy.
This already you have now in HEAD. I fear you'd rather need to add
access to suprivilegroup by dyngroupID __READ__
and be (un)happy...
Why would it need read? The acl's should be something like:
because dynlist uses an internal search, and an internal search need "search" on filter attrs and "read" on attributes to be returned. This before ITS#4806 enhancement.
access to group by uid=a read by uid=b compare
access to other group by uid=c read
etc
and then in dynlist, I supply a proxy ID that is used internally to do the comparisons to generate the membership. Then only that proxy ID needs to do any sort of internal lookups. The initial user's credentials are still used with the ACLs to see what, if anything, they can do with the generated information.
Something perhaps like:
overlay dynlist
dynlist-proxyID cn=dynlist
Then in my ACL's as well:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attr=suprivilegegroup by dn.base="cn=dynlist" compare
After ITS#4806 enhancement, "compare" would be enough, if the proxy ID is implemented. At this point, the proxy ID could be contained in the entry itself, to allow more granular, data driven identity selection. A mechanism like authzFrom could be used to select who's authorized to assume the proxy ID and thus to get to override access rule to the hidden data. Something like:
<dynamic group>: <static members>, (<dynamic members> + <authzFrom>)
when reading <dynamic group>, static members undergo usual ACLs; dynamic members undergo usual ACLs for their direct access; plus, if the client's identity complies with the <authzFrom> rule, the <dynamic group> identity is assumed to perform dynamic group expansion, otherwise the client's identity is used.
To simplify things, we could well recycle authzFrom to check if the client is authorized to use the dynamic group's identity, and, in case, let the client assume the privileged identity by using the dynamic group's DN.
Or, we could define /configurable) dynamic group specific attrs that implement the dynamic group's identity (groupManager?) and authorization rules (groupAuthzFrom?; groupAuthzTo would make sense as well; it could be used to check if a dynamic group is allowed to let a user assume the privileged identity when accessing a certain datum, the "to" of groupAuthzTo).
p.
--On Saturday, January 20, 2007 4:09 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attr=suprivilegegroup by dn.base="cn=dynlist" compare
After ITS#4806 enhancement, "compare" would be enough, if the proxy ID is implemented. At this point, the proxy ID could be contained in the entry itself, to allow more granular, data driven identity selection. A mechanism like authzFrom could be used to select who's authorized to assume the proxy ID and thus to get to override access rule to the hidden data. Something like:
<dynamic group>: <static members>, (<dynamic members> + <authzFrom>)
when reading <dynamic group>, static members undergo usual ACLs; dynamic members undergo usual ACLs for their direct access; plus, if the client's identity complies with the <authzFrom> rule, the <dynamic group> identity is assumed to perform dynamic group expansion, otherwise the client's identity is used.
To simplify things, we could well recycle authzFrom to check if the client is authorized to use the dynamic group's identity, and, in case, let the client assume the privileged identity by using the dynamic group's DN.
Or, we could define /configurable) dynamic group specific attrs that implement the dynamic group's identity (groupManager?) and authorization rules (groupAuthzFrom?; groupAuthzTo would make sense as well; it could be used to check if a dynamic group is allowed to let a user assume the privileged identity when accessing a certain datum, the "to" of groupAuthzTo).
I guess my issue here, is that I want the proxy ID to not be associated with the client's ID at all. I simply want a way to have the dynamic group to use the ACL's to decide whether or not the client has read or compare to the membership list, and if it does, then to use an internal identity that knows nothing about the client itself to do the compare or membership generation as necessary. So I guess the second solution would work best in that case?
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Quanah Gibson-Mount wrote:
--On Saturday, January 20, 2007 4:09 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attr=suprivilegegroup by dn.base="cn=dynlist" compare
After ITS#4806 enhancement, "compare" would be enough, if the proxy ID is implemented. At this point, the proxy ID could be contained in the entry itself, to allow more granular, data driven identity selection. A mechanism like authzFrom could be used to select who's authorized to assume the proxy ID and thus to get to override access rule to the hidden data. Something like:
<dynamic group>: <static members>, (<dynamic members> + <authzFrom>)
when reading <dynamic group>, static members undergo usual ACLs; dynamic members undergo usual ACLs for their direct access; plus, if the client's identity complies with the <authzFrom> rule, the <dynamic group> identity is assumed to perform dynamic group expansion, otherwise the client's identity is used.
To simplify things, we could well recycle authzFrom to check if the client is authorized to use the dynamic group's identity, and, in case, let the client assume the privileged identity by using the dynamic group's DN.
Or, we could define /configurable) dynamic group specific attrs that implement the dynamic group's identity (groupManager?) and authorization rules (groupAuthzFrom?; groupAuthzTo would make sense as well; it could be used to check if a dynamic group is allowed to let a user assume the privileged identity when accessing a certain datum, the "to" of groupAuthzTo).
I guess my issue here, is that I want the proxy ID to not be associated with the client's ID at all. I simply want a way to have the dynamic group to use the ACL's to decide whether or not the client has read or compare to the membership list, and if it does, then to use an internal identity that knows nothing about the client itself to do the compare or membership generation as necessary. So I guess the second solution would work best in that case?
Well, mine was basically a suggestion to make things more finely tunable; of course, a safe default would be, for example, if no dynamic group exploitation authorization were defined, to allow users to use the dynlist and to deny anonymous. The latter could be enabled by setting groupAuthzFrom to "*" (shortcut for "dn.regex:.*").
So, in the end you would have what you need, while the feature could be restricted as needed.
p.
--On Monday, January 22, 2007 10:22 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
Quanah Gibson-Mount wrote:
--On Saturday, January 20, 2007 4:09 PM +0100 Pierangelo Masarati ando@sys-net.it wrote:
access to dn.subtree="cn=people,dc=stanford,dc=edu" attr=suprivilegegroup by dn.base="cn=dynlist" compare
After ITS#4806 enhancement, "compare" would be enough, if the proxy ID is implemented. At this point, the proxy ID could be contained in the entry itself, to allow more granular, data driven identity selection. A mechanism like authzFrom could be used to select who's authorized to assume the proxy ID and thus to get to override access rule to the hidden data. Something like:
<dynamic group>: <static members>, (<dynamic members> + <authzFrom>)
when reading <dynamic group>, static members undergo usual ACLs; dynamic members undergo usual ACLs for their direct access; plus, if the client's identity complies with the <authzFrom> rule, the <dynamic group> identity is assumed to perform dynamic group expansion, otherwise the client's identity is used.
To simplify things, we could well recycle authzFrom to check if the client is authorized to use the dynamic group's identity, and, in case, let the client assume the privileged identity by using the dynamic group's DN.
Or, we could define /configurable) dynamic group specific attrs that implement the dynamic group's identity (groupManager?) and authorization rules (groupAuthzFrom?; groupAuthzTo would make sense as well; it could be used to check if a dynamic group is allowed to let a user assume the privileged identity when accessing a certain datum, the "to" of groupAuthzTo).
I guess my issue here, is that I want the proxy ID to not be associated with the client's ID at all. I simply want a way to have the dynamic group to use the ACL's to decide whether or not the client has read or compare to the membership list, and if it does, then to use an internal identity that knows nothing about the client itself to do the compare or membership generation as necessary. So I guess the second solution would work best in that case?
Well, mine was basically a suggestion to make things more finely tunable; of course, a safe default would be, for example, if no dynamic group exploitation authorization were defined, to allow users to use the dynlist and to deny anonymous. The latter could be enabled by setting groupAuthzFrom to "*" (shortcut for "dn.regex:.*").
So, in the end you would have what you need, while the feature could be restricted as needed.
Sounds great to me. Of course, in my case, since my ACL's deny access to anonymous to the group entry, they wouldn't see it anyhow. ;) Although I probably will have some groups that are world readable, which is part of why I'd want an internal identity with the right authority to lookup against the attribute rather than anon.
--Quanah
-- Quanah Gibson-Mount Principal Software Developer ITS/Shared Application Services Stanford University GnuPG Public Key: http://www.stanford.edu/~quanah/pgp.html
Pierangelo Masarati wrote:
Quanah Gibson-Mount wrote:
--On Saturday, January 20, 2007 4:09 PM +0100 Pierangelo Masarati
Or, we could define /configurable) dynamic group specific attrs that implement the dynamic group's identity (groupManager?) and authorization rules (groupAuthzFrom?; groupAuthzTo would make sense as well; it could be used to check if a dynamic group is allowed to let a user assume the privileged identity when accessing a certain datum, the "to" of groupAuthzTo).
I guess my issue here, is that I want the proxy ID to not be associated with the client's ID at all. I simply want a way to have the dynamic group to use the ACL's to decide whether or not the client has read or compare to the membership list, and if it does, then to use an internal identity that knows nothing about the client itself to do the compare or membership generation as necessary. So I guess the second solution would work best in that case?
Well, mine was basically a suggestion to make things more finely tunable; of course, a safe default would be, for example, if no dynamic group exploitation authorization were defined, to allow users to use the dynlist and to deny anonymous. The latter could be enabled by setting groupAuthzFrom to "*" (shortcut for "dn.regex:.*").
So, in the end you would have what you need, while the feature could be restricted as needed.
Funny how we hashed out the same things as this draft http://www.ietf.org/internet-drafts/draft-haripriya-dynamicgroup-02.txt
I wish we had better communication sometimes; I never saw any talk of this on the ldapext mailing list nor any announcement of the draft being available.
Quanah Gibson-Mount wrote:
--On Tuesday, January 16, 2007 11:36 AM -0800 Quanah Gibson-Mount quanah@stanford.edu wrote:
I will try it, but it is not of help.
And this does work:
ldapcompare -Q -h ldap-dev1 "cn=registry-consult,cn=groups,cn=applications,dc=stanford,dc=edu" "member:suRegID=ff44e0a6e76a11d1a28c2436000baa77,cn=people,dc=stanford,dc=edu"
TRUE
so that fixes half my problem. ;)
Great. For the listing, honestly I remain on my positions. A possible exception, which would probably solve your problem and at the same time not hinder what access is being applied to data is to design a new access privilege that means something like "disclose to internal operations". This would need to be explicitly added to data that one wants to be accessible by internal operations but not directly by regular ops, like in your case. What I don't like of this access privilege is that it's too generic: it doesn't allow to tell what an internal operation would do with that data. For example, an internal operation may want to modify it, or give it away or so. Note that I have no idea (nor intention: I still remember how much I had to sweat to add "add" and "zap" privileges!) of how to implement it, right now.
p.