Exemplo n.º 1
0
def diff_service(id, old_revision, new_revision):
    if not acl_module_check(resource_type='service',
                            action='metadata',
                            resource_id=id):
        msg = "{} does not have access to diff service {}".format(
            authnz.get_logged_in_user(),
            id
        )
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    try:
        old_service = Service.get('{}-{}'.format(id, old_revision))
    except DoesNotExist:
        return jsonify({'error': 'Service not found.'}), 404
    if old_service.data_type != 'archive-service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    try:
        new_service = Service.get('{}-{}'.format(id, new_revision))
    except DoesNotExist:
        logging.warning(
            'Item with id {0} does not exist.'.format(id)
        )
        return jsonify({}), 404
    if new_service.data_type != 'archive-service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    return jsonify(old_service.diff(new_service))
Exemplo n.º 2
0
def get_archive_service_revisions(id):
    try:
        service = Service.get(id)
    except DoesNotExist:
        logging.warning('Item with id {0} does not exist.'.format(id))
        return jsonify({}), 404
    if (service.data_type != 'service'
            and service.data_type != 'archive-service'):
        return jsonify({}), 404
    revisions = []
    _range = range(1, service.revision + 1)
    ids = []
    for i in _range:
        ids.append("{0}-{1}".format(id, i))
    for revision in Service.batch_get(ids):
        revisions.append({
            'id': revision.id,
            'account': revision.account,
            'revision': revision.revision,
            'enabled': revision.enabled,
            'credentials': list(revision.credentials),
            'blind_credentials': list(revision.blind_credentials),
            'modified_date': revision.modified_date,
            'modified_by': revision.modified_by
        })
    return jsonify({
        'revisions':
        sorted(revisions, key=lambda k: k['revision'], reverse=True)
    })
Exemplo n.º 3
0
def get_archive_service_revisions(id):
    try:
        service = Service.get(id)
    except Service.DoesNotExist:
        return jsonify({}), 404
    if (service.data_type != 'service' and
            service.data_type != 'archive-service'):
        return jsonify({}), 404
    revisions = []
    _range = range(1, service.revision + 1)
    ids = []
    for i in _range:
        ids.append("{0}-{1}".format(id, i))
    for revision in Service.batch_get(ids):
        revisions.append({
            'id': revision.id,
            'revision': revision.revision,
            'enabled': revision.enabled,
            'credentials': list(revision.credentials),
            'modified_date': revision.modified_date,
            'modified_by': revision.modified_by
        })
    return jsonify({
        'revisions': sorted(
            revisions,
            key=lambda k: k['revision'],
            reverse=True
        )
    })
Exemplo n.º 4
0
def get_archive_service_revisions(id):
    if not acl_module_check(resource_type='service',
                            action='metadata',
                            resource_id=id):
        msg = "{} does not have access to service {} revisions".format(
            authnz.get_logged_in_user(),
            id
        )
        error_msg = {'error': msg}
        return jsonify(error_msg), 403
    try:
        service = Service.get(id)
    except DoesNotExist:
        logging.warning(
            'Item with id {0} does not exist.'.format(id)
        )
        return jsonify({}), 404
    if (service.data_type != 'service' and
            service.data_type != 'archive-service'):
        return jsonify({}), 404
    _range = range(1, service.revision + 1)
    ids = []
    for i in _range:
        ids.append("{0}-{1}".format(id, i))
    revisions_response = RevisionsResponse.from_services(
        Service.batch_get(ids)
    )
    return revisions_response_schema.dumps(revisions_response)
Exemplo n.º 5
0
def create_dynamodb_tables():
    i = 0
    # This loop is absurd, but there's race conditions with dynamodb local
    while i < 5:
        try:
            if not Credential.exists():
                Credential.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            if not BlindCredential.exists():
                BlindCredential.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            if not Service.exists():
                Service.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            break
        except TableError:
            i = i + 1
            time.sleep(2)
Exemplo n.º 6
0
def get_latest_service_revision(id, revision):
    i = revision + 1
    while True:
        _id = '{0}-{1}'.format(id, i)
        try:
            Service.get(_id)
        except DoesNotExist:
            return i
        i = i + 1
Exemplo n.º 7
0
def test_equals(mocker):
    service1 = Service(
        id='test',
        credentials=['abc', 'def'],
        blind_credentials=['123', '456'],
        account='test-account',
    )
    service2 = Service(
        id='test',
        credentials=['abc', 'def'],
        blind_credentials=['123', '456'],
        account='test-account',
    )
    assert service1.equals(service2) is True
Exemplo n.º 8
0
def get_service(id):
    '''
    Get service metadata and all credentials for this service. This endpoint
    allows basic authentication.
    '''
    if authnz.user_in_role('service') and 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
    logging.debug('Authz succeeded for service {0}.'.format(id))
    try:
        service = Service.get(id)
    except Service.DoesNotExist:
        return jsonify({}), 404
    if (service.data_type != 'service' and
            service.data_type != 'archive-service'):
        return jsonify({}), 404
    try:
        credentials = _get_credentials(service.credentials)
    except KeyError:
        return jsonify({'error': 'Decryption error.'}), 500
    return jsonify({
        'id': service.id,
        'credentials': credentials,
        'enabled': service.enabled,
        'revision': service.revision,
        'modified_date': service.modified_date,
        'modified_by': service.modified_by
    })
Exemplo n.º 9
0
def get_grants(id):
    if not acl_module_check(
          resource_type='service',
          action='metadata',
          resource_id=id,
    ):
        msg = "{} does not have access to get grants for service {}"
        msg = msg.format(authnz.get_logged_in_user(), id)
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({
        'id': id,
        'grants': grants
    })
Exemplo n.º 10
0
def ensure_grants(id):
    # we pass [] in for the credential IDs, because this action isn't related
    # to adding or removing credentials, but just a generic update of a
    # service.
    if not acl_module_check(resource_type='service',
                            action='update',
                            resource_id=id,
                            kwargs={
                                'credential_ids': [],
                            }):
        msg = "{} does not have access to ensure grants for service {}"
        msg = msg.format(authnz.get_logged_in_user(), id)
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        keymanager.ensure_grants(id)
    except keymanager.ServiceCreateGrantError:
        msg = 'Failed to add grants for service.'
        logging.error(msg)
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({'id': id, 'grants': grants})
Exemplo n.º 11
0
def get_service(id):
    '''
    Get service metadata and all credentials for this service. This endpoint
    allows basic authentication.
    '''
    if authnz.user_in_role('service') and not authnz.user_is_service(id):
        log.warning('Authz failed for service {0}.'.format(id))
        msg = 'Authenticated user is not authorized.'
        return jsonify({'error': msg}), 401
    log.debug('Authz succeeded for service {0}.'.format(id))
    try:
        service = Service.get(id)
    except Service.DoesNotExist:
        return jsonify({}), 404
    if (service.data_type != 'service'
            and service.data_type != 'archive-service'):
        return jsonify({}), 404
    try:
        credentials = _get_credentials(service.credentials)
    except KeyError:
        return jsonify({'error': 'Decryption error.'}), 500
    return jsonify({
        'id': service.id,
        'credentials': credentials,
        'enabled': service.enabled,
        'revision': service.revision,
        'modified_date': service.modified_date,
        'modified_by': service.modified_by
    })
Exemplo n.º 12
0
def mapped_service(mocker):
    mocked = mocker.patch.object(Service, 'data_type_date_index')
    mocked.query = mocker.Mock(
        return_value=[Service(id='test-service', revision=1, enabled=True)], )
    mocker.patch(
        'confidant.scripts.archive.ArchiveCredentials.credential_in_service',
        return_value=True,
    )
Exemplo n.º 13
0
 def test_valid_kms_auth_token_good_account(self, keymanager_mock):
     app.debug = True
     app.config['USE_AUTH'] = True
     service = Service(
         id='confidant-development',
         data_type='service',
         account='sandbox',
         credentials=[],
         blind_credentials=[],
         enabled=True,
         revision=1,
         modified_by='test-user'
     )
     service.save()
     keymanager_mock.return_value = {
         "payload": {"fake": "payload"},
         "key_alias": "sandbox-auth-key"
     }
     auth = base64.b64encode(
         '{0}:{1}'.format('confidant-development', 'faketoken')
     )
     ret = self.test_client.open(
         '/v1/services/confidant-development',
         'GET',
         headers={'Authorization': 'Basic {0}'.format(auth)},
         follow_redirects=False
     )
     service.delete()
     self.assertEquals(ret.status_code, 200)
Exemplo n.º 14
0
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
    })
Exemplo n.º 15
0
def get_grants(id):
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({'id': id, 'grants': grants})
Exemplo n.º 16
0
def test_diff(mocker):
    modified_by = '*****@*****.**'
    modified_date_old = datetime.now
    modified_date_new = datetime.now
    old = Service(
        id='test',
        revision=1,
        credentials=['abc', 'def'],
        blind_credentials=['123', '456'],
        account='test-account',
        modified_by=modified_by,
        modified_date=modified_date_old,
    )
    new = Service(
        id='test',
        revision=1,
        credentials=['def'],
        blind_credentials=['123', '456', '789'],
        account='test-account2',
        modified_by=modified_by,
        modified_date=modified_date_new,
    )
    # If the revisions are the same we short-circuit, so even if the contents
    # differ, there should be no diff.
    assert old.diff(new) == {}

    new.revision = 2
    expected_diff = {
        'credentials': {
            'removed': ['abc'],
        },
        'blind_credentials': {
            'added': ['789'],
        },
        'account': {
            'removed': 'test-account',
            'added': 'test-account2',
        },
        'modified_by': {
            'removed': '*****@*****.**',
            'added': '*****@*****.**',
        },
        'modified_date': {
            'removed': modified_date_old,
            'added': modified_date_new,
        },
    }
    assert old.diff(new) == expected_diff
Exemplo n.º 17
0
def get_grants(id):
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except Service.DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({
        'id': id,
        'grants': grants
    })
Exemplo n.º 18
0
def ensure_grants(id):
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except Service.DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        keymanager.ensure_grants(id)
    except keymanager.ServiceCreateGrantError:
        msg = 'Failed to add grants for service.'
        logging.error(msg)
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({'id': id, 'grants': grants})
Exemplo n.º 19
0
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
    })
Exemplo n.º 20
0
def map_service_credentials(id):
    """
    Create or update a service to credential mapping.

    .. :quickref: Service; Create or update a service to credential mapping
                  with the data provided in the PUT body.

    **Example request**:

    .. sourcecode:: http

       PUT /v1/services/example-development

    :param id: The service ID to create or update.
    :type id: str
    :<json List[string] credentials: A list of credential IDs to map to this
      service.
    :<json List[string] blind_credentials: A list of blind_credential IDs to
      map to this service.
    :<json boolean enabled: Whether or not this service is enabled.
      (default: true)
    :<json string account: An AWS account to scope this service to.

    **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 400: Invalid input; Either required fields were not provided
                     or credentials being mapped would result in credential key
                     conflicts.
    :statuscode 403: Client does not have permissions to create or update the
                     specified service ID.
    """
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
        revision = servicemanager.get_latest_service_revision(
            id,
            _service.revision
        )
    except DoesNotExist:
        revision = 1
        _service = None

    if revision == 1 and not acl_module_check(
          resource_type='service',
          action='create',
          resource_id=id,
    ):
        msg = "{} does not have access to create service {}".format(
            authnz.get_logged_in_user(),
            id
        )
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    data = request.get_json()
    credentials = data.get('credentials', [])
    blind_credentials = data.get('blind_credentials', [])
    combined_credentials = credentials + blind_credentials
    if not acl_module_check(
          resource_type='service',
          action='update',
          resource_id=id,
          kwargs={
              'credential_ids': combined_credentials,
          }
    ):
        msg = ("{} does not have access to map the credentials "
               "because they do not own the credentials being added")
        msg = msg.format(authnz.get_logged_in_user())
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    conflicts = credentialmanager.pair_key_conflicts_for_credentials(
        credentials,
        blind_credentials,
    )
    if conflicts:
        ret = {
            'error': 'Conflicting key pairs in mapped service.',
            'conflicts': conflicts
        }
        return jsonify(ret), 400

    accounts = list(settings.SCOPED_AUTH_KEYS.values())
    if data.get('account') and data['account'] not in accounts:
        ret = {'error': '{0} is not a valid account.'}
        return jsonify(ret), 400

    # If this is the first revision, we should attempt to create a grant for
    # this service.
    if revision == 1:
        try:
            keymanager.ensure_grants(id)
        except keymanager.ServiceCreateGrantError:
            msg = 'Failed to add grants for {0}.'.format(id)
            logger.error(msg)
    credentials = credentialmanager.get_credentials(data.get('credentials'))
    blind_credentials = credentialmanager.get_blind_credentials(
        data.get('blind_credentials'),
    )
    # Use the IDs from the fetched IDs, to ensure we filter any archived
    # credential IDs.
    filtered_credential_ids = [cred.id for cred in credentials]
    # Try to save to the archive
    try:
        Service(
            id='{0}-{1}'.format(id, revision),
            data_type='archive-service',
            credentials=filtered_credential_ids,
            blind_credentials=data.get('blind_credentials'),
            account=data.get('account'),
            enabled=data.get('enabled'),
            revision=revision,
            modified_by=authnz.get_logged_in_user()
        ).save(id__null=True)
    except PutError as e:
        logger.error(e)
        return jsonify({'error': 'Failed to add service to archive.'}), 500

    try:
        service = Service(
            id=id,
            data_type='service',
            credentials=filtered_credential_ids,
            blind_credentials=data.get('blind_credentials'),
            account=data.get('account'),
            enabled=data.get('enabled'),
            revision=revision,
            modified_by=authnz.get_logged_in_user()
        )
        service.save()
    except PutError as e:
        logger.error(e)
        return jsonify({'error': 'Failed to update active service.'}), 500
    servicemanager.send_service_mapping_graphite_event(service, _service)
    webhook.send_event('service_update', [service.id], service.credentials)
    permissions = {
        'create': True,
        'metadata': True,
        'get': True,
        'update': True,
    }
    service_response = ServiceResponse.from_service_expanded(
        service,
        credentials=credentials,
        blind_credentials=blind_credentials,
    )
    service_response.permissions = permissions
    return service_expanded_response_schema.dumps(service_response)
