3434import sys
3535import base64
3636
37+ from pprint import pformat
38+
3739from spyne .util .six .moves .http_cookies import SimpleCookie
3840
3941# bcrypt seems to be among the latest consensus around cryptograpic circles on
4648 print ('easy_install --user py-bcrypt to get it.' )
4749 raise
4850
49- from spyne .application import Application
50- from spyne .decorator import rpc
51- from spyne .error import ResourceNotFoundError
52- from spyne .model .complex import ComplexModel
53- from spyne .model .fault import Fault
54- from spyne .model .primitive import Mandatory
55- from spyne .model .primitive import String
51+ from spyne import Unicode , Application , rpc , Service
52+ from spyne import M , ComplexModel , Fault , String
53+ from spyne import ResourceNotFoundError
5654from spyne .protocol .soap import Soap11
5755from spyne .server .wsgi import WsgiApplication
58- from spyne . service import Service
56+
5957
6058class PublicKeyError (Fault ):
6159 __namespace__ = 'spyne.examples.authentication'
@@ -126,33 +124,48 @@ class Preferences(ComplexModel):
126124})
127125
128126
127+ class Encoding :
128+ SESSION_ID = 'ascii'
129+ USER_NAME = PASSWORD = CREDENTIALS = 'utf8'
130+
131+
129132class UserService (Service ):
130133 __tns__ = 'spyne.examples.authentication'
131134
132- @rpc (Mandatory .String , Mandatory .String , _returns = None ,
133- _throws = AuthenticationError )
135+ @rpc (M (Unicode ), M (Unicode ), _throws = AuthenticationError )
134136 def authenticate (ctx , user_name , password ):
137+ ENC_C = Encoding .CREDENTIALS
138+ ENC_SID = Encoding .SESSION_ID
139+
135140 password_hash = user_db .get (user_name , None )
136141
137142 if password_hash is None :
138143 raise AuthenticationError (user_name )
139144
140- if bcrypt .hashpw (password , password_hash ) != password_hash :
145+ password_b = password .encode (ENC_C )
146+ if bcrypt .hashpw (password_b , password_hash ) != password_hash :
141147 raise AuthenticationError (user_name )
142148
143- session_id = (user_name , '%x' % random .randint (1 << 128 , (1 << 132 )- 1 ))
144- session_db .add (session_id )
149+ session_id = '%x' % (random .randint (1 << 128 , (1 << 132 )- 1 ))
150+ session_key = (
151+ user_name .encode (ENC_C ),
152+ session_id .encode (ENC_SID ),
153+ )
154+ session_db .add (session_key )
145155
146156 cookie = SimpleCookie ()
147- cookie ["session-id" ] = base64 .urlsafe_b64encode (str (session_id [0 ]) + "\0 " + str (session_id [1 ]))
157+ cookie ["session-id" ] = \
158+ base64 .urlsafe_b64encode (b"\0 " .join (session_key )) \
159+ .decode ('ascii' ) # find out how to do urlsafe_b64encodestring
160+
148161 cookie ["session-id" ]["max-age" ] = 3600
149162 header_name , header_value = cookie .output ().split (":" , 1 )
150163 ctx .transport .resp_headers [header_name ] = header_value .strip ()
151- from pprint import pprint
152- pprint ( ctx .transport .resp_headers )
164+
165+ logging . debug ( "Response headers: %s" , pformat ( ctx .transport .resp_headers ) )
153166
154167
155- @rpc (Mandatory . String , _throws = PublicKeyError , _returns = Preferences )
168+ @rpc (M ( String ) , _throws = PublicKeyError , _returns = Preferences )
156169 def get_preferences (ctx , user_name ):
157170 # Only allow access to the users own preferences.
158171 if user_name != ctx .udc :
@@ -162,22 +175,32 @@ def get_preferences(ctx, user_name):
162175
163176 return retval
164177
178+
165179def _on_method_call (ctx ):
166180 if ctx .descriptor .name == "authenticate" :
167181 # No checking of session cookie for call to authenticate
168182 return
169183
184+ logging .debug ("Request headers: %s" , pformat (ctx .transport .req_env ))
185+
170186 cookie = SimpleCookie ()
171187 http_cookie = ctx .transport .req_env .get ("HTTP_COOKIE" )
172188 if http_cookie :
173189 cookie .load (http_cookie )
190+
174191 if "session-id" not in cookie :
175192 raise UnauthenticatedError ()
193+
176194 session_cookie = cookie ["session-id" ].value
177- session_id = tuple (base64 .urlsafe_b64decode (session_cookie ).split ("\0 " , 1 ))
195+
196+ user_name , session_id = base64 .urlsafe_b64decode (session_cookie ) \
197+ .split (b"\0 " , 1 )
198+
199+ session_id = tuple (base64 .urlsafe_b64decode (session_cookie ).split (b"\0 " , 1 ))
178200 if not session_id in session_db :
179201 raise AuthenticationError (session_id [0 ])
180- ctx .udc = session_id [0 ] # user name
202+
203+ ctx .udc = session_id [0 ].decode (Encoding .USER_NAME )
181204
182205
183206UserService .event_manager .add_listener ('method_call' , _on_method_call )
0 commit comments