launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06364
[Merge] lp:~wgrant/launchpad/sso-xmlrpc into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/sso-xmlrpc into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/sso-xmlrpc/+merge/92937
SSO currently grabs a person's name, timezone and team memberships from a few mirrored LP DB tables. This means the two databases must be part of a single Slony cluster, causing awkward deployment constraints.
After discussions with ISD, we're switching SSO to a private XML-RPC API provided by LP. This is that API. SSO will make a request with the OpenID identifier fragment, and get back the name, timezone and public and private team memberships.
--
https://code.launchpad.net/~wgrant/launchpad/sso-xmlrpc/+merge/92937
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/sso-xmlrpc into lp:launchpad.
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2012-02-14 00:20:34 +0000
+++ lib/lp/registry/configure.zcml 2012-02-14 10:09:49 +0000
@@ -1108,6 +1108,16 @@
interface="lp.registry.interfaces.person.ISoftwareCenterAgentAPI"
class="lp.registry.xmlrpc.softwarecenteragent.SoftwareCenterAgentAPI"
permission="zope.Public"/>
+ <securedutility
+ class="lp.registry.xmlrpc.canonicalsso.CanonicalSSOApplication"
+ provides="lp.registry.interfaces.person.ICanonicalSSOApplication">
+ <allow interface="lp.registry.interfaces.person.ICanonicalSSOApplication" />
+ </securedutility>
+ <xmlrpc:view
+ for="lp.registry.interfaces.person.ICanonicalSSOApplication"
+ interface="lp.registry.interfaces.person.ICanonicalSSOAPI"
+ class="lp.registry.xmlrpc.canonicalsso.CanonicalSSOAPI"
+ permission="zope.Public"/>
<!-- Helper page for held message approval -->
=== modified file 'lib/lp/registry/interfaces/person.py'
--- lib/lp/registry/interfaces/person.py 2012-02-14 00:20:34 +0000
+++ lib/lp/registry/interfaces/person.py 2012-02-14 10:09:49 +0000
@@ -11,6 +11,8 @@
'CLOSED_TEAM_POLICY',
'IAdminPeopleMergeSchema',
'IAdminTeamMergeSchema',
+ 'ICanonicalSSOAPI',
+ 'ICanonicalSSOApplication',
'IHasStanding',
'IObjectReassignment',
'IPerson',
@@ -18,11 +20,11 @@
'IPersonPublic',
'IPersonSet',
'IPersonSettings',
- 'ISoftwareCenterAgentAPI',
- 'ISoftwareCenterAgentApplication',
'IPersonLimitedView',
'IPersonViewRestricted',
'IRequestPeopleMerge',
+ 'ISoftwareCenterAgentAPI',
+ 'ISoftwareCenterAgentApplication',
'ITeam',
'ITeamContactAddressForm',
'ITeamCreation',
@@ -2550,6 +2552,17 @@
"""
+class ICanonicalSSOApplication(ILaunchpadApplication):
+ """XMLRPC application root for ICanonicalSSOAPI."""
+
+
+class ICanonicalSSOAPI(Interface):
+ """XMLRPC API used by the software center agent."""
+
+ def getPersonDetailsByOpenIDIdentifier(openid_identifier):
+ """Get the details of an LP person based on an OpenID identifier."""
+
+
class ISoftwareCenterAgentApplication(ILaunchpadApplication):
"""XMLRPC application root for ISoftwareCenterAgentAPI."""
=== modified file 'lib/lp/registry/tests/test_xmlrpc.py'
--- lib/lp/registry/tests/test_xmlrpc.py 2012-01-20 06:58:13 +0000
+++ lib/lp/registry/tests/test_xmlrpc.py 2012-02-14 10:09:49 +0000
@@ -15,19 +15,20 @@
ISoftwareCenterAgentAPI,
ISoftwareCenterAgentApplication,
PersonCreationRationale,
+ PersonVisibility,
)
from lp.registry.xmlrpc.softwarecenteragent import SoftwareCenterAgentAPI
from lp.services.identity.interfaces.account import AccountStatus
from lp.services.webapp.servers import LaunchpadTestRequest
from lp.testing import TestCaseWithFactory
-from lp.testing.layers import LaunchpadFunctionalLayer
+from lp.testing.layers import DatabaseFunctionalLayer
from lp.testing.xmlrpc import XMLRPCTestTransport
from lp.xmlrpc.interfaces import IPrivateApplication
class TestSoftwareCenterAgentAPI(TestCaseWithFactory):
- layer = LaunchpadFunctionalLayer
+ layer = DatabaseFunctionalLayer
def setUp(self):
super(TestSoftwareCenterAgentAPI, self).setUp()
@@ -61,7 +62,7 @@
class TestSoftwareCenterAgentApplication(TestCaseWithFactory):
- layer = LaunchpadFunctionalLayer
+ layer = DatabaseFunctionalLayer
def setUp(self):
super(TestSoftwareCenterAgentApplication, self).setUp()
@@ -129,14 +130,54 @@
'http://test@xxxxxxxxxxxxx:test@'
'xmlrpc.launchpad.dev/softwarecenteragent',
transport=XMLRPCTestTransport())
-
- # assertRaises doesn't let us check the type of Fault.
- protocol_error_raised = False
- try:
- public_rpc_proxy.getOrCreateSoftwareCenterCustomer(
- 'openid-ident', 'a@xxxxx', 'Joe Blogs')
- except xmlrpclib.ProtocolError, e:
- protocol_error_raised = True
- self.assertEqual(404, e.errcode)
-
- self.assertTrue(protocol_error_raised)
+ e = self.assertRaises(
+ xmlrpclib.ProtocolError,
+ public_rpc_proxy.getOrCreateSoftwareCenterCustomer,
+ 'openid-ident', 'a@xxxxx', 'Joe Blogs')
+ self.assertEqual(404, e.errcode)
+
+
+class TestCanonicalSSOApplication(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def setUp(self):
+ super(TestCanonicalSSOApplication, self).setUp()
+ self.rpc_proxy = xmlrpclib.ServerProxy(
+ 'http://xmlrpc-private.launchpad.dev:8087/canonicalsso',
+ transport=XMLRPCTestTransport())
+
+ def test_getPersonDetailsByOpenIDIdentifier(self):
+ person = self.factory.makePerson(time_zone='Australia/Melbourne')
+ self.factory.makeTeam(
+ name='pubteam', members=[person],
+ visibility=PersonVisibility.PUBLIC)
+ self.factory.makeTeam(
+ name='privteam', members=[person],
+ visibility=PersonVisibility.PRIVATE)
+ openid_identifier = removeSecurityProxy(
+ person.account).openid_identifiers.any().identifier
+ result = self.rpc_proxy.getPersonDetailsByOpenIDIdentifier(
+ openid_identifier)
+ self.assertEqual(
+ dict(
+ name=person.name,
+ time_zone=person.location.time_zone,
+ teams={'pubteam': False, 'privteam': True}),
+ result)
+
+ def test_not_available_on_public_api(self):
+ # The person set api is not available on the public xmlrpc
+ # service.
+ person = self.factory.makePerson()
+ openid_identifier = removeSecurityProxy(
+ person.account).openid_identifiers.any().identifier
+ public_rpc_proxy = xmlrpclib.ServerProxy(
+ 'http://test@xxxxxxxxxxxxx:test@'
+ 'xmlrpc.launchpad.dev/canonicalsso',
+ transport=XMLRPCTestTransport())
+ e = self.assertRaises(
+ xmlrpclib.ProtocolError,
+ public_rpc_proxy.getPersonDetailsByOpenIDIdentifier,
+ openid_identifier)
+ self.assertEqual(404, e.errcode)
=== added file 'lib/lp/registry/xmlrpc/canonicalsso.py'
--- lib/lp/registry/xmlrpc/canonicalsso.py 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/xmlrpc/canonicalsso.py 2012-02-14 10:09:49 +0000
@@ -0,0 +1,56 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""XMLRPC APIs for Canonical SSO to retrieve person details."""
+
+__metaclass__ = type
+__all__ = [
+ 'CanonicalSSOAPI',
+ 'CanonicalSSOApplication',
+ ]
+
+
+from zope.component import getUtility
+from zope.interface import implements
+from zope.security.proxy import removeSecurityProxy
+
+from lp.registry.interfaces.person import (
+ ICanonicalSSOAPI,
+ ICanonicalSSOApplication,
+ IPerson,
+ )
+from lp.services.identity.interfaces.account import IAccountSet
+from lp.services.webapp import LaunchpadXMLRPCView
+
+
+class CanonicalSSOAPI(LaunchpadXMLRPCView):
+ """See `ICanonicalSSOAPI`."""
+
+ implements(ICanonicalSSOAPI)
+
+ def getPersonDetailsByOpenIDIdentifier(self, openid_identifier):
+ try:
+ account = getUtility(IAccountSet).getByOpenIDIdentifier(
+ openid_identifier.decode('ascii'))
+ except LookupError:
+ return None
+ person = IPerson(account, None)
+ if person is None:
+ return
+
+ time_zone = person.location and person.location.time_zone
+ team_names = dict(
+ (removeSecurityProxy(t).name, t.private)
+ for t in person.teams_participated_in)
+ return {
+ 'name': person.name,
+ 'time_zone': time_zone,
+ 'teams': team_names,
+ }
+
+
+class CanonicalSSOApplication:
+ """Canonical SSO end-point."""
+ implements(ICanonicalSSOApplication)
+
+ title = "Canonical SSO API"
=== modified file 'lib/lp/xmlrpc/application.py'
--- lib/lp/xmlrpc/application.py 2012-01-01 02:58:52 +0000
+++ lib/lp/xmlrpc/application.py 2012-02-14 10:09:49 +0000
@@ -27,7 +27,10 @@
ICodeImportSchedulerApplication,
)
from lp.registry.interfaces.mailinglist import IMailingListApplication
-from lp.registry.interfaces.person import ISoftwareCenterAgentApplication
+from lp.registry.interfaces.person import (
+ ICanonicalSSOApplication,
+ ISoftwareCenterAgentApplication,
+ )
from lp.services.authserver.interfaces import IAuthServerApplication
from lp.services.features.xmlrpc import IFeatureFlagApplication
from lp.services.webapp import LaunchpadXMLRPCView
@@ -70,6 +73,11 @@
return getUtility(ISoftwareCenterAgentApplication)
@property
+ def canonicalsso(self):
+ """See `IPrivateApplication`."""
+ return getUtility(ICanonicalSSOApplication)
+
+ @property
def featureflags(self):
"""See `IPrivateApplication`."""
return getUtility(IFeatureFlagApplication)
=== modified file 'lib/lp/xmlrpc/interfaces.py'
--- lib/lp/xmlrpc/interfaces.py 2011-12-24 17:49:30 +0000
+++ lib/lp/xmlrpc/interfaces.py 2012-02-14 10:09:49 +0000
@@ -30,4 +30,7 @@
softwarecenteragent = Attribute(
"""Software center agent XML-RPC end point.""")
+ canonicalsso = Attribute(
+ """Canonical SSO XML-RPC end point.""")
+
featureflags = Attribute("""Feature flag information endpoint""")