Example #1
0
class FxATestAccount:
    """A base test class that can be extended by other tests to include utility methods."""

    password = ''.join([random.choice(string.ascii_letters) for i in range(8)])

    def __init__(self, url=DEV_URL):
        """ Creates an FxATestAccount object, which includes a verified account.

        :param url: The url for the api host. Defaults to DEV_URL.
        """
        self.url = url
        random_string = ''.join(
            random.choice(string.ascii_lowercase) for _ in range(12))
        email_pattern = random_string + '@{hostname}'
        self.account = TestEmailAccount(email=email_pattern)
        self.client = Client(self.url)
        # Create and verify the Firefox account
        self.session = self.client.create_account(self.account.email,
                                                  self.password)
        print('fxapom created an account for email: %s at %s on %s' %
              (self.account.email, self.url, datetime.now()))
        m = self.account.wait_for_email(
            lambda m: "x-verify-code" in m["headers"])
        if not m:
            raise RuntimeError("Verification email was not received")
        self.session.verify_email_code(m["headers"]["x-verify-code"])

    def __del__(self):
        """ Deletes the Firefox Account that was created during __init__. """
        try:
            self.account.clear()
            self.client.destroy_account(self.email, self.password)
            print('fxapom deleted the account for email: %s at %s on %s' %
                  (self.account.email, self.url, datetime.now()))
        except ClientError as err:
            # 'Unknown Account' error is ok - account already deleted
            # https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
            if err.errno == 102:
                return
            raise

    def login(self):
        try:
            session = self.client.login(self.email, self.password)
            return session
        except ClientError as err:
            # 'Unknown Account' error is the only one we care about and will
            # cause us to throw a custom exception
            # https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
            if err.errno == 102:
                raise AccountNotFoundException('FxA Account Not Found')
            raise

    @property
    def email(self):
        return self.account.email

    @property
    def is_verified(self):
        return self.session.get_email_status()['verified']
Example #2
0
class FxATestAccount:
    """A base test class that can be extended by other tests to include utility methods."""

    password = ''.join([random.choice(string.letters) for i in range(8)])

    def __init__(self, url=DEV_URL):
        """ Creates an FxATestAccount object, which includes a verified account.

        :param url: The url for the api host. Defaults to DEV_URL.
        """
        self.url = url
        random_string = ''.join(random.choice(string.ascii_lowercase) for _ in range(12))
        email_pattern = random_string + '@{hostname}'
        self.account = TestEmailAccount(email=email_pattern)
        self.client = Client(self.url)
        # Create and verify the Firefox account
        self.session = self.client.create_account(self.account.email, self.password)
        print 'fxapom created an account for email: %s at %s on %s' % (
            self.account.email, self.url, datetime.now())
        m = self.account.wait_for_email(lambda m: "x-verify-code" in m["headers"])
        if not m:
            raise RuntimeError("Verification email was not received")
        self.session.verify_email_code(m["headers"]["x-verify-code"])

    def __del__(self):
        """ Deletes the Firefox Account that was created during __init__. """
        try:
            self.account.clear()
            self.client.destroy_account(self.email, self.password)
            print 'fxapom deleted the account for email: %s at %s on %s' % (
                self.account.email, self.url, datetime.now())
        except ClientError as err:
            # 'Unknown Account' error is ok - account already deleted
            # https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
            if err.errno == 102:
                return
            raise

    def login(self):
        try:
            session = self.client.login(self.email, self.password)
            return session
        except ClientError as err:
            # 'Unknown Account' error is the only one we care about and will
            # cause us to throw a custom exception
            # https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
            if err.errno == 102:
                raise AccountNotFoundException('FxA Account Not Found')
            raise

    @property
    def email(self):
        return self.account.email

    @property
    def is_verified(self):
        return self.session.get_email_status()['verified']
Example #3
0
 def test_resend_verify_code(self):
     acct = TestEmailAccount()
     session = self.client.create_account(
         email=acct.email,
         stretchpwd=DUMMY_STRETCHED_PASSWORD,
     )
     self._accounts_to_delete.append(acct)
     is_verify_email = lambda m: "x-verify-code" in m["headers"]
     m1 = acct.wait_for_email(is_verify_email)
     code1 = m1["headers"]["x-verify-code"]  # NOQA
     acct.clear()
     session.resend_email_code()
