Merge lp:~salgado/launchpad/remove-lp-services-openid into lp:launchpad

Proposed by Guilherme Salgado
Status: Merged
Approved by: Aaron Bentley
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~salgado/launchpad/remove-lp-services-openid
Merge into: lp:launchpad
Prerequisite: lp:~salgado/launchpad/remove-auth-store
Diff against target: 943 lines (+0/-861)
11 files modified
lib/canonical/launchpad/browser/launchpad.py (+0/-2)
lib/lp/services/openid/browser/configure.zcml (+0/-60)
lib/lp/services/openid/browser/openidrpconfig.py (+0/-124)
lib/lp/services/openid/configure.zcml (+0/-18)
lib/lp/services/openid/doc/openid-rp-config.txt (+0/-171)
lib/lp/services/openid/interfaces/openidrpconfig.py (+0/-120)
lib/lp/services/openid/model/openidrpconfig.py (+0/-111)
lib/lp/services/openid/stories/rpconfig-admin.txt (+0/-190)
lib/lp/services/openid/templates/openidrpconfig-add.pt (+0/-16)
lib/lp/services/openid/templates/openidrpconfig-edit.pt (+0/-16)
lib/lp/services/openid/templates/openidrpconfigset-index.pt (+0/-33)
To merge this branch: bzr merge lp:~salgado/launchpad/remove-lp-services-openid
Reviewer Review Type Date Requested Status
Aaron Bentley (community) Approve
Review via email: mp+22807@code.launchpad.net

Description of the change

Remove the unused bits from lp/services/openid. These were once used by canonical-identity-provider, which will be removed shortly.

