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:
commit
6852a1aba7
@ -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
|
||||
|
@ -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_*/
|
||||
|
@ -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_*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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_*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
36
share/onetoken/onetoken.sh
Normal file
36
share/onetoken/onetoken.sh
Normal 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
|
||||
}
|
@ -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
|
||||
|
132
src/cli/oneuser
132
src/cli/oneuser
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
#######################################################################
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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 )
|
||||
|
Loading…
x
Reference in New Issue
Block a user