Example #4
0
 def test_resend_verify_code(self):
     acct = TestEmailAccount()
     session = self.client.create_account(
         email=acct.email,
         stretchpwd=DUMMY_STRETCHED_PASSWORD,
     )
     self._accounts_to_delete.append(acct)
     is_verify_email = lambda m: "x-verify-code" in m["headers"]
     m1 = acct.wait_for_email(is_verify_email)
     code1 = m1["headers"]["x-verify-code"]  # NOQA
     acct.clear()
     session.resend_email_code()
Example #5
0
def create(ctx):
    """Create a Firefox Account."""
    account = TestEmailAccount()
    client = Client(ctx.obj["URL"])
    password = "".join([random.choice(string.ascii_letters) for i in range(8)])
    session = client.create_account(account.email, password)
    add(ctx.obj["URL"], account.email, password)
    click.echo("Account {}!\n{}".format(
        crayons.yellow("created"),
        render(ctx.obj["URL"], account.email, password)))
    message = account.wait_for_email(lambda m: "x-verify-code" in m["headers"])
    session.verify_email_code(message["headers"]["x-verify-code"])
    click.echo("Account {}! 🎉".format(crayons.green("verified")))
    account.clear()
Example #6
0
def test_add_content(env, conf):
    # Grab a bearer token that we can use to talk to the webextensions endpoint
    acct = TestEmailAccount()
    email = acct.email
    passwd = str(uuid.uuid4())
    fxaclient = FxaClient("https://api.accounts.firefox.com")
    session = fxaclient.create_account(email, passwd)
    m = acct.wait_for_email(lambda m: "x-verify-code" in m["headers"])

    if m is None:
        raise RuntimeErrors("Verification email did not arrive")

    session.verify_email_code(m["headers"]["x-verify-code"])
    auth = FxABearerTokenAuth(
        email,
        passwd,
        scopes=['sync:addon_storage'],
        client_id=DEFAULT_CLIENT_ID,
        account_server_url=conf.get(env, 'account_server_url'),
        oauth_server_url=conf.get(env, 'oauth_server_url'),
    )
    client = Client(server_url=conf.get(env, 'we_server_url'), auth=auth)

    # Add a record to our QA collection and make sure we have N+1 records
    existing_records = client.get_records(collection=conf.get(
        env, 'qa_collection'),
                                          bucket='default')
    assert len(existing_records) == 0

    data = {"payload": {"encrypted": "SmluZ28gdGVzdA=="}}
    resp = client.create_record(data=data,
                                collection=conf.get(env, 'qa_collection'),
                                bucket='default')
    new_record_id = resp['data']['id']
    updated_records = client.get_records(collection=conf.get(
        env, 'qa_collection'),
                                         bucket='default')
    assert len(updated_records) == len(existing_records) + 1

    client.delete_record(id=new_record_id,
                         collection=conf.get(env, 'qa_collection'))
    updated_records = client.get_records(collection=conf.get(
        env, 'qa_collection'),
                                         bucket='default')
    assert len(updated_records) == len(existing_records)

    # Clean up the account that we created for the test
    acct.clear()
    fxaclient.destroy_account(email, passwd)
Example #7
0
def fxa_account(fxa_client):
    logger = logging.getLogger()
    account = TestEmailAccount()
    password = ''.join([random.choice(string.ascii_letters) for i in range(8)])
    FxAccount = collections.namedtuple('FxAccount', 'email password')
    fxa_account = FxAccount(email=account.email, password=password)
    session = fxa_client.create_account(fxa_account.email,
                                        fxa_account.password)
    logger.info('Created: {}'.format(fxa_account))
    account.fetch()
    message = account.wait_for_email(lambda m: 'x-verify-code' in m['headers'])
    session.verify_email_code(message['headers']['x-verify-code'])
    logger.info('Verified: {}'.format(fxa_account))
    yield fxa_account
    account.clear()
    fxa_client.destroy_account(fxa_account.email, fxa_account.password)
    logger.info('Removed: {}'.format(fxa_account))
