Commit 69c3f7cc authored by Maiken's avatar Maiken

Merge branch 'anonymous_info' into 'master'

Refactoring a-rex ws authorization for public information (BUGZ-3917)

See merge request nordugrid/arc!974
parents 453bf85e e3654a0b
......@@ -20,6 +20,7 @@
## [arex/data-staging]
## [arex/ws]
## [arex/ws/jobs]
## [arex/ws/publicinfo]
## [arex/ws/cache]
## [arex/ws/candypond]
## [arex/ws/argus]
......@@ -1380,6 +1381,27 @@
### end of the [arex/ws/jobs] block ##############################
### The [arex/ws/publicinfo] block ################################
## AREX allows access to public informaton for non-authorized users.
## Presence of this block enables such feature.
#[arex/ws/publicinfo]
## CHANGE: new block
## allowaccess = authgroup - Defines that the specified authgroup members are authorized to access
## public information. For more information see similar configuration option in [arex/ws/jobs] block.
## default: undefined
## multivalued
#allowaccess=monitors
## denyaccess = authgroup - Defines that the specified authgroup members are REJECTED, not authorized
## to access public information. For more information see similar configuration option in [arex/ws/jobs] block.
## default: undefined
## multivalued
#denyaccess=badactors
### end of the [arex/ws/publicinfo] block ####################
### The [arex/ws/cache] block ################################
## The content of the A-REX cache can be accessed via a WS-interface.
## Configuring this block will allow reading cache files through a special URL.
......
......@@ -447,18 +447,19 @@ prepare() {
fi
# Authorization and user mapping for A-REX/EMIES
emies_legacy_shc="
<!-- Do authorization in same way as jobs plugin of gridftpd does -->
<!-- Beware of hardcoded block name -->
<SecHandler name=\"arc.authz\" event=\"incoming\">
<PDP name=\"arclegacy.pdp\">
<ConfigBlock>
<ConfigFile>$ARC_RUNTIME_CONFIG</ConfigFile>
<BlockName>$USERAUTH_BLOCK</BlockName>
</ConfigBlock>
</PDP>
</SecHandler>
"
emies_legacy_shc=""
# emies_legacy_shc="
#<!-- Do authorization in same way as jobs plugin of gridftpd does -->
#<!-- Beware of hardcoded block name -->
#<SecHandler name=\"arc.authz\" event=\"incoming\">
# <PDP name=\"arclegacy.pdp\">
# <ConfigBlock>
# <ConfigFile>$ARC_RUNTIME_CONFIG</ConfigFile>
# <BlockName>$USERAUTH_BLOCK</BlockName>
# </ConfigBlock>
# </PDP>
#</SecHandler>
#"
if [ "$mapping_present" = 'true' ]; then
emies_legacy_shc="$emies_legacy_shc
<!-- Perform client mapping according to rules of gridftpd -->
......
......@@ -238,6 +238,43 @@ std::string ARexSecAttr::get(const std::string& id) const {
return "";
};
static bool match_lists(const std::list<std::pair<bool,std::string> >& list1, const std::list<std::string>& list2, std::string& matched) {
for(std::list<std::pair<bool,std::string> >::const_iterator l1 = list1.begin(); l1 != list1.end(); ++l1) {
for(std::list<std::string>::const_iterator l2 = list2.begin(); l2 != list2.end(); ++l2) {
if((l1->second) == (*l2)) {
matched = l1->second;
return l1->first;
};
};
};
return false;
}
static bool match_groups(std::list<std::pair<bool,std::string> > const & groups, Arc::Message& inmsg) {
std::string matched_group;
if(!groups.empty()) {
Arc::MessageAuth* auth = inmsg.Auth();
if(auth) {
Arc::SecAttr* sattr = auth->get("ARCLEGACY");
if(sattr) {
if(match_lists(groups, sattr->getAll("GROUP"), matched_group)) {
return true;
};
};
};
auth = inmsg.AuthContext();
if(auth) {
Arc::SecAttr* sattr = auth->get("ARCLEGACY");
if(sattr) {
if(match_lists(groups, sattr->getAll("GROUP"), matched_group)) {
return true;
};
};
};
};
return false;
}
static Arc::XMLNode ESCreateResponse(Arc::PayloadSOAP& res,const char* opname) {
Arc::XMLNode response = res.NewChild(ES_CREATE_NPREFIX + ":" + opname + "Response");
return response;
......@@ -486,6 +523,17 @@ ARexConfigContext* ARexService::get_configuration(Arc::Message& inmsg) {
};
endpoint+=GetPath(http_endpoint);
};
// Do authorization according to allowed/denied authgroups
std::list<std::pair<bool,std::string> > const & groups = config_.MatchingGroups("");
if(!groups.empty()) {
if(!match_groups(groups, inmsg)) {
logger_.msg(Arc::ERROR, "Service access is not allowed for this user");
return NULL;
};
};
// Create configuration for this user
config=new ARexConfigContext(config_,uname,grid_name,endpoint);
if(config) {
if(*config) {
......@@ -626,7 +674,26 @@ Arc::MCC_Status ARexService::process(Arc::Message& inmsg,Arc::Message& outmsg) {
// Process grid-manager configuration if not done yet
ARexConfigContext* config = get_configuration(inmsg);
if(!config) {
// Service is not operational except public information
// Service is not operational except public information.
// But public information also has own authorization rules
if(!config_.PublicInformationEnabled()) {
logger_.msg(Arc::VERBOSE, "Can't obtain configuration. Public information is disabled.");
char const* fault = "User can't be assigned configuration";
return (method == "POST") ?
make_soap_fault(outmsg, fault) :
make_http_fault(outmsg, HTTP_ERR_FORBIDDEN, fault);
};
// Check additional authorization rules
std::list<std::pair<bool,std::string> > const & groups = config_.MatchingGroupsPublicInformation();
if(!groups.empty()) {
if(!match_groups(groups, inmsg)) {
logger_.msg(Arc::VERBOSE, "Can't obtain configuration. Public information is disallowed for this user.");
char const* fault = "User can't be assigned configuration";
return (method == "POST") ?
make_soap_fault(outmsg, fault) :
make_http_fault(outmsg, HTTP_ERR_FORBIDDEN, fault);
};
};
logger_.msg(Arc::VERBOSE, "Can't obtain configuration. Only public information is provided.");
} else {
config->ClearAuths();
......
......@@ -91,30 +91,33 @@ bool CoreConfig::ParseConfINI(GMConfig& config, Arc::ConfigFile& cfile) {
bool job_log_log_is_set = false;
Arc::ConfigIni cf(cfile);
cf.SetSectionIndicator(".");
static const int common_secnum = 0;
static const int perflog_secnum = 0;
cf.AddSection("common/perflog");
static const int common_secnum = 1;
cf.AddSection("common");
static const int ganglia_secnum = 1;
static const int ganglia_secnum = 2;
cf.AddSection("arex/ganglia");
static const int emies_secnum = 2;
static const int emies_secnum = 3;
cf.AddSection("arex/ws/jobs");
static const int ws_secnum = 3;
static const int publicinfo_secnum = 4;
cf.AddSection("arex/ws/publicinfo");
static const int ws_secnum = 5;
cf.AddSection("arex/ws");
static const int jura_secnum = 4;
static const int jura_secnum = 6;
cf.AddSection("arex/jura");
static const int gm_secnum = 5;
static const int gm_secnum = 7;
cf.AddSection("arex");
static const int infosys_secnum = 6;
static const int cluster_secnum = 8;
cf.AddSection("infosys/cluster");
static const int infosys_secnum = 9;
cf.AddSection("infosys");
static const int queue_secnum = 7;
static const int queue_secnum = 10;
cf.AddSection("queue");
static const int ssh_secnum = 8;
static const int ssh_secnum = 11;
cf.AddSection("lrms/ssh");
static const int lrms_secnum = 9;
static const int lrms_secnum = 12;
cf.AddSection("lrms");
static const int cluster_secnum = 10;
cf.AddSection("infosys/cluster");
static const int perflog_secnum = 11;
cf.AddSection("common/perflog");
if (config.job_perf_log) {
config.job_perf_log->SetEnabled(false);
config.job_perf_log->SetOutput("/var/log/arc/perfdata/arex.perflog");
......@@ -406,7 +409,6 @@ bool CoreConfig::ParseConfINI(GMConfig& config, Arc::ConfigFile& cfile) {
};
if (cf.SectionNum() == ws_secnum) { // arex/ws
if (cf.SubSection()[0] == '\0') {
if(command == "wsurl") {
config.arex_endpoint = rest;
......@@ -456,6 +458,28 @@ bool CoreConfig::ParseConfINI(GMConfig& config, Arc::ConfigFile& cfile) {
continue;
};
if (cf.SectionNum() == publicinfo_secnum) { // arex/ws/publicinfo
if (cf.SubSection()[0] == '\0') {
config.enable_publicinfo = true;
if (command == "allowaccess") {
while(!rest.empty()) {
std::string str = Arc::ConfigIni::NextArg(rest);
if(!str.empty()) {
config.matching_groups_publicinfo.push_back(std::pair<bool,std::string>(true,str));
};
};
} else if (command == "denyaccess") {
while(!rest.empty()) {
std::string str = Arc::ConfigIni::NextArg(rest);
if(!str.empty()) {
config.matching_groups_publicinfo.push_back(std::pair<bool,std::string>(false,str));
};
};
};
};
continue;
};
if (cf.SectionNum() == jura_secnum) { // arex/jura
if (cf.SubSection()[0] == '\0') {
jobreport_publisher = "jura-ng";
......
......@@ -101,6 +101,7 @@ void GMConfig::SetDefaults() {
enable_arc_interface = false;
enable_emies_interface = false;
enable_publicinfo = false;
cert_dir = Arc::GetEnv("X509_CERT_DIR");
voms_dir = Arc::GetEnv("X509_VOMS_DIR");
......@@ -294,6 +295,10 @@ const std::list<std::pair<bool,std::string> > & GMConfig::MatchingGroups(const c
return (pos == matching_groups.end()) ? empty_group_list : pos->second;
}
const std::list<std::pair<bool,std::string> > & GMConfig::MatchingGroupsPublicInformation() const {
return matching_groups_publicinfo;
}
bool GMConfig::Substitute(std::string& param, const Arc::User& user) const {
std::string::size_type curpos = 0;
for (;;) {
......
......@@ -184,6 +184,8 @@ public:
bool EMIESInterfaceEnabled() const { return enable_emies_interface; }
/// GridFTP job interface endpoint
const std::string & GridFTPEndpoint() const { return gridftp_endpoint; }
/// Whether public information interface is enabled
bool PublicInformationEnabled() const { return enable_publicinfo; }
/// A-REX WS-interface job submission endpoint
const std::string & AREXEndpoint() const { return arex_endpoint; }
......@@ -245,6 +247,8 @@ public:
/// Returns list of authorization groups for specified queue.
/// If queue is not specified value for server is returned.
const std::list<std::pair<bool,std::string> > & MatchingGroups(const char * queue = "") const;
/// Returns list of authorization groups for public information.
const std::list<std::pair<bool,std::string> > & MatchingGroupsPublicInformation() const;
bool UseSSH() const { return sshfs_mounts_enabled; }
/// Check if remote directory is mounted
......@@ -341,6 +345,8 @@ private:
bool enable_arc_interface;
/// Whether EMI-ES interface is enabled
bool enable_emies_interface;
/// Whether public information interface is enabled
bool enable_publicinfo;
/// GridFTP job endpoint
std::string gridftp_endpoint;
/// WS-interface endpoint
......@@ -353,6 +359,8 @@ private:
std::map<std::string, std::list<std::string> > authorized_vos;
/// groups allowed per queue with allow/deny mark (true/false)
std::map<std::string, std::list<std::pair<bool, std::string> > > matching_groups;
/// groups allowed to access public information with allow/deny mark (true/false)
std::list<std::pair<bool, std::string> > matching_groups_publicinfo;
/// Indicates whether session, runtime and cache dirs are mounted through sshfs (only suppored by Python backends)
bool sshfs_mounts_enabled;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment