Esempio n. 1
0
 def test_basic(self):
     """ Test generating and recovering a token. """
     svc = TokenService()
     TEST_STR = "Hello World"
     token = svc.issue(TEST_STR)
     res = svc.check(token)
     self.assertEqual(TEST_STR, res)
     # Check bad token case
     self.assertRaises(ValueError, svc.check, "BadToken")
Esempio n. 2
0
 def test_unpack(self):
     """ Test that the unpacker without verification works
         correctly.
     """
     TEST_OBJ = {"a": "field1", "b": "ASD"}
     svc = TokenService()
     token = svc.issue(TEST_OBJ)
     retval = TokenService.unpack(token)
     self.assertDictEqual(TEST_OBJ, retval)
     # Check the error handling
     self.assertRaises(ValueError, svc.unpack, "not_a_token")
Esempio n. 3
0
    def setUp(self):
        # self._mocked_facade = mocked_facade
        # self._mocked_facade.return_value = MockTransferClientFacade("anything")

        self._parser = argparse.ArgumentParser()
        subparsers = self._parser.add_subparsers()
        UserCommand(subparsers)
        self._tmp_file = tempfile.NamedTemporaryFile(dir='/tmp')
        future_date = (datetime.timedelta(0, 600) +
                       datetime.datetime.utcnow()).isoformat()
        plain = {'id': 44, 'expiry': future_date}
        svc = TokenService()
        validtoken = svc.issue(plain)
        self._tmp_file.write(validtoken)
        self._tmp_file.flush()
Esempio n. 4
0
    def setUp(self):

        self.__future_date = (datetime.timedelta(0, 600) +
                              datetime.datetime.utcnow()).isoformat()
        plain = {'id': 44, 'expiry': self.__future_date, 'email': '*****@*****.**'}
        svc = TokenService()
        self._validtoken = svc.issue(plain)

        __past_date = (-datetime.timedelta(0, 60) +
                       datetime.datetime.utcnow()).isoformat()
        plain_expired = {'id': 44, 'expiry': __past_date}
        self._expiredtoken = svc.issue(plain_expired)

        plain_incomplete = {'id': 44}
        self._incomplete = svc.issue(plain_incomplete)
Esempio n. 5
0
 def __init__(self,
              server_name,
              logger=logging.getLogger(),
              debug=False,
              token_key=None):
     """ Constructs the server.
         logger - The main logger to use.
         debug - If set to true, enable flask debug mode
                 (Which includes far more details in returned errors, etc...)
     """
     Flask.__init__(self, server_name)
     self.debug = debug
     self.before_request(self.__init_handler)
     self.after_request(self.__access_log)
     self.__acl_manager = ACLManager(logger)
     self.__update_dbctx(None)
     self.__db_classes = []
     self.__db_insts = []
     self.__startup_funcs = []
     self.__test_funcs = []
     self.__logger = logger
     if not token_key:
         token_key = os.urandom(16)
     self.secret_key = token_key + "flask"
     self.token_svc = TokenService(token_key, "pdmwebsvc")
     # We override the test client class from Flask with our
     # custom one which is more similar to RESTClient
     self.test_client_class = FlaskClientWrapper
     with self.app_context():
         current_app.log = logger
         current_app.acl_manager = self.__acl_manager
         current_app.token_svc = self.token_svc