Example #8
0
    def test_forgot_password_flow(self):
        acct = TestEmailAccount()
        self.client.create_account(
            email=acct.email,
            stretchpwd=DUMMY_STRETCHED_PASSWORD,
        )
        self._accounts_to_delete.append(acct)

        # Initiate the password reset flow, and grab the verification code.
        pftok = self.client.send_reset_code(acct.email, service="foobar")
        m = acct.wait_for_email(lambda m: "x-recovery-code" in m["headers"])
        if not m:
            raise RuntimeError("Password reset email was not received")
        acct.clear()
        code = m["headers"]["x-recovery-code"]

        # Try with an invalid code to test error handling.
        tries = pftok.tries_remaining
        self.assertTrue(tries > 1)
        with self.assertRaises(Exception):
            pftok.verify_code(mutate_one_byte(code))
        pftok.get_status()
        self.assertEqual(pftok.tries_remaining, tries - 1)

        # Re-send the code, as if we've lost the email.
        pftok.resend_code()
        m = acct.wait_for_email(lambda m: "x-recovery-code" in m["headers"])
        if not m:
            raise RuntimeError("Password reset email was not received")
        self.assertEqual(m["headers"]["x-recovery-code"], code)

        # Now verify with the actual code, and reset the account.
        artok = pftok.verify_code(code)
        self.client.reset_account(
            email=acct.email,
            token=artok,
            stretchpwd=DUMMY_STRETCHED_PASSWORD
        )
Example #9
0
class FXATestAccount(object):
    def __init__(self, server=_FXA_SERVER, oauth=_FXA_OAUTH, password=_PWD):
        self.server = server
        self.oauth = oauth
        self.session = self.token = None
        self.password = password
        self.acct = TestEmailAccount()
        self.client = Client(_FXA_SERVER)

    def _verify(self, session, response):
        code = response["headers"].get('x-verify-code')
        if code is None:
            return False
        session.verify_email_code(code)
        return True

    def create(self):
        session = self.client.create_account(self.acct.email, self.password)
        m = self.acct.wait_for_email(functools.partial(self._verify, session))
        if m is None:
            raise RuntimeError("verification email did not arrive")

        self.token = get_bearer_token(self.acct.email,
                                      self.password,
                                      account_server_url=self.server + "/v1",
                                      oauth_server_url=self.oauth,
                                      scopes=['sync:addon_storage'],
                                      client_id=DEFAULT_CLIENT_ID)

    def cleanup(self):
        self.acct.clear()
        self.client.destroy_account(self.acct.email, self.password)

    def authorization(self):
        if self.token is None:
            raise RuntimeError("You need to call create() first")
        return "Bearer %s" % self.token
Example #10
0
    def test_forgot_password_flow(self):
        acct = TestEmailAccount()
        self.client.create_account(
            email=acct.email,
            stretchpwd=DUMMY_STRETCHED_PASSWORD,
        )
        self._accounts_to_delete.append(acct)

        # Initiate the password reset flow, and grab the verification code.
        pftok = self.client.send_reset_code(acct.email, service="foobar")
        m = acct.wait_for_email(lambda m: "x-recovery-code" in m["headers"])
        if not m:
            raise RuntimeError("Password reset email was not received")
        acct.clear()
        code = m["headers"]["x-recovery-code"]

        # Try with an invalid code to test error handling.
        tries = pftok.tries_remaining
        self.assertTrue(tries > 1)
        with self.assertRaises(Exception):
            pftok.verify_code(mutate_one_byte(code))
        pftok.get_status()
        self.assertEqual(pftok.tries_remaining, tries - 1)

        # Re-send the code, as if we've lost the email.
        pftok.resend_code()
        m = acct.wait_for_email(lambda m: "x-recovery-code" in m["headers"])
        if not m:
            raise RuntimeError("Password reset email was not received")
        self.assertEqual(m["headers"]["x-recovery-code"], code)

        # Now verify with the actual code, and reset the account.
        artok = pftok.verify_code(code)
        self.client.reset_account(email=acct.email,
                                  token=artok,
                                  stretchpwd=DUMMY_STRETCHED_PASSWORD)