Exemplo n.º 21
0
def get_archive_service_revisions(id):
    """
    Get a list of revisions for the specified service ID.

    .. :quickref: Service History; Get a list of revisions for the specified
                  service ID.

    **Example request**:

    .. sourcecode:: http

       GET /v1/archive/services/example-development

    :param id: The service ID to get.
    :type id: str
    :query string next_page: If paged results were returned in a call, this
                             query string can be used to fetch the next page.

    **Example response**:

    .. sourcecode:: http

       HTTP/1.1 200 OK
       Content-Type: application/json

       {
         "revisions": [
           {
             "id": "example-development-1",
             "revision": 1,
             "enabled": true,
             "modified_date": "2019-12-16T23:16:11.413299+00:00",
             "modified_by": "*****@*****.**",
             "account": null,
             "credentials": [],
             "blind_credentials": [],
             "permissions": {}
           },
           ...
         ],
         "next_page": null
       }

    :resheader Content-Type: application/json
    :statuscode 200: Success
    :statuscode 403: Client does not have permissions to get metadata for the
                     provided service ID.
    :statuscode 404: Specified ID does not exist.
    """
    if not acl_module_check(resource_type='service',
                            action='metadata',
                            resource_id=id):
        msg = "{} does not have access to service {} revisions".format(
            authnz.get_logged_in_user(),
            id
        )
        error_msg = {'error': msg}
        return jsonify(error_msg), 403
    try:
        service = Service.get(id)
    except DoesNotExist:
        logger.warning(
            'Item with id {0} does not exist.'.format(id)
        )
        return jsonify({}), 404
    if (service.data_type != 'service' and
            service.data_type != 'archive-service'):
        return jsonify({}), 404
    _range = range(1, service.revision + 1)
    ids = []
    for i in _range:
        ids.append("{0}-{1}".format(id, i))
    revisions_response = RevisionsResponse.from_services(
        Service.batch_get(ids)
    )
    return revisions_response_schema.dumps(revisions_response)
Exemplo n.º 22
0
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)
Exemplo n.º 23
0
def ensure_grants(id):
    """
    Ensure grants are set for the provided service ID.

    .. :quickref: KMS Grants; Ensure grants are set for the provided service ID.

    **Example request**:

    .. sourcecode:: http

       PUT /v1/grants/example-development

    :param id: The service ID to ensure grants for.
    :type id: str

    **Example response**:

    .. sourcecode:: http

       HTTP/1.1 200 OK
       Content-Type: application/json

       {
         "id": "example-development",
         "grants": {
           "encrypt_grant": true,
           "decrypt_grant": true
         }
       }

    :resheader Content-Type: application/json
    :statuscode 200: Success
    :statuscode 400: Invalid input. The service provided does not exist.
    :statuscode 403: Client does not have permissions to create or update the
                     specified service ID.
    """
    # we pass [] in for the credential IDs, because this action isn't related
    # to adding or removing credentials, but just a generic update of a
    # service.
    if not acl_module_check(
          resource_type='service',
          action='update',
          resource_id=id,
          kwargs={
              'credential_ids': [],
          }
    ):
        msg = "{} does not have access to ensure grants for service {}"
        msg = msg.format(authnz.get_logged_in_user(), id)
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        keymanager.ensure_grants(id)
    except keymanager.ServiceCreateGrantError:
        msg = 'Failed to add grants for service.'
        logger.error(msg)
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({
        'id': id,
        'grants': grants
    })
