diff --git a/include/NebulaTemplate.h b/include/NebulaTemplate.h index c2a738fcf6..a6d6385ea7 100644 --- a/include/NebulaTemplate.h +++ b/include/NebulaTemplate.h @@ -137,7 +137,9 @@ private: * Sets a the defaults for a Auth drivers */ void set_conf_auth(const std::string& name, - const std::string& change_password); + const std::string& change_password, + const std::string& drvier_managed_groups, + const std::string& max_token_time); }; diff --git a/include/UserPool.h b/include/UserPool.h index 4cae92db9a..dbc94720a7 100644 --- a/include/UserPool.h +++ b/include/UserPool.h @@ -251,6 +251,16 @@ private: string& gname, set& group_ids, int& umask); + + int parse_auth_msg( + AuthRequest &ar, + int &gid, + set &group_ids, + string &driver_name, + string &mad_name, + string &mad_pass, + string &error_str); + /** * Factory method to produce User objects * @return a pointer to the new User diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 31826d3676..05445ba726 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -1014,39 +1014,59 @@ MARKET_MAD_CONF = [ # name : name of the auth driver # password_change : allow the end users to change their own password. Oneadmin # can still change other user's passwords +# driver_managed_groups : allow the driver to set the user's group even after +# user creation. In this case addgroup, delgroup and chgrp +# will be disabled, with the exception of chgrp to one of +# the groups in the list of secondary groups +# max_token_time : limit the maximum token validity, in seconds. Use -1 for +# unlimited maximum, 0 to disable login tokens #******************************************************************************* AUTH_MAD_CONF = [ NAME = "core", - PASSWORD_CHANGE = "YES" + PASSWORD_CHANGE = "YES", + DRIVER_MANAGED_GROUPS = "NO", + MAX_TOKEN_TIME = "-1" ] AUTH_MAD_CONF = [ NAME = "public", - PASSWORD_CHANGE = "NO" + PASSWORD_CHANGE = "NO", + DRIVER_MANAGED_GROUPS = "NO", + MAX_TOKEN_TIME = "-1" ] AUTH_MAD_CONF = [ NAME = "ssh", - PASSWORD_CHANGE = "YES" + PASSWORD_CHANGE = "YES", + DRIVER_MANAGED_GROUPS = "NO", + MAX_TOKEN_TIME = "-1" ] AUTH_MAD_CONF = [ NAME = "x509", - PASSWORD_CHANGE = "NO" + PASSWORD_CHANGE = "NO", + DRIVER_MANAGED_GROUPS = "NO", + MAX_TOKEN_TIME = "-1" ] AUTH_MAD_CONF = [ NAME = "ldap", - PASSWORD_CHANGE = "YES" + PASSWORD_CHANGE = "YES", + DRIVER_MANAGED_GROUPS = "YES", + MAX_TOKEN_TIME = "86400" ] AUTH_MAD_CONF = [ NAME = "server_cipher", - PASSWORD_CHANGE = "NO" + PASSWORD_CHANGE = "NO", + DRIVER_MANAGED_GROUPS = "NO", + MAX_TOKEN_TIME = "-1" ] AUTH_MAD_CONF = [ NAME = "server_x509", - PASSWORD_CHANGE = "NO" + PASSWORD_CHANGE = "NO", + DRIVER_MANAGED_GROUPS = "NO", + MAX_TOKEN_TIME = "-1" ] diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 087c3f3ce2..fc24297f84 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -166,13 +166,13 @@ void OpenNebulaTemplate::set_multiple_conf_default() # server_x509 #****** */ - set_conf_auth("core", "YES"); - set_conf_auth("public", "NO"); - set_conf_auth("ssh", "YES"); - set_conf_auth("x509", "NO"); - set_conf_auth("ldap", "YES"); - set_conf_auth("server_cipher", "NO"); - set_conf_auth("server_x509", "NO"); + set_conf_auth("core", "YES", "NO", "-1"); + set_conf_auth("public", "NO", "NO", "-1"); + set_conf_auth("ssh", "YES", "NO", "-1"); + set_conf_auth("x509", "NO", "NO", "-1"); + set_conf_auth("ldap", "YES", "YES", "86400"); + set_conf_auth("server_cipher", "NO", "NO", "-1"); + set_conf_auth("server_x509", "NO", "NO", "-1"); register_multiple_conf_default("AUTH_MAD_CONF"); } @@ -312,13 +312,17 @@ void OpenNebulaTemplate::set_conf_market(const std::string& name, /* -------------------------------------------------------------------------- */ void OpenNebulaTemplate::set_conf_auth(const std::string& name, - const std::string& password_change) + const std::string& password_change, + const std::string& driver_managed_groups, + const std::string& max_token_time) { VectorAttribute * vattribute; std::map vvalue; vvalue.insert(make_pair("NAME", name)); vvalue.insert(make_pair("PASSWORD_CHANGE", password_change)); + vvalue.insert(make_pair("DRIVER_MANAGED_GROUPS", driver_managed_groups)); + vvalue.insert(make_pair("MAX_TOKEN_TIME", max_token_time)); vattribute = new VectorAttribute("AUTH_MAD_CONF", vvalue); conf_default.insert(make_pair(vattribute->name(), vattribute)); diff --git a/src/rm/RequestManagerChown.cc b/src/rm/RequestManagerChown.cc index 5792293023..62cbec8f9a 100644 --- a/src/rm/RequestManagerChown.cc +++ b/src/rm/RequestManagerChown.cc @@ -354,6 +354,7 @@ void UserChown::request_execute(xmlrpc_c::paramList const& paramList, string ngname; string uname; + string auth_driver; User * user; Group * group; @@ -361,6 +362,10 @@ void UserChown::request_execute(xmlrpc_c::paramList const& paramList, PoolObjectAuth uperms; PoolObjectAuth ngperms; + const VectorAttribute* auth_conf; + bool driver_managed_groups; + bool new_group; + if ( ngid < 0 ) { att.resp_msg = "Wrong group ID"; @@ -368,10 +373,36 @@ void UserChown::request_execute(xmlrpc_c::paramList const& paramList, return; } - rc = get_info(upool, oid, PoolObjectSQL::USER, att, uperms, uname, true); - - if ( rc == -1 ) + if ((user = upool->get(oid,true)) == 0 ) { + att.resp_obj = PoolObjectSQL::USER; + att.resp_id = oid; + failure_response(NO_EXISTS, att); + + return; + } + + user->get_permissions(uperms); + + uname = user->get_name(); + + auth_driver = user->get_auth_driver(); + new_group = user->get_groups().count(ngid) != 1; + + user->unlock(); + + driver_managed_groups = false; + + if (Nebula::instance().get_auth_conf_attribute(auth_driver, auth_conf) == 0) + { + auth_conf->vector_value("DRIVER_MANAGED_GROUPS", driver_managed_groups); + } + + if (driver_managed_groups && new_group) + { + att.resp_msg = + "Groups cannot be manually managed for auth driver "+auth_driver; + failure_response(ACTION, att); return; } diff --git a/src/rm/RequestManagerUser.cc b/src/rm/RequestManagerUser.cc index 525a8a4392..b4e62d2981 100644 --- a/src/rm/RequestManagerUser.cc +++ b/src/rm/RequestManagerUser.cc @@ -210,14 +210,45 @@ void UserEditGroup:: string gname; string uname; + string auth_driver; PoolObjectAuth uperms; PoolObjectAuth gperms; - rc = get_info(upool, user_id, PoolObjectSQL::USER, att, uperms, uname,true); + const VectorAttribute* auth_conf; + bool driver_managed_groups; - if ( rc == -1 ) + User* user; + + if ((user = upool->get(user_id,true)) == 0 ) { + att.resp_obj = PoolObjectSQL::USER; + att.resp_id = user_id; + failure_response(NO_EXISTS, att); + + return; + } + + user->get_permissions(uperms); + + uname = user->get_name(); + + auth_driver = user->get_auth_driver(); + + user->unlock(); + + driver_managed_groups = false; + + if (Nebula::instance().get_auth_conf_attribute(auth_driver, auth_conf) == 0) + { + auth_conf->vector_value("DRIVER_MANAGED_GROUPS", driver_managed_groups); + } + + if (driver_managed_groups) + { + att.resp_msg = + "Groups cannot be manually managed for auth driver "+auth_driver; + failure_response(ACTION, att); return; } @@ -387,6 +418,9 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList, User * user; string error_str; + string auth_driver; + time_t max_token_time; + const VectorAttribute* auth_conf; PoolObjectAuth perms; @@ -425,6 +459,44 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList, return; } + auth_driver = user->get_auth_driver(); + max_token_time = -1; + + if (Nebula::instance().get_auth_conf_attribute(auth_driver, auth_conf) == 0) + { + auth_conf->vector_value("MAX_TOKEN_TIME", max_token_time); + } + + if (max_token_time == 0) + { + att.resp_msg = "Login tokens are disabled for driver '"+ + user->get_auth_driver()+"'"; + failure_response(ACTION, att); + + // Reset token + user->login_token.reset(); + pool->update(user); + user->unlock(); + + return; + } + else if (max_token_time > 0) + { + valid = max(valid, max_token_time); + + if (max_token_time < valid) + { + valid = max_token_time; + + ostringstream oss; + + oss << "Req:" << att.req_id << " " << method_name + << " Token time has been overwritten with the MAX_TOKEN_TIME of " + << max_token_time << " set in oned.conf"; + NebulaLog::log("ReM",Log::WARNING,oss); + } + } + if (valid == 0) //Reset token { user->login_token.reset(); diff --git a/src/um/UserPool.cc b/src/um/UserPool.cc index 750bd00340..0f15933ddc 100644 --- a/src/um/UserPool.cc +++ b/src/um/UserPool.cc @@ -397,9 +397,24 @@ bool UserPool::authenticate_internal(User * user, string auth_driver; string username; + bool driver_managed_groups = false; + bool update_groups; + const VectorAttribute* auth_conf; + int new_gid = -1; + set new_group_ids; + + set groups_remove; + set groups_add; + set::iterator it; + + int rc; + Nebula& nd = Nebula::instance(); AuthManager * authm = nd.get_authm(); + Group* group; + GroupPool* gpool = nd.get_gpool(); + username = user->name; password = user->password; @@ -430,6 +445,11 @@ bool UserPool::authenticate_internal(User * user, return true; } + if (nd.get_auth_conf_attribute(auth_driver, auth_conf) == 0) + { + auth_conf->vector_value("DRIVER_MANAGED_GROUPS", driver_managed_groups); + } + AuthRequest ar(user_id, group_ids); if ( auth_driver == UserPool::CORE_AUTH ) @@ -457,20 +477,141 @@ bool UserPool::authenticate_internal(User * user, { goto auth_failure_driver; } + + if (driver_managed_groups) + { + //------------------------------------------------------------------ + // Parse driver response + //------------------------------------------------------------------ + + string driver_name; + string mad_name; + string mad_pass; + string error_str; + + rc = parse_auth_msg(ar, new_gid, new_group_ids, + driver_name, mad_name, mad_pass, error_str); + + if (rc != 0) + { + oss << "An error ocurred parsing the driver message. " + << error_str; + NebulaLog::log("AuM",Log::WARNING,oss); + + oss.str(""); + } + } } else { goto auth_failure_nodriver; } + update_groups = (driver_managed_groups && + (new_gid != -1) && (new_group_ids != group_ids)); + + if (update_groups && (new_group_ids.count(group_id) == 0)) + { + // Old primary group disappears from the list of new groups + group = gpool->get(new_gid, true); + + if (group != 0) + { + group_id = new_gid; + gname = group->get_name(); + + group->unlock(); + } + } + user = get(user_id, true); if (user != 0) { user->session.set(token, _session_expiration_time); + + if (update_groups) + { + // Previous groups that were not returned this time + std::set_difference(group_ids.begin(), group_ids.end(), + new_group_ids.begin(), new_group_ids.end(), + std::inserter(groups_remove, groups_remove.end())); + + // New groups + std::set_difference(new_group_ids.begin(), new_group_ids.end(), + group_ids.begin(), group_ids.end(), + std::inserter(groups_add, groups_add.end())); + + // Set main group + user->set_group(group_id, gname); + + // Add secondary group ids in the user object + for(it = groups_add.begin(); it != groups_add.end(); it++) + { + if (gpool->get(*it, false) != 0) + { + user->add_group(*it); + } + else + { + oss << "Driver " << auth_driver + << " returned the non-existing group ID " << *it + << " for user " << uname; + NebulaLog::log("AuM",Log::WARNING,oss); + + oss.str(""); + } + } + + // Remove secondary group ids from the user object + for(it = groups_remove.begin(); it != groups_remove.end(); it++) + { + user->del_group(*it); + } + + // Update the list of groups to return + group_ids = user->get_groups(); + + update(user); + } + user->unlock(); } + // Add/remove user ID from the group objects + + for(it = groups_add.begin(); it != groups_add.end(); it++) + { + group = gpool->get(*it, true); + + if (group == 0) + { + continue; + } + + group->add_user(user_id); + + gpool->update(group); + + group->unlock(); + } + + for(it = groups_remove.begin(); it != groups_remove.end(); it++) + { + group = gpool->get(*it, true); + + if (group == 0) + { + continue; + } + + group->del_user(user_id); + + gpool->update(group); + + group->unlock(); + } + return true; auth_failure_public: @@ -650,67 +791,24 @@ auth_failure: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -bool UserPool::authenticate_external(const string& username, - const string& token, - string& password, - int& user_id, - int& group_id, - string& uname, - string& gname, - set& group_ids, - int& umask) +int UserPool::parse_auth_msg( + AuthRequest &ar, + int &gid, + set &group_ids, + string &driver_name, + string &mad_name, + string &mad_pass, + string &error_str) { - ostringstream oss; istringstream is; - string driver_name; - string mad_name; - string mad_pass; - string error_str; - string tmp_str; - string default_auth; - - Nebula& nd = Nebula::instance(); - AuthManager * authm = nd.get_authm(); - GroupPool * gpool = nd.get_gpool(); - - User* user; - Group* group; - - int gid = -1; - - set::iterator it; - set empty_set; - - AuthRequest ar(-1,empty_set); - - if (authm == 0) - { - goto auth_failure_nodriver; - } - - //Initialize authentication request and call the driver - nd.get_configuration_attribute("DEFAULT_AUTH",default_auth); - - ar.add_authenticate(default_auth, username,"-",token); - - authm->trigger(AuthManager::AUTHENTICATE, &ar); - ar.wait(); - - if (ar.result != true) //User was not authenticated - { - goto auth_failure_driver; - } - - is.str(ar.message); - - user_id = -1; - //-------------------------------------------------------------------------- // Parse driver response format is: // [gid...] //-------------------------------------------------------------------------- + is.str(ar.message); + if ( is.good() ) { is >> driver_name >> ws; @@ -735,13 +833,13 @@ bool UserPool::authenticate_external(const string& username, if ( is.fail() ) { error_str = "One or more group IDs are malformed"; - goto auth_failure_user; + return -1; } - if ( gpool->get(tmp_gid, false) == 0 ) + if ( Nebula::instance().get_gpool()->get(tmp_gid, false) == 0 ) { error_str = "One or more group IDs do not exist"; - goto auth_failure_user; + return -1; } if ( gid == -1 ) //Keep the first id for primary group @@ -752,6 +850,78 @@ bool UserPool::authenticate_external(const string& username, group_ids.insert(tmp_gid); } + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +bool UserPool::authenticate_external(const string& username, + const string& token, + string& password, + int& user_id, + int& group_id, + string& uname, + string& gname, + set& group_ids, + int& umask) +{ + ostringstream oss; + + string driver_name; + string mad_name; + string mad_pass; + string error_str; + string tmp_str; + string default_auth; + + Nebula& nd = Nebula::instance(); + AuthManager * authm = nd.get_authm(); + GroupPool * gpool = nd.get_gpool(); + + User* user; + Group* group; + + int gid = -1; + int rc; + + set::iterator it; + set empty_set; + + AuthRequest ar(-1,empty_set); + + if (authm == 0) + { + goto auth_failure_nodriver; + } + + //Initialize authentication request and call the driver + nd.get_configuration_attribute("DEFAULT_AUTH",default_auth); + + ar.add_authenticate(default_auth, username,"-",token); + + authm->trigger(AuthManager::AUTHENTICATE, &ar); + ar.wait(); + + if (ar.result != true) //User was not authenticated + { + goto auth_failure_driver; + } + + user_id = -1; + + //-------------------------------------------------------------------------- + // Parse driver response + //-------------------------------------------------------------------------- + + rc = parse_auth_msg(ar, gid, group_ids, + driver_name, mad_name, mad_pass, error_str); + + if (rc != 0) + { + goto auth_failure_user; + } + //-------------------------------------------------------------------------- // Create the user, and set primary group //-------------------------------------------------------------------------- @@ -780,17 +950,14 @@ bool UserPool::authenticate_external(const string& username, group->unlock(); } - if ( !is.fail() ) - { - allocate(&user_id, - group_id, - mad_name, - gname, - mad_pass, - driver_name, - true, - error_str); - } + allocate(&user_id, + group_id, + mad_name, + gname, + mad_pass, + driver_name, + true, + error_str); if ( user_id == -1 ) {