Example #11
0
class TestCoreClientSession(unittest.TestCase):

    server_url = TEST_SERVER_URL

    def setUp(self):
        self.client = Client(self.server_url)
        # Create a fresh testing account.
        self.acct = TestEmailAccount()
        self.stretchpwd = quick_stretch_password(
            self.acct.email,
            DUMMY_PASSWORD,
        )
        self.session = self.client.create_account(
            email=self.acct.email,
            stretchpwd=self.stretchpwd,
            keys=True,
        )
        # Verify the account so that we can actually use the session.
        m = self.acct.wait_for_email(lambda m: "x-verify-code" in m["headers"])
        if not m:
            raise RuntimeError("Verification email was not received")
        self.session.verify_email_code(m["headers"]["x-verify-code"])
        # Fetch the keys.
        self.session.fetch_keys()
        self.assertEqual(len(self.session.keys), 2)
        self.assertEqual(len(self.session.keys[0]), 32)
        self.assertEqual(len(self.session.keys[1]), 32)

    def tearDown(self):
        # Clean up the session and account.
        # This might fail if the test already cleaned it up.
        try:
            self.session.destroy_session()
        except fxa.errors.ClientError:
            pass
        try:
            self.client.destroy_account(
                email=self.acct.email,
                stretchpwd=self.stretchpwd,
            )
        except fxa.errors.ClientError:
            pass
        self.acct.clear()

    def test_session_status(self):
        self.session.check_session_status()
        self.session.destroy_session()
        with self.assertRaises(fxa.errors.ClientError):
            self.session.check_session_status()

    def test_email_status(self):
        status = self.session.get_email_status()
        self.assertTrue(status["verified"])

    def test_get_random_bytes(self):
        b1 = self.session.get_random_bytes()
        b2 = self.session.get_random_bytes()
        self.assertTrue(isinstance(b1, six.binary_type))
        self.assertNotEqual(b1, b2)

    def test_sign_certificate(self):
        email = self.acct.email
        pubkey = browserid.tests.support.get_keypair(email)[0]
        cert = self.session.sign_certificate(pubkey)
        issuer = browserid.utils.decode_json_bytes(cert.split(".")[1])["iss"]
        expected_issuer = urlparse.urlparse(self.client.server_url).hostname
        self.assertEqual(issuer, expected_issuer)

    def test_change_password(self):
        # Change the password.
        newpwd = mutate_one_byte(DUMMY_PASSWORD)
        self.stretchpwd = quick_stretch_password(self.acct.email, newpwd)
        self.session.change_password(DUMMY_PASSWORD, newpwd)

        # Check that we can use the new password.
        session2 = self.client.login(self.acct.email, newpwd, keys=True)

        # Check that encryption keys have been preserved.
        session2.fetch_keys()
        self.assertEquals(self.session.keys, session2.keys)
