def default_acl(*args, **kwargs): """ Default ACLs for confidant: always return true for users, but enforce ACLs for services, restricting access to: * resource_type: service actions: metadata, get """ resource_type = kwargs.get('resource_type') action = kwargs.get('action') resource_id = kwargs.get('resource_id') # Some ACL checks also pass extra args in via kwargs, which we would # access via: # resource_kwargs = kwargs.get('kwargs') if authnz.user_is_user_type('user'): return True elif authnz.user_is_user_type('service'): if resource_type == 'service' and action in ['metadata', 'get']: # Does the resource ID match the authenticated username? if authnz.user_is_service(resource_id): return True # We currently only allow services to access service get/metadata return False else: # This should never happen, but paranoia wins out return False
def default_acl(*args, **kwargs): """ Default ACLs for confidant: Allow access to all resource types and actions for users, except for certificate resource_type. Deny access to all resource types and actions for services, except: * resource_type: service actions: metadata, get resource_id: must match logged-in user's username * resource_type: certificate actions: get resource_id: must match against ACM_PRIVATE_CA_DOMAIN_REGEX setting for the CA for the CN in the CSR, and for all SAN values in the CSR, and the server_name named group in the regex must match the logged in user's username. kwargs (ca): CA used for this get kwargs (san): A list of subject alternative names in the CSR """ resource_type = kwargs.get('resource_type') action = kwargs.get('action') resource_id = kwargs.get('resource_id') resource_kwargs = kwargs.get('kwargs') if authnz.user_is_user_type('user'): if resource_type == 'certificate': return False elif resource_type == 'ca': return False return True elif authnz.user_is_user_type('service'): if resource_type == 'service' and action in ['metadata', 'get']: # Does the resource ID match the authenticated username? if authnz.user_is_service(resource_id): return True elif resource_type == 'ca' and action in ['list', 'get']: return True elif resource_type == 'certificate' and action in ['get']: ca_object = certificatemanager.get_ca(resource_kwargs.get('ca')) # Require a name pattern if not ca_object.settings['name_regex']: return False cert_pattern = re.compile(ca_object.settings['name_regex']) domains = [resource_id] domains.extend(resource_kwargs.get('san', [])) # Ensure the CN and every value in the SAN is allowed for this # user. for domain in domains: match = cert_pattern.match(domain) if not match: return False service_name = match.group('service_name') if not service_name: return False if not authnz.user_is_service(service_name): return False return True return False else: # This should never happen, but paranoia wins out return False
def test_user_is_user_type(self): app.config['USE_AUTH'] = False self.assertTrue(authnz.user_is_user_type('anything')) app.config['USE_AUTH'] = True with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'user' self.assertTrue(authnz.user_is_user_type('user')) with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'service' self.assertTrue(authnz.user_is_user_type('service')) with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'user' self.assertFalse(authnz.user_is_user_type('service')) with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'service' self.assertFalse(authnz.user_is_user_type('user'))
def test_user_is_user_type(self): app.config['USE_AUTH'] = False self.assertTrue(authnz.user_is_user_type('anything')) app.config['USE_AUTH'] = True with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'user' self.assertTrue(authnz.user_is_user_type('user')) with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'service' self.assertTrue(authnz.user_is_user_type('service')) with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'user' self.assertFalse(authnz.user_is_user_type('service')) with patch('confidant.authnz.g') as g_mock: g_mock.user_type = 'service' self.assertFalse(authnz.user_is_user_type('user'))
def test_user_is_user_type(mocker): mocker.patch('confidant.authnz.settings.USE_AUTH', False) assert authnz.user_is_user_type('anything') is True mocker.patch('confidant.authnz.settings.USE_AUTH', True) app = create_app() with app.app_context(): g_mock = mocker.patch('confidant.authnz.g') g_mock.user_type = 'user' assert authnz.user_is_user_type('user') is True g_mock.user_type = 'service' assert authnz.user_is_user_type('service') is True g_mock.user_type = 'user' assert authnz.user_is_user_type('service') is False g_mock.user_type = 'service' assert authnz.user_is_user_type('user') is False
def get_service(id): ''' Get service metadata and all credentials for this service. This endpoint allows basic authentication. ''' #_init_.py에 정의된 user_is_user_type함수를 통해 service값이라면 제어문 안으로 if authnz.user_is_user_type('service'): #_init_.py에 정의된 user_is_service함수를 통해 함수의 파라메터 값으로 받아온 id가 아니라면 로그에 'Authz failed for service {0}.', 'Authenticated user is not authorized.'라는 메시지와 함께 401error를 띄운다 if not authnz.user_is_service(id): logging.warning('Authz failed for service {0}.'.format(id)) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 try: #service라는 변수에 id값 대입 service = Service.get(id) #_init_.py에 정의된 service_in_account함수를 통해 account값이 일치하지 않는다면 제어문 안으로 if not authnz.service_in_account(service.account): #아래와 같은 로그를 남긴다 logging.warning( 'Authz failed for service {0} (wrong account).'.format(id) ) #msg에 아래와 같은 문자 대입 msg = 'Authenticated user is not authorized.' #401error를 msg에 대입된 문자열과 함께 jsonify시켜 리턴 return jsonify({'error': msg}), 401 #위 try문의 코드에 error발생 시 예외처리 except DoesNotExist: return jsonify({}), 404 if (service.data_type != 'service' and service.data_type != 'archive-service'): return jsonify({}), 404 logging.debug('Authz succeeded for service {0}.'.format(id)) try: #credential을 가져온다 credentials = _get_credentials(service.credentials) except KeyError: #error발생 시 500error발생 logging.exception('KeyError occurred in getting credentials') return jsonify({'error': 'Decryption error.'}), 500 blind_credentials = _get_blind_credentials(service.blind_credentials) return jsonify({ 'id': service.id, 'account': service.account, 'credentials': credentials, 'blind_credentials': blind_credentials, 'enabled': service.enabled, 'revision': service.revision, 'modified_date': service.modified_date, 'modified_by': service.modified_by })
def get_service(id): ''' Get service metadata and all credentials for this service. This endpoint allows basic authentication. ''' if authnz.user_is_user_type('service'): if not authnz.user_is_service(id): logging.warning('Authz failed for service {0}.'.format(id)) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 try: service = Service.get(id) if not authnz.service_in_account(service.account): logging.warning( 'Authz failed for service {0} (wrong account).'.format(id) ) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 except DoesNotExist: return jsonify({}), 404 if (service.data_type != 'service' and service.data_type != 'archive-service'): return jsonify({}), 404 logging.debug('Authz succeeded for service {0}.'.format(id)) try: credentials = _get_credentials(service.credentials) except KeyError: logging.exception('KeyError occurred in getting credentials') return jsonify({'error': 'Decryption error.'}), 500 blind_credentials = _get_blind_credentials(service.blind_credentials) return jsonify({ 'id': service.id, 'account': service.account, 'credentials': credentials, 'blind_credentials': blind_credentials, 'enabled': service.enabled, 'revision': service.revision, 'modified_date': service.modified_date, 'modified_by': service.modified_by })
def get_service(id): ''' Get service metadata and all credentials for this service. This endpoint allows basic authentication. ''' if authnz.user_is_user_type('service'): if not authnz.user_is_service(id): logging.warning('Authz failed for service {0}.'.format(id)) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 try: service = Service.get(id) if not authnz.service_in_account(service.account): logging.warning( 'Authz failed for service {0} (wrong account).'.format(id) ) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 except Service.DoesNotExist: return jsonify({}), 404 if (service.data_type != 'service' and service.data_type != 'archive-service'): return jsonify({}), 404 logging.debug('Authz succeeded for service {0}.'.format(id)) try: credentials = _get_credentials(service.credentials) except KeyError: return jsonify({'error': 'Decryption error.'}), 500 blind_credentials = _get_blind_credentials(service.blind_credentials) return jsonify({ 'id': service.id, 'account': service.account, 'credentials': credentials, 'blind_credentials': blind_credentials, 'enabled': service.enabled, 'revision': service.revision, 'modified_date': service.modified_date, 'modified_by': service.modified_by })
def get_service(id): ''' Get a service object from the provided service ID. .. :quickref: Service; Get a service object from the provided service ID. **Example request**: .. sourcecode:: http GET /v1/services/example-development :param id: The service ID to get. :type id: str :query boolean metadata_only: If true, only fetch metadata for this service, and do not respond with decrypted credential pairs in the credential responses. **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "id": "example-development", "revision": 1, "enabled": true, "modified_date": "2019-12-16T23:16:11.413299+00:00", "modified_by": "*****@*****.**", "account": null, "credentials": [ { "id": "abcd12345bf4f1cafe8e722d3860404", "name": "Example Credential", "credential_keys": ["test_key"], "credential_pairs": { "test_key": "test_value" }, "metadata": { "example_metadata_key": "example_value" }, "revision": 1, "enabled": true, "documentation": "Example documentation", "modified_date": "2019-12-16T23:16:11.413299+00:00", "modified_by": "*****@*****.**", "permissions": {} }, ... ], "blind_credentials": [], "permissions": { "metadata": true, "get": true, "update": true } } :resheader Content-Type: application/json :statuscode 200: Success :statuscode 403: Client does not have permissions to get the service ID provided. ''' permissions = { 'metadata': False, 'get': False, 'update': False, } metadata_only = misc.get_boolean(request.args.get('metadata_only')) logged_in_user = authnz.get_logged_in_user() action = 'metadata' if metadata_only else 'get' permissions['metadata'] = acl_module_check( resource_type='service', action='metadata', resource_id=id, ) permissions['get'] = acl_module_check( resource_type='service', action='get', resource_id=id, ) if not permissions[action]: msg = "{} does not have access to get service {}".format( authnz.get_logged_in_user(), id ) error_msg = {'error': msg, 'reference': id} return jsonify(error_msg), 403 logger.info( 'get_service called on id={} by user={} metadata_only={}'.format( id, logged_in_user, metadata_only, ) ) try: service = Service.get(id) if not authnz.service_in_account(service.account): logger.warning( 'Authz failed for service {0} (wrong account).'.format(id) ) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 except DoesNotExist: return jsonify({}), 404 if (service.data_type != 'service' and service.data_type != 'archive-service'): return jsonify({}), 404 logger.debug('Authz succeeded for service {0}.'.format(id)) try: credentials = credentialmanager.get_credentials(service.credentials) except KeyError: logger.exception('KeyError occurred in getting credentials') return jsonify({'error': 'Decryption error.'}), 500 blind_credentials = credentialmanager.get_blind_credentials( service.blind_credentials, ) # TODO: this check can be expensive, so we're gating only to user auth. # We should probably add an argument that opts in for permission hints, # rather than always checking them. if authnz.user_is_user_type('user'): combined_cred_ids = ( list(service.credentials) + list(service.blind_credentials) ) permissions['update'] = acl_module_check( resource_type='service', action='update', resource_id=id, kwargs={ 'credential_ids': combined_cred_ids, }, ) service_response = ServiceResponse.from_service_expanded( service, credentials=credentials, blind_credentials=blind_credentials, metadata_only=metadata_only, ) service_response.permissions = permissions return service_expanded_response_schema.dumps(service_response)
def get_service(id): ''' Get service metadata and all credentials for this service. This endpoint allows basic authentication. ''' permissions = { 'metadata': False, 'get': False, 'update': False, } metadata_only = request.args.get('metadata_only', default=False, type=bool) logged_in_user = authnz.get_logged_in_user() action = 'metadata' if metadata_only else 'get' permissions['metadata'] = acl_module_check( resource_type='service', action='metadata', resource_id=id, ) permissions['get'] = acl_module_check( resource_type='service', action='get', resource_id=id, ) if not permissions[action]: msg = "{} does not have access to get service {}".format( authnz.get_logged_in_user(), id) error_msg = {'error': msg, 'reference': id} return jsonify(error_msg), 403 logging.info( 'get_service called on id={} by user={} metadata_only={}'.format( id, logged_in_user, metadata_only, )) try: service = Service.get(id) if not authnz.service_in_account(service.account): logging.warning( 'Authz failed for service {0} (wrong account).'.format(id)) msg = 'Authenticated user is not authorized.' return jsonify({'error': msg}), 401 except DoesNotExist: return jsonify({}), 404 if (service.data_type != 'service' and service.data_type != 'archive-service'): return jsonify({}), 404 logging.debug('Authz succeeded for service {0}.'.format(id)) try: credentials = credentialmanager.get_credentials(service.credentials) except KeyError: logging.exception('KeyError occurred in getting credentials') return jsonify({'error': 'Decryption error.'}), 500 blind_credentials = credentialmanager.get_blind_credentials( service.blind_credentials, ) # TODO: this check can be expensive, so we're gating only to user auth. # We should probably add an argument that opts in for permission hints, # rather than always checking them. if authnz.user_is_user_type('user'): combined_cred_ids = (list(service.credentials) + list(service.blind_credentials)) permissions['update'] = acl_module_check( resource_type='service', action='update', resource_id=id, kwargs={ 'credential_ids': combined_cred_ids, }, ) service_response = ServiceResponse.from_service_expanded( service, credentials=credentials, blind_credentials=blind_credentials, metadata_only=metadata_only, ) service_response.permissions = permissions return service_expanded_response_schema.dumps(service_response)