Merge lp:~zisis00/drizzle/ldap_policy into lp:drizzle
- ldap_policy
- Merge into 7.2
Status: | Work in progress |
---|---|
Proposed branch: | lp:~zisis00/drizzle/ldap_policy |
Merge into: | lp:drizzle |
Diff against target: |
1707 lines (+1673/-2) 5 files modified
plugin/ldap_policy/docs/index.rst (+187/-0) plugin/ldap_policy/ldap_policy.cc (+1286/-0) plugin/ldap_policy/ldap_policy.hpp (+194/-0) plugin/ldap_policy/plugin.ini (+3/-0) tests/lib/server_mgmt/drizzled.py (+3/-2) |
To merge this branch: | bzr merge lp:~zisis00/drizzle/ldap_policy |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Drizzle Trunk | Pending | ||
Review via email: mp+119016@code.launchpad.net |
Commit message
Description of the change
This branch introduce a new plugin named ldap policy. The plugin is an authentication system using LDAP. Each schema/table of Drizzle and user has a record in LDAP. The ldap_policy plugin search in LDAP and dictates if access to target schema/table from user should be granted or not. Also, it is capable to search for supplementaries groups and it has an implementation of a "per-user" cache system for better performance.
Note: Extending the testing suite to have some automated tests & writing detailed documentation are currently in progress.
- 2556. By Zisis Sialveras
-
Fixed some errors in ldap_policy
- 2557. By Zisis Sialveras
-
Documentation for ldap-policy
Brian Aker (brianaker) wrote : | # |
CXX plugin/
CXX plugin/
plugin/
plugin/
plugin/
CXX plugin/
cc1plus: all warnings being treated as errors
CXX plugin/
make[2]: *** [plugin/
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory `/home/
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/
make: *** [all] Error 2
Build step 'Use builders from another project' marked build as failure
[WARNINGS] Skipping publisher since build result is FAILURE
Notifying upstream projects of job completion
Finished: FAILURE
Unmerged revisions
- 2557. By Zisis Sialveras
-
Documentation for ldap-policy
- 2556. By Zisis Sialveras
-
Fixed some errors in ldap_policy
- 2555. By Zisis Sialveras
-
Some changes in ldap_policy
- 2554. By Zisis Sialveras
-
The LDAP policy plugin.
Preview Diff
1 | === added directory 'plugin/ldap_policy' |
2 | === added directory 'plugin/ldap_policy/docs' |
3 | === added file 'plugin/ldap_policy/docs/index.rst' |
4 | --- plugin/ldap_policy/docs/index.rst 1970-01-01 00:00:00 +0000 |
5 | +++ plugin/ldap_policy/docs/index.rst 2012-08-21 14:09:20 +0000 |
6 | @@ -0,0 +1,187 @@ |
7 | +.. _ldap_policy_plugin: |
8 | + |
9 | +LDAP Authorization |
10 | +================== |
11 | + |
12 | +:program: `ldap_policy` is an :doc:`/administration/authorization` plugin that uses LDAP (Lightweight Directory Access Protocol) records to match policies. |
13 | +Each schema and table has a record in LDAP with attributes that indicate which users and groups are authorized to the target schema and/or table. |
14 | +More specifically, users exists in an LDAP directory (etc. ou=users,dc=example,dc=com). So do groups, tables and schemata. |
15 | +Schemata and tables are defined with objectClass: drizzleItem, and they can have attributes like allowedUsers and allowedGroups. |
16 | +These two attributes are the uidNumber of user or the gidNumber of the groups that should be authorized to the schema or table. |
17 | + |
18 | +The plugin is also capable to search for permissions in the supplementaries groups. |
19 | +Under the group directory (etc. ou=groups,dc=example,dc=com), may exist the groups of the users. Each group may have memberUID attribute |
20 | +if it is defined with objectClass: posixGroup. Having these, allows the plugin to understand the supplementaries groups of the user. |
21 | +So if a user has a group in supplementaries groups, and this group is authorized, then the user is authorized too, although he belong in a non-authorized |
22 | +primary group. |
23 | + |
24 | +.. seealso:: :doc:`/administration/authorization` |
25 | +.. seealso:: :doc:`/plugins/auth_ldap/index` |
26 | + |
27 | +.. _ldap_policy_loading: |
28 | + |
29 | +Loading |
30 | +------- |
31 | + |
32 | +To load this plugin, start :program:`drizzled` with:: |
33 | + |
34 | + --plugin-add=ldap_policy |
35 | + |
36 | +Loading the plugin may not enable or configure it. See the plugin's |
37 | +:ref:`ldap_policy_configuration` and :ref:`ldap_policy_variables`. |
38 | + |
39 | +.. seealso:: :ref:`drizzled_plugin_options` for more information about adding and removing plugins. |
40 | + |
41 | +.. _ldap_policy_configuration: |
42 | + |
43 | +Configuration |
44 | +------------- |
45 | + |
46 | +These command line options configure the plugin when :program:`drizzled` |
47 | +is started. See :ref:`command_line_options` for more information about specifying |
48 | +command line options. |
49 | + |
50 | +.. program:: drizzled |
51 | + |
52 | +.. option:: --ldap-policy.uri ARG |
53 | + |
54 | + :Default: ``ldap://localhost/`` |
55 | + :Variable: :ref:`ldap_policy_uri <ldap_policy_uri>` |
56 | + |
57 | + URI of LDAP server to connect. |
58 | + |
59 | +.. option:: --ldap-policy.users-dir ARG |
60 | + |
61 | + :Default: ``ou=users,dc=example,dc=com`` |
62 | + :Variable: :ref:`ldap_policy_users_dir <ldap_policy_users_dir>` |
63 | + |
64 | + The LDAP DN (distinguished name) with the users records. |
65 | + |
66 | + Users should be in this LDAP directory, and must be defined objectClass: posixAccount. uidNumber and gidNumber attributes are required. |
67 | + |
68 | +.. option:: --ldap-policy.groups-dir ARG |
69 | + |
70 | + :Default: ``ou=groups,dc=example,dc=com`` |
71 | + :Variable: :ref:`ldap_policy_groups_dir <ldap_policy_groups_dir>` |
72 | + |
73 | + The LDAP DN (distinguished name) with the groups records. |
74 | + |
75 | + Groups should be in this LDAP directory, and must be defined with objectClass: posixGroups. Although this class has as optional attribute memberUID, |
76 | + it is essential to be filled so plugin can understand the supplementaries groups of the users. |
77 | + |
78 | + |
79 | +.. option:: --ldap-policy.schemas-dir ARG |
80 | + |
81 | + :Default: ``ou=schemas,dc=example,dc=com`` |
82 | + :Variable: :ref:`ldap_policy_schemas_dir <ldap_policy_schemas_dir>` |
83 | + |
84 | + The LDAP DN (distinguished name) with the schemas records. |
85 | + |
86 | + Schemata should be in this LDAP directory, and must be defined with objectClass: drizzleItem. allowedUsers and allowedGroups attributes indicate |
87 | + which uidNumber and gidNumber should be authorized in the current schema. |
88 | + |
89 | +.. option:: --ldap-policy.tables-dir ARG |
90 | + |
91 | + :Default: ``ou=tables,dc=example,dc=com`` |
92 | + :Variable: :ref:`ldap_policy_tables_dir <ldap_policy_tables_dir>` |
93 | + |
94 | + The LDAP DN (distinguished name) with the tables records. |
95 | + |
96 | + Tables should be in this LDAP directory, and must be defined with objectClass: drizzleItem. allowedUsers and allowedGroups attributes indicate |
97 | + which uidNumber and gidNumber should be authorized in the current table. |
98 | + |
99 | +.. option:: --ldap-policy.cache-timeout ARG |
100 | + |
101 | + :Default: ``500`` |
102 | + :Variable: :ref:`ldap_policy_cache_timeout <ldap_policy_cache_timeout>` |
103 | + |
104 | + How much time is valid each cache entry. (NOT implemented yet) |
105 | + |
106 | + After a successful authorization to a schema or a table, the user and the schema/table is added in cache memory in order to achive better performance |
107 | + the next time he/she tries to access the same schema/table again. Each cache entry is valid for only specific number of seconds. |
108 | + |
109 | +.. _ldap_policy_variables: |
110 | + |
111 | +Variables |
112 | +--------- |
113 | + |
114 | +These variables show the running configuration of the plugin. |
115 | +See `variables` for more information about querying and setting variables. |
116 | + |
117 | + |
118 | +.. _ldap_policy_uri: |
119 | +* ``ldap_policy_uri`` |
120 | + |
121 | + :Scope: Global |
122 | + :Dynamic: No |
123 | + :Option: :option:`--ldap_policy.uri` |
124 | + |
125 | + URI of the LDAP server to contact. |
126 | + |
127 | +.. _ldap_policy_users_dir: |
128 | +* ``ldap_policy_users_dir`` |
129 | + |
130 | + :Scope: Global |
131 | + :Dynamic: No |
132 | + :Option: :option:`--ldap_policy.users-dir` |
133 | + |
134 | + The LDAP DN (distinguished name) with the users records. |
135 | + |
136 | +.. _ldap_policy_groups_dir: |
137 | +* ``ldap_policy_groups_dir`` |
138 | + |
139 | + :Scope: Global |
140 | + :Dynamic: No |
141 | + :Option: :option:`--ldap_policy.groups-dir` |
142 | + |
143 | + The LDAP DN (distinguished name) with the groups records. |
144 | + |
145 | +.. _ldap_policy_schemas_dir: |
146 | +* ``ldap_policy_schemas_dir`` |
147 | + |
148 | + :Scope: Global |
149 | + :Dynamic: No |
150 | + :Option: :option:`--ldap_policy.schemas-dir` |
151 | + |
152 | + The LDAP DN (distinguished name) with the schemas records. |
153 | + |
154 | +.. _ldap_policy_tables_dir: |
155 | +* ``ldap_policy_tables_dir`` |
156 | + |
157 | + :Scope: Global |
158 | + :Dynamic: No |
159 | + :Option: :option:`--ldap_policy.tables-dir` |
160 | + |
161 | + The LDAP DN (distinguished name) with the tables records. |
162 | + |
163 | + |
164 | +.. ldap_policy_authors: |
165 | + |
166 | +Authors |
167 | +------- |
168 | + |
169 | +Zisis Sialveras |
170 | + |
171 | +.. ldap_policy_version: |
172 | + |
173 | +Version |
174 | +------- |
175 | + |
176 | +This documentation applies to version **ldap_policy 0.1**. |
177 | + |
178 | +To see which version of the plugin a Drizzle server is running, execute: |
179 | + |
180 | +.. code-block:: mysql |
181 | + |
182 | + SELECT MODULE_VERSION FROM DATA_DICTIONARY.MODULES WHERE MODULE_NAME='ldap_policy' |
183 | + |
184 | + |
185 | +.. ldap_policy_changelog |
186 | + |
187 | +Changelog |
188 | +--------- |
189 | + |
190 | +v0.1 |
191 | +*First release. |
192 | + |
193 | + |
194 | |
195 | === added file 'plugin/ldap_policy/ldap_policy.cc' |
196 | --- plugin/ldap_policy/ldap_policy.cc 1970-01-01 00:00:00 +0000 |
197 | +++ plugin/ldap_policy/ldap_policy.cc 2012-08-21 14:09:20 +0000 |
198 | @@ -0,0 +1,1286 @@ |
199 | +/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- |
200 | + * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
201 | + * |
202 | + * Copyright (C) 2012 Zisis Sialveras |
203 | + * |
204 | + * This program is free software; you can redistribute it and/or modify |
205 | + * it under the terms of the GNU General Public License as published by |
206 | + * the Free Software Foundation; version 2 of the License. |
207 | + * |
208 | + * This program is distributed in the hope that it will be useful, |
209 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
210 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
211 | + * GNU General Public License for more details. |
212 | + * |
213 | + * You should have received a copy of the GNU General Public License |
214 | + * along with this program; if not, write to the Free Software |
215 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
216 | + */ |
217 | + |
218 | +#include "ldap_policy.hpp" |
219 | +#include <drizzled/module/option_map.h> |
220 | + |
221 | + |
222 | +namespace po= boost::program_options; |
223 | + |
224 | +using namespace std; |
225 | +using namespace drizzled; |
226 | + |
227 | +namespace ldap_policy |
228 | +{ |
229 | + |
230 | +static int init(module::Context &context) |
231 | +{ |
232 | + LDAP_policy *ldap_policy= new LDAP_policy(); |
233 | + |
234 | + if(ldap_policy->connect() == false) |
235 | + { |
236 | + errmsg_printf(error::ERROR, _("Could not load ldap_policy\n")); |
237 | + delete ldap_policy; |
238 | + return 1; |
239 | + } |
240 | + |
241 | + context.registerVariable(new sys_var_const_string_val("uri", uri)); |
242 | + context.registerVariable(new sys_var_const_string_val("users-dir", users_dir)); |
243 | + context.registerVariable(new sys_var_const_string_val("schema-dir", schemas_dir)); |
244 | + context.registerVariable(new sys_var_const_string_val("groups-dir", groups_dir)); |
245 | + context.registerVariable(new sys_var_const_string_val("tables-dir", tables_dir)); |
246 | + ///Remember to register the Variable Cache-timeout |
247 | + |
248 | + context.add(ldap_policy); |
249 | + return 0; |
250 | +} |
251 | + |
252 | +static void init_options(drizzled::module::option_context &context) |
253 | +{ |
254 | + context("uri", po::value<string>(&uri)->default_value(DEFAULT_URI), |
255 | + N_("URI of the LDAP server to contact")); |
256 | + context("users-dir", po::value<string>(&users_dir)->default_value(DEFAULT_USERS_DIR), |
257 | + N_("Users' LDAP directory")); |
258 | + context("schemas-dir", po::value<string>(&schemas_dir)->default_value(DEFAULT_SCHEMAS_DIR), |
259 | + N_("Schemas' LDAP directory")); |
260 | + context("groups-dir", po::value<string>(&groups_dir)->default_value(DEFAULT_GROUPS_DIR), |
261 | + N_("Groups' LDAP directory")); |
262 | + context("tables-dir", po::value<string>(&tables_dir)->default_value(DEFAULT_TABLES_DIR), |
263 | + N_("Tables' LDAP directory")); |
264 | + context("cache-timeout", po::value<time_t>(&cache_timeout)->default_value(DEFAULT_CACHE_TIMEOUT), |
265 | + N_("Cache timeout")); |
266 | +} |
267 | + |
268 | +void LDAP_policy::printerror() |
269 | +{ |
270 | + errmsg_printf(error::ERROR, _(error.c_str())); |
271 | +} |
272 | + |
273 | +/** |
274 | + * restrictProcess dictates if user A is allowed to see/kill user B connection. |
275 | + * |
276 | + * In the beginning, restrictProcess checks if user A and B has the same gidNumber |
277 | + * attribute in their LDAP records. If they have not, restrictProcess checks |
278 | + * if user's B group is one of the user's A supplementaries groups. This is done |
279 | + * by searching in user's B group LDAP record and checking if its attributes is uid |
280 | + * of user A. |
281 | + */ |
282 | + |
283 | +bool LDAP_policy::restrictProcess(const drizzled::identifier::User &user_ctx, |
284 | + const drizzled::identifier::User &session_ctx) |
285 | +{ |
286 | + |
287 | + LDAPMessage *response; |
288 | + const char *attrs[]= {"uidNumber", |
289 | + "gidNumber", |
290 | + NULL |
291 | + }; |
292 | + string filter= "(cn=" + user_ctx.username() + ")"; |
293 | + |
294 | + |
295 | + int return_code= ldap_search_ext_s(ldap, |
296 | + users_dir.c_str(), |
297 | + LDAP_SCOPE_ONELEVEL, |
298 | + filter.c_str(), |
299 | + const_cast<char**>(attrs), |
300 | + 0, |
301 | + NULL, |
302 | + NULL, |
303 | + NULL, |
304 | + 1, |
305 | + &response); |
306 | + |
307 | + if( return_code != LDAP_SUCCESS ) |
308 | + { |
309 | + error= "ldap_search_ext_s failed:"; |
310 | + error+= ldap_err2string(return_code); |
311 | + printerror(); |
312 | + |
313 | + ldap_msgfree(response); |
314 | + return true; |
315 | + } |
316 | + |
317 | + LDAPMessage *entry; |
318 | + int ldap_entries= ldap_count_entries(ldap, response); |
319 | + |
320 | + if( ldap_entries == 0 || ldap_entries == (-1)) |
321 | + { |
322 | + ldap_msgfree(response); |
323 | + return true; |
324 | + } |
325 | + |
326 | + entry= ldap_first_entry(ldap, response); |
327 | + BerElement *berv; |
328 | + char **gid, **uid, *attr; |
329 | + for(attr= ldap_first_attribute(ldap, entry, &berv); //attr is gidNumber attribute |
330 | + attr != NULL; |
331 | + attr= ldap_next_attribute(ldap, entry, berv)) |
332 | + { |
333 | + |
334 | + if(not strcmp(attr, "uidNumber")) |
335 | + { |
336 | + uid= ldap_get_values(ldap, entry, attr); |
337 | + } |
338 | + else if( not strcmp(attr, "gidNumber")) |
339 | + { |
340 | + gid= ldap_get_values(ldap, entry, attr); |
341 | + } |
342 | + } //we have uid and gid of user A |
343 | + |
344 | + if(gid == NULL) |
345 | + { |
346 | + return true; |
347 | + } |
348 | + |
349 | + struct berval brv; |
350 | + brv.bv_len= strlen(gid[0]); |
351 | + brv.bv_val= gid[0]; |
352 | + |
353 | + string dn= "cn=" + session_ctx.username() + "," + users_dir.c_str(); |
354 | + |
355 | + return_code= ldap_compare_ext_s(ldap, |
356 | + dn.c_str(), |
357 | + "gidNumber", |
358 | + &brv, |
359 | + NULL, |
360 | + NULL); |
361 | + |
362 | + if(return_code == LDAP_COMPARE_TRUE) |
363 | + { |
364 | + if(berv != NULL) |
365 | + { |
366 | + ber_free(berv, 0); |
367 | + } |
368 | + ldap_memfree(attr); |
369 | + ldap_msgfree(response); |
370 | + ldap_value_free(gid); |
371 | + ldap_value_free(uid); |
372 | + |
373 | + return false; |
374 | + } |
375 | + else if (return_code != LDAP_COMPARE_FALSE) |
376 | + { |
377 | + |
378 | + error= "ldap_compare_ext_s failed"; |
379 | + error+= ldap_err2string(return_code); |
380 | + printerror(); |
381 | + |
382 | + if(berv != NULL) |
383 | + { |
384 | + ber_free(berv, 0); |
385 | + } |
386 | + ldap_memfree(attr); |
387 | + ldap_msgfree(response); |
388 | + ldap_value_free(gid); |
389 | + ldap_value_free(uid); |
390 | + return true; |
391 | + } |
392 | + |
393 | + //If they are not in the same group, search for the supplementaries |
394 | + ldap_msgfree(response); |
395 | + ldap_memfree(attr); |
396 | + |
397 | + if(berv != NULL) |
398 | + { |
399 | + ber_free(berv, 0); |
400 | + } |
401 | + |
402 | + filter= "(cn=" + session_ctx.username() + ")"; |
403 | + |
404 | + const char *attrs2[]= {"gidNumber", NULL}; |
405 | + |
406 | + return_code= ldap_search_ext_s( ldap, |
407 | + users_dir.c_str(), |
408 | + LDAP_SCOPE_ONELEVEL, |
409 | + filter.c_str(), |
410 | + const_cast<char**>(attrs2), |
411 | + 0, |
412 | + NULL, |
413 | + NULL, |
414 | + NULL, |
415 | + 1, |
416 | + &response); |
417 | + |
418 | + |
419 | + if(return_code != LDAP_SUCCESS) |
420 | + { |
421 | + error= "ldap_search_ext_s failed:"; |
422 | + error+= ldap_err2string(return_code); |
423 | + printerror(); |
424 | + ldap_msgfree(response); |
425 | + ldap_value_free(gid); |
426 | + ldap_value_free(uid); |
427 | + return true; |
428 | + } |
429 | + |
430 | + LDAPMessage *entry2= ldap_first_entry(ldap, response); |
431 | + ldap_entries= ldap_count_entries(ldap, entry2); |
432 | + |
433 | + if(ldap_entries == 0 || ldap_entries == -1) |
434 | + { |
435 | + ldap_msgfree(response); |
436 | + ldap_value_free(gid); |
437 | + ldap_value_free(uid); |
438 | + return true; |
439 | + } |
440 | + |
441 | + attr= ldap_first_attribute(ldap, entry2, &berv); //attr is gidNumber |
442 | + char **gidNumber= ldap_get_values(ldap, entry2, attr); //we got the gidNumber of user B |
443 | + |
444 | + if(gidNumber==NULL) |
445 | + { |
446 | + if(berv != NULL) |
447 | + { |
448 | + ber_free(berv, 0); |
449 | + } |
450 | + |
451 | + ldap_memfree(attr); |
452 | + ldap_msgfree(response); |
453 | + ldap_value_free(gid); |
454 | + ldap_value_free(uid); |
455 | + return true; |
456 | + } |
457 | + |
458 | + filter= "gidNumber="; |
459 | + filter+= gidNumber[0]; |
460 | + |
461 | + // searching for the user B group attrs |
462 | + return_code= ldap_search_ext_s(ldap, |
463 | + groups_dir.c_str(), |
464 | + LDAP_SCOPE_ONELEVEL, |
465 | + filter.c_str(), |
466 | + NULL, /* all attributes are requested */ |
467 | + 0, |
468 | + NULL, |
469 | + NULL, |
470 | + NULL, |
471 | + 1, |
472 | + &response); |
473 | + |
474 | + if(return_code != LDAP_SUCCESS) |
475 | + { |
476 | + error= "ldap_search_ext_s failed:"; |
477 | + error+= ldap_err2string(return_code); |
478 | + printerror(); |
479 | + |
480 | + ldap_msgfree(response); |
481 | + ldap_value_free(gid); |
482 | + ldap_value_free(uid); |
483 | + |
484 | + return true; |
485 | + } |
486 | + |
487 | + LDAPMessage *grp_entry= ldap_first_entry(ldap, response); |
488 | + ldap_entries= ldap_count_entries(ldap, grp_entry); |
489 | + |
490 | + if(ldap_entries == 0 || ldap_entries == -1) |
491 | + { |
492 | + |
493 | + if(berv != NULL) |
494 | + { |
495 | + ber_free(berv, 0); |
496 | + } |
497 | + |
498 | + ldap_memfree(attr); |
499 | + ldap_msgfree(response); |
500 | + ldap_value_free(gidNumber); |
501 | + ldap_value_free(gid); |
502 | + ldap_value_free(uid); |
503 | + return true; |
504 | + } |
505 | + |
506 | + char *group_dn= ldap_get_dn(ldap, grp_entry); |
507 | + |
508 | + if(group_dn == NULL) |
509 | + { |
510 | + |
511 | + if(berv != NULL) |
512 | + { |
513 | + ber_free(berv, 0); |
514 | + } |
515 | + |
516 | + ldap_memfree(attr); |
517 | + ldap_value_free(gidNumber); |
518 | + ldap_value_free(gid); |
519 | + ldap_value_free(uid); |
520 | + |
521 | + return true; |
522 | + } |
523 | + |
524 | + if(uid == NULL) |
525 | + { |
526 | + return true; |
527 | + } |
528 | + struct berval ber_uid; |
529 | + ber_uid.bv_len= strlen(uid[0]); |
530 | + ber_uid.bv_val= uid[0]; |
531 | + |
532 | + return_code= ldap_compare_ext_s(ldap, |
533 | + group_dn, |
534 | + "memberUID", |
535 | + &ber_uid, |
536 | + NULL, |
537 | + NULL); |
538 | + bool retval= true; |
539 | + |
540 | + if(return_code == LDAP_COMPARE_TRUE) |
541 | + { |
542 | + retval= false; |
543 | + } |
544 | + else if(return_code != LDAP_COMPARE_FALSE) |
545 | + { |
546 | + error= "ldap_compare_ext_s failed:"; |
547 | + error+= ldap_err2string(return_code); |
548 | + printerror(); |
549 | + } |
550 | + |
551 | + ldap_memfree(group_dn); |
552 | + if(berv != NULL) |
553 | + { |
554 | + ber_free(berv, 0); |
555 | + } |
556 | + ldap_memfree(attr); |
557 | + ldap_value_free(gidNumber); |
558 | + ldap_value_free(gid); |
559 | + ldap_value_free(uid); |
560 | + |
561 | + return retval; |
562 | +} |
563 | + |
564 | + |
565 | +/** |
566 | + * check_if_allowed returns TRUE if user is NOT authorized in target table. Otherwise, it returns FALSE. |
567 | + * check_if_allowed function, checks if uidNumber attribute of user's LDAP record matches with |
568 | + * allowedUsers attribute of tables's LDAP record or gidNumber matches with allowedGroups. |
569 | + * If neither of them matches, check_if_allowed search for the supplementaries groups of user |
570 | + * and returns true if none of them is allowed. Otherwise it returns false. |
571 | + */ |
572 | + |
573 | +bool LDAP_policy::check_if_allowed(LDAPMessage *u_rep, const drizzled::identifier::User &user, const drizzled::identifier::Table &table) |
574 | +{ |
575 | + LDAPMessage *entry= ldap_first_entry(ldap, u_rep); |
576 | + int rc; |
577 | + string table_dn= "cn=" + table.getTableName() + "," + tables_dir; |
578 | + char *uattr, **gid= NULL, **uid= NULL; |
579 | + BerElement *uber_val; |
580 | + int ldap_entries= ldap_count_entries(ldap, entry); |
581 | + |
582 | + if(ldap_entries == 0 || ldap_entries == -1) |
583 | + { |
584 | + return true; |
585 | + } |
586 | + |
587 | + for(uattr= ldap_first_attribute(ldap, entry, &uber_val); |
588 | + uattr != NULL; |
589 | + uattr=ldap_next_attribute(ldap, entry, uber_val)) |
590 | + { |
591 | + if( not strcmp(uattr, "gidNumber")) |
592 | + { |
593 | + gid= ldap_get_values(ldap, entry, uattr); |
594 | + |
595 | + struct berval bval; |
596 | + bval.bv_val= gid[0]; |
597 | + bval.bv_len= strlen(gid[0]); |
598 | + |
599 | + rc= ldap_compare_ext_s( ldap, |
600 | + table_dn.c_str(), |
601 | + "allowedGroups", |
602 | + &bval, |
603 | + NULL, |
604 | + NULL); |
605 | + |
606 | + if(rc == LDAP_COMPARE_TRUE) |
607 | + { |
608 | + if(uber_val != NULL) |
609 | + { |
610 | + ber_free(uber_val, 0); |
611 | + } |
612 | + |
613 | + ldap_memfree(uattr); |
614 | + |
615 | + if(uid!=NULL) |
616 | + ldap_value_free(uid); |
617 | + |
618 | + ldap_value_free(gid); |
619 | + |
620 | + user_cache.insert(user, table, true); |
621 | + |
622 | + return false; |
623 | + } |
624 | + else if(rc != LDAP_COMPARE_FALSE) |
625 | + { |
626 | + error= "ldap_compare_ext_s failed: "; |
627 | + error+= ldap_err2string(rc); |
628 | + printerror(); |
629 | + |
630 | + if(uber_val != NULL) |
631 | + { |
632 | + ber_free(uber_val, 0); |
633 | + } |
634 | + |
635 | + ldap_memfree(uattr); |
636 | + |
637 | + if(uid!=NULL) |
638 | + ldap_value_free(uid); |
639 | + |
640 | + ldap_value_free(gid); |
641 | + |
642 | + return true; |
643 | + } |
644 | + |
645 | + } |
646 | + else if( not strcmp(uattr, "uidNumber")) |
647 | + { |
648 | + uid= ldap_get_values(ldap, entry, uattr); |
649 | + |
650 | + struct berval bval; |
651 | + bval.bv_val= uid[0]; |
652 | + bval.bv_len= strlen(uid[0]); |
653 | + |
654 | + rc= ldap_compare_ext_s( ldap, |
655 | + table_dn.c_str(), |
656 | + "allowedUsers", |
657 | + &bval, |
658 | + NULL, |
659 | + NULL); |
660 | + |
661 | + if( rc == LDAP_COMPARE_TRUE ) |
662 | + { |
663 | + |
664 | + if(uber_val != NULL) |
665 | + { |
666 | + ber_free(uber_val, 0); |
667 | + } |
668 | + ldap_memfree(uattr); |
669 | + |
670 | + if(gid!=NULL) |
671 | + ldap_value_free(gid); |
672 | + |
673 | + ldap_value_free(uid); |
674 | + |
675 | + user_cache.insert(user, table, true); |
676 | + |
677 | + return false; |
678 | + } |
679 | + else if(rc != LDAP_COMPARE_FALSE) |
680 | + { |
681 | + error= "ldap_compare_ext_s failed: "; |
682 | + error+= ldap_err2string(rc); |
683 | + printerror(); |
684 | + |
685 | + if(uber_val != NULL) |
686 | + { |
687 | + ber_free(uber_val, 0); |
688 | + } |
689 | + |
690 | + ldap_memfree(uattr); |
691 | + |
692 | + if(gid!=NULL) |
693 | + ldap_value_free(gid); |
694 | + |
695 | + ldap_value_free(uid); |
696 | + |
697 | + return true; |
698 | + } |
699 | + } |
700 | + } |
701 | + |
702 | + if(uber_val != NULL) |
703 | + { |
704 | + ber_free(uber_val, 0); |
705 | + } |
706 | + |
707 | + ldap_memfree(uattr); |
708 | + |
709 | + const char *group_attrs[]= { "gidNumber", |
710 | + NULL |
711 | + }; |
712 | + |
713 | + LDAPMessage *group_response; |
714 | + |
715 | + string filter= "(memberUID="; |
716 | + filter+= uid[0]; |
717 | + filter+= ")"; |
718 | + |
719 | + rc= ldap_search_ext_s(ldap, |
720 | + groups_dir.c_str(), |
721 | + LDAP_SCOPE_ONELEVEL, |
722 | + filter.c_str(), |
723 | + const_cast<char**>(group_attrs), |
724 | + 0, |
725 | + NULL, |
726 | + NULL, |
727 | + NULL, |
728 | + LDAP_NO_LIMIT, |
729 | + &group_response); |
730 | + |
731 | + if( rc != LDAP_SUCCESS) |
732 | + { |
733 | + error= "ldap_search_ext_s: "; |
734 | + error+= ldap_err2string(rc); |
735 | + printerror(); |
736 | + ldap_value_free(uid); |
737 | + ldap_value_free(gid); |
738 | + |
739 | + return true; |
740 | + } |
741 | + |
742 | + LDAPMessage *gentry= ldap_first_entry(ldap, group_response); |
743 | + ldap_entries= ldap_count_entries(ldap, gentry); |
744 | + |
745 | + if(ldap_entries == 0 || ldap_entries == -1) |
746 | + { |
747 | + ldap_value_free(gid); |
748 | + ldap_value_free(uid); |
749 | + ldap_msgfree(gentry); |
750 | + ldap_msgfree(group_response); |
751 | + |
752 | + return true; |
753 | + } |
754 | + |
755 | + BerElement *gber; |
756 | + char *gattr= ldap_first_attribute(ldap, gentry, &gber); // it has only one attribute, gidNumber |
757 | + |
758 | + if(gattr == NULL) |
759 | + { |
760 | + ldap_value_free(gid); |
761 | + ldap_value_free(uid); |
762 | + if(gber != NULL) |
763 | + { |
764 | + ber_free(gber, 0); |
765 | + } |
766 | + ldap_msgfree(group_response); |
767 | + ldap_msgfree(gentry); |
768 | + return true; |
769 | + } |
770 | + |
771 | + char **groups= ldap_get_values(ldap, gentry, gattr); // we have the gidNumber attribute of users' supplementaries groups |
772 | + |
773 | + if(groups == NULL) |
774 | + { |
775 | + ldap_value_free(gid); |
776 | + ldap_value_free(uid); |
777 | + if( gber != NULL ) |
778 | + { |
779 | + ber_free(gber, 0); |
780 | + } |
781 | + ldap_msgfree(group_response); |
782 | + ldap_msgfree(gentry); |
783 | + return true; |
784 | + } |
785 | + |
786 | + int num_of_val= ldap_count_values(groups) - 1; |
787 | + |
788 | + while( num_of_val >= 0) |
789 | + { |
790 | + struct berval bval; |
791 | + bval.bv_len= strlen(groups[num_of_val]); |
792 | + bval.bv_val= groups[num_of_val]; |
793 | + |
794 | + rc= ldap_compare_ext_s( ldap, |
795 | + table_dn.c_str(), |
796 | + "allowedGroups", |
797 | + &bval, |
798 | + NULL, |
799 | + NULL); |
800 | + |
801 | + if( rc == LDAP_COMPARE_TRUE ) |
802 | + { |
803 | + |
804 | + if(gber != NULL) |
805 | + { |
806 | + ber_free(gber, 0); |
807 | + } |
808 | + ldap_memfree(gattr); |
809 | + ldap_value_free(groups); |
810 | + ldap_value_free(gid); |
811 | + ldap_value_free(uid); |
812 | + ldap_msgfree(gentry); |
813 | + |
814 | + user_cache.insert(user, table, true); |
815 | + |
816 | + return false; |
817 | + } |
818 | + else if( rc != LDAP_COMPARE_FALSE ) |
819 | + { |
820 | + error= "ldap_compare_ext_s failed: "; |
821 | + error+= ldap_err2string(rc); |
822 | + printerror(); |
823 | + |
824 | + if(gber != NULL) |
825 | + { |
826 | + ber_free(gber, 0); |
827 | + } |
828 | + |
829 | + ldap_memfree(gattr); |
830 | + ldap_value_free(groups); |
831 | + ldap_value_free(gid); |
832 | + ldap_value_free(uid); |
833 | + ldap_msgfree(gentry); |
834 | + |
835 | + return true; |
836 | + } |
837 | + |
838 | + num_of_val--; |
839 | + } |
840 | + |
841 | + if(gber != NULL) |
842 | + { |
843 | + ber_free(gber, 0); |
844 | + } |
845 | + |
846 | + ldap_memfree(gattr); |
847 | + ldap_value_free(groups); |
848 | + ldap_value_free(gid); |
849 | + ldap_value_free(uid); |
850 | + ldap_msgfree(gentry); |
851 | + ldap_msgfree(group_response); |
852 | + |
853 | + user_cache.insert(user, table, false); |
854 | + |
855 | + return true; |
856 | +} |
857 | + |
858 | + |
859 | +/** |
860 | + * check_if_allowed returns TRUE if user is NOT authorized in target schema. Otherwise, it returns FALSE. |
861 | + * check_if_allowed function, checks if uidNumber attribute of user's LDAP record matches with |
862 | + * allowedUsers attribute of schema's LDAP record or gidNumber matches with allowedGroups. |
863 | + * If neither of them matches, check_if_allowed search for the supplementaries groups of user |
864 | + * and returns true if none of them is allowed. Otherwise it returns false. |
865 | + */ |
866 | + |
867 | +bool LDAP_policy::check_if_allowed(LDAPMessage *u_rep, const drizzled::identifier::User &user, const drizzled::identifier::Schema& schema) |
868 | +{ |
869 | + LDAPMessage *entry= ldap_first_entry(ldap, u_rep); |
870 | + int ldap_entries= ldap_count_entries(ldap, entry); |
871 | + if(ldap_entries == 0 || ldap_entries == -1) |
872 | + { |
873 | + return true; |
874 | + } |
875 | + |
876 | + int rc; |
877 | + string user_id; |
878 | + char *uattr, **gid= NULL, **uid= NULL; |
879 | + uid= NULL; |
880 | + BerElement *uber_val; |
881 | + string schema_dn= "cn=" + schema.getSchemaName() + "," + schemas_dir; |
882 | + |
883 | + for(uattr= ldap_first_attribute(ldap, entry, &uber_val); |
884 | + uattr!=NULL; |
885 | + uattr=ldap_next_attribute(ldap, entry, uber_val)) |
886 | + { |
887 | + |
888 | + if(not strcmp(uattr, "gidNumber")) |
889 | + { |
890 | + gid= ldap_get_values(ldap, entry, uattr); |
891 | + |
892 | + struct berval bval; |
893 | + bval.bv_val= gid[0]; |
894 | + bval.bv_len= strlen(gid[0]); |
895 | + |
896 | + rc= ldap_compare_ext_s( ldap, |
897 | + schema_dn.c_str(), |
898 | + "allowedGroups", |
899 | + &bval, |
900 | + NULL, |
901 | + NULL); |
902 | + |
903 | + if( rc == LDAP_COMPARE_TRUE) |
904 | + { |
905 | + if(uber_val != NULL) |
906 | + { |
907 | + ber_free(uber_val, 0); |
908 | + } |
909 | + ldap_memfree(uattr); |
910 | + ldap_value_free(gid); |
911 | + |
912 | + if(uid != NULL) |
913 | + ldap_value_free(uid); |
914 | + |
915 | + user_cache.insert(user, schema, true); |
916 | + |
917 | + return false; |
918 | + } |
919 | + else if(rc != LDAP_COMPARE_FALSE) |
920 | + { |
921 | + //Maybe when return code is "No such object" I could add in cache. |
922 | + |
923 | + error= "ldap_compare_ext_s failed: "; |
924 | + error+= ldap_err2string(rc); |
925 | + printerror(); |
926 | + |
927 | + if(uber_val != NULL) |
928 | + { |
929 | + ber_free(uber_val, 0); |
930 | + } |
931 | + |
932 | + ldap_memfree(uattr); |
933 | + ldap_value_free(gid); |
934 | + |
935 | + if( uid != NULL) |
936 | + ldap_value_free(uid); |
937 | + |
938 | + return true; |
939 | + } |
940 | + } |
941 | + else if (not strcmp(uattr, "uidNumber")) |
942 | + { |
943 | + uid= ldap_get_values(ldap, entry, uattr); |
944 | + |
945 | + struct berval bval; |
946 | + bval.bv_val= uid[0]; |
947 | + bval.bv_len= strlen(uid[0]); |
948 | + |
949 | + rc= ldap_compare_ext_s( ldap, |
950 | + schema_dn.c_str(), |
951 | + "allowedUsers", |
952 | + &bval, |
953 | + NULL, |
954 | + NULL); |
955 | + |
956 | + if( rc == LDAP_COMPARE_TRUE) |
957 | + { |
958 | + |
959 | + if(uber_val != NULL) |
960 | + { |
961 | + ber_free(uber_val, 0); |
962 | + } |
963 | + |
964 | + if(gid != NULL) |
965 | + ldap_value_free(gid); |
966 | + |
967 | + ldap_memfree(uattr); |
968 | + ldap_value_free(uid); |
969 | + |
970 | + user_cache.insert(user, schema, true); |
971 | + |
972 | + return false; |
973 | + } |
974 | + else if (rc != LDAP_COMPARE_FALSE) |
975 | + { |
976 | + |
977 | + error= "ldap_compare_ext_s failed: "; |
978 | + error+= ldap_err2string(rc); |
979 | + printerror(); |
980 | + if(uber_val != NULL) |
981 | + { |
982 | + ber_free(uber_val, 0); |
983 | + } |
984 | + ldap_memfree(uattr); |
985 | + |
986 | + if(uid != NULL) |
987 | + ldap_value_free(uid); |
988 | + |
989 | + ldap_value_free(gid); |
990 | + |
991 | + return true; |
992 | + } |
993 | + } |
994 | + } |
995 | + |
996 | + ldap_memfree(uattr); |
997 | + |
998 | + if(uber_val != NULL) |
999 | + { |
1000 | + ber_free(uber_val, 0); |
1001 | + } |
1002 | + |
1003 | + if(uid==NULL) |
1004 | + { |
1005 | + return true; |
1006 | + } |
1007 | + const char *gattrs[]= {"gidNumber", |
1008 | + NULL |
1009 | + }; |
1010 | + |
1011 | + LDAPMessage *group_response; |
1012 | + |
1013 | + string filter= "(memberUID="; |
1014 | + filter+= uid[0]; |
1015 | + filter+= ")"; |
1016 | + |
1017 | + rc= ldap_search_ext_s(ldap, |
1018 | + groups_dir.c_str(), |
1019 | + LDAP_SCOPE_ONELEVEL, |
1020 | + filter.c_str(), |
1021 | + const_cast<char**>(gattrs), |
1022 | + 0, |
1023 | + NULL, |
1024 | + NULL, |
1025 | + NULL, |
1026 | + LDAP_NO_LIMIT, |
1027 | + &group_response); |
1028 | + |
1029 | + if(rc != LDAP_SUCCESS) |
1030 | + { |
1031 | + error= "ldap_search_ext_s: "; |
1032 | + error+= ldap_err2string(rc); |
1033 | + printerror(); |
1034 | + return true; |
1035 | + } |
1036 | + |
1037 | + LDAPMessage *gentry= ldap_first_entry(ldap, group_response); |
1038 | + BerElement *gber; |
1039 | + |
1040 | + char *gattr= ldap_first_attribute(ldap, gentry, &gber); |
1041 | + char **groups= ldap_get_values(ldap, gentry, gattr); // exoyme ta groups sta opoia anoikei o user |
1042 | + |
1043 | + for(int num_of_values= ldap_count_values(groups) - 1; num_of_values >= 0; num_of_values--) |
1044 | + { |
1045 | + struct berval bval; |
1046 | + bval.bv_len= strlen(groups[num_of_values]); |
1047 | + bval.bv_val= groups[num_of_values]; |
1048 | + |
1049 | + if( ldap_compare_ext_s( ldap, |
1050 | + schema_dn.c_str(), |
1051 | + "allowedGroups", |
1052 | + &bval, |
1053 | + NULL, |
1054 | + NULL) == LDAP_COMPARE_TRUE) |
1055 | + { |
1056 | + |
1057 | + if(gber != NULL) |
1058 | + { |
1059 | + ber_free(gber, 0); |
1060 | + } |
1061 | + ldap_memfree(gattr); |
1062 | + ldap_value_free(groups); |
1063 | + |
1064 | + user_cache.insert(user, schema, true); |
1065 | + |
1066 | + return false; |
1067 | + } |
1068 | + } |
1069 | + |
1070 | + if(gber != NULL) |
1071 | + { |
1072 | + ber_free(gber, 0); |
1073 | + } |
1074 | + ldap_memfree(gattr); |
1075 | + ldap_value_free(groups); |
1076 | + ldap_msgfree(group_response); |
1077 | + |
1078 | + user_cache.insert(user, schema, false); |
1079 | + |
1080 | + return true; |
1081 | +} |
1082 | + |
1083 | +bool LDAP_policy::restrictTable(const drizzled::identifier::User &user_ctx, |
1084 | + const drizzled::identifier::Table& table) |
1085 | +{ |
1086 | + |
1087 | + if( table.getSchemaName() == "information_schema" || table.getSchemaName() == "INFORMATION_SCHEMA") |
1088 | + { |
1089 | + return false; |
1090 | + } |
1091 | + |
1092 | + LDAPMessage *user_response; |
1093 | + |
1094 | + const char *uattrs[]= { "uidNumber", |
1095 | + "gidNumber", |
1096 | + NULL |
1097 | + }; |
1098 | + |
1099 | + string filter= "(&(cn=" + user_ctx.username() + ")(BelongInSchema=" + table.getSchemaName() + "))"; |
1100 | + /* Schema attribute allows to determine from which schema, is the table we are looking for. |
1101 | + Still I need to implement the BelongInSchema schema */ |
1102 | + |
1103 | + CacheResponse cache_res= user_cache.is_authorized(user_ctx, table); |
1104 | + |
1105 | + if(cache_res == ALLOWED) |
1106 | + { |
1107 | + return false; |
1108 | + } |
1109 | + else if(cache_res == DENIED) |
1110 | + { |
1111 | + return true; |
1112 | + } |
1113 | + |
1114 | + int return_code= ldap_search_ext_s( ldap, |
1115 | + users_dir.c_str(), |
1116 | + LDAP_SCOPE_ONELEVEL, |
1117 | + filter.c_str(), |
1118 | + const_cast<char**>(uattrs), |
1119 | + 0, |
1120 | + NULL, |
1121 | + NULL, |
1122 | + NULL, |
1123 | + 1, |
1124 | + &user_response); |
1125 | + |
1126 | + if(return_code != LDAP_SUCCESS) |
1127 | + { |
1128 | + error= "ldap_search_ext_s failed:"; |
1129 | + error+= ldap_err2string(return_code); |
1130 | + printerror(); |
1131 | + |
1132 | + return true; |
1133 | + } |
1134 | + |
1135 | + bool restr= check_if_allowed(user_response, user_ctx, table); |
1136 | + |
1137 | + ldap_msgfree(user_response); |
1138 | + |
1139 | + return restr; |
1140 | +} |
1141 | + |
1142 | +bool LDAP_policy::restrictSchema(const drizzled::identifier::User &user_ctx, |
1143 | + const drizzled::identifier::Schema& schema) |
1144 | +{ |
1145 | + |
1146 | + if(schema.getSchemaName() == "information_schema" || schema.getSchemaName() == "INFORMATION_SCHEMA") |
1147 | + { |
1148 | + return false; |
1149 | + } |
1150 | + |
1151 | + CacheResponse cache_res= user_cache.is_authorized(user_ctx, schema); |
1152 | + |
1153 | + if(cache_res == ALLOWED) |
1154 | + { |
1155 | + return false; |
1156 | + } |
1157 | + else if (cache_res == DENIED) |
1158 | + { |
1159 | + return true; |
1160 | + } |
1161 | + |
1162 | + LDAPMessage *user_response; |
1163 | + const char *uattrs[]= { "uidNumber", |
1164 | + "gidNumber", |
1165 | + NULL |
1166 | + }; |
1167 | + string filter = "(cn=" + user_ctx.username() + ")"; |
1168 | + |
1169 | + int return_code= ldap_search_ext_s(ldap, |
1170 | + users_dir.c_str(), |
1171 | + LDAP_SCOPE_ONELEVEL, |
1172 | + filter.c_str(), |
1173 | + const_cast<char**>(uattrs), |
1174 | + 0, |
1175 | + NULL, |
1176 | + NULL, |
1177 | + NULL, |
1178 | + 1, |
1179 | + &user_response); //search for gidNumber and uidNumber in users' directory |
1180 | + |
1181 | + if(return_code != LDAP_SUCCESS) { |
1182 | + error= "ldap_search_ext_s failed:"; |
1183 | + error+= ldap_err2string(return_code); |
1184 | + printerror(); |
1185 | + return true; |
1186 | + } |
1187 | + |
1188 | + bool restr= check_if_allowed(user_response, user_ctx, schema); |
1189 | + ldap_msgfree(user_response); |
1190 | + |
1191 | + return restr; |
1192 | +} |
1193 | + |
1194 | +bool LDAP_policy::connect(void) |
1195 | +{ |
1196 | + int return_code= ldap_initialize(&ldap, (char *)uri.c_str()); |
1197 | + |
1198 | + if (return_code != LDAP_SUCCESS) |
1199 | + { |
1200 | + error= "ldap_initialize failed: "; |
1201 | + error+= ldap_err2string(return_code); |
1202 | + printerror(); |
1203 | + return false; |
1204 | + } |
1205 | + |
1206 | + int version= 3; |
1207 | + return_code= ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version); |
1208 | + |
1209 | + if (return_code != LDAP_SUCCESS) |
1210 | + { |
1211 | + ldap_unbind_ext_s(ldap, NULL, NULL); |
1212 | + ldap= NULL; |
1213 | + error= "ldap_set_option failed: "; |
1214 | + error+= ldap_err2string(return_code); |
1215 | + printerror(); |
1216 | + return false; |
1217 | + } |
1218 | + |
1219 | + return_code= ldap_simple_bind_s(ldap, NULL, NULL); |
1220 | + |
1221 | + if (return_code != LDAP_SUCCESS) |
1222 | + { |
1223 | + ldap_unbind(ldap); |
1224 | + ldap= NULL; |
1225 | + error= "ldap_simple_bind_s failed: "; |
1226 | + error+= ldap_err2string(return_code); |
1227 | + printerror(); |
1228 | + |
1229 | + return false; |
1230 | + } |
1231 | + |
1232 | + return true; |
1233 | + |
1234 | +} |
1235 | + |
1236 | +inline bool CacheItem::is_valid() const |
1237 | +{ |
1238 | + time_t temp_timer; |
1239 | + temp_timer = time(NULL); |
1240 | + |
1241 | + if(temp_timer - timer > cache_timeout) |
1242 | + { |
1243 | + return false; |
1244 | + } |
1245 | + else |
1246 | + { |
1247 | + return true; |
1248 | + } |
1249 | +} |
1250 | + |
1251 | +void UserCache::insert(const drizzled::identifier::User &user, const drizzled::identifier::Table &table, bool auth) |
1252 | +{ |
1253 | + string user_name= user.username(); |
1254 | + |
1255 | + if(table_cache.count(user_name) != 1) // user not found, need to insert a new one |
1256 | + { |
1257 | + CacheItem new_cache_item(user_name, table.getTableName(), table.getSchemaName(), auth); |
1258 | + table_cache.insert(CacheMap::value_type(user_name, ItemDeque())); |
1259 | + table_cache[user_name].push_back(new_cache_item); |
1260 | + } |
1261 | + else //user found |
1262 | + { |
1263 | + CacheItem new_cache_item(user_name, table.getTableName(), table.getSchemaName(), auth); |
1264 | + table_cache[user_name].push_back(new_cache_item); |
1265 | + } |
1266 | +} |
1267 | + |
1268 | +void UserCache::insert(const drizzled::identifier::User &user, const drizzled::identifier::Schema &schema, bool auth) |
1269 | +{ |
1270 | + string user_name= user.username(); |
1271 | + |
1272 | + if(schema_cache.count(user.username()) != 1) |
1273 | + { |
1274 | + CacheItem new_cache_item(user_name, "", schema.getSchemaName(), auth); |
1275 | + schema_cache.insert(CacheMap::value_type(user_name, ItemDeque())); |
1276 | + schema_cache[user_name].push_back(new_cache_item); |
1277 | + } |
1278 | + else |
1279 | + { |
1280 | + CacheItem new_cache_item(user_name, "", schema.getSchemaName(), auth); |
1281 | + schema_cache[user_name].push_back(new_cache_item); |
1282 | + } |
1283 | +} |
1284 | + |
1285 | +int UserCache::remove(const drizzled::identifier::User &user, const drizzled::identifier::Table &table) |
1286 | +{ |
1287 | + CacheMap_Iterator map_iterator; |
1288 | + map_iterator= table_cache.find(user.username()); |
1289 | + |
1290 | + if(map_iterator == table_cache.end() ) |
1291 | + { |
1292 | + return -1; |
1293 | + } |
1294 | + |
1295 | + ItemDeque::iterator deque_iter; |
1296 | + |
1297 | + string user_name= user.username(); |
1298 | + string table_name= table.getTableName(); |
1299 | + string schema_name= table.getSchemaName(); |
1300 | + |
1301 | + for( deque_iter= table_cache[user_name].begin(); |
1302 | + deque_iter != table_cache[user_name].end(); |
1303 | + deque_iter++) |
1304 | + { |
1305 | + if( (deque_iter->getTable() == table_name) |
1306 | + && (deque_iter->getSchema() == schema_name) ) |
1307 | + { |
1308 | + break; |
1309 | + } |
1310 | + } |
1311 | + |
1312 | + if(deque_iter != table_cache[user_name].end()) |
1313 | + { |
1314 | + table_cache[user_name].erase(deque_iter); |
1315 | + |
1316 | + return 0; |
1317 | + } |
1318 | + return -1; |
1319 | +} |
1320 | + |
1321 | +int UserCache::remove(const drizzled::identifier::User &user, const drizzled::identifier::Schema &schema) |
1322 | +{ |
1323 | + CacheMap_Iterator map_iterator; |
1324 | + map_iterator= schema_cache.find(user.username()); |
1325 | + |
1326 | + if( map_iterator == schema_cache.end()) |
1327 | + { |
1328 | + return -1; |
1329 | + } |
1330 | + |
1331 | + ItemDeque::iterator deque_iter; |
1332 | + |
1333 | + string user_name= user.username(); |
1334 | + string schema_name= schema.getSchemaName(); |
1335 | + |
1336 | + for( deque_iter= schema_cache[user_name].begin(); |
1337 | + deque_iter != schema_cache[user_name].end(); |
1338 | + deque_iter++) |
1339 | + { |
1340 | + if( deque_iter->getSchema() == schema_name) |
1341 | + { |
1342 | + break; |
1343 | + } |
1344 | + } |
1345 | + |
1346 | + if( deque_iter != schema_cache[user_name].end()) |
1347 | + { |
1348 | + schema_cache[user_name].erase(deque_iter); |
1349 | + |
1350 | + return 0; |
1351 | + } |
1352 | + return -1; |
1353 | +} |
1354 | + |
1355 | +CacheResponse UserCache::is_authorized(const drizzled::identifier::User &user, const drizzled::identifier::Schema &schema) |
1356 | +{ |
1357 | + if(schema_cache.size() == 0) |
1358 | + return NOT_FOUND; |
1359 | + |
1360 | + CacheMap_Iterator map_iterator; |
1361 | + map_iterator= schema_cache.find(user.username()); |
1362 | + |
1363 | + if(map_iterator != schema_cache.end()) |
1364 | + { |
1365 | + ItemDeque::iterator deque_iter; |
1366 | + |
1367 | + string user_name= user.username(); |
1368 | + string schema_name= schema.getSchemaName(); |
1369 | + |
1370 | + for(deque_iter= schema_cache[user_name].begin(); |
1371 | + deque_iter != schema_cache[user_name].end(); |
1372 | + deque_iter++) |
1373 | + { |
1374 | + if(deque_iter->getSchema() == schema_name) |
1375 | + { |
1376 | + break; |
1377 | + } |
1378 | + } |
1379 | + |
1380 | + |
1381 | + if(deque_iter != schema_cache[user_name].end()) |
1382 | + { |
1383 | + if(deque_iter->is_valid()) |
1384 | + { |
1385 | + if(deque_iter->is_authorized()) |
1386 | + { |
1387 | + return ALLOWED; |
1388 | + } |
1389 | + else |
1390 | + { |
1391 | + return DENIED; |
1392 | + } |
1393 | + } |
1394 | + else |
1395 | + { |
1396 | + remove(user, schema); |
1397 | + return NOT_FOUND; |
1398 | + } |
1399 | + } |
1400 | + else //not found |
1401 | + { |
1402 | + return NOT_FOUND; |
1403 | + } |
1404 | + } |
1405 | + else |
1406 | + { |
1407 | + return NOT_FOUND; |
1408 | + } |
1409 | +} |
1410 | + |
1411 | +CacheResponse UserCache::is_authorized(const drizzled::identifier::User &user, const drizzled::identifier::Table &table) |
1412 | +{ |
1413 | + if(table_cache.size() == 0) |
1414 | + return NOT_FOUND; |
1415 | + |
1416 | + CacheMap_Iterator map_iterator; |
1417 | + map_iterator= table_cache.find(user.username()); |
1418 | + |
1419 | + if(map_iterator != table_cache.end()) |
1420 | + { |
1421 | + ItemDeque::iterator deque_iter; |
1422 | + |
1423 | + string user_name= user.username(); |
1424 | + string table_name= table.getTableName(); |
1425 | + string schema_name= table.getSchemaName(); |
1426 | + |
1427 | + for(deque_iter= table_cache[user_name].begin(); |
1428 | + deque_iter != table_cache[user_name].end(); |
1429 | + deque_iter++) |
1430 | + { |
1431 | + if(deque_iter->getTable() == table_name |
1432 | + && deque_iter->getSchema() == schema_name) |
1433 | + { |
1434 | + break; |
1435 | + } |
1436 | + } |
1437 | + |
1438 | + |
1439 | + if(deque_iter != table_cache[user_name].end()) |
1440 | + { |
1441 | + if(deque_iter->is_valid()) |
1442 | + { |
1443 | + if(deque_iter->is_authorized()) |
1444 | + { |
1445 | + return ALLOWED; |
1446 | + } |
1447 | + else |
1448 | + { |
1449 | + return DENIED; |
1450 | + } |
1451 | + } |
1452 | + else //cache item has expired, so we should remove it |
1453 | + { |
1454 | + remove(user, table); |
1455 | + return NOT_FOUND; |
1456 | + } |
1457 | + } |
1458 | + else // table/schema for the user does not exist in cache |
1459 | + { |
1460 | + return NOT_FOUND; |
1461 | + } |
1462 | + } |
1463 | + else //user does not exist in cache |
1464 | + { |
1465 | + return NOT_FOUND; |
1466 | + } |
1467 | +} |
1468 | + |
1469 | +} /* namespace ldap_policy */ |
1470 | + |
1471 | +DRIZZLE_DECLARE_PLUGIN |
1472 | +{ |
1473 | + DRIZZLE_VERSION_ID, |
1474 | + "ldap_policy", |
1475 | + "0.1", |
1476 | + "Sialveras Zisis", |
1477 | + N_("LDAP based authorization system"), |
1478 | + PLUGIN_LICENSE_GPL, |
1479 | + ldap_policy::init, |
1480 | + NULL, |
1481 | + ldap_policy::init_options |
1482 | +} |
1483 | +DRIZZLE_DECLARE_PLUGIN_END; |
1484 | + |
1485 | |
1486 | === added file 'plugin/ldap_policy/ldap_policy.hpp' |
1487 | --- plugin/ldap_policy/ldap_policy.hpp 1970-01-01 00:00:00 +0000 |
1488 | +++ plugin/ldap_policy/ldap_policy.hpp 2012-08-21 14:09:20 +0000 |
1489 | @@ -0,0 +1,194 @@ |
1490 | +/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- |
1491 | + * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
1492 | + * |
1493 | + * Copyright (C) 2012 Zisis Sialveras |
1494 | + * |
1495 | + * This program is free software; you can redistribute it and/or modify |
1496 | + * it under the terms of the GNU General Public License as published by |
1497 | + * the Free Software Foundation; version 2 of the License. |
1498 | + * |
1499 | + * This program is distributed in the hope that it will be useful, |
1500 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1501 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1502 | + * GNU General Public License for more details. |
1503 | + * |
1504 | + * You should have received a copy of the GNU General Public License |
1505 | + * along with this program; if not, write to the Free Software |
1506 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1507 | + */ |
1508 | + |
1509 | + |
1510 | +#pragma once |
1511 | + |
1512 | +#include <config.h> |
1513 | + |
1514 | + |
1515 | +#include <boost/unordered_map.hpp> |
1516 | + |
1517 | +#include <drizzled/plugin/authorization.h> |
1518 | +#include <drizzled/plugin.h> |
1519 | + |
1520 | +#include <deque> |
1521 | +#include <string> |
1522 | +#include <ctime> |
1523 | + |
1524 | +#define LDAP_DEPRECATED 1 |
1525 | +#include <ldap.h> |
1526 | + |
1527 | +namespace ldap_policy |
1528 | +{ |
1529 | + |
1530 | +std::string DEFAULT_URI= "ldap://localhost/"; |
1531 | +std::string DEFAULT_USERS_DIR= "ou=users,dc=example,dc=com"; |
1532 | +std::string DEFAULT_SCHEMAS_DIR= "ou=schemas,dc=example,dc=com"; |
1533 | +std::string DEFAULT_TABLES_DIR= "ou=tables,dc=example,dc=com"; |
1534 | +std::string DEFAULT_GROUPS_DIR= "ou=groups,dc=example,dc=com"; |
1535 | +time_t DEFAULT_CACHE_TIMEOUT= 500; |
1536 | + |
1537 | +time_t cache_timeout; |
1538 | +std::string uri; |
1539 | +std::string groups_dir; |
1540 | +std::string base_dn; |
1541 | +std::string bind_passwd; |
1542 | +std::string users_dir; |
1543 | +std::string schemas_dir; |
1544 | +std::string tables_dir; |
1545 | + |
1546 | + |
1547 | +class CacheItem |
1548 | +{ |
1549 | + std::string user, table, schema; |
1550 | + bool authorized; |
1551 | + time_t timer; |
1552 | + |
1553 | + public: |
1554 | + |
1555 | + CacheItem(std::string u, std::string t, std::string s, bool a): user(u), table(t), schema(s), authorized(a) |
1556 | + { |
1557 | + timer = time(NULL); |
1558 | + }; |
1559 | + |
1560 | + /* |
1561 | + CacheItem() |
1562 | + { |
1563 | + gettimeofday(&tv, NULL); |
1564 | + }; |
1565 | + */ |
1566 | + |
1567 | + ~CacheItem(){}; |
1568 | + |
1569 | + inline bool is_valid() const; |
1570 | + |
1571 | + inline bool is_authorized() |
1572 | + { |
1573 | + return authorized; |
1574 | + }; |
1575 | + |
1576 | + void setTable(std::string t) |
1577 | + { |
1578 | + table = t; |
1579 | + }; |
1580 | + |
1581 | + void setSchema(std::string s) |
1582 | + { |
1583 | + schema = s; |
1584 | + }; |
1585 | + |
1586 | + inline std::string getTable() |
1587 | + { |
1588 | + return table; |
1589 | + }; |
1590 | + |
1591 | + inline std::string getSchema() |
1592 | + { |
1593 | + return schema; |
1594 | + }; |
1595 | + |
1596 | +}; |
1597 | + |
1598 | +typedef std::deque<CacheItem> ItemDeque; |
1599 | +typedef boost::unordered_map<std::string, ItemDeque> CacheMap; |
1600 | +typedef boost::unordered_map<std::string, ItemDeque>::const_iterator CacheMap_Iterator; |
1601 | + |
1602 | +typedef enum |
1603 | +{ |
1604 | + ALLOWED, |
1605 | + DENIED, |
1606 | + NOT_FOUND |
1607 | +} CacheResponse; |
1608 | + |
1609 | +class UserCache |
1610 | +{ |
1611 | + CacheMap table_cache, schema_cache; |
1612 | + |
1613 | + public: |
1614 | + |
1615 | + UserCache() {}; |
1616 | + |
1617 | + ~UserCache() {}; |
1618 | + |
1619 | + /** |
1620 | + * Insert a schema/table in cache for a specific user. |
1621 | + * |
1622 | + * If the last parametr is true then the user is allowed to access the schema/table. |
1623 | + * Otherwise, if it is false, access is denied. |
1624 | + */ |
1625 | + void insert(const drizzled::identifier::User &, const drizzled::identifier::Table &, bool ); |
1626 | + void insert(const drizzled::identifier::User &, const drizzled::identifier::Schema &, bool ); |
1627 | + |
1628 | + /** |
1629 | + * Removes a schema/table from cache for a specific user. |
1630 | + */ |
1631 | + int remove(const drizzled::identifier::User &, const drizzled::identifier::Table &); |
1632 | + int remove(const drizzled::identifier::User &, const drizzled::identifier::Schema &); |
1633 | + |
1634 | + /** |
1635 | + * Returns if a user is authorized to access target schema/table. |
1636 | + */ |
1637 | + CacheResponse is_authorized(const drizzled::identifier::User &, const drizzled::identifier::Table &); |
1638 | + CacheResponse is_authorized(const drizzled::identifier::User &, const drizzled::identifier::Schema &); |
1639 | + |
1640 | +} user_cache; |
1641 | + |
1642 | +class LDAP_policy : |
1643 | + public drizzled::plugin::Authorization |
1644 | +{ |
1645 | + |
1646 | + std::string error; |
1647 | + LDAP *ldap; |
1648 | + |
1649 | + void printerror(); |
1650 | + |
1651 | + bool check_if_allowed(LDAPMessage *, const drizzled::identifier::User &, const drizzled::identifier::Schema& ); |
1652 | + bool check_if_allowed(LDAPMessage *, const drizzled::identifier::User &, const drizzled::identifier::Table & ); |
1653 | + |
1654 | + public: |
1655 | + LDAP_policy(): |
1656 | + drizzled::plugin::Authorization("ldap_policy") |
1657 | + { |
1658 | + |
1659 | + } |
1660 | + |
1661 | + ~LDAP_policy() |
1662 | + { |
1663 | + if(ldap != NULL) |
1664 | + ldap_unbind(ldap); |
1665 | + } |
1666 | + |
1667 | + bool connect(void); |
1668 | + |
1669 | + virtual bool restrictSchema(const drizzled::identifier::User &user_ctx, |
1670 | + const drizzled::identifier::Schema& schema); |
1671 | + |
1672 | + virtual bool restrictProcess(const drizzled::identifier::User &user_ctx, |
1673 | + const drizzled::identifier::User &session_ctx); |
1674 | + |
1675 | + virtual bool restrictTable(const drizzled::identifier::User& user_ctx, |
1676 | + const drizzled::identifier::Table& table); |
1677 | + |
1678 | + |
1679 | +}; |
1680 | + |
1681 | +} /* namespace ldap_policy */ |
1682 | + |
1683 | + |
1684 | |
1685 | === added file 'plugin/ldap_policy/plugin.ini' |
1686 | --- plugin/ldap_policy/plugin.ini 1970-01-01 00:00:00 +0000 |
1687 | +++ plugin/ldap_policy/plugin.ini 2012-08-21 14:09:20 +0000 |
1688 | @@ -0,0 +1,3 @@ |
1689 | +[plugin] |
1690 | +build_conditional="x${ac_cv_libldap}" = "xyes" |
1691 | +ldflags=${LTLIBLDAP} |
1692 | |
1693 | === modified file 'tests/lib/server_mgmt/drizzled.py' |
1694 | --- tests/lib/server_mgmt/drizzled.py 2012-06-19 18:46:42 +0000 |
1695 | +++ tests/lib/server_mgmt/drizzled.py 2012-08-21 14:09:20 +0000 |
1696 | @@ -200,8 +200,9 @@ |
1697 | # This is what test-run.pl does and it helps us pass logging_stats tests |
1698 | # while not self.ping_server(server, quiet=True) and timer != timeout: |
1699 | |
1700 | - return self.system_manager.find_path( [self.pid_file] |
1701 | - , required=0) |
1702 | + #return self.system_manager.find_path( [self.pid_file] |
1703 | + # , required=0) |
1704 | + return self.ping(quiet=True) |
1705 | |
1706 | def create_slave_config_file(self): |
1707 | """ Create a config file suitable for use |
Thanks, this will be reviewed next.