Exemplo n.º 24
0
def map_service_credentials(id):
    data = request.get_json()
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
        revision = _service.revision + 1
        _service_credential_ids = _service.credentials
    except DoesNotExist:
        revision = 1
        _service_credential_ids = []

    if data.get('credentials') or data.get('blind_credentials'):
        conflicts = _pair_key_conflicts_for_credentials(
            data.get('credentials', []),
            data.get('blind_credentials', []),
        )
        if conflicts:
            ret = {
                'error': 'Conflicting key pairs in mapped service.',
                'conflicts': conflicts
            }
            return jsonify(ret), 400

    accounts = list(app.config['SCOPED_AUTH_KEYS'].values())
    if data.get('account') and data['account'] not in accounts:
        ret = {'error': '{0} is not a valid account.'}
        return jsonify(ret), 400

    # If this is the first revision, we should attempt to create a grant for
    # this service.
    if revision == 1:
        try:
            keymanager.ensure_grants(id)
        except keymanager.ServiceCreateGrantError:
            msg = 'Failed to add grants for {0}.'.format(id)
            logging.error(msg)
    # Try to save to the archive
    try:
        Service(id='{0}-{1}'.format(id, revision),
                data_type='archive-service',
                credentials=data.get('credentials'),
                blind_credentials=data.get('blind_credentials'),
                account=data.get('account'),
                enabled=data.get('enabled'),
                revision=revision,
                modified_by=authnz.get_logged_in_user()).save(id__null=True)
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to add service to archive.'}), 500

    try:
        service = Service(id=id,
                          data_type='service',
                          credentials=data.get('credentials'),
                          blind_credentials=data.get('blind_credentials'),
                          account=data.get('account'),
                          enabled=data.get('enabled'),
                          revision=revision,
                          modified_by=authnz.get_logged_in_user())
        service.save()
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to update active service.'}), 500
    added = list(set(service.credentials) - set(_service_credential_ids))
    removed = list(set(_service_credential_ids) - set(service.credentials))
    msg = 'Added credentials: {0}; Removed credentials {1}; Revision {2}'
    msg = msg.format(added, removed, service.revision)
    graphite.send_event([id], msg)
    webhook.send_event('service_update', [service.id], service.credentials)
    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,
        'revision': service.revision,
        'enabled': service.enabled,
        'modified_date': service.modified_date,
        'modified_by': service.modified_by
    })
Exemplo n.º 25
0
def map_service_credentials(id):
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
        revision = servicemanager.get_latest_service_revision(
            id, _service.revision)
    except DoesNotExist:
        revision = 1
        _service = None

    if revision == 1 and not acl_module_check(
            resource_type='service',
            action='create',
            resource_id=id,
    ):
        msg = "{} does not have access to create service {}".format(
            authnz.get_logged_in_user(), id)
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    data = request.get_json()
    credentials = data.get('credentials', [])
    blind_credentials = data.get('blind_credentials', [])
    combined_credentials = credentials + blind_credentials
    if not acl_module_check(resource_type='service',
                            action='update',
                            resource_id=id,
                            kwargs={
                                'credential_ids': combined_credentials,
                            }):
        msg = ("{} does not have access to map the credentials "
               "because they do not own the credentials being added")
        msg = msg.format(authnz.get_logged_in_user())
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    conflicts = credentialmanager.pair_key_conflicts_for_credentials(
        credentials,
        blind_credentials,
    )
    if conflicts:
        ret = {
            'error': 'Conflicting key pairs in mapped service.',
            'conflicts': conflicts
        }
        return jsonify(ret), 400

    accounts = list(settings.SCOPED_AUTH_KEYS.values())
    if data.get('account') and data['account'] not in accounts:
        ret = {'error': '{0} is not a valid account.'}
        return jsonify(ret), 400

    # If this is the first revision, we should attempt to create a grant for
    # this service.
    if revision == 1:
        try:
            keymanager.ensure_grants(id)
        except keymanager.ServiceCreateGrantError:
            msg = 'Failed to add grants for {0}.'.format(id)
            logging.error(msg)
    # Try to save to the archive
    try:
        Service(id='{0}-{1}'.format(id, revision),
                data_type='archive-service',
                credentials=data.get('credentials'),
                blind_credentials=data.get('blind_credentials'),
                account=data.get('account'),
                enabled=data.get('enabled'),
                revision=revision,
                modified_by=authnz.get_logged_in_user()).save(id__null=True)
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to add service to archive.'}), 500

    try:
        service = Service(id=id,
                          data_type='service',
                          credentials=data.get('credentials'),
                          blind_credentials=data.get('blind_credentials'),
                          account=data.get('account'),
                          enabled=data.get('enabled'),
                          revision=revision,
                          modified_by=authnz.get_logged_in_user())
        service.save()
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to update active service.'}), 500
    servicemanager.send_service_mapping_graphite_event(service, _service)
    webhook.send_event('service_update', [service.id], service.credentials)
    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, )
    permissions = {
        'create': True,
        'metadata': True,
        'get': True,
        'update': True,
    }
    service_response = ServiceResponse.from_service_expanded(
        service,
        credentials=credentials,
        blind_credentials=blind_credentials,
    )
    service_response.permissions = permissions
    return service_expanded_response_schema.dumps(service_response)
