launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #19983
[Merge] lp:~thomir/launchpad/devel-gpogservice-integration into lp:launchpad
Thomi Richards has proposed merging lp:~thomir/launchpad/devel-gpogservice-integration into lp:launchpad.
Commit message:
Add a read-only feature flag for the gpg service.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~thomir/launchpad/devel-gpogservice-integration/+merge/285427
Add a read-only feature flag for the gpg service.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~thomir/launchpad/devel-gpogservice-integration into lp:launchpad.
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2016-01-26 15:47:37 +0000
+++ lib/lp/registry/browser/person.py 2016-02-09 01:44:38 +0000
@@ -205,10 +205,13 @@
from lp.registry.model.person import get_recipients
from lp.services.config import config
from lp.services.database.sqlbase import flush_database_updates
+from lp.services.features import getFeatureFlag
from lp.services.feeds.browser import FeedsMixin
from lp.services.geoip.interfaces import IRequestPreferredLanguages
from lp.services.gpg.interfaces import (
+ GPG_SERVICE_READONLY_FEATURE_FLAG,
GPGKeyNotFoundError,
+ GPGReadOnly,
IGPGHandler,
)
from lp.services.identity.interfaces.account import (
@@ -2531,14 +2534,16 @@
IGPGHandler).getURLForKeyInServer(self.fingerprint, public=True)
def form_action(self):
+ if self.request.method != "POST":
+ return ''
+ if getFeatureFlag(GPG_SERVICE_READONLY_FEATURE_FLAG):
+ raise GPGReadOnly()
permitted_actions = [
'claim_gpg',
'deactivate_gpg',
'remove_gpgtoken',
'reactivate_gpg',
]
- if self.request.method != "POST":
- return ''
action = self.request.form.get('action')
if action not in permitted_actions:
raise UnexpectedFormData("Action not permitted: %s" % action)
=== modified file 'lib/lp/registry/browser/tests/test_gpgkey.py'
--- lib/lp/registry/browser/tests/test_gpgkey.py 2012-08-20 14:33:30 +0000
+++ lib/lp/registry/browser/tests/test_gpgkey.py 2016-02-09 01:44:38 +0000
@@ -5,6 +5,16 @@
__metaclass__ = type
+from testtools.matchers import (
+ Not,
+ Raises,
+ )
+
+from lp.services.features.testing import FeatureFixture
+from lp.services.gpg.interfaces import (
+ GPGReadOnly,
+ GPG_SERVICE_READONLY_FEATURE_FLAG,
+ )
from lp.services.webapp import canonical_url
from lp.testing import (
login_person,
@@ -42,3 +52,23 @@
expected_url = (
'%s/+editpgpkeys/+login?reauth=1' % canonical_url(person))
self.assertEqual(expected_url, response.getHeader('location'))
+
+ def test_gpgkeys_POST_readonly_with_feature_flag_set(self):
+ self.useFixture(FeatureFixture({
+ GPG_SERVICE_READONLY_FEATURE_FLAG: True,
+ }))
+ person = self.factory.makePerson()
+ login_person(person)
+ view = create_initialized_view(person, "+editpgpkeys", principal=person,
+ method='POST', have_fresh_login=True)
+ self.assertRaises(GPGReadOnly, view.render)
+
+ def test_gpgkeys_GET_readonly_with_feature_flag_set(self):
+ self.useFixture(FeatureFixture({
+ GPG_SERVICE_READONLY_FEATURE_FLAG: True,
+ }))
+ person = self.factory.makePerson()
+ login_person(person)
+ view = create_initialized_view(person, "+editpgpkeys", principal=person,
+ method='GET', have_fresh_login=True)
+ self.assertThat(view.render, Not(Raises()))
=== modified file 'lib/lp/services/gpg/interfaces.py'
--- lib/lp/services/gpg/interfaces.py 2016-01-26 15:47:37 +0000
+++ lib/lp/services/gpg/interfaces.py 2016-02-09 01:44:38 +0000
@@ -2,35 +2,54 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
+ 'GPG_SERVICE_READONLY_FEATURE_FLAG',
'GPGKeyAlgorithm',
'GPGKeyDoesNotExistOnServer',
'GPGKeyExpired',
+ 'GPGKeyNotFoundError',
'GPGKeyRevoked',
- 'GPGKeyNotFoundError',
'GPGKeyTemporarilyNotFoundError',
+ 'GPGReadOnly',
'GPGUploadFailure',
'GPGVerificationError',
'IGPGHandler',
+ 'IPymeKey',
'IPymeSignature',
- 'IPymeKey',
'IPymeUserId',
'MoreThanOneGPGKeyFound',
'SecretGPGKeyImportDetected',
+ 'valid_fingerprint',
'valid_keyid',
- 'valid_fingerprint',
]
-
+import httplib
import re
from lazr.enum import (
DBEnumeratedType,
DBItem,
)
+from lazr.restful.declarations import error_status
from zope.interface import (
Attribute,
Interface,
)
+from zope.security.interfaces import (
+ Forbidden,
+ )
+
+
+@error_status(httplib.FORBIDDEN)
+class GPGReadOnly(Forbidden):
+ """GPG Service is in read-only mode."""
+
+ def __init__(self):
+ super(GPGReadOnly, self).__init__(
+ "The GPG key storage facilities of Launchpad are currently "
+ "read-only. Please try again later.")
+
+
+GPG_SERVICE_READONLY_FEATURE_FLAG = u"gpgservice.read_only"
def valid_fingerprint(fingerprint):
=== modified file 'lib/lp/services/webapp/login.py'
--- lib/lp/services/webapp/login.py 2014-01-14 06:29:21 +0000
+++ lib/lp/services/webapp/login.py 2016-02-09 01:44:38 +0000
@@ -465,6 +465,8 @@
def isFreshLogin(request):
"""Return True if the principal login happened in the last 120 seconds."""
+ if getattr(request, 'have_fresh_login', False):
+ return True
session = ISession(request)
authdata = session['launchpad.authenticateduser']
logintime = authdata.get('logintime', None)
=== modified file 'lib/lp/services/webapp/servers.py'
--- lib/lp/services/webapp/servers.py 2016-01-26 15:14:01 +0000
+++ lib/lp/services/webapp/servers.py 2016-02-09 01:44:38 +0000
@@ -904,6 +904,11 @@
>>> request.charsets = ['utf-8']
>>> request.query_string_params == {'a': ['1'], 'b': ['2'], 'c': ['3']}
True
+
+ If have_fresh_login is set to True, views such as PersonGPGView that insist
+ on the user being recently logged in will render their contents rather than
+ redirecting to the login page.
+
"""
# These two attributes satisfy IParticipation.
@@ -911,7 +916,8 @@
interaction = None
def __init__(self, body_instream=None, environ=None, form=None,
- skin=None, outstream=None, method='GET', **kw):
+ skin=None, outstream=None, method='GET', have_fresh_login=False,
+ **kw):
super(LaunchpadTestRequest, self).__init__(
body_instream=body_instream, environ=environ, form=form,
skin=skin, outstream=outstream, REQUEST_METHOD=method, **kw)
@@ -921,6 +927,7 @@
self.features = get_relevant_feature_controller()
if self.features is None:
self.features = NullFeatureController()
+ self.have_fresh_login = have_fresh_login
@property
def uuid(self):
Follow ups