To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/browser/launchpad.py'
--- lib/canonical/launchpad/browser/launchpad.py 2010-03-04 20:19:39 +0000
+++ lib/canonical/launchpad/browser/launchpad.py 2010-04-05 15:45:44 +0000
@@ -100,7 +100,6 @@
100from lp.registry.interfaces.mentoringoffer import IMentoringOfferSet100from lp.registry.interfaces.mentoringoffer import IMentoringOfferSet
101from lp.registry.interfaces.person import IPersonSet101from lp.registry.interfaces.person import IPersonSet
102from lp.registry.interfaces.pillar import IPillarNameSet102from lp.registry.interfaces.pillar import IPillarNameSet
103from lp.services.openid.interfaces.openidrpconfig import IOpenIDRPConfigSet
104from lp.services.worlddata.interfaces.language import ILanguageSet103from lp.services.worlddata.interfaces.language import ILanguageSet
105from lp.soyuz.interfaces.packageset import IPackagesetSet104from lp.soyuz.interfaces.packageset import IPackagesetSet
106from lp.registry.interfaces.product import (105from lp.registry.interfaces.product import (
@@ -578,7 +577,6 @@
578 'translations': IRosettaApplication,577 'translations': IRosettaApplication,
579 'testopenid': ITestOpenIDApplication,578 'testopenid': ITestOpenIDApplication,
580 'questions': IQuestionSet,579 'questions': IQuestionSet,
581 '+rpconfig': IOpenIDRPConfigSet,
582 'temporary-blobs': ITemporaryStorageManager,580 'temporary-blobs': ITemporaryStorageManager,
583 # These three have been renamed, and no redirects done, as the old581 # These three have been renamed, and no redirects done, as the old
584 # urls now point to the product pages.582 # urls now point to the product pages.
585583
=== removed file 'lib/lp/services/openid/browser/configure.zcml'
--- lib/lp/services/openid/browser/configure.zcml 2009-11-23 03:10:04 +0000
+++ lib/lp/services/openid/browser/configure.zcml 1970-01-01 00:00:00 +0000
@@ -1,60 +0,0 @@
1<!-- Copyright 2009 Canonical Ltd. This software is licensed under the
2 GNU Affero General Public License version 3 (see the file LICENSE).
3-->
4
5<configure xmlns="http://namespaces.zope.org/zope"
6 xmlns:browser="http://namespaces.zope.org/browser">
7
8 <browser:url
9 for="..interfaces.openidrpconfig.IOpenIDRPConfig"
10 path_expression="string:${id}"
11 parent_utility="..interfaces.openidrpconfig.IOpenIDRPConfigSet"
12 />
13
14 <browser:page
15 for="..interfaces.openidrpconfig.IOpenIDRPConfig"
16 name="+edit"
17 class=".openidrpconfig.OpenIDRPConfigEditView"
18 permission="launchpad.Admin"
19 template="../templates/openidrpconfig-edit.pt"
20 />
21
22 <browser:defaultView
23 for="..interfaces.openidrpconfig.IOpenIDRPConfig"
24 name="+edit"
25 />
26
27 <!-- IOpenIDRPConfigSet -->
28
29 <browser:url
30 for="..interfaces.openidrpconfig.IOpenIDRPConfigSet"
31 path_expression="string:+rpconfig"
32 parent_utility="canonical.launchpad.interfaces.ILaunchpadRoot"
33 />
34
35 <browser:navigation
36 module=".openidrpconfig"
37 classes="OpenIDRPConfigSetNavigation"
38 />
39
40 <browser:page
41 for="..interfaces.openidrpconfig.IOpenIDRPConfigSet"
42 name="+add"
43 class=".openidrpconfig.OpenIDRPConfigAddView"
44 permission="launchpad.Admin"
45 template="../templates/openidrpconfig-add.pt"
46 />
47
48 <browser:page
49 for="..interfaces.openidrpconfig.IOpenIDRPConfigSet"
50 name="+index"
51 class=".openidrpconfig.OpenIDRPConfigSetView"
52 permission="launchpad.Admin"
53 template="../templates/openidrpconfigset-index.pt"
54 />
55
56 <browser:defaultView
57 for="..interfaces.openidrpconfig.IOpenIDRPConfigSet"
58 name="+index"
59 />
60</configure>
610
=== removed file 'lib/lp/services/openid/browser/openidrpconfig.py'
--- lib/lp/services/openid/browser/openidrpconfig.py 2009-11-23 16:14:39 +0000
+++ lib/lp/services/openid/browser/openidrpconfig.py 1970-01-01 00:00:00 +0000
@@ -1,124 +0,0 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""View classes used to edit `IOpenIDRPConfig` objects.
5
6OpenID Relying Party configurations are used to customise the
7appearance and behaviour of the login page when authenticating to a
8particular RP.
9"""
10
11__metaclass__ = type
12__all__ = []
13
14from zope.component import getUtility
15
16from canonical.launchpad import _
17from lp.services.openid.interfaces.openidrpconfig import (
18 IOpenIDRPConfig, IOpenIDRPConfigSet)
19from canonical.launchpad.webapp import (
20 LaunchpadEditFormView, LaunchpadFormView, Navigation, action,
21 canonical_url, custom_widget)
22from canonical.launchpad.webapp.publisher import LaunchpadView
23from canonical.widgets import LabeledMultiCheckBoxWidget
24from canonical.widgets.image import ImageChangeWidget
25from lp.registry.interfaces.person import PersonCreationRationale
26
27
28class OpenIDRPConfigSetNavigation(Navigation):
29 """Navigation for `IOpenIDRPConfigSet`."""
30 usedfor = IOpenIDRPConfigSet
31
32 def traverse(self, config_id):
33 """Traverse to RP configs by ID."""
34 try:
35 config_id = int(config_id)
36 except ValueError:
37 return None
38
39 return getUtility(IOpenIDRPConfigSet).get(config_id)
40
41
42class OpenIDRPConfigSetView(LaunchpadView):
43 page_title = 'OpenID Relying Party Configurations'
44 label = page_title
45
46
47class OpenIDRPConfigAddView(LaunchpadFormView):
48 """View class for adding new RP configurations."""
49
50 schema = IOpenIDRPConfig
51 field_names = ['trust_root', 'displayname', 'description', 'logo',
52 'allowed_sreg', 'creation_rationale', 'can_query_any_team',
53 'auto_authorize']
54 custom_widget('logo', ImageChangeWidget, ImageChangeWidget.ADD_STYLE)
55 custom_widget('allowed_sreg', LabeledMultiCheckBoxWidget)
56 label = 'Add an OpenID Relying Party Configuration'
57 page_title = label
58
59 initial_values = {
60 'creation_rationale':
61 PersonCreationRationale.OWNER_CREATED_UNKNOWN_TRUSTROOT,
62 }
63
64 @action(_('Create'), name='create')
65 def create_action(self, action, data):
66 """Create the new RP configuration."""
67 rpconfig = getUtility(IOpenIDRPConfigSet).new(
68 trust_root=data['trust_root'],
69 displayname=data['displayname'],
70 description=data['description'],
71 logo=data['logo'],
72 allowed_sreg=data['allowed_sreg'],
73 creation_rationale=data['creation_rationale'],
74 can_query_any_team=data['can_query_any_team'],
75 auto_authorize=data['auto_authorize'])
76 self.request.response.addInfoNotification(
77 _('Created RP configuration for ${trust_root}.',
78 mapping=dict(trust_root=data['trust_root'])))
79
80 @property
81 def next_url(self):
82 return canonical_url(getUtility(IOpenIDRPConfigSet))
83
84 cancel_url = next_url
85
86
87class OpenIDRPConfigEditView(LaunchpadEditFormView):
88 """View class for editing or removing RP configurations."""
89
90 @property
91 def label(self):
92 return 'Edit Relying Party Configuration for %s' % (
93 self.context.displayname)
94 page_title = label
95
96 schema = IOpenIDRPConfig
97 field_names = ['trust_root', 'displayname', 'description', 'logo',
98 'allowed_sreg', 'creation_rationale', 'can_query_any_team',
99 'auto_authorize']
100 custom_widget('logo', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE)
101 custom_widget('allowed_sreg', LabeledMultiCheckBoxWidget)
102
103 @action(_('Save'), name='save')
104 def save_action(self, action, data):
105 """Save the RP configuration."""
106 if self.updateContextFromData(data):
107 self.request.response.addInfoNotification(
108 _('Updated RP configuration for ${trust_root}.',
109 mapping=dict(trust_root=self.context.trust_root)))
110
111 @action(_('Remove'), name='remove')
112 def remove_action(self, action, data):
113 """Remove the RP configuration."""
114 trust_root = self.context.trust_root
115 self.context.destroySelf()
116 self.request.response.addInfoNotification(
117 _('Removed RP configuration for ${trust_root}.',
118 mapping=dict(trust_root=trust_root)))
119
120 @property
121 def next_url(self):
122 return canonical_url(getUtility(IOpenIDRPConfigSet))
123
124 cancel_url = next_url
1250
=== modified file 'lib/lp/services/openid/configure.zcml'
--- lib/lp/services/openid/configure.zcml 2009-07-18 00:05:49 +0000
+++ lib/lp/services/openid/configure.zcml 2010-04-05 15:45:44 +0000
@@ -9,23 +9,6 @@
9 i18n_domain="launchpad">9 i18n_domain="launchpad">
1010
11 <class11 <class
12 class=".model.openidrpconfig.OpenIDRPConfig">
13 <allow interface=".interfaces.openidrpconfig.IOpenIDRPConfig" />
14 <require
15 permission="launchpad.Admin"
16 attributes="destroySelf"
17 set_schema=".interfaces.openidrpconfig.IOpenIDRPConfig" />
18 </class>
19
20 <securedutility
21 class=".model.openidrpconfig.OpenIDRPConfigSet"
22 provides=".interfaces.openidrpconfig.IOpenIDRPConfigSet">
23 <allow
24 interface=".interfaces.openidrpconfig.IOpenIDRPConfigSet"
25 />
26 </securedutility>
27
28 <class
29 class=".model.openidrpsummary.OpenIDRPSummary">12 class=".model.openidrpsummary.OpenIDRPSummary">
30 <allow interface=".interfaces.openidrpsummary.IOpenIDRPSummary" />13 <allow interface=".interfaces.openidrpsummary.IOpenIDRPSummary" />
31 </class>14 </class>
@@ -44,5 +27,4 @@
44 <adapter factory=".adapters.openid.OpenIDPersistentIdentity" />27 <adapter factory=".adapters.openid.OpenIDPersistentIdentity" />
45 <adapter factory=".adapters.openid.person_to_openidpersistentidentity" />28 <adapter factory=".adapters.openid.person_to_openidpersistentidentity" />
4629
47 <include package=".browser" />
48</configure>30</configure>
4931
=== removed directory 'lib/lp/services/openid/doc'
=== removed file 'lib/lp/services/openid/doc/__init__.py'
=== removed file 'lib/lp/services/openid/doc/openid-rp-config.txt'
--- lib/lp/services/openid/doc/openid-rp-config.txt 2010-02-11 20:33:07 +0000
+++ lib/lp/services/openid/doc/openid-rp-config.txt 1970-01-01 00:00:00 +0000
@@ -1,171 +0,0 @@
1===================================
2OpenID Relying Party Configurations
3===================================
4
5Launchpad can store information about OpenID relying parties in order
6to provide a better user experience when using Launchpad to log in.
7This includes:
8
9 * Providing a human readable name for the relying party, so we don't
10 have to display the raw URL to the user.
11
12 * Providing a logo image to display on the log in page.
13
14 * Specify what fields may be disclosed to the RP via OpenID Simple
15 Registration protocol.
16
17 * What person creation rationale should be used for accounts created
18 while signing in to the RP.
19
20
21Creating OpenIDRPConfigs
22========================
23
24Configurations are created using the IOpenIDRPConfigSet utility:
25
26 >>> from zope.component import getUtility
27 >>> from lp.services.openid.interfaces.openidrpconfig import (
28 ... IOpenIDRPConfigSet)
29 >>> login(ANONYMOUS)
30 >>> rpconfig = getUtility(IOpenIDRPConfigSet).new(
31 ... trust_root='http://*.example.com/',
32 ... displayname='Example RP',
33 ... description='Example RP description',
34 ... allowed_sreg=['fullname', 'nickname'])
35
36The resulting object implements the IOpenIDRPConfig interface:
37
38 >>> from canonical.launchpad.webapp.testing import verifyObject
39 >>> from lp.services.openid.interfaces.openidrpconfig import (
40 ... IOpenIDRPConfig)
41
42 >>> verifyObject(IOpenIDRPConfig, rpconfig)
43 True
44
45The utility itself implements IOpenIDRPConfigSet:
46
47 >>> verifyObject(IOpenIDRPConfigSet, getUtility(IOpenIDRPConfigSet))
48 True
49
50Some RPs include a trailing '/' on their URLs, which is the standard,
51while others do not. The `trust_root` is always normalized to have a
52trailing slash.
53
54 >>> rpconfig2 = getUtility(IOpenIDRPConfigSet).new(
55 ... trust_root='http://foo.example.com',
56 ... displayname='Example RP',
57 ... description='Example RP description',
58 ... allowed_sreg=['fullname', 'nickname'])
59 >>> print rpconfig2.trust_root
60 http://foo.example.com/
61
62
63Modifying OpenIDRPConfig objects
64================================
65
66OpenIDRPConfig objects may only be modified by an administrator:
67
68 >>> rpconfig.displayname = 'New title'
69 Traceback (most recent call last):
70 ...
71 Unauthorized: (<OpenIDRPConfig at ...>, 'displayname', 'launchpad.Admin')
72 >>> login('foo.bar@canonical.com')
73 >>> rpconfig.displayname = 'New title'
74 >>> print rpconfig.displayname
75 New title
76
77The allowed simple registration fields attribute sorts the field names
78to normalise the result:
79
80 >>> rpconfig.allowed_sreg = ['fullname', 'email']
81 >>> print rpconfig.allowed_sreg
82 [u'email', u'fullname']
83
84The auto_authorize attribute specifies whether this RP is allowed to
85skip the authorization page. This behaviour is not turned on by
86default:
87
88 >>> rpconfig.auto_authorize
89 False
90 >>> rpconfig.auto_authorize = True
91 >>> rpconfig.auto_authorize
92 True
93
94
95Searching for OpenIDRPConfig objects
96====================================
97
98An RP config can be looked up by its ID using the get() method of the
99IOpenIDRPConfigSet:
100
101 >>> rpconfig2 = getUtility(IOpenIDRPConfigSet).get(rpconfig.id)
102 >>> print rpconfig2.trust_root
103 http://*.example.com/
104 >>> rpconfig2.id == rpconfig.id
105 True
106
107The get() method will return None for an unknown ID:
108
109 >>> print getUtility(IOpenIDRPConfigSet).get(-42)
110 None
111
112It is also possible to look up RP configs by their trust root:
113
114 >>> rpconfig3 = getUtility(IOpenIDRPConfigSet).getByTrustRoot(
115 ... 'http://*.example.com/')
116 >>> print rpconfig3.trust_root
117 http://*.example.com/
118 >>> rpconfig3.id == rpconfig.id
119 True
120
121The getByTrustRoot() method will return None for an unknown trust
122root:
123
124 >>> print getUtility(IOpenIDRPConfigSet).getByTrustRoot('http://unknown')
125 None
126
127Most RPs include the trailing '/' in their trust root URL but some do
128not. The search should match whether the trailing slash is there or
129not.
130
131 >>> rpconfig3 = getUtility(IOpenIDRPConfigSet).getByTrustRoot(
132 ... 'http://*.example.com')
133 >>> print rpconfig3.trust_root
134 http://*.example.com/
135 >>> rpconfig3.id == rpconfig.id
136 True
137
138
139Listing all OpenIDRPConfig objects
140==================================
141
142The getAll() method of the IOpenIDRPConfigSet will return a result set
143containing all OpenIDRP's.
144
145 >>> configs = getUtility(IOpenIDRPConfigSet).getAll()
146 >>> rpconfig in configs
147 True
148
149
150Destroying OpenIDRPConfig objects
151=================================
152
153RP configs can be removed using the destroySelf() method, which is
154only available to administrators:
155
156 >>> login(ANONYMOUS)
157 >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot(
158 ... 'http://*.example.com/')
159 >>> rpconfig.destroySelf()
160 Traceback (most recent call last):
161 ...
162 Unauthorized: (<OpenIDRPConfig at ...>, 'destroySelf', 'launchpad.Admin')
163
164The same method succeeds when run as an administrator. Afterwards,
165attempts to get the RP config fail:
166
167 >>> login('foo.bar@canonical.com')
168 >>> rpconfig.destroySelf()
169 >>> print getUtility(IOpenIDRPConfigSet).getByTrustRoot(
170 ... 'http://*.example.com/')
171 None
1720
=== removed file 'lib/lp/services/openid/interfaces/openidrpconfig.py'
--- lib/lp/services/openid/interfaces/openidrpconfig.py 2009-07-17 02:25:09 +0000
+++ lib/lp/services/openid/interfaces/openidrpconfig.py 1970-01-01 00:00:00 +0000
@@ -1,120 +0,0 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""OpenIDRPConfig related interfaces."""
5
6__metaclass__ = type
7__all__ = [
8 'IOpenIDRPConfig',
9 'IOpenIDRPConfigSet',
10 ]
11
12from zope.component import getUtility
13from zope.schema import Bool, Choice, Int, List, Text, TextLine
14from zope.interface import Interface
15from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
16
17from canonical.launchpad import _
18from canonical.launchpad.fields import (
19 BaseImageUpload, URIField, UniqueField)
20from lp.registry.interfaces.person import PersonCreationRationale
21
22
23class TrustRootField(UniqueField, URIField):
24 """An OpenID Relying Party trust root, which is unique."""
25
26 attribute = 'trust_root'
27 errormessage = _("%s is already in use for another Relying Party.")
28
29 @property
30 def _content_iface(self):
31 return IOpenIDRPConfig
32
33 def _getByAttribute(self, trust_root):
34 return getUtility(IOpenIDRPConfigSet).getByTrustRoot(trust_root)
35
36
37class RPLogoImageUpload(BaseImageUpload):
38
39 dimensions = (400, 100)
40 exact_dimensions = False
41 max_size = 100*1024
42
43
44sreg_fields_vocabulary = SimpleVocabulary([
45 SimpleTerm('fullname', 'fullname', 'Full name'),
46 SimpleTerm('nickname', 'nickname', 'Launchpad ID'),
47 SimpleTerm('email', 'email', 'Email address'),
48 SimpleTerm('timezone', 'timezone', 'Time zone'),
49 SimpleTerm('x_address1', 'x_address1', 'Address line 1'),
50 SimpleTerm('x_address2', 'x_address2', 'Address line 2'),
51 SimpleTerm('x_city', 'x_city', 'City'),
52 SimpleTerm('x_province', 'x_province', 'State/Province'),
53 SimpleTerm('country', 'country', 'Country'),
54 SimpleTerm('postcode', 'postcode', 'Postcode'),
55 SimpleTerm('x_phone', 'x_phone', 'Phone number'),
56 SimpleTerm('x_organization', 'x_organization', 'Organization')])
57
58
59class IOpenIDRPConfig(Interface):
60 """Configuration for a particular OpenID Relying Party."""
61 id = Int(title=u'ID', required=True)
62 trust_root = TrustRootField(
63 title=_('Trust Root'), required=True,
64 trailing_slash=True,
65 description=_('The openid.trust_root value sent by the '
66 'Relying Party'))
67 displayname = TextLine(
68 title=_('Display Name'), required=True,
69 description=_('A human readable name for the Relying Party'))
70 description = Text(
71 title=_('Description'), required=True,
72 description=_('A description of the Relying Party, explaining why '
73 'the user should authenticate.'))
74 logo = RPLogoImageUpload(
75 title=_('Logo'), required=False,
76 default_image_resource='/@@/nyet-logo',
77 description=_('A banner that identifies the Relying Party, '
78 'no larger than 400x100 pixels.'))
79 allowed_sreg = List(
80 title=_('Allowed Sreg Fields'),
81 description=_('The simple registration fields that may be '
82 'transferred to this Relying Party'),
83 value_type=Choice(vocabulary=sreg_fields_vocabulary))
84 creation_rationale = Choice(
85 title=_('Creation Rationale'),
86 description=_('The creation rationale to use for user accounts '
87 'created while logging in to this Relying Party'),
88 vocabulary=PersonCreationRationale)
89 can_query_any_team = Bool(
90 title=_('Query Any Team'),
91 description=_(
92 'Teammembership of any team can be requested, including '
93 'private teams.'),
94 required=True, readonly=False)
95 auto_authorize = Bool(
96 title=_('Automatically authorize requests'),
97 description=_(
98 'Authentication requests for this RP are responded to '
99 'automatically without explicit user authorization'),
100 required=True, readonly=False)
101
102
103class IOpenIDRPConfigSet(Interface):
104 """The set of OpenID Relying Party configurations."""
105 def new(trust_root, displayname, description, logo=None,
106 allowed_sreg=None, creation_rationale=PersonCreationRationale
107 .OWNER_CREATED_UNKNOWN_TRUSTROOT, can_query_any_team=False,
108 auto_authorize=False):
109 """Create a new IOpenIDRPConfig"""
110
111 def get(id):
112 """Get the IOpenIDRPConfig with a particular ID."""
113
114 def getAll():
115 """Return a sequence of all IOpenIDRPConfigs."""
116
117 def getByTrustRoot(trust_root):
118 """Return the IOpenIDRPConfig for a particular trust root"""
119
120
1210
=== removed file 'lib/lp/services/openid/model/openidrpconfig.py'
--- lib/lp/services/openid/model/openidrpconfig.py 2009-07-17 02:25:09 +0000
+++ lib/lp/services/openid/model/openidrpconfig.py 1970-01-01 00:00:00 +0000
@@ -1,111 +0,0 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""OpenIDRPConfig related database classes."""
5
6__metaclass__ = type
7__all__ = [
8 'OpenIDRPConfig',
9 'OpenIDRPConfigSet',
10 ]
11
12
13import re
14
15from sqlobject import BoolCol, ForeignKey, SQLObjectNotFound, StringCol
16from storm.expr import Or
17from zope.interface import implements
18
19from canonical.database.enumcol import EnumCol
20from canonical.database.sqlbase import SQLBase
21from canonical.launchpad.interfaces import IStore
22from lp.registry.interfaces.person import PersonCreationRationale
23from lp.services.openid.interfaces.openidrpconfig import (
24 IOpenIDRPConfig, IOpenIDRPConfigSet)
25
26
27class OpenIDRPConfig(SQLBase):
28 implements(IOpenIDRPConfig)
29
30 _table = 'OpenIDRPConfig'
31 trust_root = StringCol(dbName='trust_root', notNull=True)
32 displayname = StringCol(dbName='displayname', notNull=True)
33 description = StringCol(dbName='description', notNull=True)
34 logo = ForeignKey(
35 dbName='logo', foreignKey='LibraryFileAlias', default=None)
36 _allowed_sreg = StringCol(dbName='allowed_sreg')
37 creation_rationale = EnumCol(
38 dbName='creation_rationale', notNull=True,
39 schema=PersonCreationRationale,
40 default=PersonCreationRationale.OWNER_CREATED_UNKNOWN_TRUSTROOT)
41 can_query_any_team = BoolCol(
42 dbName='can_query_any_team', notNull=True, default=False)
43 auto_authorize = BoolCol()
44
45 def allowed_sreg(self):
46 value = self._allowed_sreg
47 if not value:
48 return []
49 return value.split(',')
50
51 def _set_allowed_sreg(self, value):
52 if not value:
53 self._allowed_sreg = None
54 self._allowed_sreg = ','.join(sorted(value))
55
56 allowed_sreg = property(allowed_sreg, _set_allowed_sreg)
57
58
59class OpenIDRPConfigSet:
60 implements(IOpenIDRPConfigSet)
61
62 url_re = re.compile("^(.+?)\/*$")
63
64 def _normalizeTrustRoot(self, trust_root):
65 """Given a trust root URL ensure it ends with exactly one '/'."""
66 match = self.url_re.match(trust_root)
67 assert match is not None, (
68 "Attempting to normalize trust root %s failed." % trust_root)
69 return "%s/" % match.group(1)
70
71 def new(self, trust_root, displayname, description, logo=None,
72 allowed_sreg=None,
73 creation_rationale=
74 PersonCreationRationale.OWNER_CREATED_UNKNOWN_TRUSTROOT,
75 can_query_any_team=False, auto_authorize=False):
76 """See `IOpenIDRPConfigSet`"""
77 if allowed_sreg:
78 allowed_sreg = ','.join(sorted(allowed_sreg))
79 else:
80 allowed_sreg = None
81 trust_root = self._normalizeTrustRoot(trust_root)
82 return OpenIDRPConfig(
83 trust_root=trust_root, displayname=displayname,
84 description=description, logo=logo,
85 _allowed_sreg=allowed_sreg, creation_rationale=creation_rationale,
86 can_query_any_team=can_query_any_team,
87 auto_authorize=auto_authorize)
88
89 def get(self, id):
90 """See `IOpenIDRPConfigSet`"""
91 try:
92 return OpenIDRPConfig.get(id)
93 except SQLObjectNotFound:
94 return None
95
96 def getAll(self):
97 """See `IOpenIDRPConfigSet`"""
98 return OpenIDRPConfig.select(orderBy=['displayname', 'trust_root'])
99
100 def getByTrustRoot(self, trust_root):
101 """See `IOpenIDRPConfigSet`"""
102 trust_root = self._normalizeTrustRoot(trust_root)
103 # XXX: BradCrittenden 2008-09-26 bug=274774: Until the database is
104 # updated to normalize existing data the query must look for
105 # trust_roots that end in '/' and those that do not.
106 return IStore(OpenIDRPConfig).find(
107 OpenIDRPConfig,
108 Or(OpenIDRPConfig.trust_root==trust_root,
109 OpenIDRPConfig.trust_root==trust_root[:-1])).one()
110
111
1120
=== removed directory 'lib/lp/services/openid/stories'
=== removed file 'lib/lp/services/openid/stories/__init__.py'
=== removed file 'lib/lp/services/openid/stories/rpconfig-admin.txt'
--- lib/lp/services/openid/stories/rpconfig-admin.txt 2009-07-15 15:39:49 +0000
+++ lib/lp/services/openid/stories/rpconfig-admin.txt 1970-01-01 00:00:00 +0000
@@ -1,190 +0,0 @@
1= Managing OpenID Relying Party Configurations =
2
3While Launchpad can act as an OpenID Provider for any Relying Party,
4it can provide a better user experience for RPs that it knows about,
5including:
6
7 * A human readable name for the RP.
8 * A logo for the RP to display on the login page.
9 * Some descriptive text indicating why the user should authenticate
10 to the RP.
11 * A creation rationale for new accounts created as part of the login
12 process for this RP.
13
14The pages used to view and edit these configurations are only visible
15to Launchpad administrators:
16
17 >>> user_browser.open('http://launchpad.dev/+rpconfig')
18 Traceback (most recent call last):
19 ...
20 Unauthorized: ...
21 >>> admin_browser.open('http://launchpad.dev/+rpconfig')
22 >>> print admin_browser.title
23 OpenID Relying Party Configurations
24
25
26== Adding RP Configurations ==
27
28We can add new RP configurations from this page:
29
30 >>> admin_browser.getLink('Add an RP config').click()
31 >>> print admin_browser.title
32 Add an OpenID Relying Party Configuration
33
34 >>> import os
35 >>> from canonical.config import config
36 >>> logo_file = os.path.join(
37 ... config.root, 'lib/canonical/launchpad/images/nyet-logo.png')
38
39 >>> admin_browser.getControl('Trust Root').value = 'http://example.com/'
40 >>> admin_browser.getControl('Display Name').value = 'Example RP'
41 >>> admin_browser.getControl('Description').value = 'example description'
42 >>> admin_browser.getControl(name='field.logo.action').value = ['change']
43 >>> admin_browser.getControl(name='field.logo.image').add_file(
44 ... open(logo_file), 'image/png', 'logo.png')
45 >>> admin_browser.getControl('Full name').click()
46 >>> admin_browser.getControl('Email address').click()
47 >>> admin_browser.getControl('Automatically authorize requests').click()
48 >>> admin_browser.getControl('Create').click()
49 >>> print admin_browser.title
50 OpenID Relying Party Configurations
51
52The new RP configuration page is now included in the list:
53
54 >>> print admin_browser.contents
55 <...
56 <td><a href="...">Example RP</a></td>
57 <td>http://example.com/</td>
58 ...
59
60The RP config contains all the information we'd expect:
61
62 >>> from zope.component import getUtility
63 >>> from canonical.launchpad.ftests import ANONYMOUS, login, logout
64 >>> from lp.services.openid.interfaces.openidrpconfig import (
65 ... IOpenIDRPConfigSet)
66
67 >>> login(ANONYMOUS)
68 >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot(
69 ... 'http://example.com/')
70 >>> print rpconfig.displayname
71 Example RP
72 >>> print rpconfig.description
73 example description
74 >>> print rpconfig.logo.filename
75 logo.png
76 >>> print rpconfig.allowed_sreg
77 [u'email', u'fullname']
78 >>> print rpconfig.creation_rationale.name
79 OWNER_CREATED_UNKNOWN_TRUSTROOT
80 >>> print rpconfig.auto_authorize
81 True
82 >>> logout()
83
84The trust_root will have a trailing slash appended even if the user
85does not specify one.
86
87 >>> admin_browser.open('http://launchpad.dev/+rpconfig')
88 >>> admin_browser.getLink('Add an RP config').click()
89 >>> admin_browser.getControl('Trust Root').value = 'http://example-two.com'
90 >>> admin_browser.getControl('Display Name').value = 'Example Two RP'
91 >>> admin_browser.getControl('Description').value = 'example description'
92 >>> admin_browser.getControl('Create').click()
93
94The new RP configuration page is now included in the list, with the
95trailing slash in the trust root:
96
97 >>> print admin_browser.contents
98 <...
99 <td><a href="...">Example Two RP</a></td>
100 <td>http://example-two.com/</td>
101 ...
102
103
104== Editing RP Configurations ==
105
106We can also edit existing RP configurations:
107
108 >>> admin_browser.getLink('Example RP').click()
109 >>> print admin_browser.title
110 Edit Relying Party Configuration for Example RP
111
112 >>> admin_browser.getControl('Description').value = 'new description'
113 >>> admin_browser.getControl('Launchpad ID').click()
114 >>> admin_browser.getControl('Automatically authorize requests').click()
115 >>> admin_browser.getControl('Save').click()
116 >>> print admin_browser.title
117 OpenID Relying Party Configurations
118
119The changes have now been made to the RP configuration:
120
121 >>> login(ANONYMOUS)
122 >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot(
123 ... 'http://example.com/')
124 >>> print rpconfig.description
125 new description
126 >>> print rpconfig.allowed_sreg
127 [u'email', u'fullname', u'nickname']
128 >>> print rpconfig.auto_authorize
129 False
130 >>> logout()
131
132
133== Only One RP Configuration Per Trust Root ==
134
135There can only be one RP configuration per trust root. Trying to
136create a second configuration fails:
137
138 >>> admin_browser.getLink('Add an RP config').click()
139 >>> admin_browser.getControl('Trust Root').value = 'http://example.com/'
140 >>> admin_browser.getControl('Display Name').value = 'Second RP'
141 >>> admin_browser.getControl('Description').value = 'description'
142 >>> admin_browser.getControl('Create').click()
143 >>> print admin_browser.title
144 Add an OpenID Relying Party Configuration
145
146 >>> for error in find_tags_by_class(admin_browser.contents, 'message'):
147 ... print extract_text(error)
148 There is 1 error.
149 http://example.com/ is already in use for another Relying Party.
150
151Changing the trust root value fixes the problem:
152
153 >>> admin_browser.getControl('Trust Root').value = 'http://example.net/'
154 >>> admin_browser.getControl('Create').click()
155 >>> print admin_browser.title
156 OpenID Relying Party Configurations
157
158Similarly, we can't change the trust root of a configuration to
159conflict with another configuration:
160
161 >>> admin_browser.getLink('Second RP').click()
162 >>> admin_browser.getControl('Trust Root').value = 'http://example.com/'
163 >>> admin_browser.getControl('Save').click()
164 >>> print admin_browser.title
165 Edit Relying Party Configuration for Second RP
166
167 >>> for error in find_tags_by_class(admin_browser.contents, 'message'):
168 ... print extract_text(error)
169 There is 1 error.
170 http://example.com/ is already in use for another Relying Party.
171
172
173== Deleting RP Configurations ==
174
175RP configurations can be deleted from the edit form:
176
177 >>> admin_browser.open('http://launchpad.dev/+rpconfig')
178 >>> admin_browser.getLink('Example RP').click()
179 >>> admin_browser.getControl('Remove').click()
180 >>> print admin_browser.title
181 OpenID Relying Party Configurations
182
183The RP configuration has now been removed:
184
185 >>> login(ANONYMOUS)
186 >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot(
187 ... 'http://example.com/')
188 >>> print rpconfig
189 None
190 >>> logout()
1910
=== removed file 'lib/lp/services/openid/templates/openidrpconfig-add.pt'
--- lib/lp/services/openid/templates/openidrpconfig-add.pt 2009-11-23 03:10:04 +0000
+++ lib/lp/services/openid/templates/openidrpconfig-add.pt 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
1<html
2 xmlns="http://www.w3.org/1999/xhtml"
3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 metal:use-macro="view/macro:page/main_only"
7 i18n:domain="launchpad">
8
9<body>
10
11<div metal:fill-slot="main">
12 <div metal:use-macro="context/@@launchpad_form/form" />
13</div>
14
15</body>
16</html>
170
=== removed file 'lib/lp/services/openid/templates/openidrpconfig-edit.pt'
--- lib/lp/services/openid/templates/openidrpconfig-edit.pt 2009-11-23 03:10:04 +0000
+++ lib/lp/services/openid/templates/openidrpconfig-edit.pt 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
1<html
2 xmlns="http://www.w3.org/1999/xhtml"
3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 metal:use-macro="view/macro:page/main_only"
7 i18n:domain="launchpad">
8
9<body>
10
11<div metal:fill-slot="main">
12 <div metal:use-macro="context/@@launchpad_form/form" />
13</div>
14
15</body>
16</html>
170
=== removed file 'lib/lp/services/openid/templates/openidrpconfigset-index.pt'
--- lib/lp/services/openid/templates/openidrpconfigset-index.pt 2009-11-23 16:14:39 +0000
+++ lib/lp/services/openid/templates/openidrpconfigset-index.pt 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
1<html xml:lang="en" lang="en"
2 xmlns="http://www.w3.org/1999/xhtml"
3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 metal:use-macro="view/macro:page/main_only"
7 i18n:domain="launchpad">
8
9 <body>
10 <div metal:fill-slot="main">
11 <table class="listing" tal:condition="context/getAll">
12 <thead>
13 <tr>
14 <th>Relying Party</th>
15 <th>Trust Root</th>
16 </tr>
17 </thead>
18 <tbody>
19 <tr tal:repeat="rpconfig context/getAll">
20 <td><a tal:attributes="href rpconfig/fmt:url"
21 tal:content="rpconfig/displayname">RP Config</a></td>
22 <td tal:content="rpconfig/trust_root">http://blah</td>
23 </tr>
24 </tbody>
25 </table>
26
27 <div>
28 <a tal:attributes="href string:${context/fmt:url}/+add">
29 Add an RP config</a>
30 </div>
31 </div>
32 </body>
33</html>