def test_response_header_in_minimal_mode(client, faker, broken_db): test_user = User(username=faker.safe_email().split('@')[0]) test_token = test_user.generate_token(settings.SECRET_KEY) r = client.get('/whoami', headers={'Authorization': test_token}) assert_response_ok(r) assert r.headers['X-Minimal-Mode'] == '1' assert r.headers['X-Minimal-Mode-Reason'] == 'auth'
def factory(names): for name in names: if isinstance(name, list): name, email = name else: email = '*****@*****.**' % name User.create_normal( name, faker.password(), email=email, is_active=True)
def test_minimal_mode_incompatible(client, faker, broken_db): test_user = User(username=faker.safe_email().split('@')[0]) test_token = test_user.generate_token(settings.SECRET_KEY) r = client.get('/incompatible', headers={'Authorization': test_token}) assert r.status_code == 501 assert r.json['status'] == 'NotImplemented' assert r.json['message'] == ('Current API is not suitable for working ' 'in minimal mode') assert r.json['data'] is None
def test_get_team_application_token_with_malformed_user( client, db, test_team, test_application, admin_user, admin_token, faker): """The username and email prefix are not inconsistent.""" User.create_normal('foobar', faker.uuid4()[:8], '*****@*****.**', True) r = client.post('/api/team/%s/application/%s/token' % (test_team.team_name, test_application.application_name), data={'owner_email': '*****@*****.**'}, headers={'Authorization': admin_token}) assert_response_ok(r)
def test_authenticated_user_in_minimal_mode(client, faker, mocker, broken_db): test_user = User(username=faker.safe_email().split('@')[0]) test_token = test_user.generate_token(settings.SECRET_KEY) mocker.patch.object(settings, 'ADMIN_EMERGENCY_USER_LIST', ['admin']) r = client.get('/whoami', headers={'Authorization': test_token}) assert_response_ok(r) data = r.json['data'] assert data['username'] == test_user.username assert data['is_application'] is False assert data['is_admin'] is False
def ensure(self): user = (User.get_by_name(self.name) or User.get_by_email(self.email)) if user is None: password = gen_salt(30) user = User.create_normal(self.name, password, self.email, is_active=True) deliver_email(EmailTemplate.SIGNUP, user.email, { 'username': user.username, 'password': password, }) return user
def test_get_team_application_token_by_admin_with_unknown_owner_email( client, db, test_team, test_application, admin_user, admin_token, owner_email, mocker): r = client.post('/api/team/%s/application/%s/token' % (test_team.team_name, test_application.application_name), data={'owner_email': owner_email}, headers={'Authorization': admin_token}) assert_response_ok(r) user = User.get_by_token(settings.SECRET_KEY, r.json['data']['token']) assert user and user.username == test_application.application_name owner = owner_email.split('@', 1)[0] assert User.get_by_name(owner)
def test_create_normal(db): user = User.create_normal('water', 'foobar', '*****@*****.**') assert user.username == 'water' assert user.check_password('foobar') assert not user.check_password('foobaz') assert not user.is_active assert user.is_admin is False assert user.is_application is False with raises(NameOccupiedError): User.create_normal('water', 'foobaz', '*****@*****.**') assert db.query( User.email).filter_by(username='******').scalar() == '*****@*****.**'
def test_doctor_in_minimal_mode(app, client, mocker, faker, broken_db): metrics = app.extensions['huskar_api.db.tester'].metrics on_sys_exc = mocker.patch.object(metrics, 'on_api_called_sys_exc', autospec=True) on_ok = mocker.patch.object(metrics, 'on_api_called_ok', autospec=True) test_user = User(username=faker.safe_email().split('@')[0]) test_token = test_user.generate_token(settings.SECRET_KEY) client.get('/whoami', headers={'Authorization': test_token}) assert not on_ok.called assert on_sys_exc.called
def test_authenticated_application_in_minimal_mode(client, zk, faker, mocker, broken_db, data_type): test_user = User(username=faker.uuid4()[:8]) test_token = test_user.generate_token(settings.SECRET_KEY) zk_path = '/huskar/%s/%s' % (data_type, test_user.username) zk.ensure_path(zk_path) sleep(0.1) r = client.get('/whoami', headers={'Authorization': test_token}) assert_response_ok(r) data = r.json['data'] assert data['username'] == test_user.username assert data['is_application'] is True assert data['is_admin'] is False
def _publish_new_action(user_id, remote_addr, action): if remote_addr == settings.LOCAL_REMOTE_ADDR: return user = User.get(user_id) user_type = NORMAL_USER username = None if user: username = user.username if (user.is_application or username in settings.APPLICATION_USE_USER_TOKEN_USER_LIST): user_type = APPLICATION_USER is_subscriable = any(item[0] == TYPE_APPLICATION for item in action.action_indices) severity = SEVERITY_DANGEROUS action_name = action_types[action.action_type] if action_name in settings.DANGEROUS_ACTION_NAMES_EXCLUDE_LIST: severity = SEVERITY_NORMAL insensitive_data = remove_sensitive_data(action.action_data) try: new_action_detected.send(AuditLog, action_type=action.action_type, username=username, user_type=user_type, action_data=insensitive_data, is_subscriable=is_subscriable, severity=severity) except Exception: logger.exception('Unexpected error of publish webhook event') capture_exception(data=None)
def huskar_audit_log(action_type, **extra): if not switch.is_switched_on(SWITCH_ENABLE_AUDIT_LOG): yield return action = action_creator.make_action(action_type, **extra) yield try: if switch.is_switched_on(SWITCH_ENABLE_MINIMAL_MODE, False): action_name = action_types[action_type] fallback_audit_logger.info('arch.huskar_api %s %r', action_name, action.action_data) else: user = User.get_by_name('arch.huskar_api') user_id = user.id if user else 0 AuditLog.create(user_id, settings.LOCAL_REMOTE_ADDR, action) except AuditLogTooLongError: logger.info('Audit log is too long. %s arch.huskar_api', action_types[action_type]) return except AuditLogLostError: action_name = action_types[action_type] fallback_audit_logger.info('arch.huskar %s %r', action_name, action.action_data) except Exception: logger.exception('Unexpected error of audit log')
def test_get_multi_by_index(faker, action): assert AuditLog.get_multi_by_index(AuditLog.TYPE_SITE, 0)[:] == [] assert AuditLog.get_multi_by_index(AuditLog.TYPE_TEAM, 0)[:] == [] user = User.create_normal(faker.uuid4(), '-', faker.email()) log = AuditLog.create(user.id, faker.ipv4(), action) assert AuditLog.get_multi_by_index(AuditLog.TYPE_SITE, 0)[:] == [log] assert AuditLog.get_multi_by_index(AuditLog.TYPE_TEAM, 0)[:] == []
def test_ensure_ensure_owners_send_mail_failed(mocker): deliver_email = mocker.patch('huskar_api.extras.auth.deliver_email') deliver_email.side_effect = EmailDeliveryError() prefix = 'test_ensure_ensure_owners_send_mail_failed' application_name = '{}_app'.format(prefix) owner = Owner( '{}_user'.format(prefix), '{}[email protected]'.format(prefix), 'owner', ) department = Department( '1', '{}_team'.format(prefix), '2', '{}_team'.format(prefix)) appinfo = AppInfo( department=department, application_name=application_name, owners=[owner]) assert department.team_name == '{}-{}'.format( department.parent_id, department.child_id) assert department.team_desc == '{}-{}'.format( department.parent_name, department.child_name) assert len(list(ensure_owners(appinfo))) == 0 assert User.get_by_name('{}_user'.format(prefix)) is not None deliver_email.assert_called_once() mocker.patch.object(owner, 'ensure', mocker.MagicMock(side_effect=NameOccupiedError)) assert len(list(ensure_owners(appinfo))) == 0
def test_create_application(db, zk, test_team, faker): application_name = faker.uuid4()[:8] stat = zk.exists('/huskar/service/%s' % application_name) assert stat is None application = Application.create(application_name, test_team.id) assert zk.exists('/huskar/service/%s' % application_name) assert application.id > 0 assert application.application_name == application_name assert application.domain_name == application_name assert application.team_id == test_team.id assert application.team.team_name == test_team.team_name user = User.get_by_name(application_name) assert user is not None assert user.is_application assert not user.is_admin assert application.check_auth(Authority.WRITE, user.id) assert application.check_auth(Authority.READ, user.id) with raises(NameOccupiedError): Application.create(application_name, test_team.id) # name conflicts application = Application.create('baz', test_team.id) assert application.application_name == 'baz'
def test_add_application_auth_to_invalid_user( client, faker, add_user, admin_token, last_audit_log, test_application): add_user(['foo']) user = User.get_by_name('foo') user.archive() application_name = test_application.application_name unknow_user = faker.uuid4()[:6] r = client.post( '/api/auth/application/%s' % application_name, data={'username': unknow_user, 'authority': 'read'}, headers={'Authorization': admin_token}) assert r.status_code == 400 assert r.json['status'] == 'BadRequest' assert r.json['message'] == 'user %s does not exist' % unknow_user r = client.post( '/api/auth/application/%s' % application_name, data={'username': '******', 'authority': 'read'}, headers={'Authorization': admin_token}) assert r.status_code == 400 assert r.json['status'] == 'BadRequest' assert r.json['message'] == 'user foo does not exist' assert last_audit_log() is None
def post(self): """Obtains an user token by checking username and password. :form username: Required. The username of user. :form password: Required. The password of user. :form expiration: Optional. The life time in seconds of the token. ``0`` or omitted will make token be expired in 30 days. Default is ``0``. :<header Content-Type: :mimetype:`application/x-www-form-urlencoded` :status 400: The username or password is incorrect. :status 200: You could find token from the response body: ``{"status": "SUCCESS", "data": {"token": "..", "expires_in": 1}}`` """ username = request.form['username'].strip() password = request.form['password'].strip() expires_in = request.form.get('expiration', type=int, default=0) if expires_in > 0: expires_in = min(expires_in, settings.ADMIN_MAX_EXPIRATION) else: expires_in = settings.ADMIN_MAX_EXPIRATION user = User.get_by_name(username) if user is None or user.is_application: raise UserNotExistedError('user not found') if not user.check_password(password): raise LoginError("username or password not correct") g.auth = SessionAuth.from_user(user) with audit_log(audit_log.types.OBTAIN_USER_TOKEN, user=user): token = user.generate_token(settings.SECRET_KEY, expires_in) return api_response({'token': token, 'expires_in': expires_in})
def test_change_password(db, user_foo, input_password, hashed_password): user_foo.change_password(input_password) assert db.query(User.password).filter_by( username=user_foo.username).scalar() == hashed_password db.close() # clear identity map assert User.get(user_foo.id).password == hashed_password
def test_dismiss_admin(db, user_foo, present_is_admin): user_foo.huskar_admin = present_is_admin db.commit() user_foo.dismiss_admin() assert user_foo.is_admin is False assert User.get(user_foo.id, force=True).is_admin is False
def test_get_application_token_by_admin(client, db, test_application, admin_token): r = client.post('/api/application/%s/token' % test_application.application_name, headers={'Authorization': admin_token}) assert_response_ok(r) user = User.get_by_token(settings.SECRET_KEY, r.json['data']['token']) assert user and user.username == test_application.application_name
def test_get_application_token_with_malformed_application( client, faker, capsys, db, test_team, admin_token): _application = Application.create(faker.uuid4()[:8], test_team.id) _user = User.get_by_name(_application.application_name) with DBSession() as session: session.delete(_user) session.commit() _user = User.create_normal(_application.application_name, '-', is_active=True) r = client.post('/api/application/%s/token' % _application.application_name, headers={'Authorization': admin_token}) assert r.status_code == 400 assert r.json['status'] == 'BadRequest' assert r.json['message'] == ('malformed application: %s' % _application.application_name) assert r.json['data'] is None
def test_initdb_with_admin_present(mocker, admin_user): prompt_pass = mocker.patch.object(huskar_api.cli, 'prompt_pass') with pytest.raises(SystemExit): huskar_api.cli.initadmin() prompt_pass.assert_not_called() user = User.get_by_name('admin') assert user is admin_user
def test_get_application_token_with_orphan_application(client, faker, db, test_team, admin_token): _application = Application.create(faker.uuid4()[:8], test_team.id) _user = User.get_by_name(_application.application_name) _user.archive() user = User.get_by_name(_application.application_name) assert db.query(User).filter_by(username=_application.application_name, is_active=True).count() == 0 r = client.post('/api/application/%s/token' % _application.application_name, headers={'Authorization': admin_token}) assert_response_ok(r) user = User.get_by_token(settings.SECRET_KEY, r.json['data']['token']) assert user and user.username == _application.application_name assert User.get_by_name(_application.application_name) is not None assert db.query(User).filter_by( username=_application.application_name).count() == 1
def test_get_application_token_by_writer(client, db, method, test_application, test_user, test_token): test_application.ensure_auth(Authority.WRITE, test_user.id) r = client.open('/api/application/%s/token' % test_application.application_name, method=method, headers={'Authorization': test_token}) assert_response_ok(r) user = User.get_by_token(settings.SECRET_KEY, r.json['data']['token']) assert user and user.username == test_application.application_name
def post(self): """Creates a new user with your site admin authority. We will send you an email of random password if don't specify password explicitly. :form username: The username of new user. :form password: The optional password of new user. :form email: The email of new user. :<header Authorization: Huskar Token (See :ref:`token`) :status 400: The username is used or the format is invalid. :status 200: The new user is created successfully. """ g.auth.require_admin('only admin can add users') username = request.form['username'].strip() password = request.form.get('password', gen_salt(30)) is_generated_password = '******' not in request.form email = request.form['email'].strip() validate_fields(user_schema, {'username': username, 'email': email}) user = User.get_by_name(username) if user: abort(400, u'{0} is used username'.format(username)) try: user = User.create_normal(username, password, email, is_active=True) except NameOccupiedError: abort(400, u'User %s has been archived' % username) audit_log.emit(audit_log.types.CREATE_USER, user=user) if is_generated_password: deliver_email(EmailTemplate.SIGNUP, user.email, { 'username': user.username, 'password': password, }) return api_response()
def test_get_user_token(client, mocker, admin_user): g.auth = None r = client.post('/api/auth/token', data={ 'username': admin_user.username, 'password': '******' }) assert_response_ok(r) assert r.json['data']['expires_in'] == settings.ADMIN_MAX_EXPIRATION user = User.get_by_token(settings.SECRET_KEY, r.json['data']['token']) assert user and user.username == admin_user.username assert g.auth and g.auth.id == admin_user.id
def test_get_all_normal(db, user_foo): assert User.get_all_normal() == [user_foo] user_bar = User.create_application('base.bar') user_baz = User.create_normal('baz', '-', '*****@*****.**', is_active=True) user_too = User.create_normal('too', '-', '*****@*****.**', is_active=False) assert User.get_all_normal() == [user_foo, user_baz] assert user_bar not in User.get_all_normal() assert user_too not in User.get_all_normal()
def reset_password(username, token, new_password): key = _PASSWORD_RESET_KEY.format(username=username) expected_token = _redis_client.get(key) if expected_token and safe_str_cmp(token.hex, expected_token): _redis_client.delete(key) user = User.get_by_name(username) if user is None or user.is_application: abort(404, u'user {0} not found'.format(username)) user.change_password(new_password) else: abort(403, u'token is expired') return user
def test_recreate_archived_user(client, admin_token, add_test_user): user_data = {'username': '******', 'password': '******', 'email': '*****@*****.**'} headers = {'Authorization': admin_token} add_test_user(user_data) user = User.get_by_name('foo') user.archive() r = client.post('/api/user', data=user_data, headers=headers) assert r.status_code == 400 assert r.json['message']
def get(self, username=None): """Gets the entity data of an user or a list of users. :param username: If specified then respond an user instead a list of users. :<header Authorization: Huskar Token (See :ref:`token`) :status 404: The username is specified but there is nothing found. :status 200: An user or a list of users. """ if username: user = self._get_user_or_404(username) return api_response(user_schema.dump(user).data) else: user_list = User.get_all_normal() return api_response(user_schema.dump(user_list, many=True).data)