Exemplo n.º 26
0
from confidant.models.blind_credential import BlindCredential
from confidant.models.service import Service

if app.config['DYNAMODB_CREATE_TABLE']:
    i = 0
    # This loop is absurd, but there's race conditions with dynamodb local
    while i < 5:
        try:
            if not Credential.exists():
                Credential.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            if not BlindCredential.exists():
                BlindCredential.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            if not Service.exists():
                Service.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            break
        except TableError:
            i = i + 1
            time.sleep(2)
Exemplo n.º 27
0
def revert_service_to_revision(id, to_revision):
    if not acl_module_check(
            resource_type='service', action='revert', resource_id=id):
        msg = "{} does not have access to revert service {}".format(
            authnz.get_logged_in_user(), id)
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    try:
        current_service = Service.get(id)
    except DoesNotExist:
        logging.warning('Item with id {0} does not exist.'.format(id))
        return jsonify({}), 404
    if current_service.data_type != 'service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    new_revision = servicemanager.get_latest_service_revision(
        id, current_service.revision)
    try:
        revert_service = Service.get('{}-{}'.format(id, to_revision))
    except DoesNotExist:
        logging.warning('Item with id {0} does not exist.'.format(id))
        return jsonify({}), 404
    if revert_service.data_type != 'archive-service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    if revert_service.equals(current_service):
        ret = {'error': 'No difference between old and new service.'}
        return jsonify(ret), 400
    if revert_service.credentials or revert_service.blind_credentials:
        conflicts = credentialmanager.pair_key_conflicts_for_credentials(
            revert_service.credentials,
            revert_service.blind_credentials,
        )
        if conflicts:
            ret = {
                'error': 'Conflicting key pairs in mapped service.',
                'conflicts': conflicts
            }
            return jsonify(ret), 400
    # Try to save to the archive
    try:
        Service(id='{0}-{1}'.format(id, new_revision),
                data_type='archive-service',
                credentials=revert_service.credentials,
                blind_credentials=revert_service.blind_credentials,
                account=revert_service.account,
                enabled=revert_service.enabled,
                revision=new_revision,
                modified_by=authnz.get_logged_in_user()).save(id__null=True)
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to add service to archive.'}), 500

    try:
        service = Service(id=id,
                          data_type='service',
                          credentials=revert_service.credentials,
                          blind_credentials=revert_service.blind_credentials,
                          account=revert_service.account,
                          enabled=revert_service.enabled,
                          revision=new_revision,
                          modified_by=authnz.get_logged_in_user())
        service.save()
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to update active service.'}), 500
    servicemanager.send_service_mapping_graphite_event(service,
                                                       current_service)
    webhook.send_event(
        'service_update',
        [service.id],
        service.credentials,
    )
    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, )
    return service_expanded_response_schema.dumps(
        ServiceResponse.from_service_expanded(
            service,
            credentials=credentials,
            blind_credentials=blind_credentials,
        ))
Exemplo n.º 28
0
import time

from confidant import app
from confidant.models.credential import Credential
from confidant.models.service import Service
from pynamodb.exceptions import TableError

# Only used when using dynamodb local
if app.config.get('DYNAMODB_URL'):
    i = 0
    # This loop is absurd, but there's race conditions with dynamodb local
    while i < 5:
        try:
            if not Credential.exists():
                Credential.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            if not Service.exists():
                Service.create_table(
                    read_capacity_units=10,
                    write_capacity_units=10,
                    wait=True
                )
            break
        except TableError:
            i = i + 1
            time.sleep(2)
