Changeset 136
- Timestamp:
- 11/06/07 00:37:54
- Files:
-
- AuthKit/trunk/authkit/authenticate/open_id.py (modified) (20 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
AuthKit/trunk/authkit/authenticate/open_id.py
r114 r136 18 18 This middleware actually sets two cookies, one for AuthKit and one for a session 19 19 store to store the ID which OpenID information is keyed against. 20 21 The OpenID sreg variables you can use include: 22 23 ``nickname`` 24 Any UTF-8 string that the End User wants to use as a nickname. 25 26 ``email`` 27 The email address of the End User as specified in section 3.4.1 of 28 [RFC2822] (Resnick, P., "Internet Message Format," .). 29 30 ``fullname`` 31 UTF-8 string free text representation of the End User's full name. 32 33 ``dob`` 34 The End User's date of birth as YYYY-MM-DD. Any values whose representation 35 uses fewer than the specified number of digits should be zero-padded. The 36 length of this value MUST always be 10. If the End User user does not want 37 to reveal any particular component of this value, it MUST be set to zero. 38 For instance, if a End User wants to specify that his date of birth is in 39 1980, but not the month or day, the value returned SHALL be "1980-00-00". 40 41 ``gender`` 42 The End User's gender, "M" for male, "F" for female. 43 44 ``postcode`` 45 UTF-8 string free text that SHOULD conform to the End User's country's 46 postal system. 47 48 ``country`` 49 The End User's country of residence as specified by ISO3166. 50 51 ``language`` 52 End User's preferred language as specified by ISO639. 53 54 ``timezone`` 55 ASCII string from TimeZone database 56 For example, "Europe/Paris" or "America/Los_Angeles". 20 57 """ 21 58 … … 27 64 from paste.request import construct_url 28 65 from openid.consumer import consumer 29 from openid.oidutil import appendArgs 30 from yadis.discover import DiscoveryFailure 31 from urljr.fetchers import HTTPFetchingError 66 from openid import sreg 67 from openid.cryptutil import randomString 32 68 from authkit.authenticate import get_template, valid_password, \ 33 69 get_authenticate_function, strip_base, RequireEnvironKey, \ 34 70 AuthKitUserSetter, AuthKitAuthHandler 35 71 from authkit.authenticate.multi import MultiHandler, status_checker 36 from beaker.middleware import SessionMiddleware37 72 38 73 def template(): … … 116 151 from openid.store.sqlstore import MySQLStore 117 152 from sqlalchemy.engine.url import make_url 118 153 119 154 def create_conn(dburi): 120 155 url = make_url(dburi) … … 134 169 raise Exception("Invalid store type %r"%store) 135 170 return conn, cstore 136 171 137 172 class AuthOpenIDHandler: 138 173 """ … … 148 183 path_signedin, 149 184 template=None, 150 session_secret=None,151 session_key='authkit_openid',152 185 session_middleware='beaker.session', 153 186 path_verify='/verify', … … 166 199 self.path_process = path_process 167 200 self.session_middleware = session_middleware 168 self.session_key = session_key169 self.session_secret = session_secret170 201 self.app = app 171 202 self.urltouser = urltouser … … 218 249 [ 219 250 ('Content-type', 'text/html'+self.charset), 220 ('Content-length', len(response))251 ('Content-length', str(len(response))) 221 252 ] 222 253 ) … … 225 256 try: 226 257 request_ = oidconsumer.begin(openid_url) 227 except HTTPFetchingError, exc: 228 response = render( 229 self.template, 230 message='Error retrieving identity URL: %s' % ( 231 cgi.escape(str(exc.why)) 232 ), 233 value=self._quoteattr(openid_url), 234 css_class='error', 235 action=baseurl + self.path_verify 236 ) 237 start_response( 238 '200 OK', 239 [ 240 ('Content-type', 'text/html'+self.charset), 241 ('Content-length', len(response)) 242 ] 243 ) 244 return response 245 except DiscoveryFailure, exc: 258 except consumer.DiscoveryFailure, exc: 246 259 response = render( 247 260 self.template, … … 257 270 [ 258 271 ('Content-type', 'text/html'+self.charset), 259 ('Content-length', len(response))272 ('Content-length', str(len(response))) 260 273 ] 261 274 ) … … 276 289 [ 277 290 ('Content-type', 'text/html'+self.charset), 278 ('Content-length', len(response))291 ('Content-length', str(len(response))) 279 292 ] 280 293 ) 281 294 return response 282 295 else: 296 session = environ[self.session_middleware] 297 if 'HTTP_REFERER' in environ and \ 298 not environ['HTTP_REFERER'].endswith(self.path_verify) and \ 299 not environ['HTTP_REFERER'].endswith(self.path_process): 300 session['referer'] = environ['HTTP_REFERER'] 301 302 if self.sreg_required or self.sreg_optional or self.sreg_policyurl: 303 required_list = [] 304 if self.sreg_required: 305 required_list = [opt.strip() for opt in self.sreg_required.split(',')] 306 optional_list = [] 307 if self.sreg_optional: 308 optional_list = [opt.strip() for opt in self.sreg_optional.split(',')] 309 sreg_request = sreg.SRegRequest( 310 required=required_list, 311 optional=optional_list, 312 policy_url=self.sreg_policyurl) 313 request_.addExtension(sreg_request) 314 283 315 trust_root = baseurl 284 316 return_to = baseurl + self.path_process 285 if self.sreg_required: 286 request_.addExtensionArg('sreg', 'required', self.sreg_required) 287 if self.sreg_optional: 288 request_.addExtensionArg('sreg', 'optional', self.sreg_optional) 289 if self.sreg_policyurl: 290 request_.addExtensionArg('sreg', 'policy_url', self.sreg_policyurl) 291 292 redirect_url = request_.redirectURL(trust_root, return_to) 293 start_response( 294 '301 Redirect', 295 [ 296 ('Content-type', 'text/html'+self.charset), 297 ('Location', redirect_url) 298 ] 299 ) 300 return [] 317 318 if request_.shouldSendRedirect(): 319 redirect_url = request_.redirectURL( 320 trust_root, return_to) 321 322 start_response( 323 '301 Redirect', 324 [ 325 ('Content-type', 'text/html'+self.charset), 326 ('Location', redirect_url) 327 ] 328 ) 329 return [] 330 else: 331 # This gets called with sites such as myopenid.com 332 form_html = request_.formMarkup( 333 trust_root, return_to, 334 form_tag_attrs={'id':'openid_message'}) 335 content = """\ 336 <html><head><title>OpenID transaction in progress</title></head> 337 <body onload='document.getElementById("%s").submit()'> 338 %s 339 </body></html> 340 """%('openid_message', form_html) 341 start_response( 342 "200 OK", 343 [ 344 ('Content-Type', 'text/html'+self.charset), 345 ('Content-Length', str(len(content))) 346 ] 347 ) 348 return [content] 301 349 302 350 def process(self, environ, start_response): … … 309 357 css_class = 'error' 310 358 message = '' 359 311 360 params = dict(paste.request.parse_querystring(environ)) 312 361 oidconsumer = self._get_consumer(environ) 313 362 info = oidconsumer.complete(dict(params)) 314 css_class = 'error' 363 315 364 if info.status == consumer.FAILURE and info.identity_url: 316 365 fmt = "Verification of %s failed." … … 321 370 elif info.status == consumer.SUCCESS: 322 371 username = info.identity_url 323 user_data = str(info.extensionResponse( 'sreg' )) 372 if info.endpoint.canonicalID: 373 username = cgi.escape(info.endpoint.canonicalID) 374 user_data = str(sreg.SRegResponse.fromSuccessResponse(info).getExtensionArgs()) 324 375 # Set the cookie 325 376 if self.urltouser: … … 327 378 environ['paste.auth_tkt.set_user'](username, user_data=user_data) 328 379 # Return a page that does a meta refresh 380 session = environ[self.session_middleware] 381 if 'referer' in session: 382 redirect_url = session.pop('referer') 383 else: 384 redirect_url = self.baseurl + self.path_signedin 385 329 386 response = """ 330 387 <HTML> … … 337 394 </BODY> 338 395 </HTML> 339 """ % ( self.baseurl + self.path_signedin)396 """ % (redirect_url) 340 397 start_response( 341 398 '200 OK', 342 399 [ 343 400 ('Content-type', 'text/html'+self.charset), 344 ('Content-length', len(response))401 ('Content-length', str(len(response))) 345 402 ] 346 403 ) … … 348 405 elif info.status == consumer.CANCEL: 349 406 message = 'Verification cancelled' 407 elif info.status == consumer.SETUP_NEEDED: 408 if info.setup_url: 409 message = '<a href=%s>Setup needed</a>' % ( 410 self._quoteattr(info.setup_url),) 411 else: 412 message = 'Setup needed' 350 413 else: 351 414 environ['wsgi.errors'].write("Passurl Message: %s"%info.message) … … 363 426 [ 364 427 ('Content-type', 'text/html'+self.charset), 365 ('Content-length', len(response))428 ('Content-length', str(len(response))) 366 429 ] 367 430 ) … … 375 438 session = environ[self.session_middleware] 376 439 session['id'] = session.id 377 idconsumer = consumer.Consumer(session, self.store) 440 oidconsumer = consumer.Consumer(session, self.store) 441 oidconsumer.consumer.openid1_nonce_query_arg_name = 'passurl_nonce' 378 442 session.save() 379 return idconsumer443 return oidconsumer 380 444 381 445 def _quoteattr(self, s): … … 384 448 qs = cgi.escape(s, 1) 385 449 return '"%s"' % (qs,) 386 387 450 388 451 class OpenIDUserSetter(AuthKitUserSetter): … … 402 465 sreg_policyurl=options['sreg_policyurl'], 403 466 ) 404 405 if options['session_middleware'] == 'beaker.session':406 app = SessionMiddleware(407 app,408 key=options['session_key'],409 secret=options['session_secret']410 )411 467 self.app = app 412 468 413 469 def __call__(self, environ, start_response): 414 470 return self.app(environ, start_response) 415 416 471 417 472 def load_openid_config( … … 447 502 'sreg_optional': auth_conf.get('sreg.optional'), 448 503 'sreg_policyurl': auth_conf.get('sreg.policyurl'), 449 # XXX This need to actually be configurable, not hard coded450 'session_secret': 'asdasd',451 'session_key': 'authkit_openid',452 504 'session_middleware': 'beaker.session', 453 505 } 454 if user_setter_params['session_middleware'] == 'beaker.session':455 if not user_setter_params['session_secret']:456 raise AuthKitConfigError('No session_secret set')457 506 auth_handler_params={ 458 507 'template':user_setter_params['template'],
