def test_get_exception_users(ldap_uri): """Test that the exceptions list can be retrieved from LDAP.""" app = create_app('estuary.config.TestAuthConfig') app.config['LDAP_URI'] = ldap_uri app.config[ 'LDAP_EXCEPTIONS_GROUP_DN'] = 'cn=estuary-exceptions,cn=something,dc=domain,dc=local' # Create the mock LDAP instance server = ldap3.Server('ldaps://test.domain.local') connection = ldap3.Connection(server, client_strategy=ldap3.MOCK_SYNC) estuary_exceptions_group_attrs = { app.config['LDAP_GROUP_MEMBERSHIP_ATTRIBUTE']: [ 'uid=mprahl,ou=users,dc=domain,dc=local', 'uid=tbrady,ou=users,dc=domain,dc=local', ], 'cn': ['estuary-exceptions'], 'gidNumber': 1234, 'objectClass': ['top', 'groupOfUniqueNames', 'rhatRoverGroup'], } connection.strategy.add_entry( app.config['LDAP_EXCEPTIONS_GROUP_DN'], estuary_exceptions_group_attrs, ) with app.app_context(): with patch.object(ldap3, 'Tls', Mock(wraps=ldap3.Tls)) as mock_ldap_tls: with patch('ldap3.Connection') as mock_ldap: mock_ldap.return_value = connection assert _get_exception_users() == {'mprahl', 'tbrady'} if ldap_uri.startswith('ldaps'): mock_ldap_tls.assert_called_once() else: mock_ldap_tls.assert_not_called()
def test_get_exception_users_invalid_config(config): """Test that an exception is raised when configuration values are missing.""" app = create_app('estuary.config.TestAuthConfig') app.config.update(config) with app.app_context(): with pytest.raises(InternalServerError): _get_exception_users()
def test_is_user_authorized_exception(mock_geu, users, authorized): """Test that a non-employee that is in the exceptions users is authorized.""" mock_geu.return_value = users app = create_app('estuary.config.TestAuthConfig') app.config['LDAP_EXCEPTIONS_GROUP_DN'] = 'cn=something,dc=domain,dc=local' with app.app_context(): assert is_user_authorized('jlennon', 'Contractor') is authorized
def test_get_story_auth(mock_oidc, employee_type): """Test getting the story when authentication is required.""" mock_oidc.return_value.validate_token.return_value = True mock_oidc.return_value._get_token_info.return_value = \ {'active': True, 'employeeType': employee_type} client = create_app('estuary.config.TestAuthConfig').test_client() mock_oidc.assert_called_once() KojiBuild.get_or_create({ 'completion_time': datetime(2017, 4, 2, 19, 39, 6), 'creation_time': datetime(2017, 4, 2, 19, 39, 6), 'epoch': '0', 'id_': '2345', 'name': 'slf4j', 'release': '4.el7_4', 'start_time': datetime(2017, 4, 2, 19, 39, 6), 'state': 1, 'version': '1.7.4' })[0] expected = { 'data': [{ 'advisories': [], 'commit': None, 'completion_time': '2017-04-02T19:39:06Z', 'creation_time': '2017-04-02T19:39:06Z', 'epoch': '0', 'extra': None, 'id': '2345', 'name': 'slf4j', 'owner': None, 'release': '4.el7_4', 'resource_type': 'KojiBuild', 'module_builds': [], 'display_name': 'slf4j-1.7.4-4.el7_4', 'start_time': '2017-04-02T19:39:06Z', 'state': 1, 'tags': [], 'timeline_timestamp': '2017-04-02T19:39:06Z', 'version': '1.7.4' }], 'meta': { 'requested_node_index': 0, 'story_related_nodes_backward': [0], 'story_related_nodes_forward': [0], 'story_type': 'container', 'total_lead_time': 0.0, 'total_processing_time': 0.0, 'processing_time_flag': False, 'total_wait_time': 0.0, 'wait_times': [0] } } rv = client.get('/api/v1/story/kojibuild/2345', headers={'Authorization': 'Bearer 123456'}) assert rv.status_code == 200 assert json.loads(rv.data.decode('utf-8')) == expected
def test_get_story_auth_invalid_token(mock_oidc): """Test accessing a protected route with an invalid token.""" mock_oidc.return_value.validate_token.return_value = 'Token required but invalid' client = create_app('estuary.config.TestAuthConfig').test_client() mock_oidc.assert_called_once() rv = client.get('/api/v1/story/kojibuild/2345', headers={'Authorization': 'Bearer 123456'}) expected = {'message': 'Token required but invalid', 'status': 401} assert rv.status_code == 401 assert json.loads(rv.data.decode('utf-8')) == expected
def test_search_failed(mock_connection): """Test that an empty set is returned when the search fails.""" mock_connection.return_value.search.return_value = False app = create_app('estuary.config.TestAuthConfig') app.config['LDAP_URI'] = 'ldaps://domain.local' app.config[ 'LDAP_EXCEPTIONS_GROUP_DN'] = 'cn=estuary-exceptions,dc=domain,dc=local' with app.app_context(): assert _get_exception_users() == set() mock_connection.return_value.search.assert_called_once()
def test_get_story_auth_no_header(mock_oidc): """Test accessing a protected route without the "Authorization" header.""" client = create_app('estuary.config.TestAuthConfig').test_client() mock_oidc.assert_called_once() rv = client.get('/api/v1/story/kojibuild/2345') expected = { 'message': 'An "Authorization" header wasn\'t provided', 'status': 401 } assert rv.status_code == 401 assert json.loads(rv.data.decode('utf-8')) == expected
def test_get_story_auth_invalid_header(mock_oidc): """Test accessing a protected route with an invalid "Authorization" header.""" client = create_app('estuary.config.TestAuthConfig').test_client() mock_oidc.assert_called_once() rv = client.get('/api/v1/story/kojibuild/2345', headers={'Authorization': 'not bearer'}) expected = { 'message': 'The "Authorization" header must start with "Bearer"', 'status': 401 } assert rv.status_code == 401 assert json.loads(rv.data.decode('utf-8')) == expected
def test_connection_error(mock_connection): """Test that an exception is raised when the LDAP connection fails.""" mock_connection.return_value.open.side_effect = ldap3.core.exceptions.LDAPSocketOpenError( ) app = create_app('estuary.config.TestAuthConfig') app.config['LDAP_URI'] = 'ldaps://domain.local' app.config[ 'LDAP_EXCEPTIONS_GROUP_DN'] = 'cn=estuary-exceptions,dc=domain,dc=local' with app.app_context(): with pytest.raises(InternalServerError): _get_exception_users() mock_connection.return_value.open.assert_called_once()
def test_get_story_auth_not_employee(mock_oidc): """Test accessing a protected route with a valid token of a non-employee.""" mock_oidc.return_value.validate_token.return_value = True mock_oidc.return_value._get_token_info.return_value = \ {'active': True, 'employeeType': 'Contractor'} client = create_app('estuary.config.TestAuthConfig').test_client() mock_oidc.assert_called_once() rv = client.get('/api/v1/story/kojibuild/2345', headers={'Authorization': 'Bearer 123456'}) expected = { 'message': 'You must be an employee to access this service', 'status': 401 } assert rv.status_code == 401 assert json.loads(rv.data.decode('utf-8')) == expected
def test_load_secrets(): """Test that EstuaryOIDC.load_secrets returns the correct dictionary.""" app = create_app('estuary.config.TestAuthConfig') oidc = EstuaryOIDC() assert oidc.load_secrets(app) == { 'web': { 'redirect_uris': None, 'token_uri': None, 'auth_uri': None, 'client_id': 'estuary', 'client_secret': 'some_secret', 'userinfo_uri': None, 'token_introspection_uri': 'https://provider.domain.local/oauth2/default/v1/introspect' } }
def test_is_user_authorized_with_employee(employeeType, authorized): """Test that only employees are authorized.""" app = create_app('estuary.config.TestAuthConfig') with app.app_context(): assert is_user_authorized('jlennon', employeeType) is authorized
def client(): """Pytest fixture that creates a Flask application object for the pytest session.""" return create_app('estuary.config.TestConfig').test_client()
# SPDX-License-Identifier: GPL-3.0+ from estuary.app import create_app app = create_app()