Esempio n. 6
0
 def setUp(self, site_mock):
     self.__site_mock = site_mock
     conf = {
         'token_validity': '01:00:00',
         'smtp_server': 'localhost',
         'verification_url':
         'https://pdm.grid.hep.ph.ic.ac.uk:5443/web/verify',
         'smtp_server_login': '******',
         'smtp_starttls': 'OPTIONAL',
         'smtp_login_req': 'OPTIONAL',
         'display_from_address': 'PDM mailer <centos@localhost>',
         'mail_subject':
         'PDM registration - please verify your email address.',
         'mail_expiry': '12:00:00',
         'mail_token_secret': 'somemailsecretstring'
     }
     self._conf = copy.deepcopy(conf)
     self.__service = FlaskServer("pdm.userservicedesk.HRService")
     self.__service.test_mode(HRService, None)  # to skip DB auto build
     self.__service.fake_auth("ALL")
     self.__future_date = (datetime.timedelta(0, 600) +
                           datetime.datetime.utcnow()).isoformat()
     self.__past_date = (-datetime.timedelta(0, 60) +
                         datetime.datetime.utcnow()).isoformat()
     # database
     self.__service.build_db()  # build manually
     #
     db = self.__service.test_db()
     new_user = db.tables.User(name='John',
                               surname='Smith',
                               email='*****@*****.**',
                               state=HRServiceUserState.VERIFIED,
                               password=hash_pass('very_secret'))
     db.session.add(new_user)
     db.session.commit()
     self.__service.before_startup(conf)  # to continue startup
     #
     self.__test = self.__service.test_client()
     # mail token
     time_struct = time.strptime("12:00:00", "%H:%M:%S")
     self.token_duration = datetime.timedelta(hours=time_struct.tm_hour,
                                              minutes=time_struct.tm_min,
                                              seconds=time_struct.tm_sec)
     self.mail_token_service = TokenService(self._conf['mail_token_secret'])
Esempio n. 7
0
 def test_key(self):
     """ Check that different keys yield different results. """
     TEST_STR = "Key Test"
     svc1 = TokenService(key="KeyA")
     token1 = svc1.issue(TEST_STR)
     svc2 = TokenService(key="KeyB")
     token2 = svc2.issue(TEST_STR)
     self.assertNotEqual(token1, token2)
     self.assertRaises(ValueError, svc1.check, token2)
     self.assertRaises(ValueError, svc2.check, token1)
     self.assertEqual(TEST_STR, svc1.check(token1))
     self.assertEqual(TEST_STR, svc2.check(token2))
Esempio n. 8
0
 def test_salt(self):
     """ Check that setting the salt works. """
     TEST_STR = "Salt Test"
     svc1 = TokenService(key="FixedKey", salt="salt1")
     token1 = svc1.issue(TEST_STR)
     svc2 = TokenService(key="FixedKey", salt="salt2")
     token2 = svc2.issue(TEST_STR)
     self.assertNotEqual(token1, token2)
     self.assertRaises(ValueError, svc1.check, token2)
     self.assertRaises(ValueError, svc2.check, token1)
     self.assertEqual(TEST_STR, svc1.check(token1))
     self.assertEqual(TEST_STR, svc2.check(token2))
Esempio n. 9
0
    def get_token_username_insecure(token):
        """
        Get username from a token.

        :param token:
        :return:
        """
        unpacked_token = TokenService.unpack(token)
        username = unpacked_token.get('email')
        if not username:
            HRUtils._logger.error("Token does not contain user information")
        return username
Esempio n. 10
0
    def get_token_expiry_insecure(token):
        """
        Get token expiry date in ISO format, Insecure - token integrity not checked.

        :param token: token in
        :return: ISO of the unpacked token
        """

        unpacked_token = TokenService.unpack(token)
        expiry_iso = unpacked_token.get('expiry')
        if not expiry_iso:
            HRUtils._logger.error("Token does not contain expiry information")
        return expiry_iso
Esempio n. 11
0
    def get_token_userid(token):
        """
        Get the value of the 'key' part of the token to be used to contact the CS
        The token holds internally:
        id: user id
        expiry: expiry info (to be decided)
        key: hashed key (from pdm.utils.hashing.hash_pass()).

        :param   token: encrypted token
        :return: the value of the 'key' field of the token dictionary
        """
        unpacked_user_token = TokenService.unpack(token)
        userid = unpacked_user_token.get('id', None)
        return userid
Esempio n. 12
0
 def test_inst(self):
     """ Check that two instances with the same parameters
         generate compatible tokens.
     """
     TEST_STR = "Inst Test"
     params = ("KeyStr", "SaltStr")
     svc1 = TokenService(*params)
     token1 = svc1.issue(TEST_STR)
     svc2 = TokenService(*params)
     token2 = svc2.issue(TEST_STR)
     # Tokens should be identical
     self.assertEqual(token1, token2)
     self.assertEqual(TEST_STR, svc1.check(token2))