Exemplo n.º 29
0
def revert_service_to_revision(id, to_revision):
    '''
    Revert the provided service to the provided revision.

    .. :quickref: Service; Revert the provided service to the provided
                  revision

    **Example request**:

    .. sourcecode:: http

       PUT /v1/services/example-development/1

    :param id: The service ID to revert.
    :type id: str
    :param to_revision: The revision to revert this service to.
    :type to_revision: int

    **Example response**:

    .. sourcecode:: http

       HTTP/1.1 200 OK
       Content-Type: application/json

       {
         "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": {}
       }

    :resheader Content-Type: application/json
    :statuscode 200: Success
    :statuscode 400: Invalid input; the update would create conflicting
                     credential keys in the service mapping.
    :statuscode 403: Client does not have access to revert the provided
                     service ID.
    '''
    if not acl_module_check(resource_type='service',
                            action='revert',
                            resource_id=id):
        msg = "{} does not have access to revert service {}".format(
            authnz.get_logged_in_user(),
            id
        )
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    try:
        current_service = Service.get(id)
    except DoesNotExist:
        logger.warning(
            'Item with id {0} does not exist.'.format(id)
        )
        return jsonify({}), 404
    if current_service.data_type != 'service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    new_revision = servicemanager.get_latest_service_revision(
        id,
        current_service.revision
    )
    try:
        revert_service = Service.get('{}-{}'.format(id, to_revision))
    except DoesNotExist:
        logger.warning(
            'Item with id {0} does not exist.'.format(id)
        )
        return jsonify({}), 404
    if revert_service.data_type != 'archive-service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    if revert_service.credentials or revert_service.blind_credentials:
        conflicts = credentialmanager.pair_key_conflicts_for_credentials(
            revert_service.credentials,
            revert_service.blind_credentials,
        )
        if conflicts:
            ret = {
                'error': 'Conflicting key pairs in mapped service.',
                'conflicts': conflicts
            }
            return jsonify(ret), 400
    credentials = credentialmanager.get_credentials(
        revert_service.credentials,
    )
    blind_credentials = credentialmanager.get_blind_credentials(
        revert_service.blind_credentials,
    )
    # Use the IDs from the fetched IDs, to ensure we filter any archived
    # credential IDs.
    revert_service.credentials = [cred.id for cred in credentials]
    if revert_service.equals(current_service):
        ret = {
            'error': 'No difference between old and new service.'
        }
        return jsonify(ret), 400
    # Try to save to the archive
    try:
        Service(
            id='{0}-{1}'.format(id, new_revision),
            data_type='archive-service',
            credentials=revert_service.credentials,
            blind_credentials=revert_service.blind_credentials,
            account=revert_service.account,
            enabled=revert_service.enabled,
            revision=new_revision,
            modified_by=authnz.get_logged_in_user()
        ).save(id__null=True)
    except PutError as e:
        logger.error(e)
        return jsonify({'error': 'Failed to add service to archive.'}), 500

    try:
        service = Service(
            id=id,
            data_type='service',
            credentials=revert_service.credentials,
            blind_credentials=revert_service.blind_credentials,
            account=revert_service.account,
            enabled=revert_service.enabled,
            revision=new_revision,
            modified_by=authnz.get_logged_in_user()
        )
        service.save()
    except PutError as e:
        logger.error(e)
        return jsonify({'error': 'Failed to update active service.'}), 500
    servicemanager.send_service_mapping_graphite_event(service, current_service)
    webhook.send_event(
        'service_update',
        [service.id],
        service.credentials,
    )
    return service_expanded_response_schema.dumps(
        ServiceResponse.from_service_expanded(
            service,
            credentials=credentials,
            blind_credentials=blind_credentials,
        )
    )
Exemplo n.º 30
0
def diff_service(id, old_revision, new_revision):
    """
    Returns a diff between old_revision and new_revision for the provided
    service id.

    .. :quickref: Service Diff; Get a diff of two revisions of a service.

    **Example request**:

    .. sourcecode:: http

       GET /v1/services/example-development/1/2

    :param id: The service ID to get.
    :type id: str
    :param old_revision: One of the two revisions to diff against.
    :type old_revision: int
    :param new_revision: One of the two revisions to diff against.
    :type new_revision: int

    **Example response**:

    .. sourcecode:: http

       HTTP/1.1 200 OK
       Content-Type: application/json

       {
         "enabled": {
           "added": true,
           "removed": false
         },
         "credentials": {
           "added": [
             "abcd12345bf4f1cafe8e722d3860404"
           ],
           "removed": [
             "aaaa33335bf4f1cafe8e722d3860404"
           ]
         },
         "blind_credentials": {},
         "modified_date": {
           "added": "2019-12-16T23:16:11.413299+00:00",
           "removed": "2019-11-16T23:16:11.413299+00:00"
         },
         "modified_by": {
           "added": "*****@*****.**",
           "removed": "*****@*****.**"
         }
       }

    :resheader Content-Type: application/json
    :statuscode 200: Success
    :statuscode 403: Client does not have permissions to diff the provided
                     service ID.
    :statuscode 404: The provided service ID or one of the provided
                     revisions does not exist.
    """
    if not acl_module_check(resource_type='service',
                            action='metadata',
                            resource_id=id):
        msg = "{} does not have access to diff service {}".format(
            authnz.get_logged_in_user(),
            id
        )
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403

    try:
        old_service = Service.get('{}-{}'.format(id, old_revision))
    except DoesNotExist:
        return jsonify({'error': 'Service not found.'}), 404
    if old_service.data_type != 'archive-service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    try:
        new_service = Service.get('{}-{}'.format(id, new_revision))
    except DoesNotExist:
        logger.warning(
            'Item with id {0} does not exist.'.format(id)
        )
        return jsonify({}), 404
    if new_service.data_type != 'archive-service':
        msg = 'id provided is not a service.'
        return jsonify({'error': msg}), 400
    return jsonify(old_service.diff(new_service))
