Files
one/src/um/UserPool.cc
T
Ruben S. Montero 9aa1041103 F #3600: Initial PostgreSQL Support
co-authored-by: Igor Sivy <igorsivy@gmail.com>
co-authored-by: Pavel Czerny <pczerny@opennebula.io>
co-authored-by: Vlastimil Holer <vholer@opennebula.io>
(cherry picked from commit c52f62018c32281c6e418211f33f1bba46388e98)
2020-04-13 17:35:06 +02:00

1502 lines
36 KiB
C++

/* -------------------------------------------------------------------------- */
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
/* ************************************************************************** */
/* User Pool */
/* ************************************************************************** */
#include "UserPool.h"
#include "NebulaLog.h"
#include "Nebula.h"
#include "AuthManager.h"
#include "NebulaUtil.h"
#include "Client.h"
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <fnmatch.h>
const char * UserPool::CORE_AUTH = "core";
const char * UserPool::SERVER_AUTH = "server*";
const char * UserPool::PUBLIC_AUTH = "public";
const char * UserPool::SERVER_NAME = "serveradmin";
const int UserPool::ONEADMIN_ID = 0;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
time_t UserPool::_session_expiration_time;
string UserPool::oneadmin_name;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
UserPool::UserPool(SqlDB * db, time_t __session_expiration_time, bool is_slave,
vector<const SingleAttribute *>& restricted_attrs):PoolSQL(db, User::table)
{
int one_uid = -1;
int server_uid = -1;
int i;
ostringstream oss;
string one_token;
string one_name;
string one_pass;
string random;
set<int> gids;
set<int> agids;
string filenames[5];
string error_str;
Nebula& nd = Nebula::instance();
_session_expiration_time = __session_expiration_time;
// Set restricted attributes
UserTemplate::parse_restricted(restricted_attrs);
User * oneadmin_user = get_ro(0);
//Slaves do not need to init the pool, just the oneadmin username
if (is_slave)
{
if (oneadmin_user == 0)
{
throw("Database has not been bootstrapped with master data.");
}
oneadmin_name = oneadmin_user->get_name();
oneadmin_user->unlock();
return;
}
if (oneadmin_user != 0)
{
oneadmin_name = oneadmin_user->get_name();
oneadmin_user->unlock();
return;
}
// User oneadmin needs to be added in the bootstrap
if ( Client::read_oneauth(one_token, error_str) != 0 )
{
goto error_readoneauth;
}
if (User::split_secret(one_token,one_name,one_pass) != 0)
{
goto error_token;
}
oneadmin_name = one_name;
if ( one_name == SERVER_NAME )
{
goto error_one_name;
}
random = one_util::random_password();
filenames[0] = nd.get_var_location() + "/.one/sunstone_auth";
filenames[1] = nd.get_var_location() + "/.one/occi_auth";
filenames[2] = nd.get_var_location() + "/.one/ec2_auth";
filenames[3] = nd.get_var_location() + "/.one/onegate_auth";
filenames[4] = nd.get_var_location() + "/.one/oneflow_auth";
mkdir(string(nd.get_var_location() + "/.one").c_str(), S_IRWXU);
for (i=0 ; i < 5; i++)
{
struct stat file_stat;
if ( stat(filenames[i].c_str(), &file_stat) == 0 )
{
goto erro_exists;
}
int cfile = creat(filenames[i].c_str(), S_IRUSR | S_IWUSR);
close(cfile);
ofstream ofile;
ofile.open(filenames[i].c_str(), ios::out | ios::trunc);
if ( !ofile.is_open() )
{
goto error_no_open;
}
ofile << SERVER_NAME << ":" << random << endl;
ofile.close();
}
gids.insert(GroupPool::ONEADMIN_ID);
allocate(&one_uid,
one_name,
GroupPool::ONEADMIN_ID,
one_pass,
UserPool::CORE_AUTH,
true,
gids,
agids,
error_str);
if ( one_uid != 0 )
{
goto error_oneadmin;
}
allocate(&server_uid,
SERVER_NAME,
GroupPool::ONEADMIN_ID,
one_util::sha256_digest(random),
"server_cipher",
true,
gids,
agids,
error_str);
if ( server_uid != 1 )
{
goto error_serveradmin;
}
return;
error_readoneauth:
oss << "Error reading one_auth: " << error_str;
goto error_common;
error_token:
oss << "Wrong format must be <username>:<password>";
goto error_common;
error_one_name:
oss << "The name '" << SERVER_NAME << "' is reserved";
goto error_common;
error_no_open:
oss << "Could not create configuration file "<< filenames[i];
goto error_common;
erro_exists:
oss << "Password file " << filenames[i] << " already exists "
<< "but OpenNebula is boostraping the database. Check your "
<< "database configuration in oned.conf.";
goto error_common;
error_oneadmin:
oss << "Error creating oneadmin user: " << error_str;
goto error_common;
error_serveradmin:
oss << "Error creating server_admin user: " << error_str;
error_common:
NebulaLog::log("ONE",Log::ERROR,oss);
throw runtime_error(oss.str());
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static int master_allocate(const string& uname, const string& passwd,
const string& driver, const set<int>& gids, string& error_str)
{
Client * client = Client::client();
xmlrpc_c::value result;
vector<xmlrpc_c::value> values;
std::ostringstream oss("Cannot allocate user at federation master: ",
std::ios::ate);
try
{
client->call("one.user.allocate", "sssI", &result, uname.c_str(),
passwd.c_str(), driver.c_str(), &gids);
}
catch (exception const& e)
{
oss << e.what();
error_str = oss.str();
return -1;
}
values = xmlrpc_c::value_array(result).vectorValueValue();
if ( xmlrpc_c::value_boolean(values[0]) == false )
{
std::string error_xml = xmlrpc_c::value_string(values[1]);
oss << error_xml;
error_str = oss.str();
return -1;
}
int oid = xmlrpc_c::value_int(values[1]);
return oid;
}
/* -------------------------------------------------------------------------- */
static int master_chgrp(int user_id, int group_id, string& error_str)
{
Client * client = Client::client();
xmlrpc_c::value result;
vector<xmlrpc_c::value> values;
std::ostringstream oss("Cannot change user group at federation master: ",
std::ios::ate);
try
{
client->call("one.user.chgrp", "ii", &result, user_id, group_id);
}
catch (exception const& e)
{
oss << e.what();
error_str = oss.str();
return -1;
}
values = xmlrpc_c::value_array(result).vectorValueValue();
if ( xmlrpc_c::value_boolean(values[0]) == false )
{
std::string error_xml = xmlrpc_c::value_string(values[1]);
oss << error_xml;
error_str = oss.str();
return -1;
}
return 0;
};
/* -------------------------------------------------------------------------- */
int UserPool::allocate(
int * oid,
const string& uname,
int gid,
const string& password,
const string& auth,
bool enabled,
const set<int>& gids,
const set<int>& agids,
string& error_str)
{
Nebula& nd = Nebula::instance();
int db_oid;
User * user;
GroupPool * gpool = nd.get_gpool();
string auth_driver = auth;
string upass = password;
string gname;
ostringstream oss;
if (nd.is_federation_slave())
{
*oid = master_allocate(uname, password, auth, gids, error_str);
if ( *oid < 0 )
{
NebulaLog::log("ONE", Log::ERROR, error_str);
return -1;
}
if ( master_chgrp(*oid, gid, error_str) == -1 )
{
NebulaLog::log("ONE", Log::ERROR, error_str);
}
return *oid;
}
// Check username and password
if ( !User::pass_is_valid(password, error_str) )
{
goto error_pass;
}
if (!PoolObjectSQL::name_is_valid(uname,User::INVALID_NAME_CHARS,error_str))
{
goto error_name;
}
// Check for duplicates
db_oid = exist(uname);
if ( db_oid != -1 )
{
goto error_duplicated;
}
// Set auth driver and hash password for CORE_AUTH
if (auth_driver.empty())
{
auth_driver = UserPool::CORE_AUTH;
}
if (auth_driver == UserPool::CORE_AUTH)
{
upass = one_util::sha256_digest(password);
}
if (gids.empty())
{
goto error_no_groups;
}
gname = gpool->get_name(gid);
if(gname.empty())
{
goto error_no_groups;
}
// Build a new User object
user = new User(-1, gid, uname, gname, upass, auth_driver, enabled);
// Add the primary and secondary groups to the collection
for(set<int>::const_iterator it = gids.begin(); it != gids.end(); it++)
{
user->add_group(*it);
}
// Set a password for the OneGate tokens
user->add_template_attribute("TOKEN_PASSWORD", one_util::random_password());
// Insert the Object in the pool
*oid = PoolSQL::allocate(user, error_str);
if ( *oid < 0 )
{
return *oid;
}
// Add the user to the main and secondary groups
for(set<int>::const_iterator it = gids.begin(); it != gids.end(); it++)
{
Group * group = gpool->get(*it);
if( group == 0 ) //Secondary group no longer exists
{
goto error_group;
}
group->add_user(*oid);
gpool->update(group);
group->unlock();
}
// Set the user group admin
for(set<int>::const_iterator it = agids.begin(); it != agids.end(); it++)
{
Group * group = gpool->get(*it);
if( group == 0 ) //Secondary group no longer exists
{
goto error_group;
}
group->add_admin(*oid, error_str);
gpool->update(group);
group->unlock();
}
return *oid;
error_pass:
oss << error_str << ".";
goto error_common;
error_name:
oss << error_str << ".";
goto error_common;
error_duplicated:
oss << "NAME is already taken by USER " << db_oid << ".";
goto error_common;
error_no_groups:
oss << "The array of groups needs to have at least a valid Group ID.";
goto error_common;
error_group:
user = get(*oid);
if ( user != 0 )
{
string aux_str;
drop(user, aux_str);
user->unlock();
}
// Remove from all the groups, just in case the user id was added to a any
// of them before a non-existing group was found
for(set<int>::const_iterator it = gids.begin(); it != gids.end(); it++)
{
Group * group = gpool->get(*it);
if( group == 0 ) //Secondary group no longer exists
{
continue;
}
group->del_user(*oid);
gpool->update(group);
group->unlock();
}
oss << "One or more of the groups "
<< one_util::join(gids.begin(), gids.end(), ',') << " do not exist.";
goto error_common;
error_common:
*oid = -1;
error_str = oss.str();
return *oid;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserPool::drop(PoolObjectSQL * objsql, string& error_msg)
{
if (Nebula::instance().is_federation_slave())
{
NebulaLog::log("ONE",Log::ERROR,
"UserPool::drop called, but this "
"OpenNebula is a federation slave");
return -1;
}
int oid = (static_cast<User *>(objsql))->oid;
int rc = PoolSQL::drop(objsql, error_msg);
if ( rc == 0 )
{
delete_session_token(oid);
}
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserPool::update(PoolObjectSQL * objsql)
{
if (Nebula::instance().is_federation_slave())
{
NebulaLog::log("ONE",Log::ERROR,
"UserPool::update called, but this "
"OpenNebula is a federation slave");
return -1;
}
return PoolSQL::update(objsql);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserPool::update_quotas(User * user)
{
return user->update_quotas(db);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static int parse_auth_msg(
AuthRequest &ar,
int &gid,
set<int> &group_ids,
set<int> &group_admin_ids,
string &driver_name,
string &mad_name,
string &mad_pass,
string &error_str)
{
istringstream is;
//--------------------------------------------------------------------------
// Parse driver response format is:
// <driver> <username> <passwd> [gid...]
//--------------------------------------------------------------------------
is.str(ar.message);
if ( is.good() )
{
is >> driver_name >> ws;
}
if ( !is.fail() )
{
is >> mad_name >> ws;
}
if ( !is.fail() )
{
is >> mad_pass >> ws;
}
while ( is.good() )
{
int tmp_gid;
bool gr_admin = false;
char c = is.peek();
if ( c == '*' )
{
is.get(c);
gr_admin = true;
}
is >> tmp_gid >> ws;
if ( is.fail() )
{
error_str = "One or more group IDs are malformed";
return -1;
}
if ( Nebula::instance().get_gpool()->exist(tmp_gid) == -1 )
{
error_str = "One or more group IDs do not exist";
return -1;
}
if ( gid == -1 ) //Keep the first id for primary group
{
gid = tmp_gid;
}
group_ids.insert(tmp_gid);
if ( gr_admin )
{
group_admin_ids.insert(tmp_gid);
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool UserPool::authenticate_internal(User * user,
const string& token,
string& password,
int& user_id,
int& group_id,
string& uname,
string& gname,
set<int>& group_ids,
int& umask)
{
ostringstream oss;
string auth_driver;
string username;
string error_str;
bool driver_managed_groups = false;
int egid = -1;
int new_gid = -1;
string new_gname;
set<int> new_group_ids;
set<int> group_admin_ids;
set<int> new_group_admin_ids;
set<int> groups_remove;
set<int> groups_add;
set<int> groups_same;
set<int>::iterator it;
Nebula& nd = Nebula::instance();
AuthManager * authm = nd.get_authm();
Group* group;
GroupPool* gpool = nd.get_gpool();
// -------------------------------------------------------------------------
// Initialize authentication variables
// -------------------------------------------------------------------------
username = user->name;
password = user->password;
user_id = user->oid;
group_id = user->gid;
group_ids = user->get_groups();
uname = user->name;
gname = user->gname;
umask = user->get_umask();
auth_driver = user->auth_driver;
if (nd.get_auth_conf_attribute(auth_driver, "DRIVER_MANAGED_GROUPS",
driver_managed_groups) != 0)
{
driver_managed_groups = false;
}
AuthRequest ar(user_id, group_ids);
// -------------------------------------------------------------------------
// Update SHA1 to SHA256
// -------------------------------------------------------------------------
if (password == one_util::sha1_digest(token))
{
int rc = user->set_password(token, error_str);
if ( rc == 0 )
{
update(user);
}
}
// -------------------------------------------------------------------------
// Check if token is a login or session token, and set EGID if needed
// -------------------------------------------------------------------------
bool exists_token = false;
if ( user->login_tokens.is_valid(token, egid, exists_token) )
{
if ( egid != -1 && !user->is_in_group(egid) )
{
user->login_tokens.reset(token);
update(user);
user->unlock();
goto auth_failure_egid;
}
user->unlock();
if ( egid != -1 )
{
group_id = egid;
gname = gpool->get_name(egid);
group_ids.clear();
group_ids.insert(egid);
}
return true;
}
else if (user->session->is_valid(token))
{
user->unlock();
return true;
}
else if ( exists_token )
{
user->unlock();
goto auth_failure_token;
}
user->unlock();
// -------------------------------------------------------------------------
// Not a valid token, perform authentication
// -------------------------------------------------------------------------
if ( auth_driver == UserPool::CORE_AUTH )
{
ar.add_authenticate("",username,password,token);
if ( !ar.core_authenticate() )
{
goto auth_failure;
}
}
else if (auth_driver == UserPool::PUBLIC_AUTH )
{
goto auth_failure_public;
}
else if ( authm != 0 )
{
ar.add_authenticate(auth_driver,username,password,token);
authm->trigger(AMAction::AUTHENTICATE,&ar);
ar.wait();
if ( ar.result != true )
{
goto auth_failure_driver;
}
if ( driver_managed_groups ) // Parse driver response
{
string str;
if ( parse_auth_msg(ar, new_gid, new_group_ids, new_group_admin_ids,
str, str, str, error_str) != 0 )
{
goto auth_failure_parse;
};
new_gname = gpool->get_name(new_gid);
}
}
else
{
goto auth_failure_nodriver;
}
//--------------------------------------------------------------------------
// Cache session token
//--------------------------------------------------------------------------
user = get(user_id);
if ( user == 0 )
{
return false;
}
user->session->set(token, _session_expiration_time);
// Search and store previous groups where user was admin
for(it = group_ids.begin(); it != group_ids.end(); it++)
{
group = gpool->get_ro(*it);
if( group == 0 ) // group no longer exists
{
continue;
}
if ( group->is_admin(user_id) )
{
group_admin_ids.insert(*it);
}
group->unlock();
}
if ( !driver_managed_groups || new_gid == -1 ||
( new_group_ids == group_ids
&& group_admin_ids == new_group_admin_ids ) )
{
user->unlock();
return true;
}
//--------------------------------------------------------------------------
// Update user groups with driver response & primary group if needed
//--------------------------------------------------------------------------
//Primary group disappears from the list of new groups
if ( new_group_ids.count(group_id) == 0 && !new_gname.empty() )
{
group_id = new_gid;
gname = new_gname;
user->set_group(group_id, gname);
}
// 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()));
// Same groups
std::set_intersection(group_ids.begin(), group_ids.end(),
new_group_ids.begin(), new_group_ids.end(),
std::inserter(groups_same, groups_same.end()));
for(it = groups_add.begin(); it != groups_add.end(); it++)
{
if ( gpool->exist(*it) != -1 )
{
user->add_group(*it);
}
}
for(it = groups_remove.begin(); it != groups_remove.end(); it++)
{
user->del_group(*it);
}
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);
if (group == 0)
{
continue;
}
group->add_user(*it);
if ( new_group_admin_ids.find(*it) != new_group_admin_ids.end() )
{
group->add_admin(*it, error_str);
}
group->add_user(user_id);
gpool->update(group);
group->unlock();
}
for(it = groups_remove.begin(); it != groups_remove.end(); it++)
{
group = gpool->get(*it);
if (group == 0)
{
continue;
}
group->del_user(user_id);
gpool->update(group);
group->unlock();
}
// -------------------------------------------------------------------------
// For groups which user remained member also check if the admin status
// did not changed
// -------------------------------------------------------------------------
for(it = groups_same.begin(); it != groups_same.end(); it++)
{
// user was admin before but is not now
if ( group_admin_ids.find(*it) != group_admin_ids.end()
&& new_group_admin_ids.find(*it) == new_group_admin_ids.end() )
{
group = gpool->get(*it);
group->del_admin(user_id, error_str);
gpool->update(group);
group->unlock();
}
// user was not admin before but is now
if ( group_admin_ids.find(*it) == group_admin_ids.end()
&& new_group_admin_ids.find(*it) != new_group_admin_ids.end() )
{
group = gpool->get(*it);
group->add_admin(user_id, error_str);
gpool->update(group);
group->unlock();
}
}
return true;
auth_failure_egid:
oss << "Token sets an EGID no longer part of user group list";
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_parse:
oss << "An error ocurred parsing the driver message: " << error_str;
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_public:
oss << "User: " << username << " attempted a direct authentication.";
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_driver:
oss << "Auth Error: " << ar.message;
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_token:
NebulaLog::log("AuM", Log::ERROR, "Token has expired.");
goto auth_failure;
auth_failure_nodriver:
NebulaLog::log("AuM",Log::ERROR,
"Auth Error: Authentication driver not enabled. "
"Check AUTH_MAD in oned.conf");
auth_failure:
user_id = -1;
group_id = -1;
password = "";
group_ids.clear();
uname = "";
gname = "";
umask = 0;
return false;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool UserPool::authenticate_server(User * user,
const string& token,
string& password,
int& user_id,
int& group_id,
string& uname,
string& gname,
set<int>& group_ids,
int& umask)
{
bool result = false;
ostringstream oss;
string server_password;
string auth_driver;
string server_username;
string target_username;
string second_token;
string egid;
istringstream iss;
int egid_i = -1;
Nebula& nd = Nebula::instance();
AuthManager* authm = nd.get_authm();
GroupPool* gpool = nd.get_gpool();
server_username = user->name;
server_password = user->password;
auth_driver = user->auth_driver;
AuthRequest ar(user->oid, user->get_groups());
user->unlock();
// token = target_username:second_token
int rc = User::split_secret(token, target_username, second_token);
if ( rc != 0 )
{
goto wrong_server_token;
}
// Look for a EGID in the user token. The second token can be:
// second_token = egid:server_admin_auth
// second_token = server_admin_auth
rc = User::split_secret(second_token, egid, second_token);
if ( rc == -1 ) //No EGID found
{
egid_i = -1;
}
else
{
iss.str(egid);
iss >> egid_i;
if (iss.fail() || !iss.eof())
{
goto wrong_server_token;
}
}
user = get_ro(target_username);
if ( user == 0 )
{
goto auth_failure_user;
}
password = user->get_password();
user_id = user->oid;
group_id = user->gid;
group_ids = user->get_groups();
uname = user->name;
gname = user->gname;
result = user->session->is_valid(second_token);
umask = user->get_umask();
user->unlock();
//server_admin token set a EGID, update auth info
if ( egid_i != - 1 )
{
group_id = egid_i;
gname = gpool->get_name(egid_i);
group_ids.clear();
group_ids.insert(egid_i);
}
if (result)
{
return true;
}
if ( authm == 0 )
{
goto auth_failure_nodriver;
}
//Initialize authentication request and call the driver
ar.add_authenticate(auth_driver,
server_username,
server_password,
second_token);
authm->trigger(AMAction::AUTHENTICATE,&ar);
ar.wait();
if (ar.result!=true) //User was not authenticated
{
goto auth_failure_driver;
}
user = get(user_id);
if (user != 0)
{
user->session->set(second_token, _session_expiration_time);
user->unlock();
}
return true;
wrong_server_token:
oss << "Wrong token format";
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_user:
oss << "User: " << target_username
<< " does not exist. Returned by server auth";
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_driver:
oss << "Auth Error: " << ar.message;
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_nodriver:
NebulaLog::log("AuM",Log::ERROR,
"Auth Error: Authentication driver not enabled. "
"Check AUTH_MAD in oned.conf");
auth_failure:
user_id = -1;
group_id = -1;
password = "";
group_ids.clear();
uname = "";
gname = "";
umask = 0;
return false;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool UserPool::authenticate_external(const string& username,
const string& token,
string& password,
int& user_id,
int& group_id,
string& uname,
string& gname,
set<int>& 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();
int gid = -1;
int rc;
set<int>::iterator it;
set<int> empty_set;
set<int> group_admin_ids;
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(AMAction::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, group_admin_ids,
driver_name, mad_name, mad_pass, error_str);
if (rc != 0)
{
goto auth_failure_user;
}
//--------------------------------------------------------------------------
// Create the user, and set primary group
//--------------------------------------------------------------------------
if ( gid == -1 )
{
group_id = GroupPool::USERS_ID;
gname = GroupPool::USERS_NAME;
group_ids.insert( group_id );
}
else
{
group_id = gid;
gname = gpool->get_name(group_id);
if(gname.empty())
{
error_str = "Primary Group no longer exist";
goto auth_failure_user;
}
}
allocate(&user_id,
mad_name,
group_id,
mad_pass,
driver_name,
true,
group_ids,
group_admin_ids,
error_str);
if ( user_id == -1 )
{
goto auth_failure_user;
}
uname = mad_name;
password = mad_pass;
umask = User::get_default_umask();
return true;
auth_failure_user:
oss << "Can't create user: " << error_str << ". Driver response: "
<< ar.message;
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_driver:
oss << "Auth Error: " << ar.message;
NebulaLog::log("AuM",Log::ERROR,oss);
goto auth_failure;
auth_failure_nodriver:
NebulaLog::log("AuM",Log::ERROR,
"Auth Error: Authentication driver not enabled. "
"Check AUTH_MAD in oned.conf");
auth_failure:
user_id = -1;
group_id = -1;
password = "";
group_ids.clear();
uname = "";
gname = "";
umask = 0;
return false;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool UserPool::authenticate(const string& session,
string& password,
int& user_id,
int& group_id,
string& uname,
string& gname,
set<int>& group_ids,
int& umask)
{
User * user = 0;
string username;
string token;
int rc;
bool ar;
rc = User::split_secret(session,username,token);
if ( rc != 0 )
{
return false;
}
user = get(username);
if (user != 0 ) //User known to OpenNebula
{
string driver = user->get_auth_driver();
if ( fnmatch(UserPool::SERVER_AUTH, driver.c_str(), 0) == 0 )
{
ar = authenticate_server(user, token, password, user_id, group_id,
uname, gname, group_ids, umask);
}
else
{
ar = authenticate_internal(user, token, password, user_id, group_id,
uname, gname, group_ids, umask);
}
}
else
{
ar = authenticate_external(username, token, password, user_id, group_id,
uname, gname, group_ids, umask);
}
return ar;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserPool::authorize(AuthRequest& ar)
{
Nebula& nd = Nebula::instance();
AuthManager * authm = nd.get_authm();
int rc = -1;
if (authm == 0 || !authm->is_authz_enabled())
{
if (ar.core_authorize())
{
rc = 0;
}
}
else
{
authm->trigger(AMAction::AUTHORIZE,&ar);
ar.wait();
if (ar.result==true)
{
rc = 0;
}
else
{
ostringstream oss;
oss << "Auth Error: " << ar.message;
NebulaLog::log("AuM",Log::ERROR,oss);
}
}
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserPool::dump(string& oss, const string& where, int sid, int eid, bool desc)
{
int rc;
string def_quota_xml;
ostringstream cmd;
cmd << "SELECT " << User::table << ".body, "
<< UserQuotas::db_table << ".body"<< " FROM " << User::table
<< " LEFT JOIN " << UserQuotas::db_table << " ON "
<< User::table << ".oid=" << UserQuotas::db_table << ".user_oid";
if ( !where.empty() )
{
cmd << " WHERE " << where;
}
cmd << " ORDER BY oid";
if ( desc == true )
{
cmd << " DESC";
}
if ( eid != -1 )
{
cmd << " " << db->limit_string(sid, eid);
}
oss.append("<USER_POOL>");
string_cb cb(2);
cb.set_callback(&oss);
rc = db->exec_rd(cmd, &cb);
cb.unset_callback();
oss.append(Nebula::instance().get_default_user_quota().to_xml(def_quota_xml));
oss.append("</USER_POOL>");
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string UserPool::get_token_password(int oid, int bck_oid){
string token_password = "";
User * user = get_ro(oid);
if (user != 0)
{
user->get_template_attribute("TOKEN_PASSWORD", token_password);
user->unlock();
}
else
{
user = get_ro(bck_oid);
if (user != 0)
{
user->get_template_attribute("TOKEN_PASSWORD", token_password);
user->unlock();
}
}
return token_password;
}