Commit 6c5bbade authored by Maiken's avatar Maiken
Browse files

Merge branch 'mapping_processing_policy' into 'master'

Mapping processing policy modifiers

See merge request nordugrid/arc!559
parents ff57df85 5bfb89a2
......@@ -65,7 +65,7 @@
## keywords and optionally block identifiers. Keywords may be separated by "/"
## and used to label subblocks (e.g. [arex/jura]), while block identifiers
## are separated by ":" from keywords. For example, in the [queue:short]
## block header 'queue' is a keyword while 'short' is an identifier, e.g. the name of the queue.
## block header "queue" is a keyword while "short" is an identifier, e.g. the name of the queue.
## Block headers must be UNIQUE.
##
## A block starts with a unique [keyword:identifier] blockheader and ends where the next block
......@@ -111,7 +111,7 @@
## no values. Furthermore, configuration options within disabled blocks takes no values either.
##
## Configuration blocks related to authorization are ORDER-DEPENDENT! The authorization blocks
## [authgroup:name] MUST be defined before used in the blocks such as [mapping], [arex] or
## [authgroup:name] MUST be defined before used in the blocks such as [mapping], [arex/ws/jobs] or
## [gridftp/jobs]. The same rule applies to defining legacy [userlist:name] blocks.
## Furthermore, the order of the authorization blocks itself may have influence over
## authorization decisions!
......@@ -119,23 +119,27 @@
## Below we give a detailed description of all the configuration options of the
## different configuration blocks. Every configuration option is described
## in a dedicated paragraph with the following reference syntax notation.
## This file is parsed by configuration validation script and so
## it is important that it follows the agreed syntax: For each block or
## option please add explanatory text with two ## followed by a space at the
## beginning of the line and then an example with a single # and no spaces at
## the beginning of the line. These examples are used as reference parameters
## for the block and configuration option names!
## This file is parsed at buildtime to assist in configuration default parsing and validation script
## and so it is important that it follows the agreed syntax: For each block or
## option please add explanatory text with two "##" followed by a space at the
## beginning of the line and then an example with a single "#" and no spaces at
## the beginning of the line.
##
## example_config_option = value [optional values] - Here comes the explanation
## of the config option. Mandatory configuration options are indicated by an asterix prefix to the
## option name e.g: *mandatory_configoption vs. optional_configoption.
## The explanation is followed by the special keyword "multivalued" in a separate line to indicate
## that it can be set multiple times (multivalued). Missing such keyword means the config option
## can only occur once in the arc.conf. By default the arc.conf config options are optional
## and single-valued. For some config options only a fix set of values are allowed. These are
## option name e.g: "*mandatory_configoption" vs. "optional_configoption".
## The explanation can be followed by the special keywords in a separate line:
## - "multivalued" - used to indicate that config option can be specified multiple times.
## This forms a set of values for the same configuration option irrespective of lines order.
## - "sequenced" - used to indicate that config option is a part of the sequence and its
## effect on configuration depends on the lines order. Sequenced option can be specified
## several times in the configuration sequence independently.
## Missing such keywords means the config option can only occur once in the arc.conf.
## By default the arc.conf config options are optional and single-valued.
## For some config options only a fix set of values are allowed. These are
## listed in a separate line after the "allowedvalues" keyword.
## The default of every config option is explicitly given in the "default:" line.
## Default can be a pre-set value, a substitution or the undefined keyword.
## Default can be a pre-set value, a substitution or the "undefined" keyword.
## The last line of the paragraph is always a valid example preceded by a single "#"
## multivalued
## allowedvalues: 12 34 56
......@@ -253,14 +257,14 @@
## subject = certificate_subject - Rule to match specific subject of user's
## X.509 certificate. No masks, patterns and regular expressions are allowed.
## multivalued
## sequenced
## default: undefined
#subject=/O=Grid/O=Big VO/CN=Main Boss
#subject=/O=Grid/O=Big VO/CN=Deputy Boss
## file = path - Processes a list of DNs stored in an external file one per line and adds those to
## the authgroup.
## multivalued
## sequenced
## default: undefined
#file=/etc/grid-security/local_users
#file=/etc/grid-security/atlas_users
......@@ -268,7 +272,7 @@
## voms = vo group role capabilities - Match VOMS attribute in user's credential.
## Use "*" to match any value.
## multivalued
## sequenced
## default: undefined
#voms=nordugrid Guests * *
#voms=atlas students prodman *
......@@ -278,7 +282,7 @@
## arc.conf configuration file. Multiple authgroup names may be specified for this rule.
## That allows creating hierarchical structure of authorization groups like
## "all-atlas" are those which are "atlas-users" and "atlas-admins".
## multivalued
## sequenced
## default: undefined
#authgroup=local_admins
#authgroup=local_admins remote_users
......@@ -286,7 +290,7 @@
## userlist = ulist_name [ulist_name ...] - (previously vo) Match user belonging to ulist_name defined
## in an earlier [userlist:ulist_name] block. Multiple userlist names are allowed for this rule.
## multivalued
## sequenced
## default: undefined
#userlist=biousers
## CHANGE: renamed
......@@ -298,12 +302,13 @@
## - "%P" - path to proxy
## ARC ships with LCAS plugin that can be enabled with following plugin configuration.
## For more information about configuring LCAS refer to 'Using LCAS/LCMAPS' document.
## multivalued
## sequenced
## default: undefined
#plugin=10 /usr/libexec/arc/arc-lcas %D %P liblcas.so /usr/lib64 /etc/lcas/lcas.db
## all = yes|no - Matches any or none user identity. For "yes" argument this rule
## always returns positive match. For "no" it is always no match.
## sequenced
## default: undefined
#all=yes
## CHANGE: MODIFIED options
......@@ -313,49 +318,49 @@
### The [mapping] block ##############################################
## This block defines the grid-identity to local UNIX identity mapping rules
## This block defines the grid-identity to local UNIX identity mapping rules
## used by various ARC components.
##
## Mapping rules are processed sequentially in the defined order.
## Each rule defines mapping method that triggered for specified "authgroup" members.
## Processing of the next rule depends on the "options" defined for the current rule
## and can be flexibly tuned.
## By default:
## - mapping process continue to the next rule in case of grid-identity is not
## matched specified "authgroup" or mapping rule is not able to accomplish mapping.
## - mapping process stops if user is a member of authgroup and mapping rule returns
## valid UNIX identity
##
## NOTE that if mapping process had stopped and there is still no local UNIX identity
## Rules in the [mapping] block are processed IN A SEQUENCE in line order of the
## configuration file (from top to bottom).
##
## There are two kind of rules:
## - mapping rules that defines how the particular "authgroup" members are mapped
## - policy rules that modifies the mapping rules sequence processing
##
## Default policy for mapping rules processing is:
## - processing CONTINUES to the next rule if identity of user DO NOT match "authgroup"
## specified in the rule (can be redefined with "policy_on_nogroup" option)
## - processing STOPS if identity of user match "authgroup" specified in the mapping rule.
## Depend on whether this mapping rule returns valid UNIX identity the processing can be
## redefined with "policy_on_map" and "policy_on_nomap" options.
##
## Policy can be redefined at the any point of configuration sequence and affects
## all mapping rules defined after the polcy rule.
##
## NOTE that if mapping process STOPS and there is still no local UNIX identity
## identified, the user running A-REX will be used.
## NOTE that when grid-identity is mapped to "root" account request processing fails implicitely.
## NOTE that when grid-identity is mapped to "root" account - request processing fails implicitely.
##
##
#[mapping]
## CHANGE: This is a new block
## map_to_user = options authgroup_name unixname[:unixgroup] - the users that belongs to
## map_to_user = authgroup_name unixname[:unixgroup] - the users that belongs to
## specified authgroup are mapped to "unixname" local UNIX account that may be
## optionally followed by a "unixgroup" UNIX group.
##
## The options are list of comma separated "event=action" pairs or "*" as placeholder.
## Possible actions are:
## - "stop" - stop processing maping commands,
## - "continue" - proceed to next mapping command.
## Possible events are:
## - "onnogroup" - specified authgroup does not match (default action is "continue")
## - "onnomap" - specified authgroup matches but mapping processing fails (defalt action is "continue"),
## - "onmap" - specified authgroup matches and mapping processing succedes (defalt action is "stop"),
## In case of non-existing "unixname" local user the mapping rule triggers "onnomap" event.
## multivalued
## In case of non-existing "unixname" account the mapping rule treated as a rule that
## did not returned mapped identity (nomap).
## sequenced
## default: undefined
#map_to_user=* any nobody:nobody
#map_to_user=any nobody:nobody
## map_to_pool = options authgroup_name directory - the user that belong to specified
## map_to_pool = authgroup_name directory - the user that belong to specified
## authgroup is assigned one of the local UNIX accounts in the pool. Account names that
## are part of this pool are stored line-by-line in the "pool" file inside the "directory".
## The "directory" also contains information about used accont names stored in another files.
## If there are no more available accounts in the defined pool for mapping then
## accounts not used for a configurable time period may be reassigned.
## accounts not used for a configurable time period may be reassigned.
## The pool behaviour, including account reuse, is configureable with the opional
## "directory/config" file that has INI syntax (line-by-line "key=value").
## Possible keys of the "config" file are:
......@@ -363,19 +368,17 @@
## Define the timeout in days (default is "10") after which the UNIX
## account can be reassigned to another user if not used. The "0" value
## means no lease expiration.
## Options are the same as in "map_to_user" command.
## multivalued
## sequenced
## default: undefined
#map_to_pool=onnomap=stop atlas /etc/grid-security/pool/atlas
#map_to_pool=atlas /etc/grid-security/pool/atlas
## map_with_file = options authgroup_name file - for users that belongs to specified
## map_with_file = authgroup_name file - for users that belongs to specified
## authgroup the subject of certificate is matched against a list of subjects
## stored in the specified "file", one per line followed by a local UNIX account
## name. This rule can be used to implement legacy grid-mapfile aproach.
## Options are the same as in "map_to_user" command.
## multivalued
## sequenced
## default: undefined
#map_with_file=* any /etc/grid-security/grid-mapfile
#map_with_file=any /etc/grid-security/grid-mapfile
## map_with_plugin = authgroup_name timeout plugin [arg1 [arg2 [...]]] - run
## external "plugin" executable with specified arguments to find the UNIX account
......@@ -387,15 +390,43 @@
## In the arguments the following substitutions are applied before the plugin is started:
## - "%D" - subject of user's certificate,
## - "%P" - path to credentials' proxy file.
## Options are the same as in "map_to_user" command.
##
## ARC ships with LCMAPS plugin that can be enabled with the corresponfing
## configuration. For more information about configuring LCMAPS refer to
## 'Using LCAS/LCMAPS' document.
## multivalued
## sequenced
## default: undefined
#map_with_plugin=onnomap=continue altas 30 /usr/libexec/arc/arc-lcmaps %D %P liblcmaps.so /usr/lib64 /etc/lcmaps/lcmaps.db arc
##
#map_with_plugin=altas 30 /usr/libexec/arc/arc-lcmaps %D %P liblcmaps.so /usr/lib64 /etc/lcmaps/lcmaps.db arc
## policy_on_nomap = continue/stop - redefines mapping rules sequence processing policy
## in case identity of user match "authgroup" specified in the mapping rule and mapping
## rule DO NOT return valid UNIX identity. Default policy is "stop" processing the furhter
## rules.
## For example this policy will be triggered if pool is depleted, certificate subject is
## missing in the map file used for defined authgroup or plugin execution failed.
## sequenced
## default: undefined
## allowedvalues: continue stop
#policy_on_nomap=continue
## policy_on_map = continue/stop - redefines mapping rules sequence processing policy
## in case identity of user match "authgroup" specified in the mapping rule and mapping
## rule return valid UNIX identity. Default policy is "stop" processing the furhter
## rules.
## This policy will be triggered if rule successfully returns the result (allocated in pool,
## matched in map file, plugin call was successful).
## sequenced
## default: undefined
## allowedvalues: continue stop
#policy_on_map=stop
## policy_on_nogroup = continue/stop - redefines mapping rules sequence processing policy
## in case identity of user DO NOT match "authgroup" specified in the mapping rule.
## Default policy is "continue" processing the furhter rules.
## sequenced
## default: undefined
## allowedvalues: continue stop
#policy_on_nogroup=stop
##
### end of the [mapping] block ##############################################
......@@ -2913,7 +2944,7 @@
## userlist (with optional mapping info).
## If the same file specified as output for different [userlist:name] blocks
## then nordugridmap will automatically merge entries following the order of the blocks.
## default: $VAR{[common/mapping]gridmap}
## default: /etc/grid-security/grid-mapfile
#outfile=/etc/grid-security/lists/atlas-users
## CHANGE: renamed from "file"
......@@ -2993,7 +3024,7 @@
## then nordugridmap will skip users without mapping information
## (if no mapping information provided by sources)
## default: nobody
#mapped_unixid
#mapped_unixid=
#mapped_unixid=gridtest
## CHANGE: Modified. The empty value should work the same way as missing parameter. set the default to "nobody"
......
......@@ -100,11 +100,20 @@ class LegacyMapCP: public ConfigParser {
virtual bool ConfigLine(const std::string& id, const std::string& name, const std::string& cmd, const std::string& line) {
if(!is_block_) return true;
if(map_) return true; // already mapped
// Now we have only one command left "unixgroupmap" and it is not indicated at all.
//# [unixgroupmap] rule [=] authgroup args
if(map_.mapgroup(cmd.c_str(), line.c_str()) == AAA_FAILURE) {
logger_.msg(Arc::ERROR, "Failed processing user mapping command: %s %s", cmd, line);
return false;
if(cmd.compare(0,4,"map_") == 0) {
// All mapping rules starts with 'map_'
// Now we have only one command left "unixgroupmap" and it is not indicated at all.
//# [unixgroupmap] rule [=] authgroup args
if(map_.mapgroup(cmd.c_str(), line.c_str()) == AAA_FAILURE) {
logger_.msg(Arc::ERROR, "Failed processing user mapping command: %s %s", cmd, line);
return false;
};
} else if(cmd.compare(0,7,"policy_") == 0) {
// Rules that change the stack processing policy starts with 'policy_'
if(!map_.set_map_policy(cmd.c_str(), line.c_str())) {
logger_.msg(Arc::ERROR, "Failed to change mapping stack processing policy in: %s = %s", cmd, line);
return false;
};
};
return true;
};
......
......@@ -27,7 +27,8 @@ UnixMap::source_t UnixMap::sources[] = {
};
UnixMap::UnixMap(AuthUser& user,const std::string& id):
user_(user),map_id_(id),mapped_(false) {
user_(user),map_id_(id),mapped_(false),
map_policy_({MAPPING_CONTINUE,MAPPING_STOP,MAPPING_STOP}) {
}
UnixMap::~UnixMap(void) {
......@@ -51,86 +52,48 @@ static inline void skip_till_space(char const * & line) {
for(;*line;line++) if(isspace(*line)) break;
}
enum opt_action {
action_continue,
action_stop
};
enum opt_event {
event_nogroup,
event_nomap,
event_map
};
static char const option_none_str[] = { "*" };
static char const action_continue_str[] = { "continue" };
static char const action_stop_str[] = { "stop" };
static char const event_nogroup_str[] = { "onnogroup" };
static char const event_nomap_str[] = { "onnomap" };
static char const event_map_str[] = { "onmap" };
static char const action_stop_str[] = { "stop" };
#define match_string(tag,start,end) (((end-start+1) == sizeof(tag)) && (strncmp(start,tag,end-start) == 0))
static char const option_nogroup_str[] = { "policy_on_nogroup" };
static char const option_nomap_str[] = { "policy_on_nomap" };
static char const option_map_str[] = { "policy_on_map" };
static bool parse_option(const char* option, int option_len, opt_event& event, opt_action& action) {
const char* option_end = option+option_len;
if(match_string(option_none_str,option,option_end)) return true;
const char* event_start = option;
for(;option<option_end;option++) if(*option == '=') break;
if(option >= option_end) return false;
const char* event_end = option;
++option;
const char* action_start = option;
const char* action_end = option_end;
if(match_string(event_nogroup_str,event_start,event_end)) {
event = event_nogroup;
} else if(match_string(event_nomap_str,event_start,event_end)) {
event = event_nomap;
} else if(match_string(event_map_str,event_start,event_end)) {
event = event_map;
// Set mapping rules stack processing policy options
bool UnixMap::set_map_policy(const char* rule, const char* line) {
if(!line) {
logger.msg(Arc::ERROR,"Mapping policy option has empty value");
return false;
};
skip_spaces(line);
if(*line == 0) {
logger.msg(Arc::ERROR,"Mapping policy option has empty value");
return false;
};
// parse event action
map_action_t action;
if(strcmp(line, action_continue_str) == 0) {
action = MAPPING_CONTINUE;
} else if(strcmp(line, action_stop_str) == 0) {
action = MAPPING_STOP;
} else {
logger.msg(Arc::ERROR,"Unsupported mapping policy action: %s",line);
return false;
}
if(match_string(action_continue_str,action_start,action_end)) {
action = action_continue;
} else if(match_string(action_stop_str,action_start,action_end)) {
action = action_stop;
// parse policy event type
if(strcmp(rule, option_nogroup_str) == 0) {
map_policy_.nogroup = action;
} else if(strcmp(rule, option_nomap_str) == 0) {
map_policy_.nomap = action;
} else if(strcmp(rule, option_map_str) == 0) {
map_policy_.map = action;
} else {
logger.msg(Arc::ERROR,"Unsupported mapping policy option: %s",rule);
return false;
}
return true;
}
static bool parse_options(const char* options, int options_len, opt_action& onnogroup, opt_action& onnomap, opt_action& onmap) {
// default actions
onnogroup = action_continue;
onnomap = action_continue;
onmap = action_stop;
const char* options_end = options+options_len;
while(options<options_end) {
const char* option = options;
for(;options<options_end;options++) if(*options == ',') break;
opt_event event;
opt_action action;
if(!parse_option(option, options-option, event, action))
return false;
switch(event) {
case event_nogroup:
onnogroup = action;
break;
case event_nomap:
onnomap = action;
break;
case event_map:
onmap = action;
break;
};
++options;
}
return true;
}
// Now default and only mapping command
AuthResult UnixMap::mapgroup(const char* rule, const char* line) {
// was: unixgroupmap = authgroup rule
......@@ -146,10 +109,6 @@ AuthResult UnixMap::mapgroup(const char* rule, const char* line) {
return AAA_FAILURE;
};
// identify common parts of mapping commands
const char* options = line;
skip_till_space(line);
int options_len = line-options;
skip_spaces(line);
const char* groupname = line;
skip_till_space(line);
int groupname_len = line-groupname;
......@@ -157,18 +116,10 @@ AuthResult UnixMap::mapgroup(const char* rule, const char* line) {
logger.msg(Arc::ERROR,"User name mapping has empty authgroup: %s", groupname);
return AAA_FAILURE;
};
// parse options
opt_action onnogroup;
opt_action onnomap;
opt_action onmap;
if(!parse_options(options, options_len, onnogroup, onnomap, onmap)) {
logger.msg(Arc::ERROR,"User name mapping options parsing error");
return AAA_FAILURE;
};
// match specified authgroup
if(!user_.check_group(std::string(groupname,groupname_len))) {
// event onnogroup
mapped_= (onnogroup == action_stop);
// nogroup event
mapped_= (map_policy_.nogroup == MAPPING_STOP);
return AAA_NO_MATCH;
};
unix_user_.name.resize(0);
......@@ -178,8 +129,8 @@ AuthResult UnixMap::mapgroup(const char* rule, const char* line) {
if(strcmp(s->cmd,rule) == 0) {
AuthResult res=(this->*(s->map))(user_,unix_user_,line);
if(res == AAA_POSITIVE_MATCH) {
// event onmap
mapped_= (onmap == action_stop);
// map event
mapped_= (map_policy_.map == MAPPING_STOP);
return AAA_POSITIVE_MATCH;
};
if(res == AAA_FAILURE) {
......@@ -187,8 +138,8 @@ AuthResult UnixMap::mapgroup(const char* rule, const char* line) {
return AAA_FAILURE;
};
// Paranoid about negative match
// event onnomap
mapped_= (onnomap == action_stop);
// nomap event
mapped_= (map_policy_.nomap == MAPPING_STOP);
return AAA_NO_MATCH;
};
};
......
......@@ -16,6 +16,15 @@ class UnixMap {
const char* cmd;
map_func_t map;
} source_t;
typedef enum {
MAPPING_CONTINUE,
MAPPING_STOP
} map_action_t;
typedef struct {
map_action_t nogroup;
map_action_t nomap;
map_action_t map;
} map_events_t;
static source_t sources[]; // Supported evaluation sources
// Unix user obtained after mapping
unix_user_t unix_user_;
......@@ -23,6 +32,8 @@ class UnixMap {
AuthUser& user_;
// Identity of mapping request.
std::string map_id_;
// Mapping processing policy
map_events_t map_policy_;
// Mapping was done
bool mapped_;
AuthResult map_mapfile(const AuthUser& user,unix_user_t& unix_user,const char* line);
......@@ -43,6 +54,8 @@ class UnixMap {
AuthUser& user(void) { return user_; };
// Map
AuthResult mapgroup(const char* rule, const char* line);
// Stack processing policy
bool set_map_policy(const char* rule, const char* line);
};
} // namespace ArcSHCLegacy
......
......@@ -11,7 +11,7 @@ x509_host_cert = /etc/grid-security/testCA-hostcert.pem
file = /etc/grid-security/testCA.allowed-subjects
[mapping]
map_to_user = * zero nobody:nobody
map_to_user = zero nobody:nobody
[lrms]
lrms = fork
......
......@@ -25,7 +25,8 @@ UnixMap::source_t UnixMap::sources[] = {
};
UnixMap::UnixMap(AuthUser& user,const std::string& id):
user_(user),map_id_(id),mapped_(false) {
user_(user),map_id_(id),mapped_(false),
map_policy_({MAPPING_CONTINUE,MAPPING_STOP,MAPPING_STOP}) {
}
UnixMap::~UnixMap(void) {
......@@ -49,86 +50,49 @@ static inline void skip_till_space(char const * & line) {
for(;*line;line++) if(isspace(*line)) break;
}
enum opt_action {
action_continue,
action_stop
};
enum opt_event {
event_nogroup,
event_nomap,
event_map
};
static char const option_none_str[] = { "*" };
static char const action_continue_str[] = { "continue" };
static char const action_stop_str[] = { "stop" };
static char const event_nogroup_str[] = { "onnogroup" };
static char const event_nomap_str[] = { "onnomap" };
static char const event_map_str[] = { "onmap" };
static char const action_stop_str[] = { "stop" };
#define match_string(tag,start,end) (((end-start+1) == sizeof(tag)) && (strncmp(start,tag,end-start) == 0))
static char const option_nogroup_str[] = { "policy_on_nogroup" };
static char const option_nomap_str[] = { "policy_on_nomap" };
static char const option_map_str[] = { "policy_on_map" };
static bool parse_option(const char* option, int option_len, opt_event& event, opt_action& action) {
const char* option_end = option+option_len;
if(match_string(option_none_str,option,option_end)) return true;
const char* event_start = option;
for(;option<option_end;option++) if(*option == '=') break;
if(option >= option_end) return false;
const char* event_end = option;
++option;
const char* action_start = option;
const char* action_end = option_end;
if(match_string(event_nogroup_str,event_start,event_end)) {
event = event_nogroup;
} else if(match_string(event_nomap_str,event_start,event_end)) {
event = event_nomap;
} else if(match_string(event_map_str,event_start,event_end)) {
event = event_map;
// Set mapping rules stack processing policy options
bool UnixMap::set_map_policy(const char* rule, const char* line) {
if(!line) {
logger.msg(Arc::ERROR,"Mapping policy option has empty value");
return false;
};
skip_spaces(line);
if(*line == 0) {
logger.msg(Arc::ERROR,"Mapping policy option has empty value");
return false;
};
// parse event action
map_action_t action;
if(strcmp(line, action_continue_str) == 0) {
action = MAPPING_CONTINUE;
} else if(strcmp(line, action_stop_str) == 0) {
action = MAPPING_STOP;
} else {
logger.msg(Arc::ERROR,"Unsupported mapping policy action: %s",line);
return false;
}
if(match_string(action_continue_str,action_start,action_end)) {
action = action_continue;
} else if(match_string(action_stop_str,action_start,action_end)) {
action = action_stop;
// parse policy event type
if(strcmp(rule, option_nogroup_str) == 0) {
map_policy_.nogroup = action;
} else if(strcmp(rule, option_nomap_str) == 0) {
map_policy_.nomap = action;
} else if(strcmp(rule, option_map_str) == 0) {
map_policy_.map = action;
} else {
logger.msg(Arc::ERROR,"Unsupported mapping policy option: %s",rule);
return false;
}
return true;
}