1 | """ZSI Server side SOAP Binding for Session Manager Web Service |
---|
2 | |
---|
3 | NERC Data Grid Project""" |
---|
4 | __author__ = "P J Kershaw" |
---|
5 | __date__ = "01/10/08" |
---|
6 | __copyright__ = "(C) 2008 STFC" |
---|
7 | __license__ = \ |
---|
8 | """This software may be distributed under the terms of the Q Public |
---|
9 | License, version 1.0 or later.""" |
---|
10 | __contact__ = "Philip.Kershaw@stfc.ac.uk" |
---|
11 | __revision__ = '$Id$' |
---|
12 | import os, sys |
---|
13 | import base64 |
---|
14 | import logging |
---|
15 | log = logging.getLogger(__name__) |
---|
16 | |
---|
17 | |
---|
18 | from ndg.security.server.zsi.sessionmanager.SessionManager_services_server \ |
---|
19 | import SessionManagerService as _SessionManagerService |
---|
20 | from ndg.security.common.zsi.sessionmanager.SessionManager_services import \ |
---|
21 | connectInputMsg, disconnectInputMsg, getSessionStatusInputMsg, \ |
---|
22 | getAttCertInputMsg |
---|
23 | |
---|
24 | |
---|
25 | from ndg.security.server.sessionmanager import SessionManager |
---|
26 | from ndg.security.common.credentialwallet import \ |
---|
27 | CredentialWalletAttributeRequestDenied |
---|
28 | from ndg.security.common.wssecurity.dom import SignatureHandler |
---|
29 | from ndg.security.common.X509 import X509Cert, X509CertRead |
---|
30 | |
---|
31 | class SessionManagerWSConfigError(Exception): |
---|
32 | '''Raise for errors related to the Session Manager Web Service |
---|
33 | configuration''' |
---|
34 | |
---|
35 | class SessionManagerWS(_SessionManagerService): |
---|
36 | '''Session Manager ZSI SOAP Service Binding class''' |
---|
37 | |
---|
38 | def __init__(self, **kw): |
---|
39 | |
---|
40 | # Stop in debugger at beginning of SOAP stub if environment variable |
---|
41 | # is set |
---|
42 | self.__debug = bool(os.environ.get('NDGSEC_INT_DEBUG')) |
---|
43 | if self.__debug: |
---|
44 | import pdb |
---|
45 | pdb.set_trace() |
---|
46 | |
---|
47 | # Extract local Attribute Authority environ identifier |
---|
48 | self.attributeAuthorityFilterID = kw.pop('attributeAuthorityFilterID', |
---|
49 | None) |
---|
50 | if self.attributeAuthorityFilterID is None: |
---|
51 | log.warning('No "attributeAuthorityFilterID" option was ' |
---|
52 | 'set in the input config: link to a local Attibute ' |
---|
53 | 'Authority instance is disabled') |
---|
54 | |
---|
55 | # ... and WS-Security signature verification filter |
---|
56 | self.wsseSignatureVerificationFilterID = kw.pop( |
---|
57 | 'wsseSignatureVerificationFilterID', |
---|
58 | None) |
---|
59 | if self.wsseSignatureVerificationFilterID is None: |
---|
60 | log.warning('No "wsseSignatureVerificationFilterID" option was ' |
---|
61 | 'set in the input config') |
---|
62 | |
---|
63 | # Initialise Attribute Authority class - property file will be |
---|
64 | # picked up from default location under $NDG_DIR directory |
---|
65 | self.sm = SessionManager(**kw) |
---|
66 | |
---|
67 | |
---|
68 | def soap_connect(self, ps): |
---|
69 | '''Connect to Session Manager and create a user session |
---|
70 | |
---|
71 | @type ps: ZSI ParsedSoap |
---|
72 | @param ps: client SOAP message |
---|
73 | @rtype: tuple |
---|
74 | @return: request and response objects''' |
---|
75 | |
---|
76 | if self.__debug: |
---|
77 | import pdb |
---|
78 | pdb.set_trace() |
---|
79 | |
---|
80 | request = ps.Parse(connectInputMsg.typecode) |
---|
81 | response = _SessionManagerService.soap_connect(self, ps) |
---|
82 | |
---|
83 | result = self.sm.connect(username=request.Username, |
---|
84 | passphrase=request.Passphrase, |
---|
85 | createServerSess=request.CreateServerSess) |
---|
86 | |
---|
87 | response.UserX509Cert, response.UserPriKey, response.issuingCert, \ |
---|
88 | response.SessID = result |
---|
89 | |
---|
90 | return response |
---|
91 | |
---|
92 | |
---|
93 | def soap_disconnect(self, ps): |
---|
94 | '''Disconnect and remove user's session |
---|
95 | |
---|
96 | @type ps: ZSI ParsedSoap |
---|
97 | @param ps: client SOAP message |
---|
98 | @rtype: tuple |
---|
99 | @return: request and response objects''' |
---|
100 | if self.__debug: |
---|
101 | import pdb |
---|
102 | pdb.set_trace() |
---|
103 | |
---|
104 | request = ps.Parse(disconnectInputMsg.typecode) |
---|
105 | response = _SessionManagerService.soap_disconnect(self, ps) |
---|
106 | |
---|
107 | # Derive designated user ID differently according to whether |
---|
108 | # a session ID was passed and the message was signed |
---|
109 | sessID = request.SessID or None |
---|
110 | |
---|
111 | # Derive designated holder X.509 cert differently according to whether |
---|
112 | # a signed message is expected from the client - NB, this is dependent |
---|
113 | # on whether a reference to the signature filter was set in the |
---|
114 | # environment |
---|
115 | signatureFilter = self.referencedWSGIFilters.get( |
---|
116 | self.wsseSignatureVerificationFilterID) |
---|
117 | if signatureFilter is not None: |
---|
118 | # Get certificate corresponding to private key that signed the |
---|
119 | # message - i.e. the user's certificate |
---|
120 | log.debug("Reading holder certificate from WS-Security " |
---|
121 | "signature header") |
---|
122 | userX509Cert = signatureFilter.signatureHandler.verifyingCert |
---|
123 | else: |
---|
124 | # No signature from client - they must instead provide the |
---|
125 | # designated holder cert via the UserX509Cert input |
---|
126 | log.debug('Reading holder certificate from SOAP "userX509Cert" ' |
---|
127 | 'parameter') |
---|
128 | userX509Cert = request.UserX509Cert |
---|
129 | |
---|
130 | self.sm.deleteUserSession(sessID=sessID, userX509Cert=userX509Cert) |
---|
131 | return response |
---|
132 | |
---|
133 | |
---|
134 | def soap_getSessionStatus(self, ps): |
---|
135 | '''Check for existence of a session with given session ID or user |
---|
136 | Distinguished Name |
---|
137 | |
---|
138 | @type ps: ZSI ParsedSoap |
---|
139 | @param ps: client SOAP message |
---|
140 | @rtype: tuple |
---|
141 | @return: request and response objects''' |
---|
142 | |
---|
143 | if self.__debug: |
---|
144 | import pdb |
---|
145 | pdb.set_trace() |
---|
146 | |
---|
147 | request = ps.Parse(getSessionStatusInputMsg.typecode) |
---|
148 | response = _SessionManagerService.soap_getSessionStatus(self, ps) |
---|
149 | |
---|
150 | response.IsAlive = self.sm.getSessionStatus(userDN=request.UserDN, |
---|
151 | sessID=request.SessID) |
---|
152 | |
---|
153 | return response |
---|
154 | |
---|
155 | |
---|
156 | def soap_getAttCert(self, ps): |
---|
157 | '''Get Attribute Certificate from a given Attribute Authority |
---|
158 | and cache it in user's Credential Wallet |
---|
159 | |
---|
160 | @type ps: ZSI ParsedSoap |
---|
161 | @param ps: client SOAP message |
---|
162 | @rtype: tuple |
---|
163 | @return: request and response objects''' |
---|
164 | if self.__debug: |
---|
165 | import pdb |
---|
166 | pdb.set_trace() |
---|
167 | |
---|
168 | request = ps.Parse(getAttCertInputMsg.typecode) |
---|
169 | response = _SessionManagerService.soap_getAttCert(self, ps) |
---|
170 | |
---|
171 | # Derive designated holder X.509 cert. differently according to whether |
---|
172 | # a signed message is expected from the client - NB, this is dependent |
---|
173 | # on whether a reference to the signature filter was set in the |
---|
174 | # environment |
---|
175 | signatureFilter = self.referencedWSGIFilters.get( |
---|
176 | self.wsseSignatureVerificationFilterID) |
---|
177 | if signatureFilter is not None: |
---|
178 | # Get certificate corresponding to private key that signed the |
---|
179 | # message - i.e. the user's proxy |
---|
180 | log.debug("Reading holder certificate from WS-Security " |
---|
181 | "signature header") |
---|
182 | userX509Cert = signatureFilter.signatureHandler.verifyingCert |
---|
183 | else: |
---|
184 | # No signature from client - they must instead provide the |
---|
185 | # designated holder cert via the UserX509Cert input |
---|
186 | log.debug('Reading holder certificate from SOAP "userX509Cert" ' |
---|
187 | 'parameter') |
---|
188 | userX509Cert = request.UserX509Cert |
---|
189 | |
---|
190 | # If no Attribute Authority URI is set pick up local Attribute |
---|
191 | # instance Authority |
---|
192 | if request.AttributeAuthorityURI is None: |
---|
193 | attributeAuthorityFilter = \ |
---|
194 | self.referencedWSGIFilters.get(self.attributeAuthorityFilterID) |
---|
195 | |
---|
196 | try: |
---|
197 | attributeAuthority= \ |
---|
198 | attributeAuthorityFilter.serviceSOAPBinding.aa |
---|
199 | except AttributeError, e: |
---|
200 | raise SessionManagerWSConfigError("No Attribute Authority URI " |
---|
201 | "was input and no Attribute Authority instance " |
---|
202 | "reference set in environ: %s" % e) |
---|
203 | else: |
---|
204 | attributeAuthority = None |
---|
205 | |
---|
206 | # X.509 Cert used in signature is preferred over userX509Cert input |
---|
207 | # element - userX509Cert may have been omitted. |
---|
208 | try: |
---|
209 | attCert = self.sm.getAttCert( |
---|
210 | userX509Cert=userX509Cert or request.UserX509Cert, |
---|
211 | sessID=request.SessID, |
---|
212 | attributeAuthorityURI=request.AttributeAuthorityURI, |
---|
213 | attributeAuthority=attributeAuthority, |
---|
214 | reqRole=request.ReqRole, |
---|
215 | mapFromTrustedHosts=request.MapFromTrustedHosts, |
---|
216 | rtnExtAttCertList=request.RtnExtAttCertList, |
---|
217 | extAttCertList=request.ExtAttCert, |
---|
218 | extTrustedHostList=request.ExtTrustedHost) |
---|
219 | response.AttCert = attCert.toString() |
---|
220 | |
---|
221 | except CredentialWalletAttributeRequestDenied, e: |
---|
222 | # Exception object contains a list of attribute certificates |
---|
223 | # which could be used to re-try to get authorisation via a mapped |
---|
224 | # certificate |
---|
225 | response.Msg = str(e) |
---|
226 | response.ExtAttCertOut = e.extAttCertList |
---|
227 | |
---|
228 | return response |
---|