Merge ~silverdrake11/canonical-identity-provider:ax-verified-emails into canonical-identity-provider:master

Proposed by Kevin Nasto
Status: Merged
Approved by: Daniel Manrique
Approved revision: 5c23068c8d3ef9cd7b670c025c577e62f6ba169a
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~silverdrake11/canonical-identity-provider:ax-verified-emails
Merge into: canonical-identity-provider:master
Diff against target: 183 lines (+93/-0)
5 files modified
README (+2/-0)
src/identityprovider/const.py (+3/-0)
src/identityprovider/forms.py (+14/-0)
src/identityprovider/tests/test_forms.py (+46/-0)
src/identityprovider/tests/test_views_server.py (+28/-0)
Reviewer Review Type Date Requested Status
John Paraskevopoulos Approve
Daniel Manrique (community) Approve
Review via email: mp+419248@code.launchpad.net

Commit message

This adds an ax attribute which can be requested during login via the ax uri (alias "extra_emails"). This attribute contains a comma separated list of additional verified email addresses not including the preferred one.

This is useful to get emails associated with an ubuntu login id. In Landscape we would want to prevent using notification emails not associated with the current ubuntu login. Also tie invitations to current ubuntu login, and verify emails in one interface.

To post a comment you must log in.
Revision history for this message
Daniel Manrique (roadmr) wrote :

Looks good, a minor suggestion to simplify the _get_extra_emails method but it's optional.

review: Approve
9f3b1f2... by Kevin Nasto

insert spaces for ui separating ax emails, unicode, list comprehension, linter errors

Revision history for this message
Kevin Nasto (silverdrake11) wrote :

> Looks good, a minor suggestion to simplify the _get_extra_emails method but
> it's optional.

Thanks for the heads up I fixed it

Revision history for this message
John Paraskevopoulos (quantifics) wrote :

From what I see this MP doesn't clash with the issues (and fixes) we faced in the Python 3 transition. Those issues were related to the way python and django were validating email addresses when sending emails. So since this is for extra form fields, there's no conflict.

LGTM as well

review: Approve
5e856c0... by Kevin Nasto

Added readme instructions if common issue occurs with LXC

5c23068... by Kevin Nasto

