Back to index

nordugrid-arc-nox  1.1.0~rc6
MessageAuth.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include "MessageAuth.h"
00006 
00007 namespace Arc {
00008 
00009 MessageAuth::MessageAuth(void):attrs_created_(true) { }
00010 
00011 MessageAuth::~MessageAuth(void) {
00012   if(!attrs_created_) return;
00013   std::map<std::string,SecAttr*>::iterator attr = attrs_.begin();
00014   for(;attr != attrs_.end();++attr) {
00015     if(attr->second) delete attr->second;
00016   };
00017 }
00018 
00019 void MessageAuth::set(const std::string& key, SecAttr* value) {
00020   if(!attrs_created_) return;
00021   std::map<std::string,SecAttr*>::iterator attr = attrs_.find(key);
00022   if(attr == attrs_.end()) {
00023     attrs_[key]=value;
00024   } else {
00025     if(attr->second) delete attr->second;
00026     attr->second=value;
00027   };
00028 }
00029 
00030 void MessageAuth::remove(const std::string& key) {
00031   std::map<std::string,SecAttr*>::iterator attr = attrs_.find(key);
00032   if(attr != attrs_.end()) {
00033     if(attrs_created_) if(attr->second) delete attr->second;
00034     attrs_.erase(attr);
00035   };
00036 }
00037 
00038 SecAttr* MessageAuth::get(const std::string& key) {
00039   std::map<std::string,SecAttr*>::iterator attr = attrs_.find(key);
00040   if(attr == attrs_.end()) return NULL;
00041   return attr->second;
00042 }
00043 
00044 class _XMLPair {
00045  public:
00046   XMLNode element;
00047   XMLNode context;
00048   _XMLPair(XMLNode e,XMLNode c):element(e),context(c) { };
00049 };
00050 
00051 void copy_xml_elements(XMLNode item,XMLNode elements) {
00052   for(;(bool)elements;++elements) {
00053     item.NewChild(elements);
00054   };
00055 }
00056 
00057 // All permutations of Subject, Resource, Action elements are generated.
00058 // Attribute sub-elements get collected in single Element (Subject, Condition).
00059 // Each element withoit Attribute sub-elements are put into separate
00060 // RequestItem. Attributes of Condition are collected inside single
00061 // Condition element in every RequestItem if it comes from same source
00062 // as corresponding Subject, Resource or Action.
00063 // All generated content is merged to existing content in val variable.
00064 // TODO: Avoid duplicate Context attributes
00065 bool MessageAuth::Export(SecAttrFormat format,XMLNode &val) const {
00066   if(format == SecAttr::ARCAuth) {
00067     // Making XML document top level Request element
00068     NS ns;
00069     ns["ra"]="http://www.nordugrid.org/schemas/request-arc";
00070     if(!val) XMLNode(ns,"ra:Request").New(val);
00071     XMLNode newreq = val;
00072     newreq.Namespaces(ns);
00073     newreq.Name("ra:Request");
00074     XMLNodeContainer xmls;
00075     std::list<_XMLPair> subjects;
00076     std::list<_XMLPair> resources;
00077     std::list<_XMLPair> actions;
00078     // Collecting elements from previously generated request
00079     for(XMLNode item = newreq["RequestItem"];(bool)item;++item) {
00080       for(XMLNode subject = item["Subject"];(bool)subject;++subject) {
00081         subjects.push_back(_XMLPair(subject,item["Context"]));
00082       };
00083       for(XMLNode resource = item["Resource"];(bool)resource;++resource) {
00084         resources.push_back(_XMLPair(resource,item["Context"]));
00085       };
00086       for(XMLNode action = item["Action"];(bool)action;++action) {
00087         actions.push_back(_XMLPair(action,item["Context"]));
00088       };
00089     };
00090     int subjects_new = subjects.size();
00091     int resources_new = resources.size();
00092     int actions_new = actions.size();
00093 
00094     // Getting XMLs from all SecAttr
00095     std::map<std::string,SecAttr*>::const_iterator attr = attrs_.begin();
00096     for(;attr != attrs_.end();++attr) {
00097       xmls.AddNew(XMLNode(ns,""));
00098       XMLNode r = xmls[xmls.Size()-1];
00099       if(!(attr->second)) return false;
00100       if(!(attr->second->Export(format,r))) return false;
00101 
00102       //std::string str;
00103       //r.GetXML(str);
00104       //std::cout<<"SecAttr: ++++ Name: "<<attr->first<<"XML: "<<str<<std::endl;
00105 
00106       for(XMLNode item = r["RequestItem"];(bool)item;++item) {
00107         for(XMLNode subject = item["Subject"];(bool)subject;++subject) {
00108           subjects.push_back(_XMLPair(subject,item["Context"]));
00109         };
00110         for(XMLNode resource = item["Resource"];(bool)resource;++resource) {
00111           resources.push_back(_XMLPair(resource,item["Context"]));
00112         };
00113         for(XMLNode action = item["Action"];(bool)action;++action) {
00114           actions.push_back(_XMLPair(action,item["Context"]));
00115         };
00116       };
00117     };
00118 
00119     // Merge all collected elements into single request
00120     // Collecting new subject attributes into one element.
00121     XMLNode new_subject(ns,"ra:Subject");
00122     XMLNode new_context(ns,"ra:Context");
00123     {
00124       std::list<_XMLPair>::iterator subject = subjects.begin();
00125       for(int subject_n = 0;;++subject_n,++subject) {
00126         if(subject_n < subjects_new) continue;
00127         if(subject == subjects.end()) break;
00128         if(subject->element.Size() > 0) {
00129           copy_xml_elements(new_subject,subject->element["SubjectAttribute"]);
00130           copy_xml_elements(new_context,subject->context["ContextAttribute"]);
00131         };
00132       };
00133     };
00134     // Add new subject into existing ones - assuming all
00135     // already existing subjests are the same.
00136     {
00137       std::list<_XMLPair>::iterator subject = subjects.begin();
00138       for(int subject_n = 0;;++subject_n,++subject) {
00139         if(subject_n >= subjects_new) break;
00140         if(subject == subjects.end()) break;
00141         copy_xml_elements(subject->element,new_subject["SubjectAttribute"]);
00142         copy_xml_elements(subject->context,new_subject["ContextAttribute"]);
00143       };
00144     };
00145     // Use one of existing old subjects as template for new
00146     // elements (if present)
00147     if(subjects_new > 0) {
00148       new_subject=subjects.begin()->element;
00149       new_context=subjects.begin()->context;
00150     };
00151     // Create all permutations of Action and Resource elements
00152     std::list<_XMLPair>::iterator action = actions.begin();
00153     for(int action_n = 0;;++action_n) {
00154       std::list<_XMLPair>::iterator resource = resources.begin();
00155       for(int resource_n = 0;;++resource_n) {
00156         if((action_n < actions_new) &&
00157            (resource_n < resources_new)) {
00158           if(resources.size()) ++resource;
00159           if(resource == resources.end()) break;
00160           continue; // This combination is already in request
00161         };
00162         XMLNode newitem = newreq.NewChild("ra:RequestItem");
00163         XMLNode newctx = newitem.NewChild("ra:Context");
00164         if(new_subject.Size() > 0) {
00165           newitem.NewChild(new_subject);
00166           copy_xml_elements(newctx,new_context["ContextAttribute"]);
00167         };
00168         if(action != actions.end()) {
00169           newitem.NewChild(action->element);
00170           copy_xml_elements(newctx,action->context["ContextAttribute"]);
00171         };
00172         if(resource != resources.end()) {
00173           newitem.NewChild(resource->element);
00174           copy_xml_elements(newitem,resource->context["ContextAttribute"]);
00175         };
00176         if(resources.size()) ++resource;
00177         if(resource == resources.end()) break;
00178       };
00179       if(actions.size()) ++action;
00180       if(action == actions.end()) break;
00181     };
00182     return true;
00183   }
00184   else if(format == SecAttr::XACML) {
00185     // Making XML document top level Request element
00186     /* XACML request is like this:
00187      <Request>
00188        <Subject>
00189          <Attruibute/>
00190          ......
00191        </Subject>
00192        <Resource>
00193          <Attribute/>
00194          ......
00195        </Resource>
00196        <Action>
00197          <Attribute/>
00198          ......
00199        </Action>
00200        <Environment>
00201          <Attribute/>
00202          ......
00203        </Environment>
00204     </Request>
00205     */
00206 
00207     NS ns;
00208     ns["ra"]="urn:oasis:names:tc:xacml:2.0:context:schema:os";
00209     if(!val) XMLNode(ns,"ra:Request").New(val);
00210     XMLNode newreq = val;
00211     newreq.Namespaces(ns);
00212     newreq.Name("ra:Request");
00213 
00214     XMLNodeContainer xmls;
00215     // Getting XMLs from all SecAttr
00216     std::map<std::string,SecAttr*>::const_iterator attr = attrs_.begin();
00217     for(;attr != attrs_.end();++attr) {
00218       xmls.AddNew(XMLNode(ns,""));
00219       XMLNode r = xmls[xmls.Size()-1];
00220       if(!(attr->second)) return false;
00221       if(!(attr->second->Export(format,r))) return false;
00222     };
00223 
00224     // Merge all collected elements into single request
00225     XMLNode subject = newreq["Subject"];
00226     if(!subject) subject = newreq.NewChild("Subject");
00227     XMLNode resource = newreq["Resource"];
00228     if(!resource) resource = newreq.NewChild("Resource");
00229     XMLNode action = newreq["Action"];
00230     if(!action) action = newreq.NewChild("Action");
00231     XMLNode environment = newreq["Environment"];
00232     if(!environment) environment = newreq.NewChild("Environment");
00233 
00234     for(int i=0; i<xmls.Size(); i++) {
00235       XMLNode r = xmls[i];
00236       copy_xml_elements(subject, r["Subject"].Child());
00237       copy_xml_elements(resource, r["Resource"].Child());
00238       copy_xml_elements(action, r["Action"].Child());
00239       copy_xml_elements(environment, r["Environment"].Child());
00240     };
00241     return true;
00242   }
00243   return false;
00244 }
00245 
00246 #if 0
00247 static void add_new_elements(XMLNode item,XMLNode element) {
00248   for(;(bool)element;++element) item.NewChild(element);
00249 }
00250 
00251 // Subject, Resource, Action, Context  RequestItem in each component
00252 // goes into one seperated output <RequestItem>.
00253 // The Subject from all of the SecAttr goes into every output <RequestItem>,
00254 // because there is only one request entity (with a few SubjectAttribute)
00255 //for the incoming  message chain
00256 bool MessageAuth::Export(SecAttrFormat format,XMLNode &val) const {
00257   // Currently only ARCAuth is supported
00258   if(format != SecAttr::ARCAuth) return false;
00259   NS ns;
00260   ns["ra"]="http://www.nordugrid.org/schemas/request-arc";
00261   XMLNode newreq = val;
00262   newreq.Namespaces(ns);
00263   newreq.Name("ra:Request");
00264 
00265   //A specific RequestItem for collecting all of the <Request> from
00266   //differenc SecAttr
00267   XMLNode subjects(ns,"ra:RequestItem");
00268 
00269   std::map<std::string,SecAttr*>::const_iterator attr = attrs_.begin();
00270   for(;attr != attrs_.end();++attr) {
00271     XMLNode r(ns,"");
00272     if(!(attr->second)) return false;
00273     if(!(attr->second->Export(format,r))) return false;
00274     XMLNode item, newitem;
00275     for(item = r["RequestItem"];(bool)item;++item) {
00276       //If there ["Resource"] or ["Action"] inside input ["RequestItem"], we generate a new
00277       //["RequstItem"] for output.
00278       if(((bool)item) && ( ((bool)(item["Resource"])) || ((bool)(item["Action"])) ))
00279         newitem=newreq.NewChild("ra:RequestItem");
00280 
00281       //Collect all of the <Subject/>s. Since in HED each incomming/outgoing message
00282       //is supposed to implicitly have only one meaningful entity(Subject), it doesn't hurt
00283       //if we put all of the <Subject/>s together and merge(later) them into one <Subject/> (with
00284       //a number of <Attribute/>s from different original <Subject>s).
00285       add_new_elements(subjects,item["Subject"]);
00286 
00287       //<Context/> is also collected.
00288       add_new_elements(subjects,item["Context"]);
00289 
00290       //We store <Resource/> <Action/> <Context/> into the just generated new
00291       //<RequestItem/> by keeping the original organizing shape.
00292       //Notice that we do not put the <Subject> into new <RequestItem> now.
00293       if( ((bool)(item["Resource"])) || ((bool)(item["Action"])) ) {
00294         add_new_elements(newitem,item["Resource"]);
00295         add_new_elements(newitem,item["Action"]);
00296         add_new_elements(newitem,item["Context"]);
00297       };
00298     };
00299   };
00300 
00301   //Reset the namespaces to delete the namespaces inside subnode
00302   subjects.Namespaces(ns);
00303 
00304   //Merge the <Subject>s into one <Subject>
00305   XMLNode new_subject(ns, "ra:Subject");
00306   XMLNode sub = subjects["ra:Subject"];
00307   for(sub = subjects["Subject"];(bool)sub;++sub) {
00308     add_new_elements(new_subject, sub["SubjectAttribute"]);
00309   }
00310 
00311   //Merge the <Context>s into one <Context>
00312   XMLNode new_context(ns, "ra:Context");
00313   for(XMLNode ctx = subjects["ra:Context"];(bool)ctx;++ctx) {
00314     add_new_elements(new_context, ctx["ContextAttribute"]);
00315   }
00316 
00317   //If finally, there is not any output ["RequestItem"], we use the just generated new <Subject/>.
00318   //This is the case: There is MCCTLS SecAttr which has no elements except ["Subject"], and
00319   //there is no other SecAttr exist.
00320   //<Context/> is also added
00321   XMLNode item = newreq["ra:RequestItem"];
00322   if(!item) {
00323     XMLNode newitem = newreq.NewChild("ra:RequestItem");
00324     add_new_elements(newitem, new_subject);
00325     add_new_elements(newitem, new_context);
00326   }
00327 
00328   //Put the new <Subject/> into each new <RequestItem/>
00329   for(;(bool)item;++item) {
00330     add_new_elements(item, new_subject);
00331   };
00332 
00333   //Reset the namespaces to delete the namespace inside subnode.
00334   newreq.Namespaces(ns);
00335 
00336   return true;
00337 }
00338 #endif
00339 
00340 MessageAuth* MessageAuth::Filter(const std::list<std::string>& selected_keys,const std::list<std::string>& rejected_keys) {
00341   MessageAuth* newauth = new MessageAuth;
00342   newauth->attrs_created_=false;
00343   if(selected_keys.empty()) {
00344     newauth->attrs_=attrs_;
00345   } else {
00346     for(std::list<std::string>::const_iterator key = selected_keys.begin();
00347                        key!=selected_keys.end();++key) {
00348       std::map<std::string,SecAttr*>::const_iterator attr = attrs_.find(*key);
00349       if((attr != attrs_.end()) && (attr->second != NULL)) newauth->attrs_[*key]=attr->second;
00350     };
00351   };
00352   if(!rejected_keys.empty()) {
00353     for(std::list<std::string>::const_iterator key = rejected_keys.begin();
00354                        key!=rejected_keys.end();++key) {
00355       newauth->remove(*key);
00356     };
00357   };
00358   return newauth;
00359 }
00360 
00361 }
00362