Example #12
0
class TestCoreClientSession(unittest.TestCase):

    server_url = TEST_SERVER_URL

    def setUp(self):
        self.client = Client(self.server_url)
        # Create a fresh testing account.
        self.acct = TestEmailAccount()
        self.stretchpwd = quick_stretch_password(
            self.acct.email,
            DUMMY_PASSWORD,
        )
        self.session = self.client.create_account(
            email=self.acct.email,
            stretchpwd=self.stretchpwd,
            keys=True,
        )
        # Verify the account so that we can actually use the session.
        m = self.acct.wait_for_email(lambda m: "x-verify-code" in m["headers"])
        if not m:
            raise RuntimeError("Verification email was not received")
        self.acct.clear()
        self.session.verify_email_code(m["headers"]["x-verify-code"])
        # Fetch the keys.
        self.session.fetch_keys()
        self.assertEqual(len(self.session.keys), 2)
        self.assertEqual(len(self.session.keys[0]), 32)
        self.assertEqual(len(self.session.keys[1]), 32)

    def tearDown(self):
        # Clean up the session and account.
        # This might fail if the test already cleaned it up.
        try:
            self.session.destroy_session()
        except fxa.errors.ClientError:
            pass
        try:
            self.client.destroy_account(
                email=self.acct.email,
                stretchpwd=self.stretchpwd,
            )
        except fxa.errors.ClientError:
            pass
        self.acct.clear()

    def test_session_status(self):
        self.session.check_session_status()
        self.session.destroy_session()
        with self.assertRaises(fxa.errors.ClientError):
            self.session.check_session_status()

    def test_email_status(self):
        status = self.session.get_email_status()
        self.assertTrue(status["verified"])

    def test_get_random_bytes(self):
        b1 = self.session.get_random_bytes()
        b2 = self.session.get_random_bytes()
        self.assertTrue(isinstance(b1, binary_type))
        self.assertNotEqual(b1, b2)

    def test_sign_certificate(self):
        email = self.acct.email
        pubkey = browserid.tests.support.get_keypair(email)[0]
        cert = self.session.sign_certificate(pubkey)
        issuer = browserid.utils.decode_json_bytes(cert.split(".")[1])["iss"]
        expected_issuer = urlparse(self.client.server_url).hostname
        self.assertEqual(issuer, expected_issuer)

    def test_sign_certificate_handles_duration(self):
        email = self.acct.email
        pubkey = browserid.tests.support.get_keypair(email)[0]
        millis = int(round(time.time() * 1000))
        cert = self.session.sign_certificate(pubkey, duration=4000)
        cert_exp = browserid.utils.decode_json_bytes(cert.split(".")[1])["exp"]
        ttl = round(float(cert_exp - millis) / 1000)
        self.assertGreaterEqual(ttl, 2)
        self.assertLessEqual(ttl, 30)

    def test_change_password(self):
        # Change the password.
        newpwd = mutate_one_byte(DUMMY_PASSWORD)
        self.stretchpwd = quick_stretch_password(self.acct.email, newpwd)
        self.session.change_password(DUMMY_PASSWORD, newpwd)

        # Check that we can use the new password.
        session2 = self.client.login(self.acct.email, newpwd, keys=True)
        if not session2.get_email_status().get("verified"):

            def has_verify_code(m):
                return "x-verify-code" in m["headers"]

            m = self.acct.wait_for_email(has_verify_code)
            if not m:
                raise RuntimeError("Verification email was not received")
            self.acct.clear()
            session2.verify_email_code(m["headers"]["x-verify-code"])

        # Check that encryption keys have been preserved.
        session2.fetch_keys()
        self.assertEquals(self.session.keys, session2.keys)

    def test_get_identity_assertion(self):
        assertion = self.session.get_identity_assertion("http://example.com")
        data = browserid.verify(assertion, audience="http://example.com")
        self.assertEquals(data["status"], "okay")
        expected_issuer = urlparse(self.session.server_url).hostname
        self.assertEquals(data["issuer"], expected_issuer)
        expected_email = "{0}@{1}".format(self.session.uid, expected_issuer)
        self.assertEquals(data["email"], expected_email)

    def test_get_identity_assertion_handles_duration(self):
        millis = int(round(time.time() * 1000))
        bid_assertion = self.session.get_identity_assertion(
            "http://example.com", 1234)
        cert, assertion = browserid.utils.unbundle_certs_and_assertion(
            bid_assertion)
        cert = jwt.parse(cert[0]).payload
        assertion = jwt.parse(assertion).payload

        # Validate cert expiry
        ttl = round(float(cert['exp'] - millis) / 1000)
        self.assertGreaterEqual(ttl, 1230)
        self.assertLessEqual(ttl, 1260)

        # Validate assertion expiry
        ttl = round(float(assertion['exp'] - millis) / 1000)
        self.assertGreaterEqual(ttl, 1230)
        self.assertLessEqual(ttl, 1260)

    def test_get_identity_assertion_accepts_service(self):
        # We can't observe any side-effects of sending the service query param,
        # but we can test that it doesn't error out.
        assertion = self.session.get_identity_assertion("http://example.com",
                                                        service="test-me")
        data = browserid.verify(assertion, audience="http://example.com")
        self.assertEquals(data["status"], "okay")

    def test_totp(self):
        resp = self.session.totp_create()

        # Double create causes a client error
        with self.assertRaises(fxa.errors.ClientError):
            self.session.totp_create()

        # Created but not verified returns false (and deletes the token)
        self.assertFalse(self.session.totp_exists())

        # Creating again should work this time
        resp = self.session.totp_create()

        # Verify the code
        code = pyotp.TOTP(resp["secret"]).now()
        self.assertTrue(self.session.totp_verify(code))
        self.assertTrue(self.session.verified)

        # Should exist now
        self.assertTrue(self.session.totp_exists())

        # Remove the code
        resp = self.session.totp_delete()

        # And now should not exist
        self.assertFalse(self.session.totp_exists())
