-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,6 +98,7 @@ Social backends | |
moves | ||
naszaklasa | ||
nationbuilder | ||
ngpvan_actionid | ||
odnoklassnikiru | ||
openstreetmap | ||
orbi | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
NGP VAN ActionID | ||
================ | ||
|
||
`NGP VAN`_'s ActionID_ service provides an OpenID 1.1 endpoint, which provides | ||
first name, last name, email address, and phone number. | ||
|
||
ActionID doesn't require major settings beside being defined on | ||
``AUTHENTICATION_BACKENDS`` | ||
|
||
.. code-block:: python | ||
SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( | ||
... | ||
'social.backends.ngpvan.ActionIDOpenID', | ||
... | ||
) | ||
If you want to be able to access the "phone" attribute offered by NGP VAN | ||
within ``extra_data`` you can add the following to your settings: | ||
|
||
.. code-block:: python | ||
SOCIAL_AUTH_ACTIONID_OPENID_AX_EXTRA_DATA = [ | ||
('http://openid.net/schema/contact/phone/business', 'phone') | ||
] | ||
NGP VAN offers the ability to have your domain whitelisted, which will disable | ||
the "{domain} is requesting a link to your ActionID" warning when your app | ||
attempts to login using an ActionID account. Contact | ||
`NGP VAN Developer Support`_ for more information | ||
|
||
.. _NGP VAN: http://www.ngpvan.com/ | ||
.. _ActionID: http://developers.ngpvan.com/action-id | ||
.. _NGP VAN Developer Support: http://developers.ngpvan.com/support/contact |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
""" | ||
NGP VAN's `ActionID` Provider | ||
http://developers.ngpvan.com/action-id | ||
""" | ||
from social.backends.open_id import OpenIdAuth | ||
from openid.extensions import ax | ||
|
||
|
||
class ActionIDOpenID(OpenIdAuth): | ||
""" | ||
NGP VAN's ActionID OpenID 1.1 authentication backend | ||
""" | ||
name = 'actionid-openid' | ||
URL = 'https://accounts.ngpvan.com/Home/Xrds' | ||
USERNAME_KEY = 'email' | ||
|
||
def get_ax_attributes(self): | ||
""" | ||
Return the AX attributes that ActionID responds with, as well as the | ||
user data result that it must map to. | ||
""" | ||
return [ | ||
('http://openid.net/schema/contact/internet/email', 'email'), | ||
('http://openid.net/schema/contact/phone/business', 'phone'), | ||
('http://openid.net/schema/namePerson/first', 'first_name'), | ||
('http://openid.net/schema/namePerson/last', 'last_name'), | ||
('http://openid.net/schema/namePerson', 'fullname'), | ||
] | ||
|
||
def setup_request(self, params=None): | ||
""" | ||
Setup the OpenID request | ||
Because ActionID does not advertise the availiability of AX attributes | ||
nor use standard attribute aliases, we need to setup the attributes | ||
manually instead of rely on the parent OpenIdAuth.setup_request() | ||
""" | ||
request = self.openid_request(params) | ||
|
||
fetch_request = ax.FetchRequest() | ||
fetch_request.add(ax.AttrInfo( | ||
'http://openid.net/schema/contact/internet/email', | ||
alias='ngpvanemail', | ||
required=True)) | ||
|
||
fetch_request.add(ax.AttrInfo( | ||
'http://openid.net/schema/contact/phone/business', | ||
alias='ngpvanphone', | ||
required=False)) | ||
fetch_request.add(ax.AttrInfo( | ||
'http://openid.net/schema/namePerson/first', | ||
alias='ngpvanfirstname', | ||
required=False)) | ||
fetch_request.add(ax.AttrInfo( | ||
'http://openid.net/schema/namePerson/last', | ||
alias='ngpvanlastname', | ||
required=False)) | ||
request.addExtension(fetch_request) | ||
|
||
return request |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
"""Tests for NGP VAN ActionID Backend""" | ||
import datetime | ||
|
||
from httpretty import HTTPretty | ||
|
||
from social.p3 import urlencode | ||
from social.tests.backends.open_id import OpenIdTest | ||
|
||
|
||
JANRAIN_NONCE = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') | ||
|
||
|
||
class NGPVANActionIDOpenIDTest(OpenIdTest): | ||
"""Test the NGP VAN ActionID OpenID 1.1 Backend""" | ||
backend_path = 'social.backends.ngpvan.ActionIDOpenID' | ||
expected_username = '[email protected]' | ||
discovery_body = ' '.join( | ||
[ | ||
'<?xml version="1.0" encoding="UTF-8"?>', | ||
'<xrds:XRDS', | ||
'xmlns:xrds="xri://$xrds"', | ||
'xmlns:openid="http://openid.net/xmlns/1.0"', | ||
'xmlns="xri://$xrd*($v*2.0)">', | ||
'<XRD>', | ||
'<Service priority="10">', | ||
'<Type>http://specs.openid.net/auth/2.0/signon</Type>', | ||
'<Type>http://openid.net/extensions/sreg/1.1</Type>', | ||
'<Type>http://axschema.org/contact/email</Type>', | ||
'<URI>https://accounts.ngpvan.com/OpenId/Provider</URI>', | ||
'</Service>', | ||
'<Service priority="20">', | ||
'<Type>http://openid.net/signon/1.0</Type>', | ||
'<Type>http://openid.net/extensions/sreg/1.1</Type>', | ||
'<Type>http://axschema.org/contact/email</Type>', | ||
'<URI>https://accounts.ngpvan.com/OpenId/Provider</URI>', | ||
'</Service>', | ||
'</XRD>', | ||
'</xrds:XRDS>', | ||
]) | ||
server_response = urlencode({ | ||
'openid.claimed_id': 'https://accounts.ngpvan.com/user/abcd123', | ||
'openid.identity': 'https://accounts.ngpvan.com/user/abcd123', | ||
'openid.sig': 'Midw8F/rCDwW7vMz3y+vK6rjz6s=', | ||
'openid.signed': 'claimed_id,identity,assoc_handle,op_endpoint,return_' | ||
'to,response_nonce,ns.alias3,alias3.mode,alias3.type.' | ||
'alias1,alias3.value.alias1,alias3.type.alias2,alias3' | ||
'.value.alias2,alias3.type.alias3,alias3.value.alias3' | ||
',alias3.type.alias4,alias3.value.alias4,alias3.type.' | ||
'alias5,alias3.value.alias5,alias3.type.alias6,alias3' | ||
'.value.alias6,alias3.type.alias7,alias3.value.alias7' | ||
',alias3.type.alias8,alias3.value.alias8,ns.sreg,sreg' | ||
'.fullname', | ||
'openid.assoc_handle': '{635790678917902781}{GdSyFA==}{20}', | ||
'openid.op_endpoint': 'https://accounts.ngpvan.com/OpenId/Provider', | ||
'openid.return_to': 'http://myapp.com/complete/actionid-openid/', | ||
'openid.response_nonce': JANRAIN_NONCE + 'MMgBGEre', | ||
'openid.mode': 'id_res', | ||
'openid.ns': 'http://specs.openid.net/auth/2.0', | ||
'openid.ns.alias3': 'http://openid.net/srv/ax/1.0', | ||
'openid.alias3.mode': 'fetch_response', | ||
'openid.alias3.type.alias1': 'http://openid.net/schema/contact/phone/b' | ||
'usiness', | ||
'openid.alias3.value.alias1': '+12015555555', | ||
'openid.alias3.type.alias2': 'http://openid.net/schema/contact/interne' | ||
't/email', | ||
'openid.alias3.value.alias2': '[email protected]', | ||
'openid.alias3.type.alias3': 'http://openid.net/schema/namePerson/firs' | ||
't', | ||
'openid.alias3.value.alias3': 'John', | ||
'openid.alias3.type.alias4': 'http://openid.net/schema/namePerson/las' | ||
't', | ||
'openid.alias3.value.alias4': 'Smith', | ||
'openid.alias3.type.alias5': 'http://axschema.org/namePerson/first', | ||
'openid.alias3.value.alias5': 'John', | ||
'openid.alias3.type.alias6': 'http://axschema.org/namePerson/last', | ||
'openid.alias3.value.alias6': 'Smith', | ||
'openid.alias3.type.alias7': 'http://axschema.org/namePerson', | ||
'openid.alias3.value.alias7': 'John Smith', | ||
'openid.alias3.type.alias8': 'http://openid.net/schema/namePerson', | ||
'openid.alias3.value.alias8': 'John Smith', | ||
'openid.ns.sreg': 'http://openid.net/extensions/sreg/1.1', | ||
'openid.sreg.fullname': 'John Smith', | ||
}) | ||
|
||
def setUp(self): | ||
"""Setup the test""" | ||
super(NGPVANActionIDOpenIDTest, self).setUp() | ||
|
||
# Mock out the NGP VAN endpoints | ||
HTTPretty.register_uri( | ||
HTTPretty.POST, | ||
'https://accounts.ngpvan.com/Home/Xrds', | ||
status=200, | ||
body=self.discovery_body) | ||
HTTPretty.register_uri( | ||
HTTPretty.GET, | ||
'https://accounts.ngpvan.com/user/abcd123', | ||
status=200, | ||
body=self.discovery_body) | ||
HTTPretty.register_uri( | ||
HTTPretty.GET, | ||
'https://accounts.ngpvan.com/OpenId/Provider', | ||
status=200, | ||
body=self.discovery_body) | ||
|
||
def test_login(self): | ||
"""Test the login flow using python-social-auth's built in test""" | ||
self.do_login() | ||
|
||
def test_partial_pipeline(self): | ||
"""Test the partial flow using python-social-auth's built in test""" | ||
self.do_partial_pipeline() | ||
|
||
def test_get_ax_attributes(self): | ||
"""Test that the AX attributes that NGP VAN responds with are present""" | ||
records = self.backend.get_ax_attributes() | ||
|
||
self.assertEqual( | ||
records, | ||
[ | ||
('http://openid.net/schema/contact/internet/email', 'email'), | ||
('http://openid.net/schema/contact/phone/business', 'phone'), | ||
('http://openid.net/schema/namePerson/first', 'first_name'), | ||
('http://openid.net/schema/namePerson/last', 'last_name'), | ||
('http://openid.net/schema/namePerson', 'fullname'), | ||
] | ||
) | ||
|
||
def test_setup_request(self): | ||
"""Test the setup_request functionality in the NGP VAN backend""" | ||
# We can grab the requested attributes by grabbing the HTML of the | ||
# OpenID auth form and pulling out the hidden fields | ||
_, inputs = self.get_form_data(self.backend.auth_html()) | ||
|
||
# Confirm that the only required attribute is email | ||
self.assertEqual(inputs['openid.ax.required'], 'ngpvanemail') | ||
|
||
# Confirm that the 3 optional attributes are requested "if available" | ||
self.assertIn('ngpvanphone', inputs['openid.ax.if_available']) | ||
self.assertIn('ngpvanfirstname', inputs['openid.ax.if_available']) | ||
self.assertIn('ngpvanlastname', inputs['openid.ax.if_available']) | ||
|
||
# Verify the individual attribute properties | ||
self.assertEqual( | ||
inputs['openid.ax.type.ngpvanemail'], | ||
'http://openid.net/schema/contact/internet/email') | ||
self.assertEqual( | ||
inputs['openid.ax.type.ngpvanfirstname'], | ||
'http://openid.net/schema/namePerson/first') | ||
self.assertEqual( | ||
inputs['openid.ax.type.ngpvanlastname'], | ||
'http://openid.net/schema/namePerson/last') | ||
self.assertEqual( | ||
inputs['openid.ax.type.ngpvanphone'], | ||
'http://openid.net/schema/contact/phone/business') | ||
|
||
def test_user_data(self): | ||
"""Ensure that the correct user data is being passed to create_user""" | ||
self.strategy.set_settings({ | ||
'USER_FIELDS': [ | ||
'email', | ||
'first_name', | ||
'last_name', | ||
'username', | ||
'phone', | ||
'fullname' | ||
] | ||
}) | ||
user = self.do_start() | ||
|
||
self.assertEqual(user.username, u'[email protected]') | ||
self.assertEqual(user.email, u'[email protected]') | ||
self.assertEqual(user.extra_user_fields['phone'], u'+12015555555') | ||
self.assertEqual(user.extra_user_fields['first_name'], u'John') | ||
self.assertEqual(user.extra_user_fields['last_name'], u'Smith') | ||
self.assertEqual(user.extra_user_fields['fullname'], u'John Smith') | ||
|
||
def test_extra_data_phone(self): | ||
"""Confirm that you can get a phone number via the relevant setting""" | ||
self.strategy.set_settings({ | ||
'SOCIAL_AUTH_ACTIONID_OPENID_AX_EXTRA_DATA': [ | ||
('http://openid.net/schema/contact/phone/business', 'phone') | ||
] | ||
}) | ||
user = self.do_start() | ||
self.assertEqual(user.social_user.extra_data['phone'], u'+12015555555') | ||
|
||
def test_association_uid(self): | ||
"""Test that the correct association uid is stored in the database""" | ||
user = self.do_start() | ||
self.assertEqual( | ||
user.social_user.uid, | ||
'https://accounts.ngpvan.com/user/abcd123') |