Exemplo n.º 31
0
def map_service_credentials(id):
    data = request.get_json()
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
        revision = _service.revision + 1
        _service_credential_ids = _service.credentials
    except Service.DoesNotExist:
        revision = 1
        _service_credential_ids = []

    if data.get('credentials'):
        conflicts = _pair_key_conflicts_for_credentials(
            copy.deepcopy(data['credentials'])
        )
        if conflicts:
            ret = {
                'error': 'Conflicting key pairs in mapped service.',
                'conflicts': conflicts
            }
            return jsonify(ret), 400

    # If this is the first revision, we should attempt to create a grant for
    # this service.
    if revision == 1:
        try:
            keymanager.ensure_grants(id)
        except keymanager.ServiceCreateGrantError:
            msg = 'Failed to add grants for {0}.'.format(id)
            logging.error(msg)
    # Try to save to the archive
    try:
        Service(
            id='{0}-{1}'.format(id, revision),
            data_type='archive-service',
            credentials=data.get('credentials'),
            enabled=data.get('enabled'),
            revision=revision,
            modified_by=authnz.get_logged_in_user_email()
        ).save(id__null=True)
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to add service to archive.'}), 500

    try:
        service = Service(
            id=id,
            data_type='service',
            credentials=data['credentials'],
            enabled=data.get('enabled'),
            revision=revision,
            modified_by=authnz.get_logged_in_user_email()
        )
        service.save()
    except PutError as e:
        logging.error(e)
        return jsonify({'error': 'Failed to update active service.'}), 500
    added = list(set(service.credentials) - set(_service_credential_ids))
    removed = list(set(_service_credential_ids) - set(service.credentials))
    msg = 'Added credentials: {0}; Removed credentials {1}; Revision {2}'
    msg = msg.format(added, removed, service.revision)
    graphite.send_event([id], msg)
    try:
        credentials = _get_credentials(service.credentials)
    except KeyError:
        return jsonify({'error': 'Decryption error.'}), 500
    return jsonify({
        'id': service.id,
        'credentials': credentials,
        'revision': service.revision,
        'enabled': service.enabled,
        'modified_date': service.modified_date,
        'modified_by': service.modified_by
    })
Exemplo n.º 32
0
def get_grants(id):
    """
    Get grants for the provided service ID.

    .. :quickref: KMS Grants; Get grants for the provided service ID.

    **Example request**:

    .. sourcecode:: http

       GET /v1/grants/example-development

    :param id: The service ID to ensure grants for.
    :type id: str

    **Example response**:

    .. sourcecode:: http

       HTTP/1.1 200 OK
       Content-Type: application/json

       {
         "id": "example-development",
         "grants": {
           "encrypt_grant": true,
           "decrypt_grant": true
         }
       }

    :resheader Content-Type: application/json
    :statuscode 200: Success
    :statuscode 400: Invalid input. The service provided does not exist.
    :statuscode 403: Client does not have permissions to get service metadata
                     for the specified service ID.
    """
    if not acl_module_check(
          resource_type='service',
          action='metadata',
          resource_id=id,
    ):
        msg = "{} does not have access to get grants for service {}"
        msg = msg.format(authnz.get_logged_in_user(), id)
        error_msg = {'error': msg, 'reference': id}
        return jsonify(error_msg), 403
    try:
        _service = Service.get(id)
        if _service.data_type != 'service':
            msg = 'id provided is not a service.'
            return jsonify({'error': msg}), 400
    except DoesNotExist:
        msg = 'id provided does not exist.'
        return jsonify({'error': msg}), 400
    try:
        grants = keymanager.grants_exist(id)
    except keymanager.ServiceGetGrantError:
        msg = 'Failed to get grants.'
        return jsonify({'error': msg}), 500
    return jsonify({
        'id': id,
        'grants': grants
    })
Exemplo n.º 33
0
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)