Example #13
0
class TestCoreClientSession(unittest.TestCase):

    server_url = TEST_SERVER_URL

    def setUp(self):
        self.client = Client(self.server_url)
        # Create a fresh testing account.
        self.acct = TestEmailAccount()
        self.stretchpwd = quick_stretch_password(
            self.acct.email,
            DUMMY_PASSWORD,
        )
        self.session = self.client.create_account(
            email=self.acct.email,
            stretchpwd=self.stretchpwd,
            keys=True,
        )
        # Verify the account so that we can actually use the session.
        m = self.acct.wait_for_email(lambda m: "x-verify-code" in m["headers"])
        if not m:
            raise RuntimeError("Verification email was not received")
        self.acct.clear()
        self.session.verify_email_code(m["headers"]["x-verify-code"])
        # Fetch the keys.
        self.session.fetch_keys()
        self.assertEqual(len(self.session.keys), 2)
        self.assertEqual(len(self.session.keys[0]), 32)
        self.assertEqual(len(self.session.keys[1]), 32)

    def tearDown(self):
        # Clean up the session and account.
        # This might fail if the test already cleaned it up.
        try:
            self.session.destroy_session()
        except fxa.errors.ClientError:
            pass
        try:
            self.client.destroy_account(
                email=self.acct.email,
                stretchpwd=self.stretchpwd,
            )
        except fxa.errors.ClientError:
            pass
        self.acct.clear()

    def test_session_status(self):
        self.session.check_session_status()
        self.session.destroy_session()
        with self.assertRaises(fxa.errors.ClientError):
            self.session.check_session_status()

    def test_email_status(self):
        status = self.session.get_email_status()
        self.assertTrue(status["verified"])

    def test_get_random_bytes(self):
        b1 = self.session.get_random_bytes()
        b2 = self.session.get_random_bytes()
        self.assertTrue(isinstance(b1, binary_type))
        self.assertNotEqual(b1, b2)

    def test_sign_certificate(self):
        email = self.acct.email
        pubkey = browserid.tests.support.get_keypair(email)[0]
        cert = self.session.sign_certificate(pubkey)
        issuer = browserid.utils.decode_json_bytes(cert.split(".")[1])["iss"]
        expected_issuer = urlparse(self.client.server_url).hostname
        self.assertEqual(issuer, expected_issuer)

    def test_sign_certificate_handles_duration(self):
        email = self.acct.email
        pubkey = browserid.tests.support.get_keypair(email)[0]
        millis = int(round(time.time() * 1000))
        cert = self.session.sign_certificate(pubkey, duration=4000)
        cert_exp = browserid.utils.decode_json_bytes(cert.split(".")[1])["exp"]
        ttl = round(float(cert_exp - millis) / 1000)
        self.assertGreaterEqual(ttl, 2)
        self.assertLessEqual(ttl, 30)

    def test_change_password(self):
        # Change the password.
        newpwd = mutate_one_byte(DUMMY_PASSWORD)
        self.stretchpwd = quick_stretch_password(self.acct.email, newpwd)
        self.session.change_password(DUMMY_PASSWORD, newpwd)

        # Check that we can use the new password.
        session2 = self.client.login(self.acct.email, newpwd, keys=True)
        if not session2.get_email_status().get("verified"):
            def has_verify_code(m):
                return "x-verify-code" in m["headers"]
            m = self.acct.wait_for_email(has_verify_code)
            if not m:
                raise RuntimeError("Verification email was not received")
            self.acct.clear()
            session2.verify_email_code(m["headers"]["x-verify-code"])

        # Check that encryption keys have been preserved.
        session2.fetch_keys()
        self.assertEquals(self.session.keys, session2.keys)

    def test_get_identity_assertion(self):
        assertion = self.session.get_identity_assertion("http://example.com")
        data = browserid.verify(assertion, audience="http://example.com")
        self.assertEquals(data["status"], "okay")
        expected_issuer = urlparse(self.session.server_url).hostname
        self.assertEquals(data["issuer"], expected_issuer)
        expected_email = "{0}@{1}".format(self.session.uid, expected_issuer)
        self.assertEquals(data["email"], expected_email)

    def test_get_identity_assertion_handles_duration(self):
        millis = int(round(time.time() * 1000))
        bid_assertion = self.session.get_identity_assertion(
            "http://example.com", 1234)
        cert, assertion = browserid.utils.unbundle_certs_and_assertion(
            bid_assertion)
        cert = jwt.parse(cert[0]).payload
        assertion = jwt.parse(assertion).payload

        # Validate cert expiry
        ttl = round(float(cert['exp'] - millis) / 1000)
        self.assertGreaterEqual(ttl, 1230)
        self.assertLessEqual(ttl, 1260)

        # Validate assertion expiry
        ttl = round(float(assertion['exp'] - millis) / 1000)
        self.assertGreaterEqual(ttl, 1230)
        self.assertLessEqual(ttl, 1260)

    def test_get_identity_assertion_accepts_service(self):
        # We can't observe any side-effects of sending the service query param,
        # but we can test that it doesn't error out.
        assertion = self.session.get_identity_assertion("http://example.com",
                                                        service="test-me")
        data = browserid.verify(assertion, audience="http://example.com")
        self.assertEquals(data["status"], "okay")

    def test_totp(self):
        resp = self.session.totp_create()

        # Double create causes a client error
        with self.assertRaises(fxa.errors.ClientError):
            self.session.totp_create()

        # Created but not verified returns false (and deletes the token)
        self.assertFalse(self.session.totp_exists())

        # Creating again should work this time
        resp = self.session.totp_create()

        # Verify the code
        code = pyotp.TOTP(resp["secret"]).now()
        self.assertTrue(self.session.totp_verify(code))
        self.assertTrue(self.session.verified)

        # Should exist now
        self.assertTrue(self.session.totp_exists())

        # Remove the code
        resp = self.session.totp_delete()

        # And now should not exist
        self.assertFalse(self.session.totp_exists())
