summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorBruno Wagner Gonçalves <bwagner@riseup.net>2015-05-04 14:22:33 -0300
committerBruno Wagner Gonçalves <bwagner@riseup.net>2015-05-04 14:22:33 -0300
commita28d2b333261d788c44d1835dda4d86427ab7728 (patch)
treee4cdd206d838b9ea9dbb684676f3254a00bc4c39 /service
parent4fe2aebde4a8bafcb2937bed4c9861f67230cb9b (diff)
parent30fe9e6c31ed8d5d0ee76c13e3344e67e26f1479 (diff)
Merge pull request #389 from pixelated-project/srp_changes
SRP changes to support LEAP 0.7
Diffstat (limited to 'service')
-rw-r--r--service/pixelated/bitmask_libraries/auth.py42
-rw-r--r--service/pixelated/bitmask_libraries/leap_srp.py147
-rw-r--r--service/pixelated/bitmask_libraries/nicknym.py10
-rw-r--r--service/pixelated/bitmask_libraries/provider.py6
-rw-r--r--service/pixelated/bitmask_libraries/register.py5
-rw-r--r--service/pixelated/bitmask_libraries/session.py59
-rw-r--r--service/pixelated/bitmask_libraries/smtp.py9
-rw-r--r--service/pixelated/bitmask_libraries/soledad.py19
-rw-r--r--service/pixelated/config/app_factory.py5
-rw-r--r--service/pixelated/config/register.py3
-rw-r--r--service/setup.py1
-rw-r--r--service/test/unit/bitmask_libraries/test_abstract_leap.py12
-rw-r--r--service/test/unit/bitmask_libraries/test_leap_srp.py157
-rw-r--r--service/test/unit/bitmask_libraries/test_nicknym.py18
-rw-r--r--service/test/unit/bitmask_libraries/test_session.py2
-rw-r--r--service/test/unit/bitmask_libraries/test_smtp.py9
-rw-r--r--service/test/unit/bitmask_libraries/test_soledad.py12
17 files changed, 90 insertions, 426 deletions
diff --git a/service/pixelated/bitmask_libraries/auth.py b/service/pixelated/bitmask_libraries/auth.py
deleted file mode 100644
index 9a2fdcb2..00000000
--- a/service/pixelated/bitmask_libraries/auth.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Copyright (c) 2014 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-from .leap_srp import LeapSecureRemotePassword
-from .certs import which_api_CA_bundle
-
-USE_PASSWORD = None
-
-
-class LeapCredentials(object):
- def __init__(self, user_name, password, db_passphrase=USE_PASSWORD):
- self.user_name = user_name
- self.password = password
- self.db_passphrase = db_passphrase if db_passphrase is not None else password
-
-
-class LeapAuthenticator(object):
- def __init__(self, provider):
- self._provider = provider
-
- def authenticate(self, credentials):
- config = self._provider.config
- srp = LeapSecureRemotePassword(ca_bundle=which_api_CA_bundle(self._provider), timeout_in_s=config.timeout_in_s)
- srp_session = srp.authenticate(self._provider.api_uri, credentials.user_name, credentials.password)
- return srp_session
-
- def register(self, credentials):
- config = self._provider.config
- srp = LeapSecureRemotePassword(ca_bundle=which_api_CA_bundle(self._provider), timeout_in_s=config.timeout_in_s)
- srp.register(self._provider.api_uri, credentials.user_name, credentials.password)
diff --git a/service/pixelated/bitmask_libraries/leap_srp.py b/service/pixelated/bitmask_libraries/leap_srp.py
deleted file mode 100644
index 7a627c1d..00000000
--- a/service/pixelated/bitmask_libraries/leap_srp.py
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-# Copyright (c) 2014 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import binascii
-import json
-
-import requests
-from requests import Session
-from srp import User, srp, create_salted_verification_key
-from requests.exceptions import HTTPError, SSLError, Timeout
-from config import SYSTEM_CA_BUNDLE
-
-
-REGISTER_USER_LOGIN_KEY = 'user[login]'
-REGISTER_USER_VERIFIER_KEY = 'user[password_verifier]'
-REGISTER_USER_SALT_KEY = 'user[password_salt]'
-
-
-class LeapAuthException(Exception):
- def __init__(self, *args, **kwargs):
- super(LeapAuthException, self).__init__(*args, **kwargs)
-
-
-class LeapSRPSession(object):
- def __init__(self, user_name, api_server_name, uuid, token, session_id, api_version='1'):
- self.user_name = user_name
- self.api_server_name = api_server_name
- self.uuid = uuid
- self.token = token
- self.session_id = session_id
- self.api_version = api_version
-
- def __str__(self):
- return 'LeapSRPSession(%s, %s, %s, %s, %s, %s)' % (self.user_name, self.api_server_name, self.uuid, self.token, self.session_id, self.api_version)
-
-
-class LeapSecureRemotePassword(object):
- def __init__(self, hash_alg=srp.SHA256, ng_type=srp.NG_1024, ca_bundle=SYSTEM_CA_BUNDLE, timeout_in_s=15,
- leap_api_version='1'):
-
- self.hash_alg = hash_alg
- self.ng_type = ng_type
- self.timeout_in_s = timeout_in_s
- self.ca_bundle = ca_bundle
- self.leap_api_version = leap_api_version
-
- def authenticate(self, api_uri, username, password):
- session = Session()
- try:
- return self._authenticate_with_session(session, api_uri, username, password)
- except Timeout, e:
- raise LeapAuthException(e)
- finally:
- session.close()
-
- def _authenticate_with_session(self, http_session, api_uri, username, password):
- try:
- srp_user = User(username.encode('utf-8'), password.encode('utf-8'), self.hash_alg, self.ng_type)
-
- salt, B_challenge = self._begin_authentication(srp_user, http_session, api_uri)
- M2_verfication_code, leap_session = self._process_challenge(srp_user, http_session, api_uri, salt,
- B_challenge)
- self._verify_session(srp_user, M2_verfication_code)
-
- return leap_session
- except (HTTPError, SSLError), e:
- raise LeapAuthException(e)
-
- def _begin_authentication(self, user, session, api_uri):
- _, A = user.start_authentication()
-
- auth_data = {
- "login": user.get_username(),
- "A": binascii.hexlify(A)
- }
- session_url = '%s/%s/sessions' % (api_uri, self.leap_api_version)
- response = session.post(session_url, data=auth_data, verify=self.ca_bundle, timeout=self.timeout_in_s)
- response.raise_for_status()
- json_content = json.loads(response.content)
-
- salt = _safe_unhexlify(json_content.get('salt'))
- B = _safe_unhexlify(json_content.get('B'))
-
- return salt, B
-
- def _process_challenge(self, user, session, api_uri, salt, B):
- M = user.process_challenge(salt, B)
-
- auth_data = {
- "client_auth": binascii.hexlify(M)
- }
-
- auth_url = '%s/%s/sessions/%s' % (api_uri, self.leap_api_version, user.get_username())
- response = session.put(auth_url, data=auth_data, verify=self.ca_bundle, timeout=self.timeout_in_s)
- response.raise_for_status()
- auth_json = json.loads(response.content)
-
- M2 = _safe_unhexlify(auth_json.get('M2'))
- uuid = auth_json.get('id')
- token = auth_json.get('token')
- session_id = response.cookies.get('_session_id')
-
- return M2, LeapSRPSession(user.get_username(), api_uri, uuid, token, session_id)
-
- def _verify_session(self, user, M2):
- user.verify_session(M2)
- if not user.authenticated():
- raise LeapAuthException()
-
- def register(self, api_uri, username, password):
- try:
- salt, verifier = create_salted_verification_key(username, password, self.hash_alg, self.ng_type)
- return self._post_registration_data(api_uri, username, salt, verifier)
- except (HTTPError, SSLError, Timeout), e:
- raise LeapAuthException(e)
-
- def _post_registration_data(self, api_uri, username, salt, verifier):
- users_url = '%s/%s/users' % (api_uri, self.leap_api_version)
-
- user_data = {
- REGISTER_USER_LOGIN_KEY: username,
- REGISTER_USER_SALT_KEY: binascii.hexlify(salt),
- REGISTER_USER_VERIFIER_KEY: binascii.hexlify(verifier)
- }
-
- response = requests.post(users_url, data=user_data, verify=self.ca_bundle, timeout=self.timeout_in_s)
- response.raise_for_status()
- reg_json = json.loads(response.content)
-
- return reg_json['ok']
-
-
-def _safe_unhexlify(hex_str):
- return binascii.unhexlify(hex_str) \
- if (len(hex_str) % 2 == 0) else binascii.unhexlify('0' + hex_str)
diff --git a/service/pixelated/bitmask_libraries/nicknym.py b/service/pixelated/bitmask_libraries/nicknym.py
index ef846bba..bee90897 100644
--- a/service/pixelated/bitmask_libraries/nicknym.py
+++ b/service/pixelated/bitmask_libraries/nicknym.py
@@ -18,14 +18,14 @@ from .certs import which_api_CA_bundle
class NickNym(object):
- def __init__(self, provider, config, soledad_session, srp_session):
+ def __init__(self, provider, config, soledad_session, username, token, uuid):
nicknym_url = _discover_nicknym_server(provider)
- self._email = '%s@%s' % (srp_session.user_name, provider.domain)
- self.keymanager = KeyManager('%s@%s' % (srp_session.user_name, provider.domain), nicknym_url,
+ self._email = '%s@%s' % (username, provider.domain)
+ self.keymanager = KeyManager('%s@%s' % (username, provider.domain), nicknym_url,
soledad_session.soledad,
- srp_session.token, which_api_CA_bundle(provider), provider.api_uri,
+ token, which_api_CA_bundle(provider), provider.api_uri,
provider.api_version,
- srp_session.uuid, config.gpg_binary)
+ uuid, config.gpg_binary)
def generate_openpgp_key(self):
if not self._key_exists(self._email):
diff --git a/service/pixelated/bitmask_libraries/provider.py b/service/pixelated/bitmask_libraries/provider.py
index a0bf4843..1564c974 100644
--- a/service/pixelated/bitmask_libraries/provider.py
+++ b/service/pixelated/bitmask_libraries/provider.py
@@ -25,6 +25,7 @@ class LeapProvider(object):
def __init__(self, server_name, config):
self.server_name = server_name
self.config = config
+ self.local_ca_crt = '%s/ca.crt' % self.config.leap_home
self.provider_json = self.fetch_provider_json()
@@ -62,12 +63,13 @@ class LeapProvider(object):
if 'mx' not in self.services:
raise Exception
- def download_certificate_to(self, filename):
+ def download_certificate(self, filename=None):
"""
Downloads the server certificate, validates it against the provided fingerprint and stores it to file
"""
+ path = filename or self.local_ca_crt
cert = self.fetch_valid_certificate()
- with open(filename, 'w') as out:
+ with open(path, 'w') as out:
out.write(cert)
def fetch_valid_certificate(self):
diff --git a/service/pixelated/bitmask_libraries/register.py b/service/pixelated/bitmask_libraries/register.py
index bb54477f..d5cce0d8 100644
--- a/service/pixelated/bitmask_libraries/register.py
+++ b/service/pixelated/bitmask_libraries/register.py
@@ -21,14 +21,15 @@ import os.path
import pixelated.bitmask_libraries.session as LeapSession
from pixelated.bitmask_libraries.config import LeapConfig
from pixelated.bitmask_libraries.provider import LeapProvider
-from pixelated.bitmask_libraries.auth import LeapAuthenticator, LeapCredentials
+from leap.auth import SRPAuth
def register_new_user(username, server_name):
config = LeapConfig()
provider = LeapProvider(server_name, config)
password = getpass.getpass('Please enter password for %s: ' % username)
- LeapAuthenticator(provider).register(LeapCredentials(username, password))
+ srp_auth = SRPAuth(provider, provider.local_ca_crt)
+ srp_auth.register(username, password)
session = LeapSession.open(username, password, server_name)
session.nicknym.generate_openpgp_key()
diff --git a/service/pixelated/bitmask_libraries/session.py b/service/pixelated/bitmask_libraries/session.py
index eb6f39d7..1c8c8c3b 100644
--- a/service/pixelated/bitmask_libraries/session.py
+++ b/service/pixelated/bitmask_libraries/session.py
@@ -27,7 +27,7 @@ from pixelated.bitmask_libraries.provider import LeapProvider
from pixelated.bitmask_libraries.certs import refresh_ca_bundle
from twisted.internet import reactor
from .nicknym import NickNym
-from .auth import LeapAuthenticator, LeapCredentials
+from leap.auth import SRPAuth
from .soledad import SoledadSessionFactory, SoledadSession
from .smtp import LeapSmtp
from .config import DEFAULT_LEAP_HOME
@@ -40,7 +40,7 @@ def open(username, password, server_name, leap_home=DEFAULT_LEAP_HOME):
config = LeapConfig(leap_home=leap_home)
provider = LeapProvider(server_name, config)
refresh_ca_bundle(provider)
- session = LeapSessionFactory(provider).create(LeapCredentials(username, password))
+ session = LeapSessionFactory(provider).create(username, password)
return session
@@ -65,7 +65,7 @@ class LeapSession(object):
- ``incoming_mail_fetcher`` Background job for fetching incoming mails from LEAP server (LeapIncomingMail)
"""
- def __init__(self, provider, srp_session, soledad_session, nicknym, soledad_account, incoming_mail_fetcher, smtp):
+ def __init__(self, provider, user_auth, soledad_session, nicknym, soledad_account, incoming_mail_fetcher, smtp):
"""
Constructor.
@@ -76,7 +76,7 @@ class LeapSession(object):
self.smtp = smtp
self.config = provider.config
self.provider = provider
- self.srp_session = srp_session
+ self.user_auth = user_auth
self.soledad_session = soledad_session
self.nicknym = nicknym
self.account = soledad_account
@@ -87,7 +87,7 @@ class LeapSession(object):
def account_email(self):
domain = self.provider.domain
- name = self.srp_session.user_name
+ name = self.user_auth.username
return '%s@%s' % (name, domain)
def close(self):
@@ -112,28 +112,29 @@ class LeapSessionFactory(object):
self._provider = provider
self._config = provider.config
- def create(self, credentials):
- key = self._session_key(credentials)
+ def create(self, username, password):
+ key = self._session_key(username)
session = self._lookup_session(key)
if not session:
- session = self._create_new_session(credentials)
+ session = self._create_new_session(username, password)
self._remember_session(key, session)
return session
- def _create_new_session(self, credentials):
+ def _create_new_session(self, username, password):
self._create_dir(self._provider.config.leap_home)
- self._provider.download_certificate_to('%s/ca.crt' % self._provider.config.leap_home)
+ self._provider.download_certificate()
- auth = LeapAuthenticator(self._provider).authenticate(credentials)
- soledad = SoledadSessionFactory.create(self._provider, auth, credentials.db_passphrase)
+ srp_auth = SRPAuth(self._provider.api_uri, self._provider.local_ca_crt)
+ auth = srp_auth.authenticate(username, password)
- nicknym = self._create_nicknym(auth, soledad)
- account = self._create_account(auth, soledad)
- incoming_mail_fetcher = self._create_incoming_mail_fetcher(nicknym, soledad,
- account, auth)
+ soledad = SoledadSessionFactory.create(self._provider, auth.token, auth.uuid, password)
- smtp = LeapSmtp(self._provider, nicknym.keymanager, auth)
+ nicknym = self._create_nicknym(auth.username, auth.token, auth.uuid, soledad)
+ account = self._create_account(auth.uuid, soledad)
+ incoming_mail_fetcher = self._create_incoming_mail_fetcher(nicknym, soledad, account, auth.username)
+
+ smtp = LeapSmtp(self._provider, auth.username, auth.session_id, nicknym.keymanager)
smtp.ensure_running()
@@ -150,8 +151,8 @@ class LeapSessionFactory(object):
global SESSIONS
SESSIONS[key] = session
- def _session_key(self, credentials):
- return hash((self._provider, credentials.user_name))
+ def _session_key(self, username):
+ return hash((self._provider, username))
def _create_dir(self, path):
try:
@@ -162,21 +163,17 @@ class LeapSessionFactory(object):
else:
raise
- def _create_soledad_session(self, srp_session, db_passphrase):
- return SoledadSession(self._provider, db_passphrase, srp_session)
-
- def _create_nicknym(self, srp_session, soledad_session):
- return NickNym(self._provider, self._config, soledad_session, srp_session)
+ def _create_nicknym(self, username, token, uuid, soledad_session):
+ return NickNym(self._provider, self._config, soledad_session, username, token, uuid)
- def _create_account(self, srp_session, soledad_session):
+ def _create_account(self, uuid, soledad_session):
memstore = MemoryStore(permanent_store=SoledadStore(soledad_session.soledad))
- return SoledadBackedAccount(srp_session.uuid, soledad_session.soledad, memstore)
+ return SoledadBackedAccount(uuid, soledad_session.soledad, memstore)
- def _create_incoming_mail_fetcher(self, nicknym, soledad_session, account, auth):
+ def _create_incoming_mail_fetcher(self, nicknym, soledad_session, account, username):
return LeapIncomingMail(nicknym.keymanager, soledad_session.soledad, account,
- self._config.fetch_interval_in_s, self._account_email(auth))
+ self._config.fetch_interval_in_s, self._account_email(username))
- def _account_email(self, auth):
+ def _account_email(self, username):
domain = self._provider.domain
- name = auth.user_name
- return '%s@%s' % (name, domain)
+ return '%s@%s' % (username, domain)
diff --git a/service/pixelated/bitmask_libraries/smtp.py b/service/pixelated/bitmask_libraries/smtp.py
index ba5e7102..a0f9c6e4 100644
--- a/service/pixelated/bitmask_libraries/smtp.py
+++ b/service/pixelated/bitmask_libraries/smtp.py
@@ -27,10 +27,11 @@ class LeapSmtp(object):
TWISTED_PORT = 4650
- def __init__(self, provider, keymanager=None, leap_srp_session=None):
+ def __init__(self, provider, username, session_id, keymanager=None):
self._provider = provider
+ self.username = username
+ self.session_id = session_id
self._keymanager = keymanager
- self._srp_session = leap_srp_session
self._hostname, self._port = self._discover_smtp_server()
self._smtp_port = None
self._smtp_service = None
@@ -56,7 +57,7 @@ class LeapSmtp(object):
os.makedirs(os.path.dirname(cert_path))
cert_url = '%s/%s/cert' % (self._provider.api_uri, self._provider.api_version)
- cookies = {"_session_id": self._srp_session.session_id}
+ cookies = {"_session_id": self.session_id}
response = requests.get(cert_url, verify=which_api_CA_bundle(self._provider), cookies=cookies, timeout=self._provider.config.timeout_in_s)
response.raise_for_status()
@@ -76,7 +77,7 @@ class LeapSmtp(object):
def start(self):
self._download_client_certificates()
cert_path = self._client_cert_path()
- email = '%s@%s' % (self._srp_session.user_name, self._provider.domain)
+ email = '%s@%s' % (self.username, self._provider.domain)
self._smtp_service, self._smtp_port = setup_smtp_gateway(
port=self.TWISTED_PORT,
diff --git a/service/pixelated/bitmask_libraries/soledad.py b/service/pixelated/bitmask_libraries/soledad.py
index 83a8caa9..f3fca95a 100644
--- a/service/pixelated/bitmask_libraries/soledad.py
+++ b/service/pixelated/bitmask_libraries/soledad.py
@@ -46,15 +46,16 @@ class LeapKeyManager(object):
class SoledadSessionFactory(object):
@classmethod
- def create(cls, provider, srp_session, encryption_passphrase):
- return SoledadSession(provider, encryption_passphrase, srp_session)
+ def create(cls, provider, user_token, user_uuid, encryption_passphrase):
+ return SoledadSession(provider, encryption_passphrase, user_token, user_uuid)
class SoledadSession(object):
- def __init__(self, provider, encryption_passphrase, leap_srp_session):
+ def __init__(self, provider, encryption_passphrase, user_token, user_uuid):
self.provider = provider
self.config = provider.config
- self.leap_srp_session = leap_srp_session
+ self.user_uuid = user_uuid
+ self.user_token = user_token
self.soledad = self._init_soledad(encryption_passphrase)
@@ -66,8 +67,8 @@ class SoledadSession(object):
secrets = self._secrets_path()
local_db = self._local_db_path()
- return Soledad(self.leap_srp_session.uuid, unicode(encryption_passphrase), secrets,
- local_db, server_url, which_api_CA_bundle(self.provider), self.leap_srp_session.token, defer_encryption=False)
+ return Soledad(self.user_uuid, unicode(encryption_passphrase), secrets,
+ local_db, server_url, which_api_CA_bundle(self.provider), self.user_token, defer_encryption=False)
except (WrongMac, UnknownMacMethod), e:
raise SoledadWrongPassphraseException(e)
@@ -76,10 +77,10 @@ class SoledadSession(object):
return "%s/soledad" % self.config.leap_home
def _secrets_path(self):
- return "%s/%s.secret" % (self._leap_path(), self.leap_srp_session.uuid)
+ return "%s/%s.secret" % (self._leap_path(), self.user_uuid)
def _local_db_path(self):
- return "%s/%s.db" % (self._leap_path(), self.leap_srp_session.uuid)
+ return "%s/%s.db" % (self._leap_path(), self.user_uuid)
def _create_database_dir(self):
try:
@@ -102,7 +103,7 @@ class SoledadSession(object):
host = hosts.keys()[0]
server_url = 'https://%s:%d/user-%s' % \
(hosts[host]['hostname'], hosts[host]['port'],
- self.leap_srp_session.uuid)
+ self.user_uuid)
return server_url
except Exception, e:
raise SoledadDiscoverException(e)
diff --git a/service/pixelated/config/app_factory.py b/service/pixelated/config/app_factory.py
index 51f76741..96412386 100644
--- a/service/pixelated/config/app_factory.py
+++ b/service/pixelated/config/app_factory.py
@@ -31,7 +31,6 @@ from pixelated.adapter.search import SearchEngine
from pixelated.adapter.services.draft_service import DraftService
from pixelated.adapter.listeners.mailbox_indexer_listener import MailboxIndexerListener
import pixelated.bitmask_libraries.session as LeapSession
-from pixelated.bitmask_libraries.leap_srp import LeapAuthException
from requests.exceptions import ConnectionError
from leap.common.events import (
register,
@@ -70,10 +69,6 @@ def init_leap_session(app, leap_home):
print("Can't connect to the requested provider", error)
reactor.stop()
sys.exit(1)
- except LeapAuthException, e:
- print("Couldn't authenticate with the credentials provided %s" % e.message)
- reactor.stop()
- sys.exit(1)
return leap_session
diff --git a/service/pixelated/config/register.py b/service/pixelated/config/register.py
index d54b10ff..8a7caa8b 100644
--- a/service/pixelated/config/register.py
+++ b/service/pixelated/config/register.py
@@ -15,7 +15,6 @@
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
import re
-from pixelated.bitmask_libraries.leap_srp import LeapAuthException
from pixelated.bitmask_libraries.register import register_new_user
@@ -23,8 +22,6 @@ def register(username, server_name):
try:
validate_username(username)
register_new_user(username, server_name)
- except LeapAuthException:
- print('User already exists')
except ValueError:
print('Only lowercase letters, digits, . - and _ allowed.')
diff --git a/service/setup.py b/service/setup.py
index 973cac47..a33ea995 100644
--- a/service/setup.py
+++ b/service/setup.py
@@ -62,6 +62,7 @@ setup(name='pixelated-user-agent',
'srp==1.0.4',
'dirspec==4.2.0',
'u1db==13.09',
+ 'leap.auth==0.1.0',
'leap.keymanager==0.3.8',
'leap.soledad.common==0.6.3',
'leap.soledad.client==0.6.3',
diff --git a/service/test/unit/bitmask_libraries/test_abstract_leap.py b/service/test/unit/bitmask_libraries/test_abstract_leap.py
index c11c7ea9..64de09bc 100644
--- a/service/test/unit/bitmask_libraries/test_abstract_leap.py
+++ b/service/test/unit/bitmask_libraries/test_abstract_leap.py
@@ -22,9 +22,9 @@ from mock import Mock, MagicMock
class AbstractLeapTest(unittest.TestCase):
- uuid = str(uuid4())
- session_id = str(uuid4())
- token = str(uuid4())
+ _uuid = str(uuid4())
+ _session_id = str(uuid4())
+ _token = str(uuid4())
leap_home = os.path.join(tempfile.mkdtemp(), 'leap')
@@ -33,7 +33,11 @@ class AbstractLeapTest(unittest.TestCase):
api_uri='https://api.some-server.test:4430', api_version='1')
soledad = Mock()
soledad_session = Mock(soledad=soledad)
- srp_session = Mock(user_name='test_user', api_server_name='some-server.test', uuid=uuid, session_id=session_id, token=token)
+ auth = Mock(username='test_user',
+ api_server_name='some-server.test',
+ uuid=_uuid,
+ session_id=_session_id,
+ token=_token)
nicknym = MagicMock()
diff --git a/service/test/unit/bitmask_libraries/test_leap_srp.py b/service/test/unit/bitmask_libraries/test_leap_srp.py
deleted file mode 100644
index 6d067e5d..00000000
--- a/service/test/unit/bitmask_libraries/test_leap_srp.py
+++ /dev/null
@@ -1,157 +0,0 @@
-#
-# Copyright (c) 2014 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import json
-import unittest
-import binascii
-from urlparse import parse_qs
-
-from httmock import urlmatch, all_requests, HTTMock, response
-from requests.exceptions import Timeout
-import srp
-from pixelated.bitmask_libraries.leap_srp import LeapSecureRemotePassword, LeapAuthException
-
-
-(salt_bytes, verification_key_bytes) = srp.create_salted_verification_key('username', 'password', hash_alg=srp.SHA256, ng_type=srp.NG_1024)
-verifier = None
-
-
-@all_requests
-def not_found_mock(url, request):
- return {'status_code': 404,
- 'content': 'foobar'}
-
-
-@all_requests
-def timeout_mock(url, request):
- raise Timeout()
-
-
-@urlmatch(netloc=r'(.*\.)?leap\.local$')
-def srp_login_server_simulator_mock(url, request):
- global verifier
-
- data = parse_qs(request.body)
- if 'login' in data:
- # SRP Authentication Step 1
- A = binascii.unhexlify(data.get('A')[0])
-
- verifier = srp.Verifier('username', salt_bytes, verification_key_bytes, A, hash_alg=srp.SHA256, ng_type=srp.NG_1024)
- (salt, B) = verifier.get_challenge()
-
- content = {
- 'salt': binascii.hexlify(salt),
- 'B': binascii.hexlify(B)
- }
-
- return {'status_code': 200,
- 'content': json.dumps(content)}
-
- else:
- # SRP Authentication Step 2
- data = parse_qs(request.body)
- client_auth = binascii.unhexlify(data.get('client_auth')[0])
-
- M2 = verifier.verify_session(client_auth)
-
- if not verifier.authenticated():
- return {'status_code': 404,
- 'content': ''}
-
- content = {
- 'M2': binascii.hexlify(M2),
- 'id': 'some id',
- 'token': 'some token'
- }
- headers = {
- 'Content-Type': 'application/json',
- 'Set-Cookie': '_session_id=some_session_id;'}
- return response(200, content, headers, None, 5, request)
-
-
-class LeapSRPTest(unittest.TestCase):
-
- def test_status_code_is_checked(self):
- with HTTMock(not_found_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lsrp.authenticate, 'https://api.leap.local', 'username', 'password')
-
- def test_invalid_username(self):
- with HTTMock(srp_login_server_simulator_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lsrp.authenticate, 'https://api.leap.local', 'invalid_user', 'password')
-
- def test_invalid_password(self):
- with HTTMock(srp_login_server_simulator_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lsrp.authenticate, 'https://api.leap.local', 'username', 'invalid')
-
- def test_login(self):
- with HTTMock(srp_login_server_simulator_mock):
- lsrp = LeapSecureRemotePassword()
- leap_session = lsrp.authenticate('https://api.leap.local', 'username', 'password')
-
- self.assertIsNotNone(leap_session)
- self.assertEqual('username', leap_session.user_name)
- self.assertEqual('1', leap_session.api_version)
- self.assertEqual('https://api.leap.local', leap_session.api_server_name)
- self.assertEqual('some token', leap_session.token)
- self.assertEqual('some_session_id', leap_session.session_id)
-
- def test_timeout(self):
- with HTTMock(timeout_mock):
- lrsp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lrsp.authenticate, 'https://api.leap.local', 'username', 'password')
-
- def test_register_raises_auth_exception_on_error(self):
- with HTTMock(not_found_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lsrp.register, 'https://api.leap.local', 'username', 'password')
-
- def test_register(self):
- @urlmatch(netloc=r'(.*\.)?leap\.local$', path='/1/users')
- def register_success(url, request):
-
- content = {
- 'login': 'username',
- 'ok': True
- }
-
- return {'status_code': 201,
- 'content': content}
-
- with HTTMock(register_success, not_found_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertTrue(lsrp.register('https://api.leap.local', 'username', 'password'))
-
- def test_register_user_exists(self):
- @urlmatch(netloc=r'(.*\.)?leap\.local$', path='/1/users')
- def register_error_user_exists(url, request):
- content = {"errors": {
- "login": [
- "has already been taken", "has already been taken", "has already been taken"
- ]}}
-
- return {'status_code': 422,
- 'content': content}
-
- with HTTMock(register_error_user_exists, not_found_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lsrp.register, 'https://api.leap.local', 'username', 'password')
-
- def test_registration_timeout(self):
- with HTTMock(timeout_mock):
- lsrp = LeapSecureRemotePassword()
- self.assertRaises(LeapAuthException, lsrp.register, 'https://api.leap.local', 'username', 'password')
diff --git a/service/test/unit/bitmask_libraries/test_nicknym.py b/service/test/unit/bitmask_libraries/test_nicknym.py
index 6e589ae9..b892c22c 100644
--- a/service/test/unit/bitmask_libraries/test_nicknym.py
+++ b/service/test/unit/bitmask_libraries/test_nicknym.py
@@ -26,12 +26,17 @@ class NickNymTest(AbstractLeapTest):
# given
# when
- NickNym(self.provider, self.config, self.soledad_session, self.srp_session)
+ NickNym(self.provider,
+ self.config,
+ self.soledad_session,
+ self.auth.username,
+ self.auth.token,
+ self.auth.uuid)
# then
init_mock.assert_called_with('test_user@some-server.test', 'https://nicknym.some-server.test:6425/',
- self.soledad, self.token, '/some/path/to/provider_ca_cert',
- 'https://api.some-server.test:4430', '1', self.uuid,
+ self.soledad, self.auth.token, '/some/path/to/provider_ca_cert',
+ 'https://api.some-server.test:4430', '1', self.auth.uuid,
'/path/to/gpg')
@patch('pixelated.bitmask_libraries.nicknym.KeyManager')
@@ -39,7 +44,12 @@ class NickNymTest(AbstractLeapTest):
# given
keyman = keymanager_mock.return_value
keyman.get_key.side_effect = KeyNotFound
- nicknym = NickNym(self.provider, self.config, self.soledad_session, self.srp_session)
+ nicknym = NickNym(self.provider,
+ self.config,
+ self.soledad_session,
+ self.auth.username,
+ self.auth.token,
+ self.auth.uuid)
# when/then
nicknym.generate_openpgp_key()
diff --git a/service/test/unit/bitmask_libraries/test_session.py b/service/test/unit/bitmask_libraries/test_session.py
index 0bfd59f2..62330481 100644
--- a/service/test/unit/bitmask_libraries/test_session.py
+++ b/service/test/unit/bitmask_libraries/test_session.py
@@ -65,7 +65,7 @@ class SessionTest(AbstractLeapTest):
self.assertEqual('test_user@some-server.test', session.account_email())
def _create_session(self):
- return LeapSession(self.provider, self.srp_session, self.soledad_session, self.nicknym, self.soledad_account,
+ return LeapSession(self.provider, self.auth, self.soledad_session, self.nicknym, self.soledad_account,
self.mail_fetcher_mock, self.smtp_mock)
diff --git a/service/test/unit/bitmask_libraries/test_smtp.py b/service/test/unit/bitmask_libraries/test_smtp.py
index c0e30573..aa2bc9ba 100644
--- a/service/test/unit/bitmask_libraries/test_smtp.py
+++ b/service/test/unit/bitmask_libraries/test_smtp.py
@@ -53,7 +53,7 @@ class LeapSmtpTest(AbstractLeapTest):
self.config.timeout_in_s = 15
def test_that_client_cert_gets_downloaded(self):
- smtp = LeapSmtp(self.provider, self.keymanager, self.srp_session)
+ smtp = LeapSmtp(self.provider, self.auth.username, self.auth.session_id, self.keymanager)
with HTTMock(ca_cert_mock, not_found_mock):
smtp._download_client_certificates()
@@ -66,7 +66,8 @@ class LeapSmtpTest(AbstractLeapTest):
@patch('pixelated.bitmask_libraries.smtp.setup_smtp_gateway')
def test_that_start_calls_setup_smtp_gateway(self, gateway_mock):
- smtp = LeapSmtp(self.provider, self.keymanager, self.srp_session)
+ smtp = LeapSmtp(self.provider, self.auth.username, self.auth.session_id, self.keymanager)
+
port = 500
smtp.TWISTED_PORT = port
gateway_mock.return_value = (None, None)
@@ -77,14 +78,14 @@ class LeapSmtpTest(AbstractLeapTest):
gateway_mock.assert_called_with(keymanager=self.keymanager, smtp_cert=cert_path, smtp_key=cert_path, userid='test_user@some-server.test', smtp_port='1234', encrypted_only=False, smtp_host='smtp.some-sever.test', port=port)
def test_that_client_stop_does_nothing_if_not_started(self):
- smtp = LeapSmtp(self.provider, self.keymanager, self.srp_session)
+ smtp = LeapSmtp(self.provider, self.auth.username, self.auth.session_id, self.keymanager)
with HTTMock(not_found_mock):
smtp.stop()
@patch('pixelated.bitmask_libraries.smtp.setup_smtp_gateway')
def test_that_running_smtp_sevice_is_stopped(self, gateway_mock):
- smtp = LeapSmtp(self.provider, self.keymanager, self.srp_session)
+ smtp = LeapSmtp(self.provider, self.auth.username, self.auth.session_id, self.keymanager)
smtp_service = MagicMock()
smtp_port = MagicMock()
diff --git a/service/test/unit/bitmask_libraries/test_soledad.py b/service/test/unit/bitmask_libraries/test_soledad.py
index a71275e0..a3a1094a 100644
--- a/service/test/unit/bitmask_libraries/test_soledad.py
+++ b/service/test/unit/bitmask_libraries/test_soledad.py
@@ -34,19 +34,19 @@ class SoledadSessionTest(AbstractLeapTest):
@patch('pixelated.bitmask_libraries.soledad.Soledad.__init__')
def test_that_soledad_is_created_with_required_params(self, soledad_mock, init_mock):
# when
- SoledadSession(self.provider, 'any-passphrase', self.srp_session)
+ SoledadSession(self.provider, 'any-passphrase', self.auth.token, self.auth.uuid)
# then
- init_mock.assert_called_with(self.uuid, 'any-passphrase', '%s/soledad/%s.secret' % (self.leap_home, self.uuid),
- '%s/soledad/%s.db' % (self.leap_home, self.uuid),
- 'https://couch1.some-server.test:1234/user-%s' % self.uuid,
+ init_mock.assert_called_with(self.auth.uuid, 'any-passphrase', '%s/soledad/%s.secret' % (self.leap_home, self.auth.uuid),
+ '%s/soledad/%s.db' % (self.leap_home, self.auth.uuid),
+ 'https://couch1.some-server.test:1234/user-%s' % self.auth.uuid,
'/some/path/to/ca_cert', self.token, defer_encryption=False)
def test_that_sync_is_called(self, soledad_mock):
instance = soledad_mock.return_value
instance.server_url = '/foo/bar'
instance.need_sync.return_value = True
- soledad_session = SoledadSession(self.provider, 'any-passphrase', self.srp_session)
+ soledad_session = SoledadSession(self.provider, 'any-passphrase', self.auth.token, self.auth.uuid)
# when
soledad_session.sync()
@@ -59,7 +59,7 @@ class SoledadSessionTest(AbstractLeapTest):
instance = mock.return_value
instance.server_url = '/foo/bar'
instance.need_sync.return_value = False
- soledad_session = SoledadSession(self.provider, 'any-passphrase', self.srp_session)
+ soledad_session = SoledadSession(self.provider, 'any-passphrase', self.auth.token, self.auth.uuid)
# when
soledad_session.sync()