REAME typo version

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/README b/README
index c7bf2ed..bf67ddb 100644
--- a/README
+++ b/README
@@ -65,6 +65,8 @@ you can e.g. ``git clone`` from Launchpad without problems)::
65From now on, instructions will assume you're inside the sso-xenial container,65From now on, instructions will assume you're inside the sso-xenial container,
66unless otherwise noted.66unless otherwise noted.
6767
68Important note. If you have issues with accessing the network in the LXC container and you are running 21.10 or greater as your host system. For example ``Temporary failure resolving 'archive.ubuntu.com'``. Then you are impacted by this issue https://github.com/lxc/lxd/issues/9413 Follow the instructions there to update your grub config to fix it. Otherwise use Multipass.
69
681. Get the code701. Get the code
6971
70.. note::72.. note::
diff --git a/src/identityprovider/const.py b/src/identityprovider/const.py
index 44756d0..be9e055 100644
--- a/src/identityprovider/const.py
+++ b/src/identityprovider/const.py
@@ -32,6 +32,7 @@ AX_URI_EMAIL = 'http://axschema.org/contact/email'
32AX_URI_TIMEZONE = 'http://axschema.org/timezone'32AX_URI_TIMEZONE = 'http://axschema.org/timezone'
33AX_URI_LANGUAGE = 'http://axschema.org/language/pref'33AX_URI_LANGUAGE = 'http://axschema.org/language/pref'
34AX_URI_ACCOUNT_VERIFIED = 'http://ns.login.ubuntu.com/2013/validation/account'34AX_URI_ACCOUNT_VERIFIED = 'http://ns.login.ubuntu.com/2013/validation/account'
35AX_URI_EXTRA_EMAILS = 'http://ns.login.ubuntu.com/2022/emails'
3536
36AX_DATA_FIELDS = NamespaceMap()37AX_DATA_FIELDS = NamespaceMap()
37AX_DATA_FIELDS.addAlias(AX_URI_FULL_NAME, 'fullname')38AX_DATA_FIELDS.addAlias(AX_URI_FULL_NAME, 'fullname')
@@ -40,6 +41,7 @@ AX_DATA_FIELDS.addAlias(AX_URI_EMAIL, 'email')
40AX_DATA_FIELDS.addAlias(AX_URI_TIMEZONE, 'timezone')41AX_DATA_FIELDS.addAlias(AX_URI_TIMEZONE, 'timezone')
41AX_DATA_FIELDS.addAlias(AX_URI_LANGUAGE, 'language')42AX_DATA_FIELDS.addAlias(AX_URI_LANGUAGE, 'language')
42AX_DATA_FIELDS.addAlias(AX_URI_ACCOUNT_VERIFIED, 'account_verified')43AX_DATA_FIELDS.addAlias(AX_URI_ACCOUNT_VERIFIED, 'account_verified')
44AX_DATA_FIELDS.addAlias(AX_URI_EXTRA_EMAILS, 'extra_emails')
4345
44AX_DATA_LABELS = {46AX_DATA_LABELS = {
45 'fullname': 'Full name',47 'fullname': 'Full name',
@@ -48,6 +50,7 @@ AX_DATA_LABELS = {
48 'timezone': 'Time zone',50 'timezone': 'Time zone',
49 'language': 'Preferred language',51 'language': 'Preferred language',
50 'account_verified': 'Account verified',52 'account_verified': 'Account verified',
53 'extra_emails': 'Additional emails',
51}54}
5255
53MACAROON_NS = 'http://ns.login.ubuntu.com/2016/openid-macaroon'56MACAROON_NS = 'http://ns.login.ubuntu.com/2016/openid-macaroon'
diff --git a/src/identityprovider/forms.py b/src/identityprovider/forms.py
index 61ab346..cc8c21b 100644
--- a/src/identityprovider/forms.py
+++ b/src/identityprovider/forms.py
@@ -550,6 +550,17 @@ class UserAttribsRequestForm(Form):
550 self.label_suffix = ''550 self.label_suffix = ''
551 self._init_fields(self.data)551 self._init_fields(self.data)
552552
553 def _get_extra_emails(self):
554 '''
555 Get verified emails for ax field but filter out preferred one since
556 we already have it, keeping the user facing UI clean
557 '''
558 user = self.request.user
559 preferred = user.preferredemail.email
560 verified_emails = user.verified_emails()
561 emails = [e.email for e in verified_emails if e.email != preferred]
562 return emails
563
553 def _split_and_filter_requested_attributes(self):564 def _split_and_filter_requested_attributes(self):
554 # Merge the requested attributes from sreg_request and ax_request and565 # Merge the requested attributes from sreg_request and ax_request and
555 # filter out any that we don't recognise or that aren't allowed by our566 # filter out any that we don't recognise or that aren't allowed by our
@@ -595,6 +606,9 @@ class UserAttribsRequestForm(Form):
595 else:606 else:
596 values['language'] = translation.get_language_from_request(607 values['language'] = translation.get_language_from_request(
597 self.request)608 self.request)
609 extra_emails = self._get_extra_emails()
610 if extra_emails: # Comma and space delimited for UI readability
611 values['extra_emails'] = u', '.join(extra_emails)
598 values['account_verified'] = (612 values['account_verified'] = (
599 'token_via_email' if user.is_verified else 'no')613 'token_via_email' if user.is_verified else 'no')
600 logger.debug('user attrib values = %s', str(values))614 logger.debug('user attrib values = %s', str(values))
diff --git a/src/identityprovider/tests/test_forms.py b/src/identityprovider/tests/test_forms.py
index 4bcf04c..2c03604 100644
--- a/src/identityprovider/tests/test_forms.py
+++ b/src/identityprovider/tests/test_forms.py
@@ -23,6 +23,7 @@ from openid.extensions.sreg import SRegRequest
23from identityprovider.const import (23from identityprovider.const import (
24 AX_URI_ACCOUNT_VERIFIED,24 AX_URI_ACCOUNT_VERIFIED,
25 AX_URI_EMAIL,25 AX_URI_EMAIL,
26 AX_URI_EXTRA_EMAILS,
26 AX_URI_FULL_NAME,27 AX_URI_FULL_NAME,
27 AX_URI_LANGUAGE,28 AX_URI_LANGUAGE,
28)29)
@@ -988,6 +989,51 @@ class UserAttribsRequestFormTest(SSOBaseTestCase):
988 self.assertIn('fullname', form.data_approved_for_request)989 self.assertIn('fullname', form.data_approved_for_request)
989 self.assertNotIn('email', form.data_approved_for_request)990 self.assertNotIn('email', form.data_approved_for_request)
990991
992 def test_ax_extra_emails_field(self):
993 '''
994 Basic test of the additional emails field. Test that emails show up
995 correctly in the form and preferred does not
996 '''
997 hello_email = u'helloƑ@example.com' # Test unicode char as well
998 world_email = u'world@example.com'
999 self.factory.make_email_for_account(email=hello_email,
1000 account=self.test_user)
1001 self.factory.make_email_for_account(email=world_email,
1002 account=self.test_user)
1003 self.rpconfig.allowed_user_attribs = 'email,extra_emails'
1004 ax_request = FetchRequest()
1005 ax_request.add(
1006 AttrInfo(AX_URI_EXTRA_EMAILS, alias='extra_emails', required=True))
1007 ax_request.add(
1008 AttrInfo(AX_URI_EMAIL, alias='email', required=True))
1009 form = UserAttribsRequestForm(
1010 request=self._get_request_with_post_args(), sreg_request=None,
1011 ax_request=ax_request, rpconfig=self.rpconfig)
1012 form_data = form.data_approved_for_request
1013 self.assertIn('extra_emails', form_data)
1014 self.assertIn('email', form_data)
1015 extra_emails = set(form_data['extra_emails'].split(', '))
1016 self.assertEqual(len(extra_emails), 2)
1017 self.assertIn(hello_email, extra_emails)
1018 self.assertIn(world_email, extra_emails)
1019
1020 def test_ax_extra_emails_field_empty(self):
1021 '''
1022 Test that field does not show up if there are no extra emails
1023 '''
1024 self.rpconfig.allowed_user_attribs = 'email,extra_emails'
1025 ax_request = FetchRequest()
1026 ax_request.add(
1027 AttrInfo(AX_URI_EXTRA_EMAILS, alias='extra_emails', required=True))
1028 ax_request.add(
1029 AttrInfo(AX_URI_EMAIL, alias='email', required=True))
1030 form = UserAttribsRequestForm(
1031 request=self._get_request_with_post_args(), sreg_request=None,
1032 ax_request=ax_request, rpconfig=self.rpconfig)
1033 form_data = form.data_approved_for_request
1034 self.assertNotIn('extra_emails', form_data)
1035 self.assertIn('email', form_data)
1036
991 def test_ax_required_fields_for_trusted_site(self):1037 def test_ax_required_fields_for_trusted_site(self):
992 """The server should always return values for required fields to1038 """The server should always return values for required fields to
993 trusted sites, regardless of the state of the checkbox in the UI.1039 trusted sites, regardless of the state of the checkbox in the UI.
diff --git a/src/identityprovider/tests/test_views_server.py b/src/identityprovider/tests/test_views_server.py
index 29a8b5a..3b01834 100644
--- a/src/identityprovider/tests/test_views_server.py
+++ b/src/identityprovider/tests/test_views_server.py
@@ -44,6 +44,7 @@ from identityprovider.const import (
44 AX_DATA_FIELDS,44 AX_DATA_FIELDS,
45 AX_URI_ACCOUNT_VERIFIED,45 AX_URI_ACCOUNT_VERIFIED,
46 AX_URI_EMAIL,46 AX_URI_EMAIL,
47 AX_URI_EXTRA_EMAILS,
47 AX_URI_FULL_NAME,48 AX_URI_FULL_NAME,
48 AX_URI_LANGUAGE,49 AX_URI_LANGUAGE,
49 MACAROON_NS,50 MACAROON_NS,
@@ -1021,6 +1022,33 @@ class DecideTestCase(DecideBaseTestCase):
1021 self.assertContains(response, "Email address")1022 self.assertContains(response, "Email address")
1022 self.assertContains(response, "Account verified")1023 self.assertContains(response, "Account verified")
10231024
1025 def test_list_of_details_extra_emails_present(self):
1026 '''
1027 Ensure that the extra emails field gets displayed correctly
1028 '''
1029 self.factory.make_email_for_account(email="hello@world.com",
1030 account=self.account)
1031
1032 # create a trusted rpconfig
1033 rpconfig = OpenIDRPConfig(
1034 trust_root='http://localhost/',
1035 allowed_user_attribs='email,extra_emails',
1036 description="Some description",
1037 )
1038 rpconfig.save()
1039 param_overrides = {
1040 'openid.ns.ax': AXMessage.ns_uri,
1041 'openid.ax.mode': FetchRequest.mode,
1042 'openid.ax.type.extra_emails': AX_URI_EXTRA_EMAILS,
1043 'openid.ax.type.email': AX_URI_EMAIL,
1044 'openid.ax.required': 'email,extra_emails',
1045 }
1046 self._prepare_openid_token(param_overrides=param_overrides)
1047 response = self.client.get('/%s/+decide' % self.token)
1048 self.assertContains(response, "Additional emails")
1049 self.assertContains(response, "Email address")
1050 self.assertContains(response, "hello@world.com")
1051
1024 def _test_state_of_checkboxes_and_data_formats(1052 def _test_state_of_checkboxes_and_data_formats(
1025 self, dom, field, label=None, value=None, required=False,1053 self, dom, field, label=None, value=None, required=False,
1026 disabled=False, checked=False):1054 disabled=False, checked=False):

Subscribers

People subscribed via source and target branches