~ubuntuone-pqm-team/canonical-identity-provider/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
Copyright 2010 Canonical Ltd.  This software is licensed under the
GNU Affero General Public License version 3 (see the file LICENSE).

= Pre-authorized consumers =

In some cases we want consumers to be pre-authorized so that the
authorization step of the protocol is skipped.  This is the case for
canonical's training site: we want the canonical shop to pre-authorize
the training site when a user buys some sort of training.

To do so the shop has to craft a link which takes the user to the
training site through Launchpad.  This is what the link looks like:

    https://openid.launchpad.net/+pre-authorize-rp?trust_root=...&callback=...

Where the value of trust_root should be the root URL of the consumer to
be pre-authorized and callback is the URL to which the user will be
redirected after the consumer is pre-authorized.

As an example we'll pre-authorize our own OpenID consumer:

    # First, some setup to ensure old data doesn't mess with the results
    >>> from identityprovider.models import OpenIDRPConfig, OpenIDAuthorization
    >>> OpenIDRPConfig.objects.all().delete()
    >>> OpenIDAuthorization.objects.all().delete()

    >>> from urllib import urlencode
    >>> args = urlencode({
    ...     'trust_root': 'http://launchpad.dev/',
    ...     'callback': 'http://openid.launchpad.dev/+edit'})
    >>> browser.handleErrors = True
    >>> browser.addHeader('REFERER', 'http://launchpad.dev/')
    >>> browser.open('http://openid.launchpad.dev/+pre-authorize-rp?%s' % args)

    # Since the user is not logged in, he'll have to login first.
    >>> browser.url
    'http://openid.launchpad.dev/+login...'
    >>> browser.getControl(name='email', index=0).value = 'mark@example.com'
    >>> browser.getControl(name='password').value = 'test'
    >>> browser.handleErrors = False
    >>> browser.getControl(name='continue').click()

    # Now he's redirected to the callback page and the RP has been
    # pre-authorized.
    >>> browser.url
    'http://openid.launchpad.dev/+edit'

From now on, and until that authorization expires, the user won't need
to authorize that consumer when he wants to log into it.

#    >>> from zope.interface import implements
#    >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
#    >>> from canonical.signon.layers import OpenIDLayer
#
#    >>> class OpenIDTestRequest(LaunchpadTestRequest):
#    ...     implements(OpenIDLayer)

#    >>> old_request = OpenIDTestRequest(
#    ...     SERVER_URL='http://openid.launchpad.dev',
#    ...     PATH_INFO='/+id/name16_oid')
#    >>> login('foo.bar@canonical.com', old_request)

    # First we will set up the helper view that lets us test the OpenID
    # protocol.
    >>> from openid.consumer.discover import OPENID_2_0_TYPE
    >>> from openid.consumer.consumer import Consumer
    >>> from openid.fetchers import setDefaultFetcher
    >>> from openid.store.memstore import MemoryStore
    >>> from canonical.signon.testing.openidhelpers import (
    ...     make_identifier_select_endpoint, PublisherFetcher)
    >>> setDefaultFetcher(PublisherFetcher())

    # The authentication process is started by the relying party issuing a
    # checkid_setup request, sending the user to Launchpad.
    >>> openid_store = MemoryStore()
    >>> consumer = Consumer(session={}, store=openid_store)
    >>> request = consumer.beginWithoutDiscovery(
    ...     make_identifier_select_endpoint(OPENID_2_0_TYPE))
    >>> browser.open(request.redirectURL(
    ...     'http://launchpad.dev/', 'http://launchpad.dev/+openid-consumer'))

The user (mark) was already logged into Launchpad, so at this point,
instead of being presented with a form asking if they want to
authenticate to the relying party, they are sent directly to the RP.

    >>> print browser.url
    http://launchpad.dev/+openid-consumer?...

If the HTTP referrer and the trust_root are not in our config's
openid_preauthorization_acl, we will not pre-authorize.

    >>> browser.open('http://openid.launchpad.dev/+logout')
    >>> browser.open('http://openid.launchpad.dev/+login')
    >>> browser.getControl(name='email', index=0).value = 'test@canonical.com'
    >>> browser.getControl(name='password').value = 'test'
    >>> browser.getControl(name='continue').click()

    >>> args = urlencode({
    ...     'trust_root': 'http://blueprints.launchpad.dev/',
    ...     'callback': 'http://openid.launchpad.dev/+edit'})
    >>> browser.open('http://openid.launchpad.dev/+pre-authorize-rp?%s' % args)
    Traceback (most recent call last):
    ...
    HTTPError: HTTP Error 400: BAD REQUEST

    >>> browser.open(request.redirectURL(
    ...     'http://blueprints.launchpad.dev/', 'http://blueprints.launchpad.dev/+openid-consumer'))
    >>> print browser.title
    Authenticate to http://blueprints.launchpad.dev/

    >>> browser.open('http://openid.launchpad.dev/+logout')
    >>> browser.open('http://openid.launchpad.dev/+login')
    >>> browser.getControl(name='email', index=0).value = 'test@canonical.com'
    >>> browser.getControl(name='password').value = 'test'
    >>> browser.getControl(name='continue').click()

    >>> args = urlencode({
    ...     'trust_root': 'http://example.com/',
    ...     'callback': 'http://launchpad.dev/people/+me'})
    >>> browser.open(
    ...     'http://openid.launchpad.dev/+pre-authorize-rp?%s' % args)
    Traceback (most recent call last):
    ...
    HTTPError: HTTP Error 400: BAD REQUEST

    >>> browser.open(request.redirectURL(
    ...     'http://example.com/', 'http://example.com/+openid-consumer'))
    >>> print browser.title
    Authenticate to http://example.com/

    >>> args = urlencode({
    ...     'trust_root': 'http://example.com/'})
    >>> browser.open(
    ...     'http://openid.launchpad.dev/+pre-authorize-rp?%s' % args)
    Traceback (most recent call last):
    ...
    HTTPError: HTTP Error 400: BAD REQUEST

    >>> browser.open(request.redirectURL(
    ...     'http://example.com/', 'http://example.com/+openid-consumer'))
    >>> print browser.title
    Authenticate to http://example.com/