Merge lp:~zisis00/drizzle/ldap_policy into lp:drizzle

Proposed by Zisis Sialveras
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
Reviewer Review Type Date Requested Status
Drizzle Trunk Pending
Review via email: mp+119016@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Brian Aker (brianaker) wrote :

Thanks, this will be reviewed next.

lp:~zisis00/drizzle/ldap_policy updated
2556. By Zisis Sialveras

Fixed some errors in ldap_policy

2557. By Zisis Sialveras

Documentation for ldap-policy

Revision history for this message
Brian Aker (brianaker) wrote :

  CXX plugin/performance_dictionary/plugin_libperformance_dictionary_plugin_la-session_usage.lo
  CXX plugin/performance_dictionary/plugin_libperformance_dictionary_plugin_la-session_usage_logger.lo
plugin/ldap_policy/ldap_policy.cc: In member function 'virtual bool ldap_policy::LDAP_policy::restrictProcess(const drizzled::identifier::User&, const drizzled::identifier::User&)':
plugin/ldap_policy/ldap_policy.cc:331:32: error: 'uid' may be used uninitialized in this function [-Werror=uninitialized]
plugin/ldap_policy/ldap_policy.cc:152:28: error: 'gid' may be used uninitialized in this function [-Werror=uninitialized]
  CXX plugin/query_log/plugin_libquery_log_plugin_la-module.lo
cc1plus: all warnings being treated as errors
  CXX plugin/query_log/plugin_libquery_log_plugin_la-query_log.lo
make[2]: *** [plugin/ldap_policy/plugin_libldap_policy_plugin_la-ldap_policy.lo] Error 1
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory `/home/jenkins/workspace/drizzle-smoke-test/label/ubuntu-12.04'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/jenkins/workspace/drizzle-smoke-test/label/ubuntu-12.04'
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches

to all changes: