background-associations.txt 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. Background association requests
  2. ###############################
  3. This document describes how to make signing in with OpenID faster for
  4. users of your application by never making the users wait for an
  5. association to be made, but using associations when they're
  6. available. Most OpenID libraries and applications attempt to make
  7. associations during the discovery phase of the OpenID authentication
  8. request. Because association requests may have to do Diffie-Hellman
  9. key exchange, which is time consuming. Even if Diffie-Hellman key
  10. exchange is not used, the user still needs to wait for the association
  11. request.
  12. Setting up your application to make associations in the background
  13. ==================================================================
  14. When making associations background, there are two components that
  15. need access to the OpenID association store: the consumer application
  16. and the background association fetcher. The consumer needs to be set
  17. up to record the server URL for any request for which an association
  18. does not exist or is expired instead of making a new association. The
  19. background fetcher looks at the server URL queue and makes
  20. associations for any server URLs that need them. After the
  21. associations are made, the consumer will use them until they expire
  22. again. While associations are expired or missing, the consumer will
  23. use stateless mode to complete authentications with the servers that
  24. need associations.
  25. The OpenID server endpoint URL queue
  26. -----------------------------------------------------------------
  27. You will have to set up a conduit between the consumer and the
  28. background association fetcher so that the background association
  29. fetcher knows what servers need associations. The background
  30. association fetcher will not fetch associations for servers that
  31. already have them, so the queue does not have to be very smart. It
  32. could be as simple as a file to which the server URLs are
  33. appended. Either way, the queue needs to be write-able by the consumer
  34. and readable by the background fetcher.
  35. Configuring the consumer
  36. -----------------------------------------------------------------
  37. Create a subclass of ``GenericConsumer`` that overrides
  38. ``_negotiateAssociation`` so that it just records the server URL that
  39. needs an association::
  40. from openid.consumer.consumer import GenericConsumer, Consumer
  41. class LazyAssociationConsumer(GenericConsumer):
  42. needs_assoc_file = None
  43. def _negotiateAssociation(self, endpoint):
  44. # Do whatever you need to do here to send the server_url to
  45. # the queue. This example just appends it to a file.
  46. self.needs_assoc_file.write(endpoint.server_url + '\n')
  47. self.needs_assoc_file.flush()
  48. You could also store the whole endpoint object. When you instantiate
  49. the consumer, pass this generic consumer class to the controlling
  50. consumer::
  51. return Consumer(session, store, consumer_class=LazyAssociationConsumer)
  52. The background association fetcher
  53. -----------------------------------------------------------------
  54. The background association fetcher is just a script that should be
  55. added to ``cron`` or triggered periodically. If you are ambitious, you
  56. could make the background fetcher listen for inserts into the queue.
  57. The background fetcher needs to do something similar to the following::
  58. def refresh(consumer, endpoint):
  59. if consumer.store.getAssociation(endpoint.server_url):
  60. logging.info("We don't need to associate with %r", endpoint.server_url)
  61. return
  62. logging.info("Associating with %r", endpoint.server_url)
  63. now = time.time()
  64. assoc = consumer._negotiateAssociation(endpoint)
  65. if assoc:
  66. elapsed = time.time() - now
  67. logging.info('(%0.2f seconds) Associated with %r', elapsed,
  68. endpoint.server_url)
  69. consumer.store.storeAssociation(endpoint.server_url, assoc)
  70. else:
  71. logging.error('Failed to make an association with %r',
  72. endpoint.server_url)
  73. The code in this example logs the amount of time that the association
  74. request took. This is time that the user would have been waiting. The
  75. ``consumer`` in this example is a standard consumer, not the
  76. ``LazyAssociationConsumer`` that was defined in the section
  77. above. This is important, because the lazy consumer above will not
  78. actually make any associations.