Example #14
0
class TestCoreClientSession(unittest.TestCase):

    server_url = TEST_SERVER_URL

    def setUp(self):
        self.client = Client(self.server_url)
        # Create a fresh testing account.
        self.acct = TestEmailAccount()
        self.stretchpwd = quick_stretch_password(
            self.acct.email,
            DUMMY_PASSWORD,
        )
        self.session = self.client.create_account(
            email=self.acct.email,
            stretchpwd=self.stretchpwd,
            keys=True,
        )
        # Verify the account so that we can actually use the session.
        m = self.acct.wait_for_email(lambda m: "x-verify-code" in m["headers"])
        if not m:
            raise RuntimeError("Verification email was not received")
        self.session.verify_email_code(m["headers"]["x-verify-code"])
        # Fetch the keys.
        self.session.fetch_keys()
        self.assertEqual(len(self.session.keys), 2)
        self.assertEqual(len(self.session.keys[0]), 32)
        self.assertEqual(len(self.session.keys[1]), 32)

    def tearDown(self):
        # Clean up the session and account.
        # This might fail if the test already cleaned it up.
        try:
            self.session.destroy_session()
        except fxa.errors.ClientError:
            pass
        try:
            self.client.destroy_account(
                email=self.acct.email,
                stretchpwd=self.stretchpwd,
            )
        except fxa.errors.ClientError:
            pass
        self.acct.clear()

    def test_session_status(self):
        self.session.check_session_status()
        self.session.destroy_session()
        with self.assertRaises(fxa.errors.ClientError):
            self.session.check_session_status()

    def test_email_status(self):
        status = self.session.get_email_status()
        self.assertTrue(status["verified"])

    def test_get_random_bytes(self):
        b1 = self.session.get_random_bytes()
        b2 = self.session.get_random_bytes()
        self.assertTrue(isinstance(b1, six.binary_type))
        self.assertNotEqual(b1, b2)

    def test_sign_certificate(self):
        email = self.acct.email
        pubkey = browserid.tests.support.get_keypair(email)[0]
        cert = self.session.sign_certificate(pubkey)
        issuer = browserid.utils.decode_json_bytes(cert.split(".")[1])["iss"]
        expected_issuer = urlparse.urlparse(self.client.server_url).hostname
        self.assertEqual(issuer, expected_issuer)

    def test_change_password(self):
        # Change the password.
        newpwd = mutate_one_byte(DUMMY_PASSWORD)
        self.stretchpwd = quick_stretch_password(self.acct.email, newpwd)
        self.session.change_password(DUMMY_PASSWORD, newpwd)

        # Check that we can use the new password.
        session2 = self.client.login(self.acct.email, newpwd, keys=True)

        # Check that encryption keys have been preserved.
        session2.fetch_keys()
        self.assertEquals(self.session.keys, session2.keys)