~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/auth_ldap/auth_ldap.cc

Merge Joe, plus I updated the tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <string>
30
30
 
31
31
#include "drizzled/plugin/authentication.h"
32
 
#include "drizzled/identifier.h"
 
32
#include "drizzled/security_context.h"
33
33
#include "drizzled/util/convert.h"
34
34
#include "drizzled/algorithm/sha1.h"
35
35
 
36
 
#include <drizzled/module/option_map.h>
37
 
#include <boost/program_options.hpp>
38
 
 
39
 
namespace po= boost::program_options;
40
36
using namespace std;
41
37
using namespace drizzled;
42
38
 
43
39
namespace auth_ldap
44
40
{
45
41
 
46
 
std::string uri;
47
 
const std::string DEFAULT_URI= "ldap://127.0.0.1/";
48
 
std::string bind_dn;
49
 
std::string bind_password;
50
 
std::string base_dn;
51
 
std::string password_attribute;
52
 
std::string DEFAULT_PASSWORD_ATTRIBUTE= "userPassword";
53
 
std::string mysql_password_attribute;
54
 
const std::string DEFAULT_MYSQL_PASSWORD_ATTRIBUTE= "mysqlUserPassword";
 
42
static char *uri= NULL;
 
43
static const char DEFAULT_URI[]= "ldap://127.0.0.1/";
 
44
static char *bind_dn= NULL;
 
45
static char *bind_password= NULL;
 
46
static char *base_dn= NULL;
 
47
static char *password_attribute= NULL;
 
48
static const char DEFAULT_PASSWORD_ATTRIBUTE[]= "userPassword";
 
49
static char *mysql_password_attribute= NULL;
 
50
static const char DEFAULT_MYSQL_PASSWORD_ATTRIBUTE[]= "mysqlUserPassword";
 
51
static int cache_timeout= 0;
55
52
static const int DEFAULT_CACHE_TIMEOUT= 600;
56
 
typedef constrained_check<int, DEFAULT_CACHE_TIMEOUT, 0, 2147483647> cachetimeout_constraint;
57
 
static cachetimeout_constraint cache_timeout= 0;
58
 
 
59
53
 
60
54
class AuthLDAP: public plugin::Authentication
61
55
{
92
86
    MYSQL_HASH
93
87
  } PasswordType;
94
88
 
95
 
  typedef std::pair<PasswordType, std::string> PasswordEntry;
96
 
  typedef std::pair<std::string, PasswordEntry> UserEntry;
97
 
  typedef std::map<std::string, PasswordEntry> UserCache;
 
89
  typedef pair<PasswordType, string> PasswordEntry;
 
90
  typedef pair<string, PasswordEntry> UserEntry;
 
91
  typedef map<string, PasswordEntry> UserCache;
98
92
 
99
93
  /**
100
94
   * Base class method to check authentication for a user.
101
95
   */
102
 
  bool authenticate(const identifier::User &sctx, const string &password);
 
96
  bool authenticate(const SecurityContext &sctx, const string &password);
103
97
 
104
98
  /**
105
99
   * Lookup a user in LDAP.
160
154
 
161
155
bool AuthLDAP::connect(void)
162
156
{
163
 
  int return_code= ldap_initialize(&ldap, (char *)uri.c_str());
 
157
  int return_code= ldap_initialize(&ldap, uri);
164
158
  if (return_code != LDAP_SUCCESS)
165
159
  {
166
160
    error= "ldap_initialize failed: ";
179
173
    return false;
180
174
  }
181
175
 
182
 
  if (not bind_dn.empty())
 
176
  if (bind_dn != NULL)
183
177
  {
184
 
    return_code= ldap_simple_bind_s(ldap, (char *)bind_dn.c_str(), (char *)bind_password.c_str());
 
178
    return_code= ldap_simple_bind_s(ldap, bind_dn, bind_password);
185
179
    if (return_code != LDAP_SUCCESS)
186
180
    {
187
181
      ldap_unbind(ldap);
200
194
  return error;
201
195
}
202
196
 
203
 
bool AuthLDAP::authenticate(const identifier::User &sctx, const string &password)
 
197
bool AuthLDAP::authenticate(const SecurityContext &sctx, const string &password)
204
198
{
205
199
  /* See if cache should be emptied. */
206
200
  if (cache_timeout > 0)
222
216
 
223
217
  pthread_rwlock_rdlock(&lock);
224
218
 
225
 
  AuthLDAP::UserCache::const_iterator user= users.find(sctx.username());
 
219
  AuthLDAP::UserCache::const_iterator user= users.find(sctx.getUser());
226
220
  if (user == users.end())
227
221
  {
228
222
    pthread_rwlock_unlock(&lock);
230
224
    pthread_rwlock_wrlock(&lock);
231
225
 
232
226
    /* Make sure the user was not added while we unlocked. */
233
 
    user= users.find(sctx.username());
 
227
    user= users.find(sctx.getUser());
234
228
    if (user == users.end())
235
 
      lookupUser(sctx.username());
 
229
      lookupUser(sctx.getUser());
236
230
 
237
231
    pthread_rwlock_unlock(&lock);
238
232
 
239
233
    pthread_rwlock_rdlock(&lock);
240
234
 
241
235
    /* Get user again because map may have changed while unlocked. */
242
 
    user= users.find(sctx.username());
 
236
    user= users.find(sctx.getUser());
243
237
    if (user == users.end())
244
238
    {
245
239
      pthread_rwlock_unlock(&lock);
253
247
    return false;
254
248
  }
255
249
 
256
 
  if (sctx.getPasswordType() == identifier::User::MYSQL_HASH)
 
250
  if (sctx.getPasswordType() == SecurityContext::MYSQL_HASH)
257
251
  {
258
252
    bool allow= verifyMySQLHash(user->second, sctx.getPasswordContext(), password);
259
253
    pthread_rwlock_unlock(&lock);
275
269
  string filter("(cn=" + user + ")");
276
270
  const char *attributes[3]=
277
271
  {
278
 
    (char *)password_attribute.c_str(),
279
 
    (char *)mysql_password_attribute.c_str(),
 
272
    password_attribute,
 
273
    mysql_password_attribute,
280
274
    NULL
281
275
  };
282
276
  LDAPMessage *result;
288
282
    {
289
283
      if (! connect())
290
284
      {
291
 
        errmsg_printf(error::ERROR, _("Reconnect failed: %s\n"),
 
285
        errmsg_printf(ERRMSG_LVL_ERROR, _("Reconnect failed: %s\n"),
292
286
                      getError().c_str());
293
287
        return;
294
288
      }
295
289
    }
296
290
 
297
291
    int return_code= ldap_search_ext_s(ldap,
298
 
                                       (char *)base_dn.c_str(),
 
292
                                       base_dn,
299
293
                                       LDAP_SCOPE_ONELEVEL,
300
294
                                       filter.c_str(),
301
295
                                       const_cast<char **>(attributes),
307
301
                                       &result);
308
302
    if (return_code != LDAP_SUCCESS)
309
303
    {
310
 
      errmsg_printf(error::ERROR, _("ldap_search_ext_s failed: %s\n"),
 
304
      errmsg_printf(ERRMSG_LVL_ERROR, _("ldap_search_ext_s failed: %s\n"),
311
305
                    ldap_err2string(return_code));
312
306
 
313
307
      /* Only try one reconnect per request. */
331
325
    new_password= AuthLDAP::PasswordEntry(NOT_FOUND, "");
332
326
  else
333
327
  {
334
 
    char **values= ldap_get_values(ldap, entry, (char *)mysql_password_attribute.c_str());
 
328
    char **values= ldap_get_values(ldap, entry, mysql_password_attribute);
335
329
    if (values == NULL)
336
330
    {
337
 
      values= ldap_get_values(ldap, entry, (char *)password_attribute.c_str());
 
331
      values= ldap_get_values(ldap, entry, password_attribute);
338
332
      if (values == NULL)
339
333
        new_password= AuthLDAP::PasswordEntry(NOT_FOUND, "");
340
334
      else
413
407
  AuthLDAP *auth_ldap= new AuthLDAP("auth_ldap");
414
408
  if (! auth_ldap->initialize())
415
409
  {
416
 
    errmsg_printf(error::ERROR, _("Could not load auth ldap: %s\n"),
 
410
    errmsg_printf(ERRMSG_LVL_ERROR, _("Could not load auth ldap: %s\n"),
417
411
                  auth_ldap->getError().c_str());
418
412
    delete auth_ldap;
419
413
    return 1;
420
414
  }
421
415
 
422
 
  context.registerVariable(new sys_var_const_string_val("uri", uri));
423
 
  context.registerVariable(new sys_var_const_string_val("bind-dn", bind_dn));
424
 
  context.registerVariable(new sys_var_const_string_val("bind-password", bind_password));
425
 
  context.registerVariable(new sys_var_const_string_val("base-dn", base_dn));
426
 
  context.registerVariable(new sys_var_const_string_val("password-attribute",password_attribute));
427
 
  context.registerVariable(new sys_var_const_string_val("mysql-password-attribute", mysql_password_attribute));
428
 
  context.registerVariable(new sys_var_constrained_value_readonly<int>("cache-timeout", cache_timeout));
429
 
 
430
416
  context.add(auth_ldap);
431
417
  return 0;
432
418
}
433
419
 
434
 
static void init_options(drizzled::module::option_context &context)
 
420
static DRIZZLE_SYSVAR_STR(uri,
 
421
                          uri,
 
422
                          PLUGIN_VAR_READONLY,
 
423
                          N_("URI of the LDAP server to contact"),
 
424
                          NULL, /* check func */
 
425
                          NULL, /* update func*/
 
426
                          DEFAULT_URI);
 
427
 
 
428
static DRIZZLE_SYSVAR_STR(bind_dn,
 
429
                          bind_dn,
 
430
                          PLUGIN_VAR_READONLY,
 
431
                          N_("DN to use when binding to the LDAP server"),
 
432
                          NULL, /* check func */
 
433
                          NULL, /* update func*/
 
434
                          NULL); /* default value */
 
435
 
 
436
static DRIZZLE_SYSVAR_STR(bind_password,
 
437
                          bind_password,
 
438
                          PLUGIN_VAR_READONLY,
 
439
                          N_("Password to use when binding the DN"),
 
440
                          NULL, /* check func */
 
441
                          NULL, /* update func*/
 
442
                          NULL); /* default value */
 
443
 
 
444
static DRIZZLE_SYSVAR_STR(base_dn,
 
445
                          base_dn,
 
446
                          PLUGIN_VAR_READONLY,
 
447
                          N_("DN to use when searching"),
 
448
                          NULL, /* check func */
 
449
                          NULL, /* update func*/
 
450
                          NULL); /* default value */
 
451
 
 
452
static DRIZZLE_SYSVAR_STR(password_attribute,
 
453
                          password_attribute,
 
454
                          PLUGIN_VAR_READONLY,
 
455
                          N_("Attribute in LDAP with plain text password"),
 
456
                          NULL, /* check func */
 
457
                          NULL, /* update func*/
 
458
                          DEFAULT_PASSWORD_ATTRIBUTE);
 
459
 
 
460
static DRIZZLE_SYSVAR_STR(mysql_password_attribute,
 
461
                          mysql_password_attribute,
 
462
                          PLUGIN_VAR_READONLY,
 
463
                          N_("Attribute in LDAP with MySQL hashed password"),
 
464
                          NULL, /* check func */
 
465
                          NULL, /* update func*/
 
466
                          DEFAULT_MYSQL_PASSWORD_ATTRIBUTE);
 
467
 
 
468
static DRIZZLE_SYSVAR_INT(cache_timeout,
 
469
                          cache_timeout,
 
470
                          PLUGIN_VAR_READONLY,
 
471
                          N_("How often to empty the users cache, 0 to disable"),
 
472
                          NULL, /* check func */
 
473
                          NULL, /* update func */
 
474
                          DEFAULT_CACHE_TIMEOUT,
 
475
                          0,
 
476
                          2147483647,
 
477
                          0);
 
478
 
 
479
static drizzle_sys_var* sys_variables[]=
435
480
{
436
 
  context("uri", po::value<string>(&uri)->default_value(DEFAULT_URI),
437
 
          N_("URI of the LDAP server to contact"));
438
 
  context("bind-db", po::value<string>(&bind_dn)->default_value(""),
439
 
          N_("DN to use when binding to the LDAP server"));
440
 
  context("bind-password", po::value<string>(&bind_password)->default_value(""),
441
 
          N_("Password to use when binding the DN"));
442
 
  context("base-dn", po::value<string>(&base_dn)->default_value(""),
443
 
          N_("DN to use when searching"));
444
 
  context("password-attribute", po::value<string>(&password_attribute)->default_value(DEFAULT_PASSWORD_ATTRIBUTE),
445
 
          N_("Attribute in LDAP with plain text password"));
446
 
  context("mysql-password-attribute", po::value<string>(&mysql_password_attribute)->default_value(DEFAULT_MYSQL_PASSWORD_ATTRIBUTE),
447
 
          N_("Attribute in LDAP with MySQL hashed password"));
448
 
  context("cache-timeout", po::value<cachetimeout_constraint>(&cache_timeout)->default_value(DEFAULT_CACHE_TIMEOUT),
449
 
          N_("How often to empty the users cache, 0 to disable"));
450
 
}
 
481
  DRIZZLE_SYSVAR(uri),
 
482
  DRIZZLE_SYSVAR(bind_dn),
 
483
  DRIZZLE_SYSVAR(bind_password),
 
484
  DRIZZLE_SYSVAR(base_dn),
 
485
  DRIZZLE_SYSVAR(password_attribute),
 
486
  DRIZZLE_SYSVAR(mysql_password_attribute),
 
487
  DRIZZLE_SYSVAR(cache_timeout),
 
488
  NULL
 
489
};
451
490
 
452
491
} /* namespace auth_ldap */
453
492
 
454
 
DRIZZLE_PLUGIN(auth_ldap::init, NULL, auth_ldap::init_options);
 
493
DRIZZLE_PLUGIN(auth_ldap::init, auth_ldap::sys_variables, NULL);