~gary/python-openid/python-openid-2.2.1-patched

« back to all changes in this revision

Viewing changes to background-associations.txt

  • Committer: Launchpad Patch Queue Manager
  • Date: 2007-11-30 02:46:28 UTC
  • mfrom: (1.1.1 pyopenid-2.0)
  • Revision ID: launchpad@pqm.canonical.com-20071130024628-qktwsew3383iawmq
[rs=SteveA] upgrade to python-openid-2.0.1

Show diffs side-by-side

added added

removed removed

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