1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-27 14:03:40 +03:00

Merge branch 'feature-4714'

This commit is contained in:
Jaime Melis 2016-09-01 17:37:06 +02:00
commit 6852a1aba7
18 changed files with 915 additions and 374 deletions

View File

@ -111,6 +111,29 @@ public:
return name;
};
/**
* Returns the name of a group
* @param id of the group
* @return name of the group
*/
const string& get_name(int gid)
{
static string error_str = "";
Group * group = get(gid, true);
if ( group == 0 )
{
return error_str;
}
const string& gname = group->get_name();
group->unlock();
return gname;
}
/**
* Update a particular Group. This method does not update the group's quotas
* @param user pointer to Group

View File

@ -21,55 +21,48 @@
#include <time.h>
#include <libxml/tree.h>
#include <map>
#include <vector>
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The login token class stores a generic token that can be used with any
* authentication driver and mechanism.
* This class is a base class for login tokens, it just stores a token
* and its expiration time.
*/
class LoginToken
class SessionToken
{
public:
LoginToken():expiration_time(0), token(""){};
SessionToken():expiration_time(0), token(""){};
~LoginToken(){};
virtual ~SessionToken(){};
/**
* Check if the token is valid (same as the one provided, and not expired)
* @param user_token provided by the user
* @return true if the token is valid
*/
bool is_valid(const std::string& user_token) const;
/**
* Register a new token, if not provided OpenNebula will generate one.
* @param valid time in seconds that the token will be considered valid
* @param user_token if provided externally (e.g. by an auth driver)
*/
const std::string& set(const std::string& user_token, time_t valid);
/**
* Clears the token if not valid
*/
/**
* Clears the token if not valid
*/
void reset();
/**
* Function to print the LoginToken into a string in XML format
* @param xml the resulting XML string
* @return a reference to the generated string
* Check if the token is valid (same as the one provided, and not expired)
* @param utk provided by the user
*
* @return true if the token is valid
*/
std::string& to_xml(std::string& xml) const;
bool is_valid(const std::string& utk) const;
/**
* Builds the token from an xml pointer
* @param node the xml object with the token
* Register a new token, if not provided OpenNebula will generate one.
* @param utk if provided externally (e.g. by an auth driver)
* @param valid time in seconds that the token will be considered valid
* @param gid the effective gid for this token
*
* @return the authentication token in string form
*/
void from_xml_node(const xmlNodePtr node);
private:
const std::string& set(const std::string& utk, time_t valid);
protected:
/**
* Expiration time of the token, it will not be valid after it.
*/
@ -78,7 +71,149 @@ private:
/**
* Token value
*/
std::string token;
std::string token;
};
/**
* The login token class stores a generic token that can be used with any
* authentication driver and mechanism.
*/
class LoginToken: public SessionToken
{
public:
LoginToken():SessionToken(), egid(-1){};
virtual ~LoginToken(){};
/**
* Check if the token is valid (same as the one provided, and not expired)
* @param utk provided by the user
* @param gid the effective gid for this token
*
* @return true if the token is valid
*/
bool is_valid(const std::string& utk, int& _egid) const
{
_egid = egid;
return SessionToken::is_valid(utk);
}
/**
* Register a new token, if not provided OpenNebula will generate one.
* @param utk if provided externally (e.g. by an auth driver)
* @param valid time in seconds that the token will be considered valid
* @param gid the effective gid for this token
*
* @return the authentication token in string form
*/
const std::string& set(const std::string& utk, time_t valid, int _egid)
{
egid = _egid;
return SessionToken::set(utk, valid);
}
/**
* Function to print the LoginToken into a string stream in XML format
* @param oss the string stream
*/
void to_xml(std::ostringstream& oss) const;
/**
* Builds the token from an xml pointer
* @param node the xml object with the token
*
* @return the authentication token in string form
*/
const std::string& from_xml_node(const xmlNodePtr node);
private:
/**
* Effective GID. Used for access control and object creation. When set
* only the EGID is used and not the full list of groups for authorization.
*
*/
int egid;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The login token class stores a generic token that can be used with any
* authentication driver and mechanism.
*/
class LoginTokenPool
{
public:
LoginTokenPool(){};
~LoginTokenPool();
/**
* Clears the given token by removing it from the pool.
* @param utk the token to remove
*
* @return 0 on success, -1 if the token does not exist
*/
int reset(const std::string& utk);
/**
* Clears all tokens
*/
void reset();
/**
* Adds a new token to the user token pool
* @param utk the token provided by the user, if empty a random one will
* be generated
* @param valid number of seconds this token can be used
* @param egid the effective group id to use when authenticated with
* this token
*
* @return 0 on success, utk stores a copy of the token added
*/
int set(std::string& utk, time_t valid, int egid);
/**
* Check if the token is valid.
* @param utk the token as provided for the user
* @param egid the effective user id to use with this session -1, to
* use the full list of group ids.
*
* @return true if token is valid false otherwise. When valid egid
* stores the effective gid. If the token is invali, it is removed
* from the pool.
*/
bool is_valid(const std::string& utk, int& egid);
/**
* Load the tokens from its XML representation.
* @param content vector of XML tokens
*/
void from_xml_node(const std::vector<xmlNodePtr>& content);
/**
* Function to print the LoginToken into a string in XML format
* @param xml the resulting XML string
* @return a reference to the generated string
*/
std::string& to_xml(std::string& xml) const;
private:
/**
* Max number of session tokens per user
*/
static const int MAX_TOKENS;
/**
* Hash of login tokens
*/
std::map<std::string, LoginToken *> tokens;
};
#endif /*LOGIN_TOKEN_H_*/

View File

@ -417,8 +417,7 @@ public:
/**
* Gets a DS configuration attribute
*/
int get_ds_conf_attribute(
const std::string& ds_name,
int get_ds_conf_attribute(const std::string& ds_name,
const VectorAttribute* &value) const
{
return get_conf_attribute("DS_MAD_CONF", ds_name, value);
@ -427,8 +426,7 @@ public:
/**
* Gets a TM configuration attribute
*/
int get_tm_conf_attribute(
const string& tm_name,
int get_tm_conf_attribute(const string& tm_name,
const VectorAttribute* &value) const
{
return get_conf_attribute("TM_MAD_CONF", tm_name, value);
@ -437,8 +435,7 @@ public:
/**
* Gets a Market configuration attribute
*/
int get_market_conf_attribute(
const string& mk_name,
int get_market_conf_attribute( const string& mk_name,
const VectorAttribute* &value) const
{
return get_conf_attribute("MARKET_MAD_CONF", mk_name, value);
@ -447,11 +444,11 @@ public:
/**
* Gets an Auth driver configuration attribute
*/
int get_auth_conf_attribute(
const string& driver_name,
const VectorAttribute* &value) const
template<typename T>
int get_auth_conf_attribute(const string& driver, const string& attribute,
T& value) const
{
return get_conf_attribute("AUTH_MAD_CONF", driver_name, value);
return get_conf_attribute("AUTH_MAD_CONF", driver, attribute, value);
};
/**
@ -756,12 +753,34 @@ private:
* @param value Value of the specific configuration parameter
* @return a reference to the generated string
*/
int get_conf_attribute(
const std::string& key,
const std::string& name,
const VectorAttribute* &value) const;
/**
* Gets a Generic configuration attribute
* @param key String that identifies the configuration parameter group name
* @param name Name of the specific configuration parameter
* @param value Value of the specific configuration parameter
* @return a reference to the generated string
*/
template<typename T>
int get_conf_attribute(
const std::string& key,
const std::string& name,
const std::string& vname,
T& value) const
{
const VectorAttribute* vattr;
if ( get_conf_attribute(key, name, vattr) != 0 )
{
return -1;
}
return vattr->vector_value(vname, value);
}
};
#endif /*NEBULA_H_*/

View File

@ -109,7 +109,7 @@ public:
* @param id ID to search
* @return true if the collection contains the given id
*/
bool contains(int id)
bool contains(int id) const
{
return collection_set.count(id) > 0;
}

View File

@ -130,7 +130,7 @@ public:
class UserLogin : public Request
{
public:
UserLogin(): Request("UserLogin", "A:sssi", "Generates or sets a login token")
UserLogin(): Request("UserLogin", "A:sssii", "Generates or sets a login token")
{
Nebula& nd = Nebula::instance();
pool = nd.get_upool();

View File

@ -96,7 +96,8 @@ public:
enabled = false;
session.reset();
login_token.reset();
login_tokens.reset();
};
/**
@ -214,6 +215,15 @@ public:
return groups.del(group_id);
}
/**
* Check if user is in this group
* @param gid id of group
*/
bool is_in_group(int _group_id) const
{
return groups.contains(_group_id);
}
// *************************************************************************
// Quotas
// *************************************************************************
@ -234,13 +244,13 @@ public:
};
// *************************************************************************
// Login token
// Login tokens
// *************************************************************************
/**
* The login token object, provides the set & reset interface for the token
*/
LoginToken login_token;
LoginTokenPool login_tokens;
private:
// -------------------------------------------------------------------------
@ -274,10 +284,9 @@ private:
ObjectCollection groups;
// *************************************************************************
// Authentication session (Private)
// Authentication session used to cache authentication calls
// *************************************************************************
LoginToken session;
SessionToken session;
// *************************************************************************
// DataBase implementation (Private)
@ -400,7 +409,6 @@ protected:
string error_str;
return insert_replace(db, true, error_str);
};
};
#endif /*USER_H_*/

View File

@ -251,16 +251,6 @@ private:
string& gname,
set<int>& group_ids,
int& umask);
int parse_auth_msg(
AuthRequest &ar,
int &gid,
set<int> &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

View File

@ -416,6 +416,7 @@ INSTALL_FILES=(
EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples
WEBSOCKIFY_SHARE_FILES:$SHARE_LOCATION/websockify
INSTALL_GEMS_SHARE_FILE:$SHARE_LOCATION
ONETOKEN_SHARE_FILE:$SHARE_LOCATION
HOOK_FT_FILES:$VAR_LOCATION/remotes/hooks/ft
COMMON_CLOUD_LIB_FILES:$LIB_LOCATION/ruby/cloud
CLOUD_AUTH_LIB_FILES:$LIB_LOCATION/ruby/cloud/CloudAuth
@ -1230,6 +1231,7 @@ HOOK_FT_FILES="share/hooks/host_error.rb"
#-------------------------------------------------------------------------------
INSTALL_GEMS_SHARE_FILE="share/install_gems/install_gems"
ONETOKEN_SHARE_FILE="share/onetoken/onetoken.sh"
#-------------------------------------------------------------------------------
# OCA Files

View File

@ -0,0 +1,36 @@
onetokenset(){
OUT=$(oneuser token --set $1)
if echo $OUT | grep -q export; then
eval "$OUT"
echo "Token loaded."
return 0
else
echo $OUT
return 1
fi
}
onetokencreate(){
echo -n "Password: "
stty -echo
read password
stty echo
echo
OUT=$(echo "$password" | oneuser token --create --stdin_password $*)
echo $OUT
if echo $OUT | grep -q "Authentication Token"; then
TOKEN=$(echo $OUT|tail -n1|cut -d: -f2)
if [ -n "$TOKEN" ]; then
onetokenset $TOKEN
else
echo "Invalid token."
return 1
fi
else
return 1
fi
}

View File

@ -104,7 +104,6 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
# Generates a token and stores it in ONE_AUTH path as defined in this class
############################################################################
def login(username, options)
#-----------------------------------------------------------------------
# Init the associated Authentication class to generate the token.
#-----------------------------------------------------------------------
@ -172,14 +171,21 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
sync = true
end
token = auth.login_token(username, options[:time])
if options[:stdin_password]
token = STDIN.read.strip
else
token = auth.login_token(username, options[:time])
end
login_client = OpenNebula::Client.new("#{username}:#{token}",
nil,
:sync => sync)
user = OpenNebula::User.new(User.build_xml, login_client)
token_oned = user.login(username, "", options[:time])
egid = options[:group] || -1
token_oned = user.login(username, "", options[:time], egid)
return -1, token_oned.message if OpenNebula.is_error?(token_oned)
@ -378,6 +384,20 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
table
end
def find_token(user, token, show_expired=false)
user_hash = user.to_hash
valid_tokens = [user_hash["USER"]["LOGIN_TOKEN"]].flatten.map do |e|
next unless e["TOKEN"].start_with?(token)
if !show_expired
next unless Time.at(e["EXPIRATION_TIME"].to_i) > Time.now
end
e["TOKEN"]
end.compact
end
private
def factory(id=nil)
@ -409,31 +429,64 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
puts str % ["SECONDARY GROUPS", groups.join(',') ] if groups.size > 1
puts str % ["PASSWORD", user['PASSWORD']]
puts str % ["AUTH_DRIVER", user['AUTH_DRIVER']]
if !user['LOGIN_TOKEN/TOKEN'].nil?
puts str % ["LOGIN_TOKEN", user['LOGIN_TOKEN/TOKEN']]
etime = user['LOGIN_TOKEN/EXPIRATION_TIME']
validity_str = case etime
when nil then ""
when "-1" then "forever"
else "not after #{Time.at(etime.to_i)}"
end
puts str % ["TOKEN VALIDITY", validity_str ]
end
puts str % ["ENABLED",
OpenNebulaHelper.boolean_to_str(user['ENABLED'])]
puts
user_hash = user.to_hash
client = @client
gid = user['GID']
tokens = [user_hash['USER']['LOGIN_TOKEN']].flatten.compact
CLIHelper.print_header(str_h1 % "TOKENS",false)
if tokens && !tokens.empty?
CLIHelper::ShowTable.new(nil, self) do
column :ID, "", :size=>7 do |d|
d["TOKEN"]
end
column :EGID, "", :left, :size=>5 do |d|
d["EGID"].to_i == -1 ? "*" + gid : d["EGID"]
end
column :EGROUP, "", :left, :size=>10 do |d|
client = OpenNebulaHelper::OneHelper.get_client
egid = d["EGID"].to_i == -1 ? gid : d["EGID"]
group = Group.new_with_id(egid, client)
rc = group.info
if OpenNebula.is_error?(rc)
"-"
else
group['NAME']
end
end
column :EXPIRATION, "", :left, :size=>20 do |d|
etime = d["EXPIRATION_TIME"]
expired = Time.now >= Time.at(d["EXPIRATION_TIME"].to_i)
case etime
when nil then ""
when "-1" then "forever"
else
if expired
"expired"
else
Time.at(etime.to_i).to_s
end
end
end
end.show(tokens,{})
end
puts
CLIHelper.print_header(str_h1 % "USER TEMPLATE",false)
puts user.template_str
user_hash = user.to_hash
default_quotas = nil
user.each('/USER/DEFAULT_USER_QUOTAS') { |elem|
@ -443,4 +496,6 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
helper = OneQuotaHelper.new
helper.format_quota(user_hash['USER'], default_quotas, user.id)
end
end

View File

@ -32,6 +32,7 @@ require 'one_helper/oneuser_helper'
require 'one_helper/onequota_helper'
require 'uri'
require 'uuidtools'
cmd=CommandParser::CmdParser.new(ARGV) do
usage "`oneuser` <command> [<args>] [<options>]"
@ -140,8 +141,56 @@ cmd=CommandParser::CmdParser.new(ARGV) do
:description => "Force one_auth file rewrite"
}
GROUP = {
:name => "group",
:large => "--group id|name" ,
:description => "Effective GID to use with this token.",
:format => String,
:proc => lambda { |o, options|
OpenNebulaHelper.rname_to_id(o, "GROUP")
}
}
TOKEN_CREATE = {
:name => "create",
:large => "--create",
:description => "Create a new token"
}
TOKEN_DELETE = {
:name => "delete",
:large => "--delete token",
:format => String,
:description => "Delete a token"
}
TOKEN_SET = {
:name => "set",
:large => "--set token",
:format => String,
:description => "Set a token"
}
STDIN_PASSWORD = {
:name => "stdin_password",
:large => "--stdin_password",
:description => "enable stdin password"
}
create_options = [READ_FILE, SHA1, SSH, X509, KEY, CERT, DRIVER]
login_options = [SSH, X509, X509_PROXY, KEY, CERT, PROXY, TIME, FORCE]
login_options = [SSH,
X509,
X509_PROXY,
KEY,
CERT,
PROXY,
TIME,
FORCE,
GROUP,
STDIN_PASSWORD]
token_options = login_options + [TOKEN_CREATE, TOKEN_DELETE, TOKEN_SET]
########################################################################
# Formatters for arguments
@ -349,7 +398,6 @@ cmd=CommandParser::CmdParser.new(ARGV) do
EOT
command :login, login_desc, :username, :options=>login_options do
options[:time] ||= 36000
helper.login(args[0], options)
@ -530,4 +578,84 @@ cmd=CommandParser::CmdParser.new(ARGV) do
helper.list_pool(options)
end
token_desc = <<-EOT.unindent
Manages user tokens. Tokens may be created, removed or set.
EOT
command :token, token_desc, :options=>token_options do
user = helper.retrieve_resource(OpenNebula::User::SELF)
rc = user.info
if OpenNebula.is_error?(rc)
puts rc.message
exit_with_code 1, rc.message
end
if options[:set]
token = helper.find_token(user, options[:set])
if token.count > 1
exit_with_code 1, "More than one token starting with '#{options[:set]}' found."
elsif token.count == 0
exit_with_code 1, "No valid tokens found."
end
token = token[0]
egid = user["LOGIN_TOKEN[TOKEN='#{token}']/EGID"]
# The token will be written to a file in $HOME/.one/<uuid>.token
# generate a random uuid
uuid = UUIDTools::UUID.random_create.to_s
auth_file = ENV['HOME'] + "/.one/#{uuid}.token"
begin
FileUtils.mkdir_p(File.dirname(auth_file))
rescue Errno::EEXIST
end
file = File.open(auth_file, "w")
file.write("#{user['NAME']}:#{token}")
file.close
File.chmod(0600, auth_file)
msg ="export ONE_AUTH=" + ENV['HOME'] + "/.one/#{uuid}.token"
msg << "; export ONE_EGID=#{egid}" if egid
exit_with_code 0, msg
elsif options[:delete]
token = helper.find_token(user, options[:delete], true)
if token.count > 1
exit_with_code 1, "More than one token starting with '#{options[:delete]}' found."
elsif token.count == 0
exit_with_code 1, "No tokens found."
end
token = token[0]
rc = user.login(user['NAME'], token, 0)
if OpenNebula.is_error?(rc)
puts rc.message
exit_with_code 1, rc.message
else
exit_with_code 0, "Token removed."
end
# Remove the token files
Dir[ENV['HOME'] + "/.one/*.token"].each do |f|
auth = File.read(f).strip
if auth == "#{user['NAME']}:#{token}"
puts "Removing #{f}"
File.unlink(f)
end
end
0
else
options[:time] ||= 36000
helper.login(user['NAME'], options)
end
end
end

View File

@ -1118,7 +1118,9 @@ int Nebula::get_conf_attribute(
std::vector<const VectorAttribute*>::const_iterator it;
std::vector<const VectorAttribute*> values;
std::string template_name;
std::string name_upper;
std::string name_upper = name;
one_util::toupper(name_upper);
nebula_configuration->get(key, values);
@ -1126,12 +1128,10 @@ int Nebula::get_conf_attribute(
{
value = *it;
template_name = (*it)->vector_value("NAME");
name_upper = name;
one_util::toupper(name_upper);
one_util::toupper(template_name);
if ( template_name == name_upper)
if ( template_name == name_upper )
{
return 0;
}

View File

@ -192,15 +192,17 @@ module OpenNebula
# Sets the LOGIN_TOKEN for the user
#
# @param username [String] of the user
# @param uname [String] of the user
# @param token [String] the login token, if empty OpenNebula will
# generate one
# @param expire [String] valid period of the token in secs. If <= 0
# the token will be reset
# @param egid [Integer] Effective GID to use with this token. To use
# the current GID and user groups set it to -1
# @return [String, OpenNebula::Error] token in case of success, Error
# otherwise
def login(username, token, expire)
return @client.call(USER_METHODS[:login], username, token, expire)
def login(uname, token, expire, egid = -1)
return @client.call(USER_METHODS[:login], uname, token, expire, egid)
end
#######################################################################

View File

@ -362,7 +362,6 @@ void UserChown::request_execute(xmlrpc_c::paramList const& paramList,
PoolObjectAuth uperms;
PoolObjectAuth ngperms;
const VectorAttribute* auth_conf;
bool driver_managed_groups;
bool new_group;
@ -387,21 +386,20 @@ void UserChown::request_execute(xmlrpc_c::paramList const& paramList,
uname = user->get_name();
auth_driver = user->get_auth_driver();
new_group = user->get_groups().count(ngid) != 1;
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)
if ( Nebula::instance().get_auth_conf_attribute(auth_driver,
"DRIVER_MANAGED_GROUPS", driver_managed_groups) != 0 )
{
auth_conf->vector_value("DRIVER_MANAGED_GROUPS", driver_managed_groups);
driver_managed_groups = false;
}
if (driver_managed_groups && new_group)
{
att.resp_msg =
"Groups cannot be manually managed for auth driver "+auth_driver;
att.resp_msg = "Groups cannot be manually managed for auth driver " +
auth_driver;
failure_response(ACTION, att);
return;
}

View File

@ -59,33 +59,28 @@ int UserChangePassword::user_action(int user_id,
{
string new_pass = xmlrpc_c::value_string(paramList.getString(2));
User * user;
string driver;
bool allowed = false;
const VectorAttribute* auth_conf;
user = static_cast<User *>(pool->get(user_id,true));
User * user = static_cast<User *>(pool->get(user_id,true));
if ( user == 0 )
{
return -1;
}
driver = user->get_auth_driver();
string driver = user->get_auth_driver();
bool allowed = false;
if (Nebula::instance().get_auth_conf_attribute(driver, auth_conf) == 0)
if ( Nebula::instance().get_auth_conf_attribute(driver, "PASSWORD_CHANGE",
allowed) != 0)
{
auth_conf->vector_value("PASSWORD_CHANGE", allowed);
allowed = false;
}
if (!allowed &&
att.uid != UserPool::ONEADMIN_ID &&
if (!allowed && att.uid != UserPool::ONEADMIN_ID &&
att.gid != GroupPool::ONEADMIN_ID)
{
error_str = "Password for driver '"+user->get_auth_driver()+
"' cannot be changed.";
error_str = "Password for driver " + user->get_auth_driver() +
" cannot be changed.";
user->unlock();
return -1;
}
@ -215,12 +210,9 @@ void UserEditGroup::
PoolObjectAuth uperms;
PoolObjectAuth gperms;
const VectorAttribute* auth_conf;
bool driver_managed_groups;
User* user = upool->get(user_id,true);
User* user;
if ((user = upool->get(user_id,true)) == 0 )
if ( user == 0 )
{
att.resp_obj = PoolObjectSQL::USER;
att.resp_id = user_id;
@ -237,17 +229,18 @@ void UserEditGroup::
user->unlock();
driver_managed_groups = false;
bool driver_managed_groups;
if (Nebula::instance().get_auth_conf_attribute(auth_driver, auth_conf) == 0)
if (Nebula::instance().get_auth_conf_attribute(auth_driver,
"DRIVER_MANAGED_GROUPS", driver_managed_groups) != 0)
{
auth_conf->vector_value("DRIVER_MANAGED_GROUPS", driver_managed_groups);
driver_managed_groups = false;
}
if (driver_managed_groups)
{
att.resp_msg =
"Groups cannot be manually managed for auth driver "+auth_driver;
att.resp_msg = "Groups cannot be manually managed for auth driver " +
auth_driver;
failure_response(ACTION, att);
return;
}
@ -412,21 +405,27 @@ int UserDelGroup::secondary_group_action(
void UserLogin::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
User * user;
string error_str;
/* ---------------------------------------------------------------------- */
/* Parse request attributes and authorize request */
/* ---------------------------------------------------------------------- */
string uname = xmlrpc_c::value_string(paramList.getString(1));
string token = xmlrpc_c::value_string(paramList.getString(2));
time_t valid = xmlrpc_c::value_int(paramList.getInt(3));
int egid = -1;
User * user;
string error_str;
string auth_driver;
time_t max_token_time;
const VectorAttribute* auth_conf;
PoolObjectAuth perms;
if ( paramList.size() > 4 )
{
egid = xmlrpc_c::value_int(paramList.getInt(4));
}
if (att.uid != 0)
{
user = static_cast<UserPool *>(pool)->get(uname,true);
PoolObjectAuth perms;
user = static_cast<UserPool *>(pool)->get(uname, true);
if ( user == 0 )
{
@ -438,7 +437,6 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList,
user->unlock();
AuthRequest ar(att.uid, att.group_ids);
ar.add_auth(auth_op, perms);
@ -451,7 +449,7 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList,
}
}
user = static_cast<UserPool *>(pool)->get(uname,true);
user = static_cast<UserPool *>(pool)->get(uname, true);
if ( user == 0 )
{
@ -459,22 +457,25 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList,
return;
}
auth_driver = user->get_auth_driver();
max_token_time = -1;
/* ---------------------------------------------------------------------- */
/* Build login attributes */
/* ---------------------------------------------------------------------- */
string auth_driver = user->get_auth_driver();
time_t max_token_time;
if (Nebula::instance().get_auth_conf_attribute(auth_driver, auth_conf) == 0)
if (Nebula::instance().get_auth_conf_attribute(auth_driver,"MAX_TOKEN_TIME",
max_token_time) != 0)
{
auth_conf->vector_value("MAX_TOKEN_TIME", max_token_time);
max_token_time = -1;
}
if (max_token_time == 0)
{
att.resp_msg = "Login tokens are disabled for driver '"+
user->get_auth_driver()+"'";
att.resp_msg = "Login tokens are disabled for driver " + auth_driver;
failure_response(ACTION, att);
// Reset token
user->login_token.reset();
// Reset any active token
user->login_tokens.reset();
pool->update(user);
user->unlock();
@ -487,25 +488,40 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList,
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();
if ( user->login_tokens.reset(token) != 0 )
{
att.resp_msg = "Could not find token: " + token;
failure_response(XML_RPC_API, att);
token = "";
user->unlock();
return;
}
}
else if (valid > 0 || valid == -1)
{
token = user->login_token.set(token, valid);
if ( egid != -1 && !user->is_in_group(egid) )
{
att.resp_msg = "EGID is not in user group list";
failure_response(XML_RPC_API, att);
user->unlock();
return;
}
if ( user->login_tokens.set(token, valid, egid) != 0 )
{
att.resp_msg = "Max number of tokens limit reached.";
failure_response(XML_RPC_API, att);
user->unlock();
return;
};
}
else
{

View File

@ -22,16 +22,154 @@
using namespace std;
bool LoginToken::is_valid(const string& user_token) const
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* LoginTokenPool class */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const int LoginTokenPool::MAX_TOKENS = 10;
/* -------------------------------------------------------------------------- */
LoginTokenPool::~LoginTokenPool()
{
reset();
}
/* -------------------------------------------------------------------------- */
void LoginTokenPool::reset()
{
std::map<std::string, LoginToken *>::iterator it;
for (it = tokens.begin() ; it != tokens.end() ; ++it)
{
delete it->second;
}
tokens.clear();
}
/* -------------------------------------------------------------------------- */
int LoginTokenPool::set(std::string& utk, time_t valid, int egid)
{
if (tokens.size() >= MAX_TOKENS || valid < -1 || valid == 0)
{
return -1;
}
LoginToken * tk = new LoginToken;
utk = tk->set(utk, valid, egid);
tokens.insert(std::pair<std::string, LoginToken *>(utk, tk));
return 0;
}
/* -------------------------------------------------------------------------- */
int LoginTokenPool::reset(const std::string& utk)
{
std::map<std::string, LoginToken *>::iterator it;
it = tokens.find(utk);
if ( it == tokens.end() )
{
return -1;
}
delete it->second;
tokens.erase(it);
return 0;
}
/* -------------------------------------------------------------------------- */
bool LoginTokenPool::is_valid(const std::string& utk, int& egid)
{
std::map<std::string, LoginToken *>::const_iterator it;
egid = -1;
it = tokens.find(utk);
if ( it == tokens.end() )
{
return false;
}
if ( it->second->is_valid(utk, egid) == true)
{
return true;
}
delete it->second;
tokens.erase(it);
return false;
}
/* -------------------------------------------------------------------------- */
void LoginTokenPool::from_xml_node(const std::vector<xmlNodePtr>& content)
{
std::vector<xmlNodePtr>::const_iterator it;
for (it = content.begin(); it != content.end(); ++it)
{
LoginToken * tk = new LoginToken;
std::string utk = tk->from_xml_node(*it);
tokens.insert(std::pair<std::string, LoginToken *>(utk, tk));
}
}
/* -------------------------------------------------------------------------- */
std::string& LoginTokenPool::to_xml(std::string& xml) const
{
std::map<std::string, LoginToken *>::const_iterator it;
std::ostringstream oss;
for ( it = tokens.begin() ; it != tokens.end() ; ++it)
{
it->second->to_xml(oss);
}
xml = oss.str();
return xml;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* LoginToken class */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool SessionToken::is_valid(const string& user_token) const
{
return ((user_token == token) &&
((expiration_time == -1) || (time(0) < expiration_time)));
}
/* -------------------------------------------------------------------------- */
void SessionToken::reset()
{
token.clear();
expiration_time = 0;
}
/* -------------------------------------------------------------------------- */
const std::string& LoginToken::set(const std::string& user_token, time_t valid)
const std::string& SessionToken::set(const std::string& user_token, time_t valid)
{
if (valid == -1)
{
@ -41,10 +179,6 @@ const std::string& LoginToken::set(const std::string& user_token, time_t valid)
{
expiration_time = time(0) + valid;
}
else
{
expiration_time = 0;
}
if (!user_token.empty())
{
@ -58,46 +192,30 @@ const std::string& LoginToken::set(const std::string& user_token, time_t valid)
return token;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void LoginToken::reset()
void LoginToken::to_xml(std::ostringstream& xml) const
{
token.clear();
expiration_time = 0;
xml << "<LOGIN_TOKEN>"
<< "<TOKEN>" << token << "</TOKEN>"
<< "<EXPIRATION_TIME>" << expiration_time << "</EXPIRATION_TIME>"
<< "<EGID>" << egid << "</EGID>"
<< "</LOGIN_TOKEN>";
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
std::string& LoginToken::to_xml(std::string& sxml) const
{
std::ostringstream xml;
if ( expiration_time == 0 )
{
xml << "<LOGIN_TOKEN/>";
}
else
{
xml << "<LOGIN_TOKEN>"
<< "<TOKEN>" << token << "</TOKEN>"
<< "<EXPIRATION_TIME>" << expiration_time << "</EXPIRATION_TIME>"
<< "</LOGIN_TOKEN>";
}
sxml = xml.str();
return sxml;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void LoginToken::from_xml_node(const xmlNodePtr node)
const std::string& LoginToken::from_xml_node(const xmlNodePtr node)
{
ObjectXML oxml(node);
oxml.xpath(token, "/LOGIN_TOKEN/TOKEN", "");
oxml.xpath<time_t>(expiration_time, "/LOGIN_TOKEN/EXPIRATION_TIME", 0);
oxml.xpath<int>(egid, "/LOGIN_TOKEN/EGID", -1);
return token;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -237,7 +237,7 @@ string& User::to_xml_extended(string& xml, bool extended) const
"<PASSWORD>" <<one_util::escape_xml(password) <<"</PASSWORD>" <<
"<AUTH_DRIVER>" <<one_util::escape_xml(auth_driver)<<"</AUTH_DRIVER>"<<
"<ENABLED>" << enabled_int <<"</ENABLED>" <<
login_token.to_xml(token_xml) <<
login_tokens.to_xml(token_xml) <<
obj_template->to_xml(template_xml);
if (extended)
@ -285,7 +285,7 @@ int User::from_xml(const string& xml)
if (!content.empty())
{
login_token.from_xml_node(content[0]);
login_tokens.from_xml_node(content);
}
ObjectXML::free_nodes(content);
@ -355,7 +355,7 @@ int User::set_password(const string& passwd, string& error_str)
session.reset();
login_token.reset();
login_tokens.reset();
}
else
{

View File

@ -380,6 +380,70 @@ int UserPool::update_quotas(User * user)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static int parse_auth_msg(
AuthRequest &ar,
int &gid,
set<int> &group_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;
is >> tmp_gid >> ws;
if ( is.fail() )
{
error_str = "One or more group IDs are malformed";
return -1;
}
if ( Nebula::instance().get_gpool()->get(tmp_gid, false) == 0 )
{
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);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool UserPool::authenticate_internal(User * user,
const string& token,
string& password,
@ -390,31 +454,32 @@ bool UserPool::authenticate_internal(User * user,
set<int>& group_ids,
int& umask)
{
bool result = false;
ostringstream oss;
string auth_driver;
string username;
string error_str;
bool driver_managed_groups = false;
bool update_groups;
const VectorAttribute* auth_conf;
int new_gid = -1;
int egid = -1;
int new_gid = -1;
string new_gname;
set<int> new_group_ids;
set<int> groups_remove;
set<int> groups_add;
set<int>::iterator it;
int rc;
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;
@ -426,37 +491,59 @@ bool UserPool::authenticate_internal(User * user,
uname = user->name;
gname = user->gname;
auth_driver = user->auth_driver;
//Check if token is a login token
result = user->login_token.is_valid(token);
if (!result) //Not a login token check if the token is a session token
{
result = user->session.is_valid(token);
}
umask = user->get_umask();
user->unlock();
auth_driver = user->auth_driver;
if (result) //Good either a valid session or login_token
if (nd.get_auth_conf_attribute(auth_driver, "DRIVER_MANAGED_GROUPS",
driver_managed_groups) != 0)
{
return true;
}
if (nd.get_auth_conf_attribute(auth_driver, auth_conf) == 0)
{
auth_conf->vector_value("DRIVER_MANAGED_GROUPS", driver_managed_groups);
driver_managed_groups = false;
}
AuthRequest ar(user_id, group_ids);
// -------------------------------------------------------------------------
// Check if token is a login or session token, and set EGID if needed
// -------------------------------------------------------------------------
if ( user->login_tokens.is_valid(token, egid) )
{
if ( egid != -1 && !user->is_in_group(egid) )
{
user->login_tokens.reset(token);
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;
}
user->unlock();
// -------------------------------------------------------------------------
// Not a valid token, perform authentication
// -------------------------------------------------------------------------
if ( auth_driver == UserPool::CORE_AUTH )
{
ar.add_authenticate("",username,password,token);
if (!ar.core_authenticate())
if ( !ar.core_authenticate() )
{
goto auth_failure;
}
@ -465,41 +552,30 @@ bool UserPool::authenticate_internal(User * user,
{
goto auth_failure_public;
}
else if ( authm != 0 ) //use auth driver if it was loaded
else if ( authm != 0 )
{
//Initialize authentication request and call the driver
ar.add_authenticate(auth_driver,username,password,token);
authm->trigger(AuthManager::AUTHENTICATE,&ar);
ar.wait();
if (ar.result!=true) //User was not authenticated
if ( ar.result != true )
{
goto auth_failure_driver;
}
if (driver_managed_groups)
if ( driver_managed_groups ) // Parse driver response
{
//------------------------------------------------------------------
// Parse driver response
//------------------------------------------------------------------
string str;
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)
if ( parse_auth_msg(ar, new_gid, new_group_ids, str, str, str,
error_str) != 0 )
{
oss << "An error ocurred parsing the driver message. "
<< error_str;
NebulaLog::log("AuM",Log::WARNING,oss);
goto auth_failure_parse;
};
oss.str("");
}
new_gname = gpool->get_name(new_gid);
}
}
else
@ -507,79 +583,69 @@ bool UserPool::authenticate_internal(User * user,
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();
}
}
//--------------------------------------------------------------------------
// Cache session token
//--------------------------------------------------------------------------
user = get(user_id, true);
if (user != 0)
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();
return false;
}
// Add/remove user ID from the group objects
user->session.set(token, _session_expiration_time);
if ( !driver_managed_groups || new_gid == -1 || new_group_ids == group_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()));
for(it = groups_add.begin(); it != groups_add.end(); it++)
{
if (gpool->get(*it, false) != 0)
{
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, true);
@ -614,6 +680,18 @@ bool UserPool::authenticate_internal(User * user,
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);
@ -671,8 +749,8 @@ bool UserPool::authenticate_server(User * user,
string target_username;
string second_token;
Nebula& nd = Nebula::instance();
AuthManager * authm = nd.get_authm();
Nebula& nd = Nebula::instance();
AuthManager* authm = nd.get_authm();
server_username = user->name;
server_password = user->password;
@ -710,7 +788,7 @@ bool UserPool::authenticate_server(User * user,
result = user->session.is_valid(second_token);
umask = user->get_umask();
umask = user->get_umask();
user->unlock();
@ -788,70 +866,6 @@ auth_failure:
return false;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserPool::parse_auth_msg(
AuthRequest &ar,
int &gid,
set<int> &group_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;
is >> tmp_gid >> ws;
if ( is.fail() )
{
error_str = "One or more group IDs are malformed";
return -1;
}
if ( Nebula::instance().get_gpool()->get(tmp_gid, false) == 0 )
{
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);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -913,7 +927,6 @@ bool UserPool::authenticate_external(const string& username,
//--------------------------------------------------------------------------
// Parse driver response
//--------------------------------------------------------------------------
rc = parse_auth_msg(ar, gid, group_ids,
driver_name, mad_name, mad_pass, error_str);
@ -925,7 +938,6 @@ bool UserPool::authenticate_external(const string& username,
//--------------------------------------------------------------------------
// Create the user, and set primary group
//--------------------------------------------------------------------------
if ( gid == -1 )
{
group_id = GroupPool::USERS_ID;
@ -967,7 +979,6 @@ bool UserPool::authenticate_external(const string& username,
//--------------------------------------------------------------------------
// Add the user to the secondary groups
//--------------------------------------------------------------------------
user = get(user_id,true);
if ( user == 0 )