fix some bugs regarding sub authority implementaiton
[sfa.git] / sfa / methods / get_credential.py
1 ### $Id$
2 ### $URL$
3
4 from sfa.trust.credential import *
5 from sfa.trust.rights import *
6 from sfa.util.faults import *
7 from sfa.util.method import Method
8 from sfa.util.parameter import Parameter, Mixed
9 from sfa.trust.auth import Auth
10 from sfa.util.record import GeniRecord
11 from sfa.util.debug import log
12
13 class get_credential(Method):
14     """
15     Retrive a credential for an object
16     If cred == Nonee then the behavior reverts to get_self_credential
17
18     @param cred credential object specifying rights of the caller
19     @param type type of object (user | slice | sa | ma | node)
20     @param hrn human readable name of object
21
22     @return the string representation of a credential object  
23     """
24
25     interfaces = ['registry']
26     
27     accepts = [
28         Mixed(Parameter(str, "credential"),
29               Parameter(None, "No credential")),  
30         Parameter(str, "Human readable name (hrn)")
31         ]
32
33     returns = Parameter(str, "String representation of a credential object")
34
35     def call(self, cred, type, hrn):
36         if not cred:
37             return self.get_self_credential(type, hrn)
38
39         self.api.auth.check(cred, 'getcredential')
40         self.api.auth.verify_object_belongs_to_me(hrn)
41         auth_hrn = self.api.auth.get_authority(hrn)
42
43         # Is this a root or sub authority 
44         if not auth_hrn or hrn == self.api.config.SFA_INTERFACE_HRN:
45             auth_hrn = hrn
46         auth_info = self.api.auth.get_auth_info(auth_hrn)
47         table = self.api.auth.get_auth_table(auth_hrn)
48         records = table.resolve(type, hrn)
49         if not records:
50             raise RecordNotFound(hrn)
51         record = records[0]
52         # verify_cancreate_credential requires that the member lists
53         # (researchers, pis, etc) be filled in
54         self.api.fill_record_info(record)
55
56         rights = self.api.auth.determine_user_rights(self.api.auth.client_cred, record)
57         if rights.is_empty():
58             raise PermissionError(self.api.auth.client_cred.get_gid_object().get_hrn() + " has no rights to " + record.get_name())
59
60         # TODO: Check permission that self.client_cred can access the object
61
62         object_gid = record.get_gid_object()
63         new_cred = Credential(subject = object_gid.get_subject())
64         new_cred.set_gid_caller(self.api.auth.client_gid)
65         new_cred.set_gid_object(object_gid)
66         new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
67         new_cred.set_pubkey(object_gid.get_pubkey())
68         new_cred.set_privileges(rights)
69         new_cred.set_delegate(True)
70
71         auth_kind = "authority,ma,sa"
72         new_cred.set_parent(self.api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
73
74         new_cred.encode()
75         new_cred.sign()
76
77         return new_cred.save_to_string(save_parents=True)
78
79     def get_self_credential(self, type, hrn):
80         """
81         get_self_credential a degenerate version of get_credential used by a client
82         to get his initial credential when de doesnt have one. This is the same as
83         get_credetial(..., cred = None, ...)
84
85         The registry ensures that the client is the principal that is named by
86         (type, name) by comparing the public key in the record's  GID to the
87         private key used to encrypt the client side of the HTTPS connection. Thus
88         it is impossible for one principal to retrive another principal's
89         credential without having the appropriate private key.
90
91         @param type type of object (user | slice | sa | ma | node)
92         @param hrn human readable name of authority to list
93         @return string representation of a credential object
94         """
95         self.api.auth.verify_object_belongs_to_me(hrn)
96         auth_hrn = self.api.auth.get_authority(hrn)
97         
98         # is this a root or sub authority
99         if not auth_hrn or hrn == self.api.config.SFA_INTERFACE_HRN:
100             auth_hrn = hrn
101
102         auth_info = self.api.auth.get_auth_info(auth_hrn)
103
104         # find a record that matches
105         record = None
106         table = self.api.auth.get_auth_table(auth_hrn)
107         records = table.resolve('*', hrn)
108         for rec in records:
109             if type in ['*'] or rec.get_type() in [type]:
110                 record = rec
111         if not record:
112             raise RecordNotFound(hrn)
113         gid = record.get_gid_object()
114         peer_cert = self.api.auth.peer_cert
115         if not peer_cert.is_pubkey(gid.get_pubkey()):
116            raise ConnectionKeyGIDMismatch(gid.get_subject())
117
118         rights = self.api.auth.determine_user_rights(None, record)
119         if rights.is_empty():
120             raise PermissionError(gid.get_hrn() + " has no rights to " + record.get_name())
121
122         # create the credential
123         gid = record.get_gid_object()
124         cred = Credential(subject = gid.get_subject())
125         cred.set_gid_caller(gid)
126         cred.set_gid_object(gid)
127         cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
128         cred.set_pubkey(gid.get_pubkey())
129         cred.set_privileges(rights)
130         cred.set_delegate(True)
131
132         auth_kind = "authority,sa,ma"
133         cred.set_parent(self.api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
134
135         cred.encode()
136         cred.sign()
137
138         return cred.save_to_string(save_parents=True)