Merge lp:~rlane/nova/ldap-schema-modifications-1 into lp:~hudson-openstack/nova/trunk
- ldap-schema-modifications-1
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Vish Ishaya |
Approved revision: | 393 |
Merged at revision: | 489 |
Proposed branch: | lp:~rlane/nova/ldap-schema-modifications-1 |
Merge into: | lp:~hudson-openstack/nova/trunk |
Diff against target: |
576 lines (+107/-153) 8 files modified
nova/auth/fakeldap.py (+3/-0) nova/auth/ldapdriver.py (+92/-73) nova/auth/nova_openldap.schema (+6/-40) nova/auth/nova_sun.schema (+5/-8) nova/auth/opendj.sh (+0/-1) nova/auth/openssh-lpk_openldap.schema (+0/-19) nova/auth/openssh-lpk_sun.schema (+0/-10) nova/auth/slap.sh (+1/-2) |
To merge this branch: | bzr merge lp:~rlane/nova/ldap-schema-modifications-1 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Devin Carlen (community) | Approve | ||
Vish Ishaya (community) | Approve | ||
Review via email: mp+42662@code.launchpad.net |
Commit message
Simplifies and improves ldap schema.
Description of the change
Vish Ishaya (vishvananda) wrote : | # |
Ryan Lane (rlane) wrote : | # |
After thinking about it more, it would be good to get rid of the isAdmin attribute altogether and use a group for this. This will cause more queries, but I can reduce that for servers that support memberOf.
This is a more standard way of handling this in LDAP.
Ryan Lane (rlane) wrote : | # |
I've found a further improvement to be made, that should likely be added before merging this...
The groupOfNames objectclass has an "owner" attribute that expects a DN. Using this we can eliminate the novaProject objectclass and attributes.
Overall I think the schema can be reduced to the novaUser objectclass, and the accessKey and secretKey attributes.
Vish Ishaya (vishvananda) wrote : | # |
Yes, I had considered the same thing (owner and group instead of specific project class). It will require refining the search for roles to make sure that it doesn't pick up projects by accident.
isAdmin could be moved to a group as well. But I think it needs to appear to external services as an attribute of the user. The purpose of isAdmin is to completely bypass role checking.
Vish
On Dec 3, 2010, at 1:25 PM, Ryan Lane wrote:
> I've found a further improvement to be made, that should likely be added before merging this...
>
> The groupOfNames objectclass has an "owner" attribute that expects a DN. Using this we can eliminate the novaProject objectclass and attributes.
>
> Overall I think the schema can be reduced to the novaUser objectclass, and the accessKey and secretKey attributes.
> --
> https:/
> Your team Nova Core is requested to review the proposed merge of lp:~rlane/nova/ldap-schema-modifications-1 into lp:nova.
Ryan Lane (rlane) wrote : | # |
All projects should have an owner, and roles shouldn't. We can refine the search for projects to include owner in the query.
Ryan Lane (rlane) wrote : | # |
Alternatively, we could require that roles and projects should be placed in separate OUs.
Ryan Lane (rlane) wrote : | # |
Made suggested schema selection change. This branch now also removes the novaProject part of the schema. Only novaUser remains.
Vish Ishaya (vishvananda) wrote : | # |
Minor nits.
Can you align the second line with the parens for multiline code?
becomes:
makes it a little easier to read.
also would you mind changing <email address hidden> > <email address hidden> ?
Finally, is there a reason why you made class variables for the params
LdapDriver.
It seems a little odd to me to change the class variables in __init__ which is the ctor for the instance of the class. Not sure if there is a prettier pattern, but perhaps if version 2 ... elif version 1 ... and using self.project_
Ryan Lane (rlane) wrote : | # |
I originally tried setting object variables, but it caused a bunch of tests to fail because the fake ldap driver couldn't access them. Also, one variable is used in a static method. Using class variables eliminated those problems. If there's a better way, I'd love to use it; I used this method because I couldn't get others to work.
Also just pushed the other requested fixes.
Vish Ishaya (vishvananda) wrote : | # |
Understandable. LGTM
Devin Carlen (devcamcar) wrote : | # |
Nice work, this is much cleaner.
OpenStack Infra (hudson-openstack) wrote : | # |
Attempt to merge into lp:nova failed due to conflicts:
text conflict in nova/auth/
Vish Ishaya (vishvananda) wrote : | # |
this needs a quick trunk merge and repush.
Ryan Lane (rlane) wrote : | # |
Merged with trunk and resolved conflict; repushed.
OpenStack Infra (hudson-openstack) wrote : | # |
The attempt to merge lp:~rlane/nova/ldap-schema-modifications-1 into lp:nova failed. Below is the output from the failed tests.
nova.tests.
AccessTestCase
test_
test_
test_
test_
nova.tests.
ApiEc2TestCase
test_
test_
test_
test_
test_
test_
XmlConversion
test_
nova.tests.
AuthManagerDb
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
Vish Ishaya (vishvananda) wrote : | # |
This looks like a bunk failure, reapproving.
Vish Ishaya (vishvananda) wrote : | # |
something odd is happening with tarmac, trying a reapprove first to get it building properly, then we'll try again.
Vish Ishaya (vishvananda) wrote : | # |
yes tarmac is complaining about some odd bzrlib error. We'll have to wait for packaging gurus to figure out what is going on.
Vish Ishaya (vishvananda) wrote : | # |
I'm also noticing that you aren't in Authors or .mailmap correctly. It also seems that you haven't signed the CLA, which might be causing the merge to fail.
Ryan Lane (rlane32) wrote : | # |
That's odd.
<email address hidden>
Sent from my iPhone
On Dec 22, 2010, at 6:41 PM, Vish Ishaya <email address hidden> wrote:
> yes tarmac is complaining about some odd bzrlib error. We'll have to wait for packaging gurus to figure out what is going on.
> --
> https:/
> You are the owner of lp:~rlane/nova/ldap-schema-modifications-1.
Ryan Lane (rlane32) wrote : | # |
I did sign the cla... I can do so again if needed.
Sent from my iPhone
On Dec 22, 2010, at 7:47 PM, Vish Ishaya <email address hidden> wrote:
> I'm also noticing that you aren't in Authors or .mailmap correctly. It also seems that you haven't signed the CLA, which might be causing the merge to fail.
> --
> https:/
> You are the owner of lp:~rlane/nova/ldap-schema-modifications-1.
Vish Ishaya (vishvananda) wrote : | # |
If you signed it, you probably just need to add your info to this page:
http://
On Dec 22, 2010, at 5:53 PM, Ryan Lane wrote:
> I did sign the cla... I can do so again if needed.
>
> Sent from my iPhone
>
> On Dec 22, 2010, at 7:47 PM, Vish Ishaya <email address hidden> wrote:
>
>> I'm also noticing that you aren't in Authors or .mailmap correctly. It also seems that you haven't signed the CLA, which might be causing the merge to fail.
>> --
>> https:/
>> You are the owner of lp:~rlane/nova/ldap-schema-modifications-1.
> --
> https:/
> You are reviewing the proposed merge of lp:~rlane/nova/ldap-schema-modifications-1 into lp:nova.
Vish Ishaya (vishvananda) wrote : | # |
It was the lack of a commit message that was causing it to fail. Trying to merge again.
Preview Diff
1 | === modified file 'nova/auth/fakeldap.py' |
2 | --- nova/auth/fakeldap.py 2010-12-22 20:59:53 +0000 |
3 | +++ nova/auth/fakeldap.py 2010-12-22 23:56:00 +0000 |
4 | @@ -150,6 +150,9 @@ |
5 | """Match a given key and value against an attribute list.""" |
6 | if key not in attrs: |
7 | return False |
8 | + # This is a wild card search. Implemented as all or nothing for now. |
9 | + if value == "*": |
10 | + return True |
11 | if key != "objectclass": |
12 | return value in attrs[key] |
13 | # it is an objectclass check, so check subclasses |
14 | |
15 | === modified file 'nova/auth/ldapdriver.py' |
16 | --- nova/auth/ldapdriver.py 2010-12-22 20:59:53 +0000 |
17 | +++ nova/auth/ldapdriver.py 2010-12-22 23:56:00 +0000 |
18 | @@ -32,11 +32,16 @@ |
19 | |
20 | |
21 | FLAGS = flags.FLAGS |
22 | +flags.DEFINE_integer('ldap_schema_version', 2, |
23 | + 'Current version of the LDAP schema') |
24 | flags.DEFINE_string('ldap_url', 'ldap://localhost', |
25 | 'Point this at your ldap server') |
26 | flags.DEFINE_string('ldap_password', 'changeme', 'LDAP password') |
27 | flags.DEFINE_string('ldap_user_dn', 'cn=Manager,dc=example,dc=com', |
28 | 'DN of admin user') |
29 | +flags.DEFINE_string('ldap_user_id_attribute', 'uid', 'Attribute to use as id') |
30 | +flags.DEFINE_string('ldap_user_name_attribute', 'cn', |
31 | + 'Attribute to use as name') |
32 | flags.DEFINE_string('ldap_user_unit', 'Users', 'OID for Users') |
33 | flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com', |
34 | 'OU for Users') |
35 | @@ -73,10 +78,20 @@ |
36 | Defines enter and exit and therefore supports the with/as syntax. |
37 | """ |
38 | |
39 | + project_pattern = '(owner=*)' |
40 | + isadmin_attribute = 'isNovaAdmin' |
41 | + project_attribute = 'owner' |
42 | + project_objectclass = 'groupOfNames' |
43 | + |
44 | def __init__(self): |
45 | """Imports the LDAP module""" |
46 | self.ldap = __import__('ldap') |
47 | self.conn = None |
48 | + if FLAGS.ldap_schema_version == 1: |
49 | + LdapDriver.project_pattern = '(objectclass=novaProject)' |
50 | + LdapDriver.isadmin_attribute = 'isAdmin' |
51 | + LdapDriver.project_attribute = 'projectManager' |
52 | + LdapDriver.project_objectclass = 'novaProject' |
53 | |
54 | def __enter__(self): |
55 | """Creates the connection to LDAP""" |
56 | @@ -104,13 +119,13 @@ |
57 | """Retrieve project by id""" |
58 | dn = 'cn=%s,%s' % (pid, |
59 | FLAGS.ldap_project_subtree) |
60 | - attr = self.__find_object(dn, '(objectclass=novaProject)') |
61 | + attr = self.__find_object(dn, LdapDriver.project_pattern) |
62 | return self.__to_project(attr) |
63 | |
64 | def get_users(self): |
65 | """Retrieve list of users""" |
66 | attrs = self.__find_objects(FLAGS.ldap_user_subtree, |
67 | - '(objectclass=novaUser)') |
68 | + '(objectclass=novaUser)') |
69 | users = [] |
70 | for attr in attrs: |
71 | user = self.__to_user(attr) |
72 | @@ -120,7 +135,7 @@ |
73 | |
74 | def get_projects(self, uid=None): |
75 | """Retrieve list of projects""" |
76 | - pattern = '(objectclass=novaProject)' |
77 | + pattern = LdapDriver.project_pattern |
78 | if uid: |
79 | pattern = "(&%s(member=%s))" % (pattern, self.__uid_to_dn(uid)) |
80 | attrs = self.__find_objects(FLAGS.ldap_project_subtree, |
81 | @@ -139,23 +154,25 @@ |
82 | # Malformed entries are useless, replace attributes found. |
83 | attr = [] |
84 | if 'secretKey' in user.keys(): |
85 | - attr.append((self.ldap.MOD_REPLACE, 'secretKey', \ |
86 | - [secret_key])) |
87 | + attr.append((self.ldap.MOD_REPLACE, 'secretKey', |
88 | + [secret_key])) |
89 | else: |
90 | - attr.append((self.ldap.MOD_ADD, 'secretKey', \ |
91 | - [secret_key])) |
92 | + attr.append((self.ldap.MOD_ADD, 'secretKey', |
93 | + [secret_key])) |
94 | if 'accessKey' in user.keys(): |
95 | - attr.append((self.ldap.MOD_REPLACE, 'accessKey', \ |
96 | - [access_key])) |
97 | - else: |
98 | - attr.append((self.ldap.MOD_ADD, 'accessKey', \ |
99 | - [access_key])) |
100 | - if 'isAdmin' in user.keys(): |
101 | - attr.append((self.ldap.MOD_REPLACE, 'isAdmin', \ |
102 | - [str(is_admin).upper()])) |
103 | - else: |
104 | - attr.append((self.ldap.MOD_ADD, 'isAdmin', \ |
105 | - [str(is_admin).upper()])) |
106 | + attr.append((self.ldap.MOD_REPLACE, 'accessKey', |
107 | + [access_key])) |
108 | + else: |
109 | + attr.append((self.ldap.MOD_ADD, 'accessKey', |
110 | + [access_key])) |
111 | + if LdapDriver.isadmin_attribute in user.keys(): |
112 | + attr.append((self.ldap.MOD_REPLACE, |
113 | + LdapDriver.isadmin_attribute, |
114 | + [str(is_admin).upper()])) |
115 | + else: |
116 | + attr.append((self.ldap.MOD_ADD, |
117 | + LdapDriver.isadmin_attribute, |
118 | + [str(is_admin).upper()])) |
119 | self.conn.modify_s(self.__uid_to_dn(name), attr) |
120 | return self.get_user(name) |
121 | else: |
122 | @@ -168,12 +185,12 @@ |
123 | 'inetOrgPerson', |
124 | 'novaUser']), |
125 | ('ou', [FLAGS.ldap_user_unit]), |
126 | - ('uid', [name]), |
127 | + (FLAGS.ldap_user_id_attribute, [name]), |
128 | ('sn', [name]), |
129 | - ('cn', [name]), |
130 | + (FLAGS.ldap_user_name_attribute, [name]), |
131 | ('secretKey', [secret_key]), |
132 | ('accessKey', [access_key]), |
133 | - ('isAdmin', [str(is_admin).upper()]), |
134 | + (LdapDriver.isadmin_attribute, [str(is_admin).upper()]), |
135 | ] |
136 | self.conn.add_s(self.__uid_to_dn(name), attr) |
137 | return self.__to_user(dict(attr)) |
138 | @@ -204,10 +221,10 @@ |
139 | if not manager_dn in members: |
140 | members.append(manager_dn) |
141 | attr = [ |
142 | - ('objectclass', ['novaProject']), |
143 | + ('objectclass', [LdapDriver.project_objectclass]), |
144 | ('cn', [name]), |
145 | ('description', [description]), |
146 | - ('projectManager', [manager_dn]), |
147 | + (LdapDriver.project_attribute, [manager_dn]), |
148 | ('member', members)] |
149 | self.conn.add_s('cn=%s,%s' % (name, FLAGS.ldap_project_subtree), attr) |
150 | return self.__to_project(dict(attr)) |
151 | @@ -223,7 +240,8 @@ |
152 | "manager %s doesn't exist") |
153 | % manager_uid) |
154 | manager_dn = self.__uid_to_dn(manager_uid) |
155 | - attr.append((self.ldap.MOD_REPLACE, 'projectManager', manager_dn)) |
156 | + attr.append((self.ldap.MOD_REPLACE, LdapDriver.project_attribute, |
157 | + manager_dn)) |
158 | if description: |
159 | attr.append((self.ldap.MOD_REPLACE, 'description', description)) |
160 | self.conn.modify_s('cn=%s,%s' % (project_id, |
161 | @@ -283,10 +301,9 @@ |
162 | return roles |
163 | else: |
164 | project_dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree) |
165 | - roles = self.__find_objects(project_dn, |
166 | - '(&(&(objectclass=groupOfNames)' |
167 | - '(!(objectclass=novaProject)))' |
168 | - '(member=%s))' % self.__uid_to_dn(uid)) |
169 | + query = ('(&(&(objectclass=groupOfNames)(!%s))(member=%s))' % |
170 | + (LdapDriver.project_pattern, self.__uid_to_dn(uid))) |
171 | + roles = self.__find_objects(project_dn, query) |
172 | return [role['cn'][0] for role in roles] |
173 | |
174 | def delete_user(self, uid): |
175 | @@ -300,14 +317,15 @@ |
176 | # Retrieve user by name |
177 | user = self.__get_ldap_user(uid) |
178 | if 'secretKey' in user.keys(): |
179 | - attr.append((self.ldap.MOD_DELETE, 'secretKey', \ |
180 | - user['secretKey'])) |
181 | + attr.append((self.ldap.MOD_DELETE, 'secretKey', |
182 | + user['secretKey'])) |
183 | if 'accessKey' in user.keys(): |
184 | - attr.append((self.ldap.MOD_DELETE, 'accessKey', \ |
185 | - user['accessKey'])) |
186 | - if 'isAdmin' in user.keys(): |
187 | - attr.append((self.ldap.MOD_DELETE, 'isAdmin', \ |
188 | - user['isAdmin'])) |
189 | + attr.append((self.ldap.MOD_DELETE, 'accessKey', |
190 | + user['accessKey'])) |
191 | + if LdapDriver.isadmin_attribute in user.keys(): |
192 | + attr.append((self.ldap.MOD_DELETE, |
193 | + LdapDriver.isadmin_attribute, |
194 | + user[LdapDriver.isadmin_attribute])) |
195 | self.conn.modify_s(self.__uid_to_dn(uid), attr) |
196 | else: |
197 | # Delete entry |
198 | @@ -329,7 +347,8 @@ |
199 | if secret_key: |
200 | attr.append((self.ldap.MOD_REPLACE, 'secretKey', secret_key)) |
201 | if admin is not None: |
202 | - attr.append((self.ldap.MOD_REPLACE, 'isAdmin', str(admin).upper())) |
203 | + attr.append((self.ldap.MOD_REPLACE, LdapDriver.isadmin_attribute, |
204 | + str(admin).upper())) |
205 | self.conn.modify_s(self.__uid_to_dn(uid), attr) |
206 | |
207 | def __user_exists(self, uid): |
208 | @@ -347,7 +366,7 @@ |
209 | def __get_ldap_user(self, uid): |
210 | """Retrieve LDAP user entry by id""" |
211 | attr = self.__find_object(self.__uid_to_dn(uid), |
212 | - '(objectclass=novaUser)') |
213 | + '(objectclass=novaUser)') |
214 | return attr |
215 | |
216 | def __find_object(self, dn, query=None, scope=None): |
217 | @@ -383,19 +402,21 @@ |
218 | |
219 | def __find_role_dns(self, tree): |
220 | """Find dns of role objects in given tree""" |
221 | - return self.__find_dns(tree, |
222 | - '(&(objectclass=groupOfNames)(!(objectclass=novaProject)))') |
223 | + query = ('(&(objectclass=groupOfNames)(!%s))' % |
224 | + LdapDriver.project_pattern) |
225 | + return self.__find_dns(tree, query) |
226 | |
227 | def __find_group_dns_with_member(self, tree, uid): |
228 | """Find dns of group objects in a given tree that contain member""" |
229 | - dns = self.__find_dns(tree, |
230 | - '(&(objectclass=groupOfNames)(member=%s))' % |
231 | - self.__uid_to_dn(uid)) |
232 | + query = ('(&(objectclass=groupOfNames)(member=%s))' % |
233 | + self.__uid_to_dn(uid)) |
234 | + dns = self.__find_dns(tree, query) |
235 | return dns |
236 | |
237 | def __group_exists(self, dn): |
238 | """Check if group exists""" |
239 | - return self.__find_object(dn, '(objectclass=groupOfNames)') is not None |
240 | + query = '(objectclass=groupOfNames)' |
241 | + return self.__find_object(dn, query) is not None |
242 | |
243 | @staticmethod |
244 | def __role_to_dn(role, project_id=None): |
245 | @@ -417,9 +438,9 @@ |
246 | if member_uids is not None: |
247 | for member_uid in member_uids: |
248 | if not self.__user_exists(member_uid): |
249 | - raise exception.NotFound(_("Group can't be created " |
250 | - "because user %s doesn't exist") |
251 | - % member_uid) |
252 | + raise exception.NotFound("Group can't be created " |
253 | + "because user %s doesn't exist" % |
254 | + member_uid) |
255 | members.append(self.__uid_to_dn(member_uid)) |
256 | dn = self.__uid_to_dn(uid) |
257 | if not dn in members: |
258 | @@ -434,9 +455,8 @@ |
259 | def __is_in_group(self, uid, group_dn): |
260 | """Check if user is in group""" |
261 | if not self.__user_exists(uid): |
262 | - raise exception.NotFound(_("User %s can't be searched in group " |
263 | - "because the user doesn't exist") |
264 | - % uid) |
265 | + raise exception.NotFound("User %s can't be searched in group " |
266 | + "because the user doesn't exist" % uid) |
267 | if not self.__group_exists(group_dn): |
268 | return False |
269 | res = self.__find_object(group_dn, |
270 | @@ -447,12 +467,11 @@ |
271 | def __add_to_group(self, uid, group_dn): |
272 | """Add user to group""" |
273 | if not self.__user_exists(uid): |
274 | - raise exception.NotFound(_("User %s can't be added to the group " |
275 | - "because the user doesn't exist") |
276 | - % uid) |
277 | + raise exception.NotFound("User %s can't be added to the group " |
278 | + "because the user doesn't exist" % uid) |
279 | if not self.__group_exists(group_dn): |
280 | - raise exception.NotFound(_("The group at dn %s doesn't exist") |
281 | - % group_dn) |
282 | + raise exception.NotFound("The group at dn %s doesn't exist" % |
283 | + group_dn) |
284 | if self.__is_in_group(uid, group_dn): |
285 | raise exception.Duplicate(_("User %s is already a member of " |
286 | "the group %s") % (uid, group_dn)) |
287 | @@ -462,18 +481,17 @@ |
288 | def __remove_from_group(self, uid, group_dn): |
289 | """Remove user from group""" |
290 | if not self.__group_exists(group_dn): |
291 | - raise exception.NotFound(_("The group at dn %s doesn't exist") |
292 | - % group_dn) |
293 | + raise exception.NotFound("The group at dn %s doesn't exist" % |
294 | + group_dn) |
295 | if not self.__user_exists(uid): |
296 | - raise exception.NotFound(_("User %s can't be removed from the " |
297 | - "group because the user doesn't exist") |
298 | - % uid) |
299 | + raise exception.NotFound("User %s can't be removed from the " |
300 | + "group because the user doesn't exist" % |
301 | + uid) |
302 | if not self.__is_in_group(uid, group_dn): |
303 | - raise exception.NotFound(_("User %s is not a member of the group") |
304 | - % uid) |
305 | + raise exception.NotFound("User %s is not a member of the group" % |
306 | + uid) |
307 | # NOTE(vish): remove user from group and any sub_groups |
308 | - sub_dns = self.__find_group_dns_with_member( |
309 | - group_dn, uid) |
310 | + sub_dns = self.__find_group_dns_with_member(group_dn, uid) |
311 | for sub_dn in sub_dns: |
312 | self.__safe_remove_from_group(uid, sub_dn) |
313 | |
314 | @@ -491,9 +509,8 @@ |
315 | def __remove_from_all(self, uid): |
316 | """Remove user from all roles and projects""" |
317 | if not self.__user_exists(uid): |
318 | - raise exception.NotFound(_("User %s can't be removed from all " |
319 | - "because the user doesn't exist") |
320 | - % uid) |
321 | + raise exception.NotFound("User %s can't be removed from all " |
322 | + "because the user doesn't exist" % uid) |
323 | role_dns = self.__find_group_dns_with_member( |
324 | FLAGS.role_project_subtree, uid) |
325 | for role_dn in role_dns: |
326 | @@ -521,13 +538,13 @@ |
327 | if attr is None: |
328 | return None |
329 | if ('accessKey' in attr.keys() and 'secretKey' in attr.keys() \ |
330 | - and 'isAdmin' in attr.keys()): |
331 | + and LdapDriver.isadmin_attribute in attr.keys()): |
332 | return { |
333 | - 'id': attr['uid'][0], |
334 | - 'name': attr['cn'][0], |
335 | + 'id': attr[FLAGS.ldap_user_id_attribute][0], |
336 | + 'name': attr[FLAGS.ldap_user_name_attribute][0], |
337 | 'access': attr['accessKey'][0], |
338 | 'secret': attr['secretKey'][0], |
339 | - 'admin': (attr['isAdmin'][0] == 'TRUE')} |
340 | + 'admin': (attr[LdapDriver.isadmin_attribute][0] == 'TRUE')} |
341 | else: |
342 | return None |
343 | |
344 | @@ -539,7 +556,8 @@ |
345 | return { |
346 | 'id': attr['cn'][0], |
347 | 'name': attr['cn'][0], |
348 | - 'project_manager_id': self.__dn_to_uid(attr['projectManager'][0]), |
349 | + 'project_manager_id': |
350 | + self.__dn_to_uid(attr[LdapDriver.project_attribute][0]), |
351 | 'description': attr.get('description', [None])[0], |
352 | 'member_ids': [self.__dn_to_uid(x) for x in member_dns]} |
353 | |
354 | @@ -549,9 +567,10 @@ |
355 | return dn.split(',')[0].split('=')[1] |
356 | |
357 | @staticmethod |
358 | - def __uid_to_dn(dn): |
359 | + def __uid_to_dn(uid): |
360 | """Convert uid to dn""" |
361 | - return 'uid=%s,%s' % (dn, FLAGS.ldap_user_subtree) |
362 | + return (FLAGS.ldap_user_id_attribute + '=%s,%s' |
363 | + % (uid, FLAGS.ldap_user_subtree)) |
364 | |
365 | |
366 | class FakeLdapDriver(LdapDriver): |
367 | |
368 | === modified file 'nova/auth/nova_openldap.schema' |
369 | --- nova/auth/nova_openldap.schema 2010-10-25 22:42:49 +0000 |
370 | +++ nova/auth/nova_openldap.schema 2010-12-22 23:56:00 +0000 |
371 | @@ -1,7 +1,9 @@ |
372 | # |
373 | # Person object for Nova |
374 | # inetorgperson with extra attributes |
375 | -# Author: Vishvananda Ishaya <vishvananda@yahoo.com> |
376 | +# Schema version: 2 |
377 | +# Authors: Vishvananda Ishaya <vishvananda@gmail.com> |
378 | +# Ryan Lane <rlane@wikimedia.org> |
379 | # |
380 | # |
381 | |
382 | @@ -31,54 +33,18 @@ |
383 | ) |
384 | |
385 | attributetype ( |
386 | - novaAttrs:3 |
387 | - NAME 'keyFingerprint' |
388 | - DESC 'Fingerprint of private key' |
389 | - EQUALITY caseIgnoreMatch |
390 | - SUBSTR caseIgnoreSubstringsMatch |
391 | - SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
392 | - SINGLE-VALUE |
393 | - ) |
394 | - |
395 | -attributetype ( |
396 | novaAttrs:4 |
397 | - NAME 'isAdmin' |
398 | - DESC 'Is user an administrator?' |
399 | + NAME 'isNovaAdmin' |
400 | + DESC 'Is user an nova administrator?' |
401 | EQUALITY booleanMatch |
402 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 |
403 | SINGLE-VALUE |
404 | ) |
405 | |
406 | -attributetype ( |
407 | - novaAttrs:5 |
408 | - NAME 'projectManager' |
409 | - DESC 'Project Managers of a project' |
410 | - SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 |
411 | - ) |
412 | - |
413 | objectClass ( |
414 | novaOCs:1 |
415 | NAME 'novaUser' |
416 | DESC 'access and secret keys' |
417 | AUXILIARY |
418 | - MUST ( uid ) |
419 | - MAY ( accessKey $ secretKey $ isAdmin ) |
420 | - ) |
421 | - |
422 | -objectClass ( |
423 | - novaOCs:2 |
424 | - NAME 'novaKeyPair' |
425 | - DESC 'Key pair for User' |
426 | - SUP top |
427 | - STRUCTURAL |
428 | - MUST ( cn $ sshPublicKey $ keyFingerprint ) |
429 | - ) |
430 | - |
431 | -objectClass ( |
432 | - novaOCs:3 |
433 | - NAME 'novaProject' |
434 | - DESC 'Container for project' |
435 | - SUP groupOfNames |
436 | - STRUCTURAL |
437 | - MUST ( cn $ projectManager ) |
438 | + MAY ( accessKey $ secretKey $ isNovaAdmin ) |
439 | ) |
440 | |
441 | === modified file 'nova/auth/nova_sun.schema' |
442 | --- nova/auth/nova_sun.schema 2010-10-25 22:42:49 +0000 |
443 | +++ nova/auth/nova_sun.schema 2010-12-22 23:56:00 +0000 |
444 | @@ -1,16 +1,13 @@ |
445 | # |
446 | # Person object for Nova |
447 | # inetorgperson with extra attributes |
448 | -# Author: Vishvananda Ishaya <vishvananda@yahoo.com> |
449 | -# Modified for strict RFC 4512 compatibility by: Ryan Lane <ryan@ryandlane.com> |
450 | +# Schema version: 2 |
451 | +# Authors: Vishvananda Ishaya <vishvananda@gmail.com> |
452 | +# Ryan Lane <rlane@wikimedia.org> |
453 | # |
454 | # using internet experimental oid arc as per BP64 3.1 |
455 | dn: cn=schema |
456 | attributeTypes: ( 1.3.6.1.3.1.666.666.3.1 NAME 'accessKey' DESC 'Key for accessing data' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) |
457 | attributeTypes: ( 1.3.6.1.3.1.666.666.3.2 NAME 'secretKey' DESC 'Secret key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) |
458 | -attributeTypes: ( 1.3.6.1.3.1.666.666.3.3 NAME 'keyFingerprint' DESC 'Fingerprint of private key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE) |
459 | -attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isAdmin' DESC 'Is user an administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) |
460 | -attributeTypes: ( 1.3.6.1.3.1.666.666.3.5 NAME 'projectManager' DESC 'Project Managers of a project' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) |
461 | -objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MUST ( uid ) MAY ( accessKey $ secretKey $ isAdmin ) ) |
462 | -objectClasses: ( 1.3.6.1.3.1.666.666.4.2 NAME 'novaKeyPair' DESC 'Key pair for User' SUP top STRUCTURAL MUST ( cn $ sshPublicKey $ keyFingerprint ) ) |
463 | -objectClasses: ( 1.3.6.1.3.1.666.666.4.3 NAME 'novaProject' DESC 'Container for project' SUP groupOfNames STRUCTURAL MUST ( cn $ projectManager ) ) |
464 | +attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isNovaAdmin' DESC 'Is user a nova administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) |
465 | +objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MAY ( accessKey $ secretKey $ isNovaAdmin ) ) |
466 | |
467 | === modified file 'nova/auth/opendj.sh' |
468 | --- nova/auth/opendj.sh 2010-11-30 23:12:19 +0000 |
469 | +++ nova/auth/opendj.sh 2010-12-22 23:56:00 +0000 |
470 | @@ -32,7 +32,6 @@ |
471 | schemapath='/var/opendj/instance/config/schema' |
472 | cp $abspath/openssh-lpk_sun.schema $schemapath/97-openssh-lpk_sun.ldif |
473 | cp $abspath/nova_sun.schema $schemapath/98-nova_sun.ldif |
474 | -chown opendj:opendj $schemapath/97-openssh-lpk_sun.ldif |
475 | chown opendj:opendj $schemapath/98-nova_sun.ldif |
476 | |
477 | cat >/etc/ldap/ldap.conf <<LDAP_CONF_EOF |
478 | |
479 | === added file 'nova/auth/openssh-lpk_openldap.schema' |
480 | --- nova/auth/openssh-lpk_openldap.schema 1970-01-01 00:00:00 +0000 |
481 | +++ nova/auth/openssh-lpk_openldap.schema 2010-12-22 23:56:00 +0000 |
482 | @@ -0,0 +1,19 @@ |
483 | +# |
484 | +# LDAP Public Key Patch schema for use with openssh-ldappubkey |
485 | +# Author: Eric AUGE <eau@phear.org> |
486 | +# |
487 | +# Based on the proposal of : Mark Ruijter |
488 | +# |
489 | + |
490 | + |
491 | +# octetString SYNTAX |
492 | +attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' |
493 | + DESC 'MANDATORY: OpenSSH Public key' |
494 | + EQUALITY octetStringMatch |
495 | + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
496 | + |
497 | +# printableString SYNTAX yes|no |
498 | +objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY |
499 | + DESC 'MANDATORY: OpenSSH LPK objectclass' |
500 | + MAY ( sshPublicKey $ uid ) |
501 | + ) |
502 | |
503 | === removed file 'nova/auth/openssh-lpk_openldap.schema' |
504 | --- nova/auth/openssh-lpk_openldap.schema 2010-10-25 22:42:49 +0000 |
505 | +++ nova/auth/openssh-lpk_openldap.schema 1970-01-01 00:00:00 +0000 |
506 | @@ -1,19 +0,0 @@ |
507 | -# |
508 | -# LDAP Public Key Patch schema for use with openssh-ldappubkey |
509 | -# Author: Eric AUGE <eau@phear.org> |
510 | -# |
511 | -# Based on the proposal of : Mark Ruijter |
512 | -# |
513 | - |
514 | - |
515 | -# octetString SYNTAX |
516 | -attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' |
517 | - DESC 'MANDATORY: OpenSSH Public key' |
518 | - EQUALITY octetStringMatch |
519 | - SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
520 | - |
521 | -# printableString SYNTAX yes|no |
522 | -objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY |
523 | - DESC 'MANDATORY: OpenSSH LPK objectclass' |
524 | - MAY ( sshPublicKey $ uid ) |
525 | - ) |
526 | |
527 | === added file 'nova/auth/openssh-lpk_sun.schema' |
528 | --- nova/auth/openssh-lpk_sun.schema 1970-01-01 00:00:00 +0000 |
529 | +++ nova/auth/openssh-lpk_sun.schema 2010-12-22 23:56:00 +0000 |
530 | @@ -0,0 +1,10 @@ |
531 | +# |
532 | +# LDAP Public Key Patch schema for use with openssh-ldappubkey |
533 | +# Author: Eric AUGE <eau@phear.org> |
534 | +# |
535 | +# Schema for Sun Directory Server. |
536 | +# Based on the original schema, modified by Stefan Fischer. |
537 | +# |
538 | +dn: cn=schema |
539 | +attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
540 | +objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY DESC 'MANDATORY: OpenSSH LPK objectclass' MAY ( sshPublicKey $ uid ) ) |
541 | |
542 | === removed file 'nova/auth/openssh-lpk_sun.schema' |
543 | --- nova/auth/openssh-lpk_sun.schema 2010-10-25 22:50:32 +0000 |
544 | +++ nova/auth/openssh-lpk_sun.schema 1970-01-01 00:00:00 +0000 |
545 | @@ -1,10 +0,0 @@ |
546 | -# |
547 | -# LDAP Public Key Patch schema for use with openssh-ldappubkey |
548 | -# Author: Eric AUGE <eau@phear.org> |
549 | -# |
550 | -# Schema for Sun Directory Server. |
551 | -# Based on the original schema, modified by Stefan Fischer. |
552 | -# |
553 | -dn: cn=schema |
554 | -attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
555 | -objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY DESC 'MANDATORY: OpenSSH LPK objectclass' MAY ( sshPublicKey $ uid ) ) |
556 | |
557 | === modified file 'nova/auth/slap.sh' |
558 | --- nova/auth/slap.sh 2010-10-25 22:42:49 +0000 |
559 | +++ nova/auth/slap.sh 2010-12-22 23:56:00 +0000 |
560 | @@ -22,7 +22,7 @@ |
561 | |
562 | abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"` |
563 | cp $abspath/openssh-lpk_openldap.schema /etc/ldap/schema/openssh-lpk_openldap.schema |
564 | -cp $abspath/nova_openldap.schema /etc/ldap/schema/nova_openldap.schema |
565 | +cp $abspath/nova_openldap.schema /etc/ldap/schema/nova.schema |
566 | |
567 | mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.orig |
568 | cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF |
569 | @@ -33,7 +33,6 @@ |
570 | include /etc/ldap/schema/core.schema |
571 | include /etc/ldap/schema/cosine.schema |
572 | include /etc/ldap/schema/inetorgperson.schema |
573 | -include /etc/ldap/schema/openssh-lpk_openldap.schema |
574 | include /etc/ldap/schema/nova.schema |
575 | pidfile /var/run/slapd/slapd.pid |
576 | argsfile /var/run/slapd/slapd.args |
Suggestion:
Can we have the isAdmin/isNovaAdmin attribute as a flag that defaults to isNovaAdmin. I'm thinking that it would be nice if we don't force an ldap data migration if users have the old schema.
On Dec 3, 2010, at 9:47 AM, Ryan Lane wrote:
> Ryan Lane has proposed merging lp:~rlane/nova/ldap-schema-modifications-1 into lp:nova. /bugs.launchpad .net/bugs/ 681030 /code.launchpad .net/~rlane/ nova/ldap- schema- modifications- 1/+merge/ 42662 ldapdriver. py' ldapdriver. py 2010-11-26 17:01:50 +0000 ldapdriver. py 2010-12-03 17:46:55 +0000 string( 'ldap_password' , 'changeme', 'LDAP password') string( 'ldap_user_ dn', 'cn=Manager, dc=example, dc=com' , DEFINE_ string( 'ldap_user_ id_attribute' , 'uid', 'Attribute to use as id') DEFINE_ string( 'ldap_user_ name_attribute' , 'cn', 'Attribute to use as name') string( 'ldap_user_ unit', 'Users', 'OID for Users') string( 'ldap_user_ subtree' , 'ou=Users, dc=example, dc=com' , ldap_user_ unit]), ldap_user_ id_attribute, [name]), ldap_user_ name_attribute, [name]), admin). upper() ]), admin). upper() ]), add_s(self. __uid_to_ dn(name) , attr) to_user( dict(attr) ) (self.ldap. MOD_REPLACE, 'secretKey', secret_key)) (self.ldap. MOD_REPLACE, 'isAdmin', str(admin) .upper( ))) (self.ldap. MOD_REPLACE, 'isNovaAdmin', str(admin) .upper( ))) modify_ s(self. __uid_to_ dn(uid) , attr) ldap_user_ id_attribute] [0], ldap_user_ name_attribute] [0], '][0], '][0], isNovaAdmin' ][0] == 'TRUE')}
>
> Requested reviews:
> Nova Core (nova-core)
> Related bugs:
> #681030 Nova's LDAP schema has an unneeded requirement on the nis or bis schema
> https:/
>
> --
> https:/
> Your team Nova Core is requested to review the proposed merge of lp:~rlane/nova/ldap-schema-modifications-1 into lp:nova.
> === modified file 'nova/auth/
> --- nova/auth/
> +++ nova/auth/
> @@ -37,6 +37,8 @@
> flags.DEFINE_
> flags.DEFINE_
> 'DN of admin user')
> +flags.
> +flags.
> flags.DEFINE_
> flags.DEFINE_
> 'OU for Users')
> @@ -131,12 +133,12 @@
> 'inetOrgPerson',
> 'novaUser']),
> ('ou', [FLAGS.
> - ('uid', [name]),
> + (FLAGS.
> ('sn', [name]),
> - ('cn', [name]),
> + (FLAGS.
> ('secretKey', [secret_key]),
> ('accessKey', [access_key]),
> - ('isAdmin', [str(is_
> + ('isNovaAdmin', [str(is_
> ]
> self.conn.
> return self.__
> @@ -274,7 +276,7 @@
> if secret_key:
> attr.append(
> if admin is not None:
> - attr.append(
> + attr.append(
> self.conn.
>
> def __user_exists(self, uid):
> @@ -450,11 +452,11 @@
> if attr == None:
> return None
> return {
> - 'id': attr['uid'][0],
> - 'name': attr['cn'][0],
> + 'id': attr[FLAGS.
> + 'name': attr[FLAGS.
> 'access': attr['accessKey
> 'secret': attr['secretKey
> - 'admin': (attr['isAdmin'][0] == 'TRUE')}
> + 'admin': (attr['
>
> def __to_project(self, attr):
> """Convert ldap attributes to Project object"""
> @@ -474,9 +476,10 @@
> return dn.split(','...