Back to index

nordugrid-arc-nox  1.1.0~rc6
security.py
Go to the documentation of this file.
00001 storage_actions = ['read', 'addEntry', 'removeEntry', 'delete', 'modifyPolicy', 'modifyStates', 'modifyMetadata']
00002 identity_type = 'http://www.nordugrid.org/schemas/policy-arc/types/tls/identity'
00003 ca_type = 'http://www.nordugrid.org/schemas/policy-arc/types/tls/ca'
00004 vomsattribute_type = 'http://www.nordugrid.org/schemas/policy-arc/types/tls/vomsattribute'
00005 storage_action_type = 'http://www.nordugrid.org/schemas/policy-arc/types/storage/action'
00006 request_ns = 'http://www.nordugrid.org/schemas/request-arc'
00007 all_user = 'ALL'
00008 anonymous_user = 'ANONYMOUS'
00009 
00010 from arcom.logger import get_logger
00011 log = get_logger('arcom.security')
00012 
00013 class AuthRequest:
00014     
00015     def __init__(self, message):
00016         auth = message.Auth()
00017         import arc
00018         xml = auth.Export(arc.SecAttr.ARCAuth)
00019         subject = xml.Get('RequestItem').Get('Subject')
00020         try:
00021             self.identity = str(subject.XPathLookup('//ra:SubjectAttribute[@AttributeId="%s"]' % identity_type, arc.NS({'ra':request_ns}))[0])
00022         except:
00023             # if there is no identity in the auth object (e.g. if not using TLS)
00024             self.identity = anonymous_user
00025             identity_node = subject.NewChild('ra:SubjectAttribute',arc.NS({'ra':request_ns}))
00026             identity_node.Set(self.identity)
00027             identity_node.NewAttribute('AttributeId').Set(identity_type)
00028             identity_node.NewAttribute('Type').Set('string')
00029         try:
00030             self.ca = str(subject.XPathLookup('//ra:SubjectAttribute[@AttributeId="%s"]' % ca_type, arc.NS({'ra':request_ns}))[0])
00031         except:
00032             self.ca = ''
00033         self.subject = subject.GetXML()
00034     
00035     def get_request(self, action, format = 'ARCAuth'):
00036         if format not in ['ARCAuth']:
00037             raise Exception, 'Unsupported format %s' % format
00038         if format == 'ARCAuth':
00039             return '<Request xmlns="%s">\n  <RequestItem>\n%s\n%s  </RequestItem>\n</Request>' % \
00040                 (request_ns, self.subject, '    <Action AttributeId="%s" Type="string">%s</Action>\n' % (storage_action_type, action))
00041             
00042     def get_identity(self):
00043         return self.identity
00044 
00045     def get_identity_and_ca(self):
00046         return self.identity, self.ca
00047             
00048     def __str__(self): 
00049         return self.subject
00050     
00051 
00052             
00053 class AuthPolicy(dict):
00054 
00055     def get_policy(self, format  = 'ARCAuth'):
00056         if format not in ['ARCAuth', 'StorageAuth']:
00057             raise Exception, 'Unsupported format %s' % format
00058         if format == 'ARCAuth':
00059             result = []
00060             for identity, actions in self.items():
00061                 if identity == all_user:
00062                     subjects = ''
00063                 elif identity.startswith('VOMS:'):
00064                     subjects = ('    <Subjects>\n' +
00065                                 '      <Subject>\n' + 
00066                                 '         <Attribute AttributeId="%s" Type="string" Function="match">/VO=%s/</Attribute>\n' % (vomsattribute_type, identity[5:]) +
00067                                 '      </Subject>\n' +
00068                                 '    </Subjects>\n')
00069                 else:
00070                     subjects = ('    <Subjects>\n' +
00071                                 '      <Subject>\n' + 
00072                                 '        <Attribute AttributeId="%s" Type="string">%s</Attribute>\n' % (identity_type, identity) +
00073                                 '      </Subject>\n' +
00074                                 '    </Subjects>\n')
00075                 raw_actions = [a for a in actions if a[1:] in storage_actions]
00076                 actions = {}
00077                 actions[True] = [action[1:] for action in raw_actions if action[0] == '+']
00078                 actions[False] = [action[1:] for action in raw_actions if action[0] != '+']
00079                 for permit, action_list in actions.items():
00080                     if action_list:
00081                         result.append('  <Rule Effect="%s">\n' % (permit and 'Permit' or 'Deny') +
00082                         '    <Description>%s is %s to %s</Description>\n' % (identity, permit and 'allowed' or 'not allowed', ', '.join(action_list)) +
00083                         subjects +
00084                         '    <Actions>\n' + 
00085                         ''.join(['      <Action AttributeId="%s" Type="string">%s</Action>\n' % (storage_action_type, action) for action in action_list]) +
00086                         '    </Actions>\n' +
00087                         '  </Rule>\n')
00088             return '<Policy xmlns="http://www.nordugrid.org/schemas/policy-arc" CombiningAlg="Deny-Overrides">\n%s</Policy>\n' % ''.join(result)            
00089         if format == 'StorageAuth':
00090             return [(identity, ' '.join([a for a in actions if a[1:] in storage_actions])) for identity, actions in self.items()]
00091     
00092     def set_policy(self, policy, format = 'StorageAuth'):
00093         if format != 'StorageAuth':
00094             raise Exception, 'Unsupported format %s' % format
00095         self.clear()
00096         if format == 'StorageAuth':
00097             for identity, actionstring in policy:
00098                 self[identity] = actionstring.split()
00099 
00100 def make_decision(policy, request):
00101     import arc
00102     loader = arc.EvaluatorLoader()
00103     evaluator = loader.getEvaluator('arc.evaluator')
00104     p = loader.getPolicy('arc.policy', arc.Source(str(policy)))
00105     evaluator.addPolicy(p)
00106     r = loader.getRequest('arc.request', arc.Source(str(request)))
00107     response = evaluator.evaluate(r)
00108     responses = response.getResponseItems()
00109     response_list = [responses.getItem(i).res for i in range(responses.size())]
00110     #print 'RESPONSE_LIST = ', response_list
00111     return response_list[0]
00112     # if response_list.count(arc.DECISION_DENY) > 0:
00113     #     return 'deny'
00114     # if response_list.count(arc.DECISION_PERMIT) > 0:
00115     #     return 'permit'
00116     # if response_list.count(arc.DECISION_NOT_APPLICABLE) > 0:
00117     #     return 'not_applicable'
00118     # return 'indeterminate'
00119 
00120 def parse_ssl_config(cfg):
00121     try:
00122         client_ssl_node = cfg.Get('ClientSSLConfig')
00123         fromFile = str(client_ssl_node.Attribute('FromFile'))
00124         if fromFile:
00125             try:
00126                 xml_string = file(fromFile).read()
00127                 import arc
00128                 client_ssl_node = arc.XMLNode(xml_string)
00129             except:
00130                 log.msg()
00131                 pass
00132         if client_ssl_node.Size() == 0:
00133             return {}
00134         ssl_config = {}
00135         ssl_config['key_file'] = str(client_ssl_node.Get('KeyPath'))
00136         ssl_config['cert_file'] = str(client_ssl_node.Get('CertificatePath'))
00137         ca_file = str(client_ssl_node.Get('CACertificatePath'))
00138         if ca_file:
00139             ssl_config['ca_file'] = ca_file
00140         else:
00141             ssl_config['ca_dir'] = str(client_ssl_node.Get('CACertificatesDir'))
00142         return ssl_config
00143     except:
00144         log.msg()
00145         return {}