Esempio n. 13
0
class TestHRService(unittest.TestCase):
    @mock.patch("pdm.userservicedesk.HRService.SiteClient")
    def setUp(self, site_mock):
        self.__site_mock = site_mock
        conf = {
            'token_validity': '01:00:00',
            'smtp_server': 'localhost',
            'verification_url':
            'https://pdm.grid.hep.ph.ic.ac.uk:5443/web/verify',
            'smtp_server_login': '******',
            'smtp_starttls': 'OPTIONAL',
            'smtp_login_req': 'OPTIONAL',
            'display_from_address': 'PDM mailer <centos@localhost>',
            'mail_subject':
            'PDM registration - please verify your email address.',
            'mail_expiry': '12:00:00',
            'mail_token_secret': 'somemailsecretstring'
        }
        self._conf = copy.deepcopy(conf)
        self.__service = FlaskServer("pdm.userservicedesk.HRService")
        self.__service.test_mode(HRService, None)  # to skip DB auto build
        self.__service.fake_auth("ALL")
        self.__future_date = (datetime.timedelta(0, 600) +
                              datetime.datetime.utcnow()).isoformat()
        self.__past_date = (-datetime.timedelta(0, 60) +
                            datetime.datetime.utcnow()).isoformat()
        # database
        self.__service.build_db()  # build manually
        #
        db = self.__service.test_db()
        new_user = db.tables.User(name='John',
                                  surname='Smith',
                                  email='*****@*****.**',
                                  state=HRServiceUserState.VERIFIED,
                                  password=hash_pass('very_secret'))
        db.session.add(new_user)
        db.session.commit()
        self.__service.before_startup(conf)  # to continue startup
        #
        self.__test = self.__service.test_client()
        # mail token
        time_struct = time.strptime("12:00:00", "%H:%M:%S")
        self.token_duration = datetime.timedelta(hours=time_struct.tm_hour,
                                                 minutes=time_struct.tm_min,
                                                 seconds=time_struct.tm_sec)
        self.mail_token_service = TokenService(self._conf['mail_token_secret'])

    def test_getUserSelf(self):
        """
        GET operation on users/self
        :return:
        """

        self.__service.fake_auth("TOKEN", {'id': 1})
        res = self.__test.get('/users/api/v1.0/users/self')
        assert (res.status_code == 500)

        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__past_date
        })
        res = self.__test.get('/users/api/v1.0/users/self')
        assert (res.status_code == 403)  # token expired

        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__future_date,
            'key': 'unused'
        })
        res = self.__test.get('/users/api/v1.0/users/self')
        assert (res.status_code == 200)
        user = json.loads(res.data)

        assert ('id' not in user)
        assert (user['name'] == 'John')
        assert (user['surname'] == 'Smith')
        assert (user['email'] == '*****@*****.**')
        assert (user['state'] == HRServiceUserState.VERIFIED)
        assert ('password' not in user)
        #
        self.__service.fake_auth("TOKEN", {
            'id': 2,
            'expiry': self.__future_date
        })
        res = self.__test.get('/users/api/v1.0/users/self')
        assert (res.status_code == 404)

    @mock.patch("pdm.userservicedesk.HRService.HRService.email_user")
    def test_addUser(self, email_user_mock):
        """
        Testinf user registration. Ignore emailer at this stage.
        :return:
        """
        self.__service.fake_auth("ALL")
        fred = {
            'surname': 'Flintstone',
            'name': 'Fred',
            'email': '*****@*****.**',
            'state': 0,
            'password': '******'
        }

        barney = {
            'surname': 'Rubble',
            'name': 'Barney',
            'email': '*****@*****.**',
            'state': 0,
            'password': '******'
        }

        res = self.__test.post('/users/api/v1.0/users', data=fred)

        assert (res.status_code == 201)
        # db
        db = self.__service.test_db()
        dbuser = db.tables.User.query.filter_by(email=fred['email']).first()
        assert (dbuser.name == fred['name'])
        assert (check_hash(dbuser.password, fred['password']))
        assert (dbuser.email == fred['email'])
        response = json.loads(res.data)
        assert (response['name'] == fred['name'])
        assert (response['surname'] == fred['surname'])
        assert (response['email'] == fred['email'])
        assert (response['state'] == fred['state'])
        assert ('password' not in response)
        # try to duplicate the user:
        res = self.__test.post('/users/api/v1.0/users', data=fred)
        assert (res.status_code == 403)

        # password too short !
        res = self.__test.post('/users/api/v1.0/users', data=barney)
        assert (res.status_code == 400)
        # barney OK, but verification email sending fails:
        barney['password'] = '******'
        email_user_mock.side_effect = RuntimeError
        res = self.__test.post('/users/api/v1.0/users', data=barney)
        assert (res.status_code == 500)
        #
        b_email = barney.pop('email')
        res = self.__test.post('/users/api/v1.0/users', data=barney)
        assert (res.status_code == 400)

        barney['email'] = b_email
        password = barney.pop('password')
        res = self.__test.post('/users/api/v1.0/users', data=barney)
        assert (res.status_code == 400)

    def test_change_password(self):
        """
        Test the password changing operation
        :return:
        """

        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__past_date
        })
        new_pass_data = {
            'passwd': 'very_secret',
            'newpasswd': 'even_more_secret'
        }
        res = self.__test.put('/users/api/v1.0/passwd', data=new_pass_data)
        assert (res.status_code == 403)

        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__future_date
        })
        # fake auth John, which is id=1
        new_pass_data = {
            'passwd': 'very_secret',
            'newpasswd': 'even_more_secret'
        }
        res = self.__test.put('/users/api/v1.0/passwd', data=new_pass_data)
        assert (res.status_code == 200)
        # check if the password was actually modified:
        db = self.__service.test_db()
        dbuser = db.tables.User.query.filter_by(
            email='*****@*****.**').first()
        assert (dbuser.name == "John")
        assert (check_hash(dbuser.password, 'even_more_secret'))
        #
        response = json.loads(res.data)
        assert ('password' not in response)
        # TODO check last login timestamp later than the time before changing the password.
        # wrong password
        wrong_pass_data = {
            'passwd': 'very_sercet',
            'newpasswd': 'even_more_secret'
        }
        res = self.__test.put('/users/api/v1.0/passwd', data=wrong_pass_data)
        assert (res.status_code == 403)
        # same pass
        same_pass_data = {
            'passwd': 'even_more_secret',
            'newpasswd': 'even_more_secret'
        }
        res = self.__test.put('/users/api/v1.0/passwd', data=same_pass_data)
        assert (res.status_code == 400)
        # no pass
        no_pass = {'passwd': None, 'newpasswd': 'even_more_secret'}
        res = self.__test.put('/users/api/v1.0/passwd', data=no_pass)
        assert (res.status_code == 400)
        no_pass = {'newpasswd': 'even_more_secret'}
        res = self.__test.put('/users/api/v1.0/passwd', data=no_pass)
        assert (res.status_code == 400)
        no_pass = {'passwd': 'even_more_secret'}
        res = self.__test.put('/users/api/v1.0/passwd', data=no_pass)
        assert (res.status_code == 400)
        #
        no_npass = {'passwd': 'even_more_secret', 'newpasswd': None}
        res = self.__test.put('/users/api/v1.0/passwd', data=no_npass)
        assert (res.status_code == 400)
        # weak pass
        weak_pass = {'passwd': 'even_more_secret', 'newpasswd': 'test'}
        res = self.__test.put('/users/api/v1.0/passwd', data=weak_pass)
        assert (res.status_code == 400)
        # non existing user
        self.__service.fake_auth("TOKEN", {
            'id': 7,
            'expiry': self.__future_date
        })
        res = self.__test.put('/users/api/v1.0/passwd', data=new_pass_data)
        assert (res.status_code == 403)

    # @mock.patch('pdm.userservicedesk.HRService.SiteClient')

    def test_delete_user(self):
        """
        Test deleting user data
        :return:
        """
        # not existing user:
        self.__service.fake_auth("TOKEN", {
            'id': 7,
            'expiry': self.__future_date
        })
        res = self.__test.delete('/users/api/v1.0/users/self')
        assert (res.status_code == 404)
        assert not self.__site_mock().del_user.called
        # attempt to delete Johnny with an expired token
        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__past_date,
            'key': 'unused'
        })  # fake auth John, which is id=1
        res = self.__test.delete('/users/api/v1.0/users/self')
        assert (res.status_code == 403)
        assert not self.__site_mock().del_user.called
        # delete poor Johnny ;-(
        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__future_date,
            'key': 'unused'
        })  # fake auth John, which is id=1
        res = self.__test.delete('/users/api/v1.0/users/self')
        assert (res.status_code == 200)
        assert self.__site_mock().del_user.called

    def test_deleteUser_SiteService_fail(self):
        """
        Test if the user is put back when SiteService fails
        :param mock_del_user:
        :return:
        """
        # delete poor Johnny ;-(
        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__future_date
        })
        # fake auth John, which is id=1
        self.__site_mock().del_user.side_effect = Exception()
        res = self.__test.delete('/users/api/v1.0/users/self')
        assert (res.status_code == 500)
        assert self.__site_mock().del_user.called
        # check if we rolled John  back !
        db = self.__service.test_db()
        dbuser = db.tables.User.query.filter_by(
            email='*****@*****.**').first()
        assert (dbuser is not None)

    @mock.patch('sqlalchemy.orm.scoping.scoped_session.delete')
    def test_deleteUser_HR_fail(self, mock_del):
        self.__service.fake_auth("TOKEN", {
            'id': 1,
            'expiry': self.__future_date
        })
        # fake auth John, which is id=1
        mock_del.side_effect = Exception()
        res = self.__test.delete('/users/api/v1.0/users/self')
        assert (res.status_code == 500)
        assert not self.__site_mock().del_user.called

    def test_loginUser(self):
        """
        Test the user login procedure
        :return:
        """

        res = self.__test.post('/users/api/v1.0/login')  # empty req.
        assert (res.status_code == 400)

        res = self.__test.post('/users/api/v1.0/login', data=('hulagula'))
        assert (res.status_code == 400)

        login_creds = {'email': '*****@*****.**', 'passwd': 'very_secret'}
        res = self.__test.post('/users/api/v1.0/login', data=login_creds)
        assert (res.status_code == 200)
        #
        token_data = self.__service.token_svc.check(json.loads(res.data))
        db = self.__service.test_db()
        dbuser = db.tables.User.query.filter_by(
            email='*****@*****.**').first()
        assert token_data['id'] == 1

        isoformat = '%Y-%m-%dT%H:%M:%S.%f'
        expiry_date = datetime.datetime.strptime(token_data['expiry'],
                                                 isoformat)
        # conf gives 1h token validity. Check if we are within 10s
        assert abs(
            (expiry_date - (datetime.datetime.utcnow() +
                            datetime.timedelta(0, 3600))).total_seconds()) < 10

        login_creds_b = {'email': '*****@*****.**'}
        res = self.__test.post('/users/api/v1.0/login', data=login_creds_b)
        assert (res.status_code == 400)
        res = self.__test.post('/users/api/v1.0/login',
                               data={
                                   'email': '*****@*****.**',
                                   'passwd': 'very_seCret'
                               })
        assert (res.status_code == 403)
        res = self.__test.post('/users/api/v1.0/login',
                               data={
                                   'email': '*****@*****.**',
                                   'passwd': 'very_secret'
                               })
        assert (res.status_code == 403)
        res = self.__test.post('/users/api/v1.0/login',
                               data={
                                   'email': '*****@*****.**',
                                   'passwd': None
                               })
        assert (res.status_code == 400)
        # make Johny unverified ;-(
        dbuser.state = HRServiceUserState.REGISTERED
        db.session.add(dbuser)
        db.session.commit()
        res = self.__test.post('/users/api/v1.0/login', data=login_creds)
        assert (res.status_code == 401)

    @mock.patch('smtplib.SMTP')
    @mock.patch.object(HRService, 'compose_and_send')
    def test_email_user(self, mcs, smtp_mock):
        with self.__service.test_request_context(path="/test"):
            with mock.patch.object(pdm.userservicedesk.HRService.current_app,
                                   'mail_token_service') as m_ts:
                m_ts.issue = mock.MagicMock(return_value='agfgffsgdf')
                HRService.email_user("*****@*****.**")
                assert mcs.call_args[0][0] == '*****@*****.**'
                assert mcs.call_args[0][1] == 'agfgffsgdf'
                #(ignore the timestamp passed in as the third arg.)

    def test_verify_user(self):
        # isssue a valid mail token
        expiry = datetime.datetime.utcnow() + self.token_duration
        plain = {'expiry': expiry.isoformat(), 'email': '*****@*****.**'}
        token = self.mail_token_service.issue(plain)
        #body = os.path.join(self._conf['verification_url'],token)
        # verify takes a token only, not the whole email body at the moment
        db = self.__service.test_db()
        dbuser = db.tables.User.query.filter_by(
            email='*****@*****.**').first()
        dbuser.state = HRServiceUserState.REGISTERED  # unverify !
        db.session.add(dbuser)
        db.session.commit()

        #token tempered with:
        res = self.__test.post('/users/api/v1.0/verify',
                               data={'mailtoken': token[1:]})
        assert res.status_code == 400

        # success ?
        res = self.__test.post('/users/api/v1.0/verify',
                               data={'mailtoken': token})
        assert res.status_code == 201

        #repeat a verification attempt
        dbuser.state = HRServiceUserState.VERIFIED
        db.session.add(dbuser)
        db.session.commit()
        res = self.__test.post('/users/api/v1.0/verify',
                               data={'mailtoken': token})
        assert res.status_code == 400

        # expired token
        dbuser.state = HRServiceUserState.REGISTERED  # unverify !
        db.session.add(dbuser)
        db.session.commit()
        expired = datetime.datetime.utcnow() - self.token_duration
        e_plain = {
            'expiry': expired.isoformat(),
            'email': '*****@*****.**'
        }
        e_token = self.mail_token_service.issue(e_plain)
        res = self.__test.post('/users/api/v1.0/verify',
                               data={'mailtoken': e_token})
        assert res.status_code == 400

        # non existent user:
        plain = {'expiry': expiry.isoformat(), 'email': '*****@*****.**'}
        token = self.mail_token_service.issue(plain)
        res = self.__test.post('/users/api/v1.0/verify',
                               data={'mailtoken': token})
        assert res.status_code == 400

    @mock.patch('smtplib.SMTP')
    def test_resend_email(self, smtp_mock):
        db = self.__service.test_db()
        dbuser = db.tables.User.query.filter_by(
            email='*****@*****.**').first()
        dbuser.state = HRServiceUserState.REGISTERED  # unverify !
        db.session.add(dbuser)
        db.session.commit()
        email = '*****@*****.**'
        data = {'email': email}
        res = self.__test.post('/users/api/v1.0/resend', data=data)
        assert res.status_code == 200
        dbuser.state = HRServiceUserState.VERIFIED
        db.session.add(dbuser)
        db.session.commit()
        res = self.__test.post('/users/api/v1.0/resend', data=data)
        assert res.status_code == 400
        res = self.__test.post('/users/api/v1.0/resend',
                               data={'email': 'hula@gula'})
        assert res.status_code == 400
        res = self.__test.post('/users/api/v1.0/resend',
                               data={'Email': 'hula@gula'})
        assert res.status_code == 400

    @mock.patch('email.MIMEMultipart.MIMEMultipart')
    @mock.patch.object(smtplib.SMTP, 'connect')
    @mock.patch.object(smtplib.SMTP, 'close')
    def test_compose_and_send(self, close_mock, connect_mock, mail_mock):
        with self.__service.test_request_context(path="/test"):
            # force connect to raise the SMTPException derived class. HRService wraps it into
            # RuntimeError
            connect_mock.return_value = (400, 'cannot connect message'
                                         )  # 220 is the success code
            with self.assertRaises(RuntimeError):
                HRService.compose_and_send("centos@localhost", 'mytoken_abc',
                                           datetime.datetime.utcnow()
                                           )  # timestamp does not matter here
            connect_mock.assert_called_with('localhost', None)  # from conf{}

            # now allow for connect() to raise a socket.error
            import socket
            connect_mock.side_effect = socket.error
            with self.assertRaises(RuntimeError):
                HRService.compose_and_send("centos@localhost", 'mytoken_abc',
                                           datetime.datetime.utcnow())

    @mock.patch('email.MIMEMultipart.MIMEMultipart')
    @mock.patch('smtplib.SMTP')
    def test_compose_and_send_sendmail(self, smtp_mock, mail_mock):
        with self.__service.test_request_context(path="/test"):
            # sendmail errors
            mytoken = 'mytoken_abc'
            toaddr = "user@remotehost"
            body = os.path.join(self._conf['verification_url'], mytoken)
            smtp_mock.return_value.sendmail.side_effect = smtplib.SMTPException
            with self.assertRaises(RuntimeError):
                HRService.compose_and_send(toaddr, mytoken,
                                           datetime.datetime.utcnow())
            args = smtp_mock.return_value.sendmail.call_args
            assert args[0][0] == self._conf['smtp_server_login']
            assert args[0][1] == toaddr
            assert body in args[0][2]  # check the important part of the email

    def test_hello(self):
        res = self.__test.get('/users/api/v1.0/hello')
        assert (res.status_code == 200)
        res_str = json.loads(res.data)
        assert (res_str == 'User Service Desk at your service !\n')
Esempio n. 14
0
    def load_userconfig(config):
        """ Configure the HRService application.
            Gets the key needed to contact the Credential Service
        """
        current_app.pwd_len = config.pop("pswd_length", 8)
        # token validity period struct (from: HH:MM:SS)
        try:
            time_struct = time.strptime(
                config.pop("token_validity", "12:00:00"), "%H:%M:%S")
            current_app.token_duration = datetime.timedelta(
                hours=time_struct.tm_hour,
                minutes=time_struct.tm_min,
                seconds=time_struct.tm_sec)
            HRService._logger.info(
                "User login token duration parsed successfully")
            m_time_struct = time.strptime(
                config.pop("mail_token_validity", "23:59:00"), "%H:%M:%S")
            current_app.mail_token_duration = datetime.timedelta(
                hours=m_time_struct.tm_hour,
                minutes=m_time_struct.tm_min,
                seconds=m_time_struct.tm_sec)
            HRService._logger.info(
                "User mail token duration parsed successfully")
        except ValueError as v_err:
            HRService._logger.error(
                " Token lifetime provided in the config "
                "file has wrong format %s. Aborting.", v_err)
            raise ValueError("Token lifetime incorrect format %s" % v_err)

        # verification email:
        current_app.smtp_server = config.pop("smtp_server", None)
        if current_app.smtp_server is None:
            HRService._logger.error(
                " Mail server not provided in the config. Aborting")
            raise ValueError(
                " Mail server not provided in the config. Aborting")

        current_app.smtp_server_port = config.pop("smtp_server_port", None)
        current_app.smtp_server_login = config.pop("smtp_server_login", None)
        current_app.mail_display_from = config.pop("display_from_address",
                                                   None)
        current_app.smtp_server_pwd = config.pop("smtp_server_pwd", None)
        current_app.mail_subject = config.pop("mail_subject", None)
        current_app.mail_expiry = config.pop("mail_expiry", "12:00:00")
        mail_server_req = ['REQUIRED', 'OPTIONAL', 'OFF']
        allowed_opts = ', '.join(mail_server_req)
        current_app.smtp_server_starttls = config.pop('smtp_starttls',
                                                      'UNDEFINED').upper()
        if current_app.smtp_server_starttls not in mail_server_req:
            HRService._logger.error(
                ' Mail server starttls option invalid (%s). Aborting.',
                current_app.smtp_server_starttls)
            HRService._logger.error("Allowed option values are: %s.",
                                    allowed_opts)
            raise ValueError(
                'Mail server starttls option invalid (%s) . Aborting.' %
                current_app.smtp_server_starttls)

        current_app.smtp_server_login_req = config.pop('smtp_login_req',
                                                       'UNDEFINED').upper()
        if current_app.smtp_server_login_req not in mail_server_req:
            HRService._logger.error(
                ' Mail server smtp_server_login_req option invalid (%s).'
                ' Aborting', current_app.smtp_server_login_req)
            HRService._logger.error("Allowed option values are: %s.",
                                    allowed_opts)
            raise ValueError(
                'Mail server smtp_server_login_req  option invalid (%s). Aborting.'
                % current_app.smtp_server_login_req)

        current_app.verification_url = config.pop("verification_url")
        if current_app.verification_url is None:
            HRService._logger.error(
                " Mail verification URL not provided in the config. Aborting")
            raise ValueError(
                " Mail verification URL not provided in the config. Aborting")

        current_app.mail_token_secret = config.pop("mail_token_secret")

        # TokenService used to generate a verification email token.
        current_app.mail_token_service = TokenService(
            current_app.mail_token_secret)
        # site client
        current_app.site_client = SiteClient()