Merge lp:~salgado/launchpad/remove-lp-services-openid into lp:launchpad
- remove-lp-services-openid
- Merge into devel
Proposed by
Guilherme Salgado
on 2010-04-05
| Status: | Merged |
|---|---|
| Approved by: | Aaron Bentley on 2010-04-05 |
| 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 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Aaron Bentley (community) | 2010-04-05 | Approve on 2010-04-05 | |
|
Review via email:
|
|||
Commit Message
Description of the Change
Remove the unused bits from lp/services/openid. These were once used by canonical-
To post a comment you must log in.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file 'lib/canonical/launchpad/browser/launchpad.py' |
| 2 | --- lib/canonical/launchpad/browser/launchpad.py 2010-03-04 20:19:39 +0000 |
| 3 | +++ lib/canonical/launchpad/browser/launchpad.py 2010-04-05 15:45:44 +0000 |
| 4 | @@ -100,7 +100,6 @@ |
| 5 | from lp.registry.interfaces.mentoringoffer import IMentoringOfferSet |
| 6 | from lp.registry.interfaces.person import IPersonSet |
| 7 | from lp.registry.interfaces.pillar import IPillarNameSet |
| 8 | -from lp.services.openid.interfaces.openidrpconfig import IOpenIDRPConfigSet |
| 9 | from lp.services.worlddata.interfaces.language import ILanguageSet |
| 10 | from lp.soyuz.interfaces.packageset import IPackagesetSet |
| 11 | from lp.registry.interfaces.product import ( |
| 12 | @@ -578,7 +577,6 @@ |
| 13 | 'translations': IRosettaApplication, |
| 14 | 'testopenid': ITestOpenIDApplication, |
| 15 | 'questions': IQuestionSet, |
| 16 | - '+rpconfig': IOpenIDRPConfigSet, |
| 17 | 'temporary-blobs': ITemporaryStorageManager, |
| 18 | # These three have been renamed, and no redirects done, as the old |
| 19 | # urls now point to the product pages. |
| 20 | |
| 21 | === removed file 'lib/lp/services/openid/browser/configure.zcml' |
| 22 | --- lib/lp/services/openid/browser/configure.zcml 2009-11-23 03:10:04 +0000 |
| 23 | +++ lib/lp/services/openid/browser/configure.zcml 1970-01-01 00:00:00 +0000 |
| 24 | @@ -1,60 +0,0 @@ |
| 25 | -<!-- Copyright 2009 Canonical Ltd. This software is licensed under the |
| 26 | - GNU Affero General Public License version 3 (see the file LICENSE). |
| 27 | ---> |
| 28 | - |
| 29 | -<configure xmlns="http://namespaces.zope.org/zope" |
| 30 | - xmlns:browser="http://namespaces.zope.org/browser"> |
| 31 | - |
| 32 | - <browser:url |
| 33 | - for="..interfaces.openidrpconfig.IOpenIDRPConfig" |
| 34 | - path_expression="string:${id}" |
| 35 | - parent_utility="..interfaces.openidrpconfig.IOpenIDRPConfigSet" |
| 36 | - /> |
| 37 | - |
| 38 | - <browser:page |
| 39 | - for="..interfaces.openidrpconfig.IOpenIDRPConfig" |
| 40 | - name="+edit" |
| 41 | - class=".openidrpconfig.OpenIDRPConfigEditView" |
| 42 | - permission="launchpad.Admin" |
| 43 | - template="../templates/openidrpconfig-edit.pt" |
| 44 | - /> |
| 45 | - |
| 46 | - <browser:defaultView |
| 47 | - for="..interfaces.openidrpconfig.IOpenIDRPConfig" |
| 48 | - name="+edit" |
| 49 | - /> |
| 50 | - |
| 51 | - <!-- IOpenIDRPConfigSet --> |
| 52 | - |
| 53 | - <browser:url |
| 54 | - for="..interfaces.openidrpconfig.IOpenIDRPConfigSet" |
| 55 | - path_expression="string:+rpconfig" |
| 56 | - parent_utility="canonical.launchpad.interfaces.ILaunchpadRoot" |
| 57 | - /> |
| 58 | - |
| 59 | - <browser:navigation |
| 60 | - module=".openidrpconfig" |
| 61 | - classes="OpenIDRPConfigSetNavigation" |
| 62 | - /> |
| 63 | - |
| 64 | - <browser:page |
| 65 | - for="..interfaces.openidrpconfig.IOpenIDRPConfigSet" |
| 66 | - name="+add" |
| 67 | - class=".openidrpconfig.OpenIDRPConfigAddView" |
| 68 | - permission="launchpad.Admin" |
| 69 | - template="../templates/openidrpconfig-add.pt" |
| 70 | - /> |
| 71 | - |
| 72 | - <browser:page |
| 73 | - for="..interfaces.openidrpconfig.IOpenIDRPConfigSet" |
| 74 | - name="+index" |
| 75 | - class=".openidrpconfig.OpenIDRPConfigSetView" |
| 76 | - permission="launchpad.Admin" |
| 77 | - template="../templates/openidrpconfigset-index.pt" |
| 78 | - /> |
| 79 | - |
| 80 | - <browser:defaultView |
| 81 | - for="..interfaces.openidrpconfig.IOpenIDRPConfigSet" |
| 82 | - name="+index" |
| 83 | - /> |
| 84 | -</configure> |
| 85 | |
| 86 | === removed file 'lib/lp/services/openid/browser/openidrpconfig.py' |
| 87 | --- lib/lp/services/openid/browser/openidrpconfig.py 2009-11-23 16:14:39 +0000 |
| 88 | +++ lib/lp/services/openid/browser/openidrpconfig.py 1970-01-01 00:00:00 +0000 |
| 89 | @@ -1,124 +0,0 @@ |
| 90 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
| 91 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
| 92 | - |
| 93 | -"""View classes used to edit `IOpenIDRPConfig` objects. |
| 94 | - |
| 95 | -OpenID Relying Party configurations are used to customise the |
| 96 | -appearance and behaviour of the login page when authenticating to a |
| 97 | -particular RP. |
| 98 | -""" |
| 99 | - |
| 100 | -__metaclass__ = type |
| 101 | -__all__ = [] |
| 102 | - |
| 103 | -from zope.component import getUtility |
| 104 | - |
| 105 | -from canonical.launchpad import _ |
| 106 | -from lp.services.openid.interfaces.openidrpconfig import ( |
| 107 | - IOpenIDRPConfig, IOpenIDRPConfigSet) |
| 108 | -from canonical.launchpad.webapp import ( |
| 109 | - LaunchpadEditFormView, LaunchpadFormView, Navigation, action, |
| 110 | - canonical_url, custom_widget) |
| 111 | -from canonical.launchpad.webapp.publisher import LaunchpadView |
| 112 | -from canonical.widgets import LabeledMultiCheckBoxWidget |
| 113 | -from canonical.widgets.image import ImageChangeWidget |
| 114 | -from lp.registry.interfaces.person import PersonCreationRationale |
| 115 | - |
| 116 | - |
| 117 | -class OpenIDRPConfigSetNavigation(Navigation): |
| 118 | - """Navigation for `IOpenIDRPConfigSet`.""" |
| 119 | - usedfor = IOpenIDRPConfigSet |
| 120 | - |
| 121 | - def traverse(self, config_id): |
| 122 | - """Traverse to RP configs by ID.""" |
| 123 | - try: |
| 124 | - config_id = int(config_id) |
| 125 | - except ValueError: |
| 126 | - return None |
| 127 | - |
| 128 | - return getUtility(IOpenIDRPConfigSet).get(config_id) |
| 129 | - |
| 130 | - |
| 131 | -class OpenIDRPConfigSetView(LaunchpadView): |
| 132 | - page_title = 'OpenID Relying Party Configurations' |
| 133 | - label = page_title |
| 134 | - |
| 135 | - |
| 136 | -class OpenIDRPConfigAddView(LaunchpadFormView): |
| 137 | - """View class for adding new RP configurations.""" |
| 138 | - |
| 139 | - schema = IOpenIDRPConfig |
| 140 | - field_names = ['trust_root', 'displayname', 'description', 'logo', |
| 141 | - 'allowed_sreg', 'creation_rationale', 'can_query_any_team', |
| 142 | - 'auto_authorize'] |
| 143 | - custom_widget('logo', ImageChangeWidget, ImageChangeWidget.ADD_STYLE) |
| 144 | - custom_widget('allowed_sreg', LabeledMultiCheckBoxWidget) |
| 145 | - label = 'Add an OpenID Relying Party Configuration' |
| 146 | - page_title = label |
| 147 | - |
| 148 | - initial_values = { |
| 149 | - 'creation_rationale': |
| 150 | - PersonCreationRationale.OWNER_CREATED_UNKNOWN_TRUSTROOT, |
| 151 | - } |
| 152 | - |
| 153 | - @action(_('Create'), name='create') |
| 154 | - def create_action(self, action, data): |
| 155 | - """Create the new RP configuration.""" |
| 156 | - rpconfig = getUtility(IOpenIDRPConfigSet).new( |
| 157 | - trust_root=data['trust_root'], |
| 158 | - displayname=data['displayname'], |
| 159 | - description=data['description'], |
| 160 | - logo=data['logo'], |
| 161 | - allowed_sreg=data['allowed_sreg'], |
| 162 | - creation_rationale=data['creation_rationale'], |
| 163 | - can_query_any_team=data['can_query_any_team'], |
| 164 | - auto_authorize=data['auto_authorize']) |
| 165 | - self.request.response.addInfoNotification( |
| 166 | - _('Created RP configuration for ${trust_root}.', |
| 167 | - mapping=dict(trust_root=data['trust_root']))) |
| 168 | - |
| 169 | - @property |
| 170 | - def next_url(self): |
| 171 | - return canonical_url(getUtility(IOpenIDRPConfigSet)) |
| 172 | - |
| 173 | - cancel_url = next_url |
| 174 | - |
| 175 | - |
| 176 | -class OpenIDRPConfigEditView(LaunchpadEditFormView): |
| 177 | - """View class for editing or removing RP configurations.""" |
| 178 | - |
| 179 | - @property |
| 180 | - def label(self): |
| 181 | - return 'Edit Relying Party Configuration for %s' % ( |
| 182 | - self.context.displayname) |
| 183 | - page_title = label |
| 184 | - |
| 185 | - schema = IOpenIDRPConfig |
| 186 | - field_names = ['trust_root', 'displayname', 'description', 'logo', |
| 187 | - 'allowed_sreg', 'creation_rationale', 'can_query_any_team', |
| 188 | - 'auto_authorize'] |
| 189 | - custom_widget('logo', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) |
| 190 | - custom_widget('allowed_sreg', LabeledMultiCheckBoxWidget) |
| 191 | - |
| 192 | - @action(_('Save'), name='save') |
| 193 | - def save_action(self, action, data): |
| 194 | - """Save the RP configuration.""" |
| 195 | - if self.updateContextFromData(data): |
| 196 | - self.request.response.addInfoNotification( |
| 197 | - _('Updated RP configuration for ${trust_root}.', |
| 198 | - mapping=dict(trust_root=self.context.trust_root))) |
| 199 | - |
| 200 | - @action(_('Remove'), name='remove') |
| 201 | - def remove_action(self, action, data): |
| 202 | - """Remove the RP configuration.""" |
| 203 | - trust_root = self.context.trust_root |
| 204 | - self.context.destroySelf() |
| 205 | - self.request.response.addInfoNotification( |
| 206 | - _('Removed RP configuration for ${trust_root}.', |
| 207 | - mapping=dict(trust_root=trust_root))) |
| 208 | - |
| 209 | - @property |
| 210 | - def next_url(self): |
| 211 | - return canonical_url(getUtility(IOpenIDRPConfigSet)) |
| 212 | - |
| 213 | - cancel_url = next_url |
| 214 | |
| 215 | === modified file 'lib/lp/services/openid/configure.zcml' |
| 216 | --- lib/lp/services/openid/configure.zcml 2009-07-18 00:05:49 +0000 |
| 217 | +++ lib/lp/services/openid/configure.zcml 2010-04-05 15:45:44 +0000 |
| 218 | @@ -9,23 +9,6 @@ |
| 219 | i18n_domain="launchpad"> |
| 220 | |
| 221 | <class |
| 222 | - class=".model.openidrpconfig.OpenIDRPConfig"> |
| 223 | - <allow interface=".interfaces.openidrpconfig.IOpenIDRPConfig" /> |
| 224 | - <require |
| 225 | - permission="launchpad.Admin" |
| 226 | - attributes="destroySelf" |
| 227 | - set_schema=".interfaces.openidrpconfig.IOpenIDRPConfig" /> |
| 228 | - </class> |
| 229 | - |
| 230 | - <securedutility |
| 231 | - class=".model.openidrpconfig.OpenIDRPConfigSet" |
| 232 | - provides=".interfaces.openidrpconfig.IOpenIDRPConfigSet"> |
| 233 | - <allow |
| 234 | - interface=".interfaces.openidrpconfig.IOpenIDRPConfigSet" |
| 235 | - /> |
| 236 | - </securedutility> |
| 237 | - |
| 238 | - <class |
| 239 | class=".model.openidrpsummary.OpenIDRPSummary"> |
| 240 | <allow interface=".interfaces.openidrpsummary.IOpenIDRPSummary" /> |
| 241 | </class> |
| 242 | @@ -44,5 +27,4 @@ |
| 243 | <adapter factory=".adapters.openid.OpenIDPersistentIdentity" /> |
| 244 | <adapter factory=".adapters.openid.person_to_openidpersistentidentity" /> |
| 245 | |
| 246 | - <include package=".browser" /> |
| 247 | </configure> |
| 248 | |
| 249 | === removed directory 'lib/lp/services/openid/doc' |
| 250 | === removed file 'lib/lp/services/openid/doc/__init__.py' |
| 251 | === removed file 'lib/lp/services/openid/doc/openid-rp-config.txt' |
| 252 | --- lib/lp/services/openid/doc/openid-rp-config.txt 2010-02-11 20:33:07 +0000 |
| 253 | +++ lib/lp/services/openid/doc/openid-rp-config.txt 1970-01-01 00:00:00 +0000 |
| 254 | @@ -1,171 +0,0 @@ |
| 255 | -=================================== |
| 256 | -OpenID Relying Party Configurations |
| 257 | -=================================== |
| 258 | - |
| 259 | -Launchpad can store information about OpenID relying parties in order |
| 260 | -to provide a better user experience when using Launchpad to log in. |
| 261 | -This includes: |
| 262 | - |
| 263 | - * Providing a human readable name for the relying party, so we don't |
| 264 | - have to display the raw URL to the user. |
| 265 | - |
| 266 | - * Providing a logo image to display on the log in page. |
| 267 | - |
| 268 | - * Specify what fields may be disclosed to the RP via OpenID Simple |
| 269 | - Registration protocol. |
| 270 | - |
| 271 | - * What person creation rationale should be used for accounts created |
| 272 | - while signing in to the RP. |
| 273 | - |
| 274 | - |
| 275 | -Creating OpenIDRPConfigs |
| 276 | -======================== |
| 277 | - |
| 278 | -Configurations are created using the IOpenIDRPConfigSet utility: |
| 279 | - |
| 280 | - >>> from zope.component import getUtility |
| 281 | - >>> from lp.services.openid.interfaces.openidrpconfig import ( |
| 282 | - ... IOpenIDRPConfigSet) |
| 283 | - >>> login(ANONYMOUS) |
| 284 | - >>> rpconfig = getUtility(IOpenIDRPConfigSet).new( |
| 285 | - ... trust_root='http://*.example.com/', |
| 286 | - ... displayname='Example RP', |
| 287 | - ... description='Example RP description', |
| 288 | - ... allowed_sreg=['fullname', 'nickname']) |
| 289 | - |
| 290 | -The resulting object implements the IOpenIDRPConfig interface: |
| 291 | - |
| 292 | - >>> from canonical.launchpad.webapp.testing import verifyObject |
| 293 | - >>> from lp.services.openid.interfaces.openidrpconfig import ( |
| 294 | - ... IOpenIDRPConfig) |
| 295 | - |
| 296 | - >>> verifyObject(IOpenIDRPConfig, rpconfig) |
| 297 | - True |
| 298 | - |
| 299 | -The utility itself implements IOpenIDRPConfigSet: |
| 300 | - |
| 301 | - >>> verifyObject(IOpenIDRPConfigSet, getUtility(IOpenIDRPConfigSet)) |
| 302 | - True |
| 303 | - |
| 304 | -Some RPs include a trailing '/' on their URLs, which is the standard, |
| 305 | -while others do not. The `trust_root` is always normalized to have a |
| 306 | -trailing slash. |
| 307 | - |
| 308 | - >>> rpconfig2 = getUtility(IOpenIDRPConfigSet).new( |
| 309 | - ... trust_root='http://foo.example.com', |
| 310 | - ... displayname='Example RP', |
| 311 | - ... description='Example RP description', |
| 312 | - ... allowed_sreg=['fullname', 'nickname']) |
| 313 | - >>> print rpconfig2.trust_root |
| 314 | - http://foo.example.com/ |
| 315 | - |
| 316 | - |
| 317 | -Modifying OpenIDRPConfig objects |
| 318 | -================================ |
| 319 | - |
| 320 | -OpenIDRPConfig objects may only be modified by an administrator: |
| 321 | - |
| 322 | - >>> rpconfig.displayname = 'New title' |
| 323 | - Traceback (most recent call last): |
| 324 | - ... |
| 325 | - Unauthorized: (<OpenIDRPConfig at ...>, 'displayname', 'launchpad.Admin') |
| 326 | - >>> login('foo.bar@canonical.com') |
| 327 | - >>> rpconfig.displayname = 'New title' |
| 328 | - >>> print rpconfig.displayname |
| 329 | - New title |
| 330 | - |
| 331 | -The allowed simple registration fields attribute sorts the field names |
| 332 | -to normalise the result: |
| 333 | - |
| 334 | - >>> rpconfig.allowed_sreg = ['fullname', 'email'] |
| 335 | - >>> print rpconfig.allowed_sreg |
| 336 | - [u'email', u'fullname'] |
| 337 | - |
| 338 | -The auto_authorize attribute specifies whether this RP is allowed to |
| 339 | -skip the authorization page. This behaviour is not turned on by |
| 340 | -default: |
| 341 | - |
| 342 | - >>> rpconfig.auto_authorize |
| 343 | - False |
| 344 | - >>> rpconfig.auto_authorize = True |
| 345 | - >>> rpconfig.auto_authorize |
| 346 | - True |
| 347 | - |
| 348 | - |
| 349 | -Searching for OpenIDRPConfig objects |
| 350 | -==================================== |
| 351 | - |
| 352 | -An RP config can be looked up by its ID using the get() method of the |
| 353 | -IOpenIDRPConfigSet: |
| 354 | - |
| 355 | - >>> rpconfig2 = getUtility(IOpenIDRPConfigSet).get(rpconfig.id) |
| 356 | - >>> print rpconfig2.trust_root |
| 357 | - http://*.example.com/ |
| 358 | - >>> rpconfig2.id == rpconfig.id |
| 359 | - True |
| 360 | - |
| 361 | -The get() method will return None for an unknown ID: |
| 362 | - |
| 363 | - >>> print getUtility(IOpenIDRPConfigSet).get(-42) |
| 364 | - None |
| 365 | - |
| 366 | -It is also possible to look up RP configs by their trust root: |
| 367 | - |
| 368 | - >>> rpconfig3 = getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 369 | - ... 'http://*.example.com/') |
| 370 | - >>> print rpconfig3.trust_root |
| 371 | - http://*.example.com/ |
| 372 | - >>> rpconfig3.id == rpconfig.id |
| 373 | - True |
| 374 | - |
| 375 | -The getByTrustRoot() method will return None for an unknown trust |
| 376 | -root: |
| 377 | - |
| 378 | - >>> print getUtility(IOpenIDRPConfigSet).getByTrustRoot('http://unknown') |
| 379 | - None |
| 380 | - |
| 381 | -Most RPs include the trailing '/' in their trust root URL but some do |
| 382 | -not. The search should match whether the trailing slash is there or |
| 383 | -not. |
| 384 | - |
| 385 | - >>> rpconfig3 = getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 386 | - ... 'http://*.example.com') |
| 387 | - >>> print rpconfig3.trust_root |
| 388 | - http://*.example.com/ |
| 389 | - >>> rpconfig3.id == rpconfig.id |
| 390 | - True |
| 391 | - |
| 392 | - |
| 393 | -Listing all OpenIDRPConfig objects |
| 394 | -================================== |
| 395 | - |
| 396 | -The getAll() method of the IOpenIDRPConfigSet will return a result set |
| 397 | -containing all OpenIDRP's. |
| 398 | - |
| 399 | - >>> configs = getUtility(IOpenIDRPConfigSet).getAll() |
| 400 | - >>> rpconfig in configs |
| 401 | - True |
| 402 | - |
| 403 | - |
| 404 | -Destroying OpenIDRPConfig objects |
| 405 | -================================= |
| 406 | - |
| 407 | -RP configs can be removed using the destroySelf() method, which is |
| 408 | -only available to administrators: |
| 409 | - |
| 410 | - >>> login(ANONYMOUS) |
| 411 | - >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 412 | - ... 'http://*.example.com/') |
| 413 | - >>> rpconfig.destroySelf() |
| 414 | - Traceback (most recent call last): |
| 415 | - ... |
| 416 | - Unauthorized: (<OpenIDRPConfig at ...>, 'destroySelf', 'launchpad.Admin') |
| 417 | - |
| 418 | -The same method succeeds when run as an administrator. Afterwards, |
| 419 | -attempts to get the RP config fail: |
| 420 | - |
| 421 | - >>> login('foo.bar@canonical.com') |
| 422 | - >>> rpconfig.destroySelf() |
| 423 | - >>> print getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 424 | - ... 'http://*.example.com/') |
| 425 | - None |
| 426 | |
| 427 | === removed file 'lib/lp/services/openid/interfaces/openidrpconfig.py' |
| 428 | --- lib/lp/services/openid/interfaces/openidrpconfig.py 2009-07-17 02:25:09 +0000 |
| 429 | +++ lib/lp/services/openid/interfaces/openidrpconfig.py 1970-01-01 00:00:00 +0000 |
| 430 | @@ -1,120 +0,0 @@ |
| 431 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
| 432 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
| 433 | - |
| 434 | -"""OpenIDRPConfig related interfaces.""" |
| 435 | - |
| 436 | -__metaclass__ = type |
| 437 | -__all__ = [ |
| 438 | - 'IOpenIDRPConfig', |
| 439 | - 'IOpenIDRPConfigSet', |
| 440 | - ] |
| 441 | - |
| 442 | -from zope.component import getUtility |
| 443 | -from zope.schema import Bool, Choice, Int, List, Text, TextLine |
| 444 | -from zope.interface import Interface |
| 445 | -from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary |
| 446 | - |
| 447 | -from canonical.launchpad import _ |
| 448 | -from canonical.launchpad.fields import ( |
| 449 | - BaseImageUpload, URIField, UniqueField) |
| 450 | -from lp.registry.interfaces.person import PersonCreationRationale |
| 451 | - |
| 452 | - |
| 453 | -class TrustRootField(UniqueField, URIField): |
| 454 | - """An OpenID Relying Party trust root, which is unique.""" |
| 455 | - |
| 456 | - attribute = 'trust_root' |
| 457 | - errormessage = _("%s is already in use for another Relying Party.") |
| 458 | - |
| 459 | - @property |
| 460 | - def _content_iface(self): |
| 461 | - return IOpenIDRPConfig |
| 462 | - |
| 463 | - def _getByAttribute(self, trust_root): |
| 464 | - return getUtility(IOpenIDRPConfigSet).getByTrustRoot(trust_root) |
| 465 | - |
| 466 | - |
| 467 | -class RPLogoImageUpload(BaseImageUpload): |
| 468 | - |
| 469 | - dimensions = (400, 100) |
| 470 | - exact_dimensions = False |
| 471 | - max_size = 100*1024 |
| 472 | - |
| 473 | - |
| 474 | -sreg_fields_vocabulary = SimpleVocabulary([ |
| 475 | - SimpleTerm('fullname', 'fullname', 'Full name'), |
| 476 | - SimpleTerm('nickname', 'nickname', 'Launchpad ID'), |
| 477 | - SimpleTerm('email', 'email', 'Email address'), |
| 478 | - SimpleTerm('timezone', 'timezone', 'Time zone'), |
| 479 | - SimpleTerm('x_address1', 'x_address1', 'Address line 1'), |
| 480 | - SimpleTerm('x_address2', 'x_address2', 'Address line 2'), |
| 481 | - SimpleTerm('x_city', 'x_city', 'City'), |
| 482 | - SimpleTerm('x_province', 'x_province', 'State/Province'), |
| 483 | - SimpleTerm('country', 'country', 'Country'), |
| 484 | - SimpleTerm('postcode', 'postcode', 'Postcode'), |
| 485 | - SimpleTerm('x_phone', 'x_phone', 'Phone number'), |
| 486 | - SimpleTerm('x_organization', 'x_organization', 'Organization')]) |
| 487 | - |
| 488 | - |
| 489 | -class IOpenIDRPConfig(Interface): |
| 490 | - """Configuration for a particular OpenID Relying Party.""" |
| 491 | - id = Int(title=u'ID', required=True) |
| 492 | - trust_root = TrustRootField( |
| 493 | - title=_('Trust Root'), required=True, |
| 494 | - trailing_slash=True, |
| 495 | - description=_('The openid.trust_root value sent by the ' |
| 496 | - 'Relying Party')) |
| 497 | - displayname = TextLine( |
| 498 | - title=_('Display Name'), required=True, |
| 499 | - description=_('A human readable name for the Relying Party')) |
| 500 | - description = Text( |
| 501 | - title=_('Description'), required=True, |
| 502 | - description=_('A description of the Relying Party, explaining why ' |
| 503 | - 'the user should authenticate.')) |
| 504 | - logo = RPLogoImageUpload( |
| 505 | - title=_('Logo'), required=False, |
| 506 | - default_image_resource='/@@/nyet-logo', |
| 507 | - description=_('A banner that identifies the Relying Party, ' |
| 508 | - 'no larger than 400x100 pixels.')) |
| 509 | - allowed_sreg = List( |
| 510 | - title=_('Allowed Sreg Fields'), |
| 511 | - description=_('The simple registration fields that may be ' |
| 512 | - 'transferred to this Relying Party'), |
| 513 | - value_type=Choice(vocabulary=sreg_fields_vocabulary)) |
| 514 | - creation_rationale = Choice( |
| 515 | - title=_('Creation Rationale'), |
| 516 | - description=_('The creation rationale to use for user accounts ' |
| 517 | - 'created while logging in to this Relying Party'), |
| 518 | - vocabulary=PersonCreationRationale) |
| 519 | - can_query_any_team = Bool( |
| 520 | - title=_('Query Any Team'), |
| 521 | - description=_( |
| 522 | - 'Teammembership of any team can be requested, including ' |
| 523 | - 'private teams.'), |
| 524 | - required=True, readonly=False) |
| 525 | - auto_authorize = Bool( |
| 526 | - title=_('Automatically authorize requests'), |
| 527 | - description=_( |
| 528 | - 'Authentication requests for this RP are responded to ' |
| 529 | - 'automatically without explicit user authorization'), |
| 530 | - required=True, readonly=False) |
| 531 | - |
| 532 | - |
| 533 | -class IOpenIDRPConfigSet(Interface): |
| 534 | - """The set of OpenID Relying Party configurations.""" |
| 535 | - def new(trust_root, displayname, description, logo=None, |
| 536 | - allowed_sreg=None, creation_rationale=PersonCreationRationale |
| 537 | - .OWNER_CREATED_UNKNOWN_TRUSTROOT, can_query_any_team=False, |
| 538 | - auto_authorize=False): |
| 539 | - """Create a new IOpenIDRPConfig""" |
| 540 | - |
| 541 | - def get(id): |
| 542 | - """Get the IOpenIDRPConfig with a particular ID.""" |
| 543 | - |
| 544 | - def getAll(): |
| 545 | - """Return a sequence of all IOpenIDRPConfigs.""" |
| 546 | - |
| 547 | - def getByTrustRoot(trust_root): |
| 548 | - """Return the IOpenIDRPConfig for a particular trust root""" |
| 549 | - |
| 550 | - |
| 551 | |
| 552 | === removed file 'lib/lp/services/openid/model/openidrpconfig.py' |
| 553 | --- lib/lp/services/openid/model/openidrpconfig.py 2009-07-17 02:25:09 +0000 |
| 554 | +++ lib/lp/services/openid/model/openidrpconfig.py 1970-01-01 00:00:00 +0000 |
| 555 | @@ -1,111 +0,0 @@ |
| 556 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
| 557 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
| 558 | - |
| 559 | -"""OpenIDRPConfig related database classes.""" |
| 560 | - |
| 561 | -__metaclass__ = type |
| 562 | -__all__ = [ |
| 563 | - 'OpenIDRPConfig', |
| 564 | - 'OpenIDRPConfigSet', |
| 565 | - ] |
| 566 | - |
| 567 | - |
| 568 | -import re |
| 569 | - |
| 570 | -from sqlobject import BoolCol, ForeignKey, SQLObjectNotFound, StringCol |
| 571 | -from storm.expr import Or |
| 572 | -from zope.interface import implements |
| 573 | - |
| 574 | -from canonical.database.enumcol import EnumCol |
| 575 | -from canonical.database.sqlbase import SQLBase |
| 576 | -from canonical.launchpad.interfaces import IStore |
| 577 | -from lp.registry.interfaces.person import PersonCreationRationale |
| 578 | -from lp.services.openid.interfaces.openidrpconfig import ( |
| 579 | - IOpenIDRPConfig, IOpenIDRPConfigSet) |
| 580 | - |
| 581 | - |
| 582 | -class OpenIDRPConfig(SQLBase): |
| 583 | - implements(IOpenIDRPConfig) |
| 584 | - |
| 585 | - _table = 'OpenIDRPConfig' |
| 586 | - trust_root = StringCol(dbName='trust_root', notNull=True) |
| 587 | - displayname = StringCol(dbName='displayname', notNull=True) |
| 588 | - description = StringCol(dbName='description', notNull=True) |
| 589 | - logo = ForeignKey( |
| 590 | - dbName='logo', foreignKey='LibraryFileAlias', default=None) |
| 591 | - _allowed_sreg = StringCol(dbName='allowed_sreg') |
| 592 | - creation_rationale = EnumCol( |
| 593 | - dbName='creation_rationale', notNull=True, |
| 594 | - schema=PersonCreationRationale, |
| 595 | - default=PersonCreationRationale.OWNER_CREATED_UNKNOWN_TRUSTROOT) |
| 596 | - can_query_any_team = BoolCol( |
| 597 | - dbName='can_query_any_team', notNull=True, default=False) |
| 598 | - auto_authorize = BoolCol() |
| 599 | - |
| 600 | - def allowed_sreg(self): |
| 601 | - value = self._allowed_sreg |
| 602 | - if not value: |
| 603 | - return [] |
| 604 | - return value.split(',') |
| 605 | - |
| 606 | - def _set_allowed_sreg(self, value): |
| 607 | - if not value: |
| 608 | - self._allowed_sreg = None |
| 609 | - self._allowed_sreg = ','.join(sorted(value)) |
| 610 | - |
| 611 | - allowed_sreg = property(allowed_sreg, _set_allowed_sreg) |
| 612 | - |
| 613 | - |
| 614 | -class OpenIDRPConfigSet: |
| 615 | - implements(IOpenIDRPConfigSet) |
| 616 | - |
| 617 | - url_re = re.compile("^(.+?)\/*$") |
| 618 | - |
| 619 | - def _normalizeTrustRoot(self, trust_root): |
| 620 | - """Given a trust root URL ensure it ends with exactly one '/'.""" |
| 621 | - match = self.url_re.match(trust_root) |
| 622 | - assert match is not None, ( |
| 623 | - "Attempting to normalize trust root %s failed." % trust_root) |
| 624 | - return "%s/" % match.group(1) |
| 625 | - |
| 626 | - def new(self, trust_root, displayname, description, logo=None, |
| 627 | - allowed_sreg=None, |
| 628 | - creation_rationale= |
| 629 | - PersonCreationRationale.OWNER_CREATED_UNKNOWN_TRUSTROOT, |
| 630 | - can_query_any_team=False, auto_authorize=False): |
| 631 | - """See `IOpenIDRPConfigSet`""" |
| 632 | - if allowed_sreg: |
| 633 | - allowed_sreg = ','.join(sorted(allowed_sreg)) |
| 634 | - else: |
| 635 | - allowed_sreg = None |
| 636 | - trust_root = self._normalizeTrustRoot(trust_root) |
| 637 | - return OpenIDRPConfig( |
| 638 | - trust_root=trust_root, displayname=displayname, |
| 639 | - description=description, logo=logo, |
| 640 | - _allowed_sreg=allowed_sreg, creation_rationale=creation_rationale, |
| 641 | - can_query_any_team=can_query_any_team, |
| 642 | - auto_authorize=auto_authorize) |
| 643 | - |
| 644 | - def get(self, id): |
| 645 | - """See `IOpenIDRPConfigSet`""" |
| 646 | - try: |
| 647 | - return OpenIDRPConfig.get(id) |
| 648 | - except SQLObjectNotFound: |
| 649 | - return None |
| 650 | - |
| 651 | - def getAll(self): |
| 652 | - """See `IOpenIDRPConfigSet`""" |
| 653 | - return OpenIDRPConfig.select(orderBy=['displayname', 'trust_root']) |
| 654 | - |
| 655 | - def getByTrustRoot(self, trust_root): |
| 656 | - """See `IOpenIDRPConfigSet`""" |
| 657 | - trust_root = self._normalizeTrustRoot(trust_root) |
| 658 | - # XXX: BradCrittenden 2008-09-26 bug=274774: Until the database is |
| 659 | - # updated to normalize existing data the query must look for |
| 660 | - # trust_roots that end in '/' and those that do not. |
| 661 | - return IStore(OpenIDRPConfig).find( |
| 662 | - OpenIDRPConfig, |
| 663 | - Or(OpenIDRPConfig.trust_root==trust_root, |
| 664 | - OpenIDRPConfig.trust_root==trust_root[:-1])).one() |
| 665 | - |
| 666 | - |
| 667 | |
| 668 | === removed directory 'lib/lp/services/openid/stories' |
| 669 | === removed file 'lib/lp/services/openid/stories/__init__.py' |
| 670 | === removed file 'lib/lp/services/openid/stories/rpconfig-admin.txt' |
| 671 | --- lib/lp/services/openid/stories/rpconfig-admin.txt 2009-07-15 15:39:49 +0000 |
| 672 | +++ lib/lp/services/openid/stories/rpconfig-admin.txt 1970-01-01 00:00:00 +0000 |
| 673 | @@ -1,190 +0,0 @@ |
| 674 | -= Managing OpenID Relying Party Configurations = |
| 675 | - |
| 676 | -While Launchpad can act as an OpenID Provider for any Relying Party, |
| 677 | -it can provide a better user experience for RPs that it knows about, |
| 678 | -including: |
| 679 | - |
| 680 | - * A human readable name for the RP. |
| 681 | - * A logo for the RP to display on the login page. |
| 682 | - * Some descriptive text indicating why the user should authenticate |
| 683 | - to the RP. |
| 684 | - * A creation rationale for new accounts created as part of the login |
| 685 | - process for this RP. |
| 686 | - |
| 687 | -The pages used to view and edit these configurations are only visible |
| 688 | -to Launchpad administrators: |
| 689 | - |
| 690 | - >>> user_browser.open('http://launchpad.dev/+rpconfig') |
| 691 | - Traceback (most recent call last): |
| 692 | - ... |
| 693 | - Unauthorized: ... |
| 694 | - >>> admin_browser.open('http://launchpad.dev/+rpconfig') |
| 695 | - >>> print admin_browser.title |
| 696 | - OpenID Relying Party Configurations |
| 697 | - |
| 698 | - |
| 699 | -== Adding RP Configurations == |
| 700 | - |
| 701 | -We can add new RP configurations from this page: |
| 702 | - |
| 703 | - >>> admin_browser.getLink('Add an RP config').click() |
| 704 | - >>> print admin_browser.title |
| 705 | - Add an OpenID Relying Party Configuration |
| 706 | - |
| 707 | - >>> import os |
| 708 | - >>> from canonical.config import config |
| 709 | - >>> logo_file = os.path.join( |
| 710 | - ... config.root, 'lib/canonical/launchpad/images/nyet-logo.png') |
| 711 | - |
| 712 | - >>> admin_browser.getControl('Trust Root').value = 'http://example.com/' |
| 713 | - >>> admin_browser.getControl('Display Name').value = 'Example RP' |
| 714 | - >>> admin_browser.getControl('Description').value = 'example description' |
| 715 | - >>> admin_browser.getControl(name='field.logo.action').value = ['change'] |
| 716 | - >>> admin_browser.getControl(name='field.logo.image').add_file( |
| 717 | - ... open(logo_file), 'image/png', 'logo.png') |
| 718 | - >>> admin_browser.getControl('Full name').click() |
| 719 | - >>> admin_browser.getControl('Email address').click() |
| 720 | - >>> admin_browser.getControl('Automatically authorize requests').click() |
| 721 | - >>> admin_browser.getControl('Create').click() |
| 722 | - >>> print admin_browser.title |
| 723 | - OpenID Relying Party Configurations |
| 724 | - |
| 725 | -The new RP configuration page is now included in the list: |
| 726 | - |
| 727 | - >>> print admin_browser.contents |
| 728 | - <... |
| 729 | - <td><a href="...">Example RP</a></td> |
| 730 | - <td>http://example.com/</td> |
| 731 | - ... |
| 732 | - |
| 733 | -The RP config contains all the information we'd expect: |
| 734 | - |
| 735 | - >>> from zope.component import getUtility |
| 736 | - >>> from canonical.launchpad.ftests import ANONYMOUS, login, logout |
| 737 | - >>> from lp.services.openid.interfaces.openidrpconfig import ( |
| 738 | - ... IOpenIDRPConfigSet) |
| 739 | - |
| 740 | - >>> login(ANONYMOUS) |
| 741 | - >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 742 | - ... 'http://example.com/') |
| 743 | - >>> print rpconfig.displayname |
| 744 | - Example RP |
| 745 | - >>> print rpconfig.description |
| 746 | - example description |
| 747 | - >>> print rpconfig.logo.filename |
| 748 | - logo.png |
| 749 | - >>> print rpconfig.allowed_sreg |
| 750 | - [u'email', u'fullname'] |
| 751 | - >>> print rpconfig.creation_rationale.name |
| 752 | - OWNER_CREATED_UNKNOWN_TRUSTROOT |
| 753 | - >>> print rpconfig.auto_authorize |
| 754 | - True |
| 755 | - >>> logout() |
| 756 | - |
| 757 | -The trust_root will have a trailing slash appended even if the user |
| 758 | -does not specify one. |
| 759 | - |
| 760 | - >>> admin_browser.open('http://launchpad.dev/+rpconfig') |
| 761 | - >>> admin_browser.getLink('Add an RP config').click() |
| 762 | - >>> admin_browser.getControl('Trust Root').value = 'http://example-two.com' |
| 763 | - >>> admin_browser.getControl('Display Name').value = 'Example Two RP' |
| 764 | - >>> admin_browser.getControl('Description').value = 'example description' |
| 765 | - >>> admin_browser.getControl('Create').click() |
| 766 | - |
| 767 | -The new RP configuration page is now included in the list, with the |
| 768 | -trailing slash in the trust root: |
| 769 | - |
| 770 | - >>> print admin_browser.contents |
| 771 | - <... |
| 772 | - <td><a href="...">Example Two RP</a></td> |
| 773 | - <td>http://example-two.com/</td> |
| 774 | - ... |
| 775 | - |
| 776 | - |
| 777 | -== Editing RP Configurations == |
| 778 | - |
| 779 | -We can also edit existing RP configurations: |
| 780 | - |
| 781 | - >>> admin_browser.getLink('Example RP').click() |
| 782 | - >>> print admin_browser.title |
| 783 | - Edit Relying Party Configuration for Example RP |
| 784 | - |
| 785 | - >>> admin_browser.getControl('Description').value = 'new description' |
| 786 | - >>> admin_browser.getControl('Launchpad ID').click() |
| 787 | - >>> admin_browser.getControl('Automatically authorize requests').click() |
| 788 | - >>> admin_browser.getControl('Save').click() |
| 789 | - >>> print admin_browser.title |
| 790 | - OpenID Relying Party Configurations |
| 791 | - |
| 792 | -The changes have now been made to the RP configuration: |
| 793 | - |
| 794 | - >>> login(ANONYMOUS) |
| 795 | - >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 796 | - ... 'http://example.com/') |
| 797 | - >>> print rpconfig.description |
| 798 | - new description |
| 799 | - >>> print rpconfig.allowed_sreg |
| 800 | - [u'email', u'fullname', u'nickname'] |
| 801 | - >>> print rpconfig.auto_authorize |
| 802 | - False |
| 803 | - >>> logout() |
| 804 | - |
| 805 | - |
| 806 | -== Only One RP Configuration Per Trust Root == |
| 807 | - |
| 808 | -There can only be one RP configuration per trust root. Trying to |
| 809 | -create a second configuration fails: |
| 810 | - |
| 811 | - >>> admin_browser.getLink('Add an RP config').click() |
| 812 | - >>> admin_browser.getControl('Trust Root').value = 'http://example.com/' |
| 813 | - >>> admin_browser.getControl('Display Name').value = 'Second RP' |
| 814 | - >>> admin_browser.getControl('Description').value = 'description' |
| 815 | - >>> admin_browser.getControl('Create').click() |
| 816 | - >>> print admin_browser.title |
| 817 | - Add an OpenID Relying Party Configuration |
| 818 | - |
| 819 | - >>> for error in find_tags_by_class(admin_browser.contents, 'message'): |
| 820 | - ... print extract_text(error) |
| 821 | - There is 1 error. |
| 822 | - http://example.com/ is already in use for another Relying Party. |
| 823 | - |
| 824 | -Changing the trust root value fixes the problem: |
| 825 | - |
| 826 | - >>> admin_browser.getControl('Trust Root').value = 'http://example.net/' |
| 827 | - >>> admin_browser.getControl('Create').click() |
| 828 | - >>> print admin_browser.title |
| 829 | - OpenID Relying Party Configurations |
| 830 | - |
| 831 | -Similarly, we can't change the trust root of a configuration to |
| 832 | -conflict with another configuration: |
| 833 | - |
| 834 | - >>> admin_browser.getLink('Second RP').click() |
| 835 | - >>> admin_browser.getControl('Trust Root').value = 'http://example.com/' |
| 836 | - >>> admin_browser.getControl('Save').click() |
| 837 | - >>> print admin_browser.title |
| 838 | - Edit Relying Party Configuration for Second RP |
| 839 | - |
| 840 | - >>> for error in find_tags_by_class(admin_browser.contents, 'message'): |
| 841 | - ... print extract_text(error) |
| 842 | - There is 1 error. |
| 843 | - http://example.com/ is already in use for another Relying Party. |
| 844 | - |
| 845 | - |
| 846 | -== Deleting RP Configurations == |
| 847 | - |
| 848 | -RP configurations can be deleted from the edit form: |
| 849 | - |
| 850 | - >>> admin_browser.open('http://launchpad.dev/+rpconfig') |
| 851 | - >>> admin_browser.getLink('Example RP').click() |
| 852 | - >>> admin_browser.getControl('Remove').click() |
| 853 | - >>> print admin_browser.title |
| 854 | - OpenID Relying Party Configurations |
| 855 | - |
| 856 | -The RP configuration has now been removed: |
| 857 | - |
| 858 | - >>> login(ANONYMOUS) |
| 859 | - >>> rpconfig = getUtility(IOpenIDRPConfigSet).getByTrustRoot( |
| 860 | - ... 'http://example.com/') |
| 861 | - >>> print rpconfig |
| 862 | - None |
| 863 | - >>> logout() |
| 864 | |
| 865 | === removed file 'lib/lp/services/openid/templates/openidrpconfig-add.pt' |
| 866 | --- lib/lp/services/openid/templates/openidrpconfig-add.pt 2009-11-23 03:10:04 +0000 |
| 867 | +++ lib/lp/services/openid/templates/openidrpconfig-add.pt 1970-01-01 00:00:00 +0000 |
| 868 | @@ -1,16 +0,0 @@ |
| 869 | -<html |
| 870 | - xmlns="http://www.w3.org/1999/xhtml" |
| 871 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
| 872 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
| 873 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
| 874 | - metal:use-macro="view/macro:page/main_only" |
| 875 | - i18n:domain="launchpad"> |
| 876 | - |
| 877 | -<body> |
| 878 | - |
| 879 | -<div metal:fill-slot="main"> |
| 880 | - <div metal:use-macro="context/@@launchpad_form/form" /> |
| 881 | -</div> |
| 882 | - |
| 883 | -</body> |
| 884 | -</html> |
| 885 | |
| 886 | === removed file 'lib/lp/services/openid/templates/openidrpconfig-edit.pt' |
| 887 | --- lib/lp/services/openid/templates/openidrpconfig-edit.pt 2009-11-23 03:10:04 +0000 |
| 888 | +++ lib/lp/services/openid/templates/openidrpconfig-edit.pt 1970-01-01 00:00:00 +0000 |
| 889 | @@ -1,16 +0,0 @@ |
| 890 | -<html |
| 891 | - xmlns="http://www.w3.org/1999/xhtml" |
| 892 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
| 893 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
| 894 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
| 895 | - metal:use-macro="view/macro:page/main_only" |
| 896 | - i18n:domain="launchpad"> |
| 897 | - |
| 898 | -<body> |
| 899 | - |
| 900 | -<div metal:fill-slot="main"> |
| 901 | - <div metal:use-macro="context/@@launchpad_form/form" /> |
| 902 | -</div> |
| 903 | - |
| 904 | -</body> |
| 905 | -</html> |
| 906 | |
| 907 | === removed file 'lib/lp/services/openid/templates/openidrpconfigset-index.pt' |
| 908 | --- lib/lp/services/openid/templates/openidrpconfigset-index.pt 2009-11-23 16:14:39 +0000 |
| 909 | +++ lib/lp/services/openid/templates/openidrpconfigset-index.pt 1970-01-01 00:00:00 +0000 |
| 910 | @@ -1,33 +0,0 @@ |
| 911 | -<html xml:lang="en" lang="en" |
| 912 | - xmlns="http://www.w3.org/1999/xhtml" |
| 913 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
| 914 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
| 915 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
| 916 | - metal:use-macro="view/macro:page/main_only" |
| 917 | - i18n:domain="launchpad"> |
| 918 | - |
| 919 | - <body> |
| 920 | - <div metal:fill-slot="main"> |
| 921 | - <table class="listing" tal:condition="context/getAll"> |
| 922 | - <thead> |
| 923 | - <tr> |
| 924 | - <th>Relying Party</th> |
| 925 | - <th>Trust Root</th> |
| 926 | - </tr> |
| 927 | - </thead> |
| 928 | - <tbody> |
| 929 | - <tr tal:repeat="rpconfig context/getAll"> |
| 930 | - <td><a tal:attributes="href rpconfig/fmt:url" |
| 931 | - tal:content="rpconfig/displayname">RP Config</a></td> |
| 932 | - <td tal:content="rpconfig/trust_root">http://blah</td> |
| 933 | - </tr> |
| 934 | - </tbody> |
| 935 | - </table> |
| 936 | - |
| 937 | - <div> |
| 938 | - <a tal:attributes="href string:${context/fmt:url}/+add"> |
| 939 | - Add an RP config</a> |
| 940 | - </div> |
| 941 | - </div> |
| 942 | - </body> |
| 943 | -</html> |
