From e3006fff2f71787e9879e2f88e57dc9b935b7782 Mon Sep 17 00:00:00 2001 From: Denis Costa Date: Tue, 25 Oct 2016 12:16:23 -0200 Subject: Adds real authentication We also did some refactoring in order to have things working. #795 --- service/pixelated/authentication.py | 36 ++++++++++--------- service/pixelated/config/leap.py | 13 ++++++- .../test/support/integration/app_test_client.py | 3 +- .../test/support/integration/multi_user_client.py | 2 +- .../test_smtp_client_certificate.py | 2 +- service/test/unit/test_authentication.py | 42 +++++++++++++++++----- 6 files changed, 70 insertions(+), 28 deletions(-) (limited to 'service') diff --git a/service/pixelated/authentication.py b/service/pixelated/authentication.py index c9961476..a8326fb9 100644 --- a/service/pixelated/authentication.py +++ b/service/pixelated/authentication.py @@ -1,29 +1,33 @@ import re +from pixelated.config.leap import authenticate +from leap.bitmask.bonafide._srp import SRPAuthError - -class Authentication(object): - def __init__(self, username, token, uuid, session_id, user_attributes): - self.username = username - self.token = token - self.uuid = uuid - self.session_id = session_id - self._user_attributes = user_attributes - - def is_admin(self): - return self._user_attributes.get('is_admin', False) +from twisted.cred.error import UnauthorizedLogin +from twisted.internet.defer import inlineCallbacks class Authenticator(object): - def __init__(self, domain): - self.domain = domain + def __init__(self, leap_provider): + self._leap_provider = leap_provider + self.domain = leap_provider.server_name + @inlineCallbacks def authenticate(self, username, password): - self.username = self.validate_username(username) - self.srp_auth(username, password) + if self.validate_username(username): + yield self._srp_auth(username, password) + else: + raise UnauthorizedLogin() + + @inlineCallbacks + def _srp_auth(self, username, password): + try: + auth = yield authenticate(self._leap_provider, username, password) + except SRPAuthError: + raise UnauthorizedLogin() def validate_username(self, username): if '@' not in username: - return True + return True extracted_username = self.extract_username(username) return self.username_with_domain(extracted_username) == username diff --git a/service/pixelated/config/leap.py b/service/pixelated/config/leap.py index 5dbfe21b..b86b756e 100644 --- a/service/pixelated/config/leap.py +++ b/service/pixelated/config/leap.py @@ -13,7 +13,6 @@ from leap.bitmask.bonafide.provider import Api from pixelated.config import credentials from pixelated.config import leap_config -from pixelated.authentication import Authentication from pixelated.bitmask_libraries.certs import LeapCertificate from pixelated.bitmask_libraries.provider import LeapProvider from pixelated.config.sessions import LeapSessionFactory @@ -86,3 +85,15 @@ def authenticate(provider, user, password): def init_monkeypatches(): import pixelated.extensions.requests_urllib3 + + +class Authentication(object): + def __init__(self, username, token, uuid, session_id, user_attributes): + self.username = username + self.token = token + self.uuid = uuid + self.session_id = session_id + self._user_attributes = user_attributes + + def is_admin(self): + return self._user_attributes.get('is_admin', False) diff --git a/service/test/support/integration/app_test_client.py b/service/test/support/integration/app_test_client.py index 1be07e58..f982407e 100644 --- a/service/test/support/integration/app_test_client.py +++ b/service/test/support/integration/app_test_client.py @@ -20,6 +20,8 @@ import shutil import time import uuid import random + +from pixelated.config.leap import Authentication from tempdir import TempDir from mock import Mock @@ -40,7 +42,6 @@ from pixelated.application import UserAgentMode, set_up_protected_resources from pixelated.config.sessions import LeapSession from pixelated.config.services import Services, ServicesFactory, SingleUserServicesFactory from pixelated.config.site import PixelatedSite -from pixelated.authentication import Authentication from pixelated.adapter.mailstore import LeapMailStore from pixelated.adapter.mailstore.searchable_mailstore import SearchableMailStore diff --git a/service/test/support/integration/multi_user_client.py b/service/test/support/integration/multi_user_client.py index 3c80bf48..0257214f 100644 --- a/service/test/support/integration/multi_user_client.py +++ b/service/test/support/integration/multi_user_client.py @@ -15,13 +15,13 @@ # along with Pixelated. If not, see . from mock import patch from mockito import mock, when, any as ANY +from pixelated.config.leap import Authentication from twisted.internet import defer from pixelated.application import UserAgentMode, set_up_protected_resources from pixelated.config.services import ServicesFactory from pixelated.config.sessions import LeapSessionFactory -from pixelated.authentication import Authentication import pixelated.config.services from pixelated.resources.root_resource import RootResource from test.support.integration import AppTestClient diff --git a/service/test/unit/bitmask_libraries/test_smtp_client_certificate.py b/service/test/unit/bitmask_libraries/test_smtp_client_certificate.py index c4d0b0b7..346fd956 100644 --- a/service/test/unit/bitmask_libraries/test_smtp_client_certificate.py +++ b/service/test/unit/bitmask_libraries/test_smtp_client_certificate.py @@ -18,8 +18,8 @@ import unittest import tempdir import leap.common.certs as certs from mockito import mock, unstub, when, any as ANY +from pixelated.config.leap import Authentication -from pixelated.authentication import Authentication from pixelated.config.sessions import SmtpClientCertificate from tempfile import NamedTemporaryFile diff --git a/service/test/unit/test_authentication.py b/service/test/unit/test_authentication.py index 34138b5e..f9f98af9 100644 --- a/service/test/unit/test_authentication.py +++ b/service/test/unit/test_authentication.py @@ -1,32 +1,58 @@ +from twisted.cred.error import UnauthorizedLogin +from twisted.internet.defer import inlineCallbacks from twisted.trial import unittest +from leap.bitmask.bonafide._srp import SRPAuthError + +from mock import patch, Mock + from pixelated.authentication import Authenticator +from pixelated.bitmask_libraries.provider import LeapProvider + + +PROVIDER_JSON = { + "api_uri": "https://api.domain.org:4430", + "api_version": "1", + "ca_cert_fingerprint": "SHA256: some_stub_sha", + "ca_cert_uri": "https://domain.org/ca.crt", + "domain": "domain.org", +} class AuthenticatorTest(unittest.TestCase): - def test_authenticates_with_username_and_password(self): - self.fail() + def setUp(self): + with patch.object(LeapProvider, 'fetch_provider_json', return_value=PROVIDER_JSON): + self._leap_provider = LeapProvider('domain.org') + + @inlineCallbacks + def test_bonafide_srp_exceptions_should_raise_unauthorized_login(self): + auth = Authenticator(self._leap_provider) + mock_bonafide_session = Mock() + mock_bonafide_session.authenticate = Mock(side_effect=SRPAuthError()) + with patch('pixelated.config.leap.Session', return_value=mock_bonafide_session): + with self.assertRaises(UnauthorizedLogin): + yield auth.authenticate('username', 'password') def test_validate_username_accepts_username(self): - auth = Authenticator('domain.org') + auth = Authenticator(self._leap_provider) self.assertTrue(auth.validate_username('username')) def test_validate_username_accepts_email_address(self): - auth = Authenticator('domain.org') + auth = Authenticator(self._leap_provider) self.assertTrue(auth.validate_username('username@domain.org')) def test_validate_username_denies_other_domains(self): - auth = Authenticator('domain.org') + auth = Authenticator(self._leap_provider) self.assertFalse(auth.validate_username('username@wrongdomain.org')) def test_username_with_domain(self): - auth = Authenticator('domain.org') + auth = Authenticator(self._leap_provider) self.assertEqual('user@domain.org', auth.username_with_domain('user')) def test_extract_username_extracts_from_plain_username(self): - auth = Authenticator('domain.org') + auth = Authenticator(self._leap_provider) self.assertEqual(auth.extract_username('user'), 'user') def test_extract_username_extracts_from_email_address(self): - auth = Authenticator('domain.org') + auth = Authenticator(self._leap_provider) self.assertEqual(auth.extract_username('user@domain.org'), 'user') -- cgit v1.2.3