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