Пример #1
0
    def authenticate(self):
        auth_header = self.request.headers.get('Authorization').split(' ')
        if len(auth_header) != 2:
            return False
        bearer, token = auth_header

        conf = dci_config.generate_conf()
        try:
            decoded_token = auth.decode_jwt(token, conf['SSO_PUBLIC_KEY'],
                                            conf['SSO_CLIENT_ID'])
        except jwt_exc.DecodeError:
            raise dci_exc.DCIException('Invalid JWT token.', status_code=401)
        except jwt_exc.ExpiredSignatureError:
            raise dci_exc.DCIException('JWT token expired, please refresh.',
                                       status_code=401)

        team_id = None
        ro_group = dci_config.generate_conf().get('SSO_READ_ONLY_GROUP')
        realm_access = decoded_token['realm_access']
        if 'roles' in realm_access and ro_group in realm_access['roles']:
            team_id = flask.g.team_redhat_id

        user_info = self._get_user_info(decoded_token, team_id)
        try:
            self.identity = self._get_or_create_user(user_info)
        except sa_exc.IntegrityError:
            raise dci_exc.DCICreationConflict(models.USERS.name, 'username')
        return True
Пример #2
0
def verify_and_get_components_ids(topic_id, components_ids, component_types,
                                  db_conn=None):
    """Process some verifications of the provided components ids."""
    db_conn = db_conn or flask.g.db_conn
    if len(components_ids) != len(component_types):
        msg = 'The number of component ids does not match the number ' \
              'of component types %s' % component_types
        raise dci_exc.DCIException(msg, status_code=412)

    # get the components from their ids
    schedule_component_types = set()
    for c_id in components_ids:
        where_clause = sql.and_(models.COMPONENTS.c.id == c_id,
                                models.COMPONENTS.c.topic_id == topic_id,
                                models.COMPONENTS.c.state == 'active')
        query = (sql.select([models.COMPONENTS])
                 .where(where_clause))
        cmpt = db_conn.execute(query).fetchone()

        if cmpt is None:
            msg = 'Component id %s not found or not exported' % c_id
            raise dci_exc.DCIException(msg, status_code=412)
        cmpt = dict(cmpt)

        if cmpt['type'] in schedule_component_types:
            msg = ('Component types malformed: type %s duplicated.' %
                   cmpt['type'])
            raise dci_exc.DCIException(msg, status_code=412)
        schedule_component_types.add(cmpt['type'])
    return components_ids
Пример #3
0
    def _get_components_from_ids(topic_id, rconfiguration, components_ids,
                                 component_types):
        # used for error message
        source = ' topic %s' % topic_id
        if (rconfiguration is not None and
                rconfiguration['component_types'] != []):
            source = ' rconfiguration %s' % rconfiguration['id']
        if len(components_ids) != len(component_types):
            msg = 'The number of component ids does not match the number ' \
                  'of component types of %s' % source
            raise dci_exc.DCIException(msg, status_code=412)

        # get the components from their ids
        schedule_component_types = set()
        for c_id in components_ids:
            where_clause = sql.and_(models.COMPONENTS.c.id == c_id,
                                    models.COMPONENTS.c.topic_id == topic_id,
                                    models.COMPONENTS.c.export_control == True,  # noqa
                                    models.COMPONENTS.c.state == 'active')
            query = (sql.select([models.COMPONENTS])
                     .where(where_clause))
            cmpt = flask.g.db_conn.execute(query).fetchone()

            if cmpt is None:
                msg = 'Component id %s not found or not exported' % c_id
                raise dci_exc.DCIException(msg, status_code=412)
            cmpt = dict(cmpt)

            if cmpt['type'] in schedule_component_types:
                msg = ('Component types malformed: type %s duplicated.' %
                       cmpt['type'])
                raise dci_exc.DCIException(msg, status_code=412)
            schedule_component_types.add(cmpt['type'])
        return components_ids
Пример #4
0
def decode_token_with_latest_public_key(token):
    """Get the latest public key and decode the JWT token with it. This
    function is usefull when the SSO server rotated its key."""
    conf = dci_config.CONFIG
    try:
        latest_public_key = get_latest_public_key()
    except Exception as e:
        raise dci_exc.DCIException(
            'Unable to get last SSO public key: %s' % str(e),  # noqa
            status_code=401)
    # SSO server didn't update its public key
    if conf['SSO_PUBLIC_KEY'] == latest_public_key:
        raise dci_exc.DCIException('Invalid JWT token.',
                                   status_code=401)  # noqa
    try:
        decoded_token = auth.decode_jwt(token, latest_public_key,
                                        conf['SSO_CLIENT_ID'])
        conf['SSO_PUBLIC_KEY'] = latest_public_key
        return decoded_token
    except (jwt_exc.DecodeError, TypeError):
        raise dci_exc.DCIException('Invalid JWT token.',
                                   status_code=401)  # noqa
    except jwt_exc.ExpiredSignatureError:
        raise dci_exc.DCIException(
            'JWT token expired, please refresh.',  # noqa
            status_code=401)
Пример #5
0
def where_query(where, table, columns):
    where_conds = []
    err_msg = 'Invalid where key: "%s"'
    for where_elem in where:
        try:
            name, value = where_elem.split(':', 1)
        except ValueError:
            payload = {
                'error': 'where key must have the following form '
                '"key:value"'
            }
            raise dci_exc.DCIException(err_msg % where_elem, payload=payload)

        if name not in columns:
            payload = {'valid_keys': list(columns.keys())}
            raise dci_exc.DCIException(err_msg % name, payload=payload)

        m_column = getattr(table.c, name)
        # TODO(yassine): do the same for columns type different from string
        # if it's an Integer column, then try to cast the value
        if str(m_column.type) == "UUID":
            pass
        elif m_column.type.python_type == int:
            try:
                value = int(value)
            except ValueError:
                payload = {name: 'not integer'}
                raise dci_exc.DCIException(err_msg % name, payload=payload)

        where_conds.append(m_column == value)
    return where_conds
Пример #6
0
    def get_client_info(self):
        """Extracts timestamp, client type and client id from a
        DCI-Client-Info header.
        Returns a hash with the three values.
        Throws an exception if the format is bad or if strptime fails."""
        if 'DCI-Client-Info' not in self.request.headers:
            raise dci_exc.DCIException('Header DCI-Client-Info missing',
                                       status_code=401)

        client_info = self.request.headers.get('DCI-Client-Info')
        client_info = client_info.split('/')
        if len(client_info) != 3 or not all(client_info):
            raise dci_exc.DCIException(
                'DCI-Client-Info should match the following format: ' +
                '"YYYY-MM-DD HH:MI:SSZ/<client_type>/<id>"')

        dateformat = '%Y-%m-%d %H:%M:%SZ'
        try:
            timestamp = datetime.strptime(client_info[0], dateformat)
            return {
                'timestamp': timestamp,
                'type': client_info[1],
                'id': client_info[2],
            }
        except ValueError:
            raise dci_exc.DCIException('Bad date format in DCI-Client-Info',
                                       '401')
Пример #7
0
def where_query(where, table, columns):
    where_conds = []
    err_msg = 'Invalid where key: "%s"'

    def _get_column(table, columns, name):
        payload = {
            'error': 'where key must have the following form '
            '"key:value"'
        }

        if '.' in name:
            subtable_name, name = name.split('.')
            table_obj = embeds.EMBED_STRING_TO_OBJECT[table.name]
            try:
                table = table_obj[subtable_name]
            except KeyError:
                payload = {'valid_keys': list(table_obj.keys())}
                raise dci_exc.DCIException(err_msg % name, payload=payload)
            columns = get_columns_name_with_objects(table)

        if name not in columns:
            payload = {'valid_keys': list(columns.keys())}
            raise dci_exc.DCIException(err_msg % name, payload=payload)
        return getattr(table.c, name)

    array_columns_to_list = {}
    for where_elem in where:
        try:
            name, value = where_elem.split(':', 1)
        except ValueError:
            payload = {
                'error': 'where key must have the following form '
                '"key:value"'
            }
            raise dci_exc.DCIException(err_msg % where_elem, payload=payload)

        m_column = _get_column(table, columns, name)
        # TODO(yassine): do the same for columns type different from string
        # if it's an Integer column, then try to cast the value
        try:
            if str(m_column.type) == "UUID" and uuid.UUID(value):
                where_conds.append(m_column == value)
            elif m_column.type.python_type == int:
                where_conds.append(m_column == int(value))
            elif m_column.type.python_type == list:
                if m_column not in array_columns_to_list:
                    array_columns_to_list[m_column] = [value]
                else:
                    array_columns_to_list[m_column] += [value]
            else:
                where_conds.append(m_column == value)
        except ValueError:
            payload = {name: '%s is not a %s' % (name, m_column.type)}
            raise dci_exc.DCIException(err_msg % name, payload=payload)

    for col, values in array_columns_to_list.items():
        where_conds.append(col.contains(values))
    return where_conds
Пример #8
0
def create_files(user):
    file_info = get_file_info_from_headers(dict(flask.request.headers))
    values = dict.fromkeys(
        ['md5', 'mime', 'jobstate_id', 'job_id', 'name', 'test_id'])
    values.update(file_info)

    if values.get('jobstate_id') is None and values.get('job_id') is None:
        raise dci_exc.DCIException('HTTP headers DCI-JOBSTATE-ID or '
                                   'DCI-JOB-ID must be specified')
    if values.get('name') is None:
        raise dci_exc.DCIException('HTTP header DCI-NAME must be specified')

    if values.get('jobstate_id') and values.get('job_id') is None:
        jobstate = v1_utils.verify_existence_and_get(values.get('jobstate_id'),
                                                     models.JOBSTATES)
        values['job_id'] = jobstate['job_id']

    job = v1_utils.verify_existence_and_get(values.get('job_id'), models.JOBS)
    if (user.is_not_in_team(job['team_id']) and user.is_read_only_user()
            and user.is_not_epm()):
        raise dci_exc.Unauthorized()

    file_id = utils.gen_uuid()
    file_path = files_utils.build_file_path(job['team_id'], values['job_id'],
                                            file_id)

    content = files_utils.get_stream_or_content_from_request(flask.request)
    store = dci_config.get_store('files')
    store.upload(file_path, content)
    s_file = store.head(file_path)

    etag = utils.gen_etag()
    values.update({
        'id': file_id,
        'created_at': datetime.datetime.utcnow().isoformat(),
        'updated_at': datetime.datetime.utcnow().isoformat(),
        'team_id': job['team_id'],
        'md5': None,
        'size': s_file['content-length'],
        'state': 'active',
        'etag': etag,
    })

    with flask.g.db_conn.begin():
        q_insert_file = _TABLE.insert().values(**values)
        flask.g.db_conn.execute(q_insert_file)
        result = json.dumps({'file': values})

        if values['mime'] == 'application/junit':
            _, junit_file = store.get(file_path)
            _process_junit_file(values, junit_file, job)

    return flask.Response(result, 201, content_type='application/json')
Пример #9
0
 def authenticate(self):
     auth = self.request.authorization
     if not auth:
         raise dci_exc.DCIException('Authorization header missing',
                                    status_code=401)
     user, is_authenticated = \
         self.get_user_and_check_auth(auth.username, auth.password)
     if not is_authenticated:
         raise dci_exc.DCIException('Invalid user credentials',
                                    status_code=401)
     self.identity = user
     return True
Пример #10
0
def _get_auth_class_from_headers(headers):
    if 'Authorization' not in headers:
        raise dci_exc.DCIException('Authorization header missing',
                                   status_code=401)

    auth_type = headers.get('Authorization').split(' ')[0]
    if auth_type == 'Bearer':
        return am.OpenIDCAuth
    elif auth_type == 'DCI-HMAC-SHA256':
        return am.HmacMechanism
    elif auth_type == 'Basic':
        return am.BasicAuthMechanism

    raise dci_exc.DCIException('Authorization scheme %s unknown' % auth_type,
                               status_code=401)
Пример #11
0
def verify_existence_and_get(id, table, name=None, get_id=False):
    """Verify the existence of a resource in the database and then
    return it if it exists, according to the condition, or raise an
    exception.

    :param id: id of the resource
    :param table: the table object
    :param name: the name of the row to look for
    :param get_id: if True, return only the ID
    :return:
    """

    where_clause = table.c.id == id
    if name:
        where_clause = table.c.name == name

    if 'state' in table.columns:
        where_clause = sql.and_(table.c.state != 'archived', where_clause)

    query = sql.select([table]).where(where_clause)
    result = flask.g.db_conn.execute(query).fetchone()

    if result is None:
        raise dci_exc.DCIException('Resource "%s" not found.' % id,
                                   status_code=404)
    if get_id:
        return result.id
    return result
Пример #12
0
def purge_archived_files(user):

    # get all archived files
    archived_files = base.get_archived_resources(_TABLE)

    store = dci_config.get_store('files')

    # for each file delete it from within a transaction
    # if the SQL deletion or the Store deletion fail then
    # rollback the transaction, otherwise commit.
    for file in archived_files:
        tx = flask.g.db_conn.begin()
        try:
            q_delete_file = _TABLE.delete().where(_TABLE.c.id == file['id'])
            flask.g.db_conn.execute(q_delete_file)
            file_path = files_utils.build_file_path(file['team_id'],
                                                    file['job_id'], file['id'])
            store.delete(file_path)
            tx.commit()
            logger.debug('file %s removed' % file_path)
        except dci_exc.StoreExceptions as e:
            if e.status_code == 404:
                logger.warn('file %s not found in store' % file_path)
            else:
                raise e
        except sa_exc.DBAPIError as e:
            logger.error('Error while removing file %s, message: %s' %
                         (file_path, str(e)))
            tx.rollback()
            raise dci_exc.DCIException(str(e))

    return flask.Response(None, 204, content_type='application/json')
Пример #13
0
def sort_query(sort,
               root_valid_columns,
               embeds_valid_columns={},
               default='-created_at'):  # noqa
    order_by = []
    if not sort and not root_valid_columns:
        return []
    if not sort:
        sort = [default]
    valid_columns_keys = list(root_valid_columns.keys())
    valid_columns = dict(root_valid_columns)
    if embeds_valid_columns:
        valid_columns.update(embeds_valid_columns)
        embed_valid_columns_keys = [
            i.replace('_', '.', 1) for i in list(embeds_valid_columns.keys())
        ]
        valid_columns_keys.extend(embed_valid_columns_keys)
    for sort_elem in sort:
        sort_order = (sql.desc if sort_elem.startswith('-') else sql.asc)
        sort_elem = sort_elem.strip(' -')
        if sort_elem not in valid_columns_keys:
            raise dci_exc.DCIException(
                'Invalid sort key: "%s"' % sort_elem,
                payload={'Valid sort keys': sorted(set(valid_columns_keys))})
        if '.' in sort_elem:
            sort_elem = sort_elem.replace('.', '_', 1)
        order_by.append(sort_order(valid_columns[sort_elem]))
    return order_by
Пример #14
0
def _validate_input(values, user):
    topic_id = values.pop('topic_id')
    remoteci_id = values.get('remoteci_id')

    values.update({
        'id': utils.gen_uuid(),
        'created_at': datetime.datetime.utcnow().isoformat(),
        'updated_at': datetime.datetime.utcnow().isoformat(),
        'etag': utils.gen_etag(),
        'status': 'new'
    })

    remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS)
    v1_utils.verify_existence_and_get(topic_id, models.TOPICS)

    # let's kill existing running jobs for the remoteci
    where_clause = sql.expression.and_(
        _TABLE.c.remoteci_id == remoteci_id,
        _TABLE.c.status.in_(('new', 'pre-run', 'running', 'post-run'))
    )
    kill_query = _TABLE .update().where(where_clause).values(status='killed')
    flask.g.db_conn.execute(kill_query)

    if remoteci['state'] != 'active':
        message = 'RemoteCI "%s" is disabled.' % remoteci_id
        raise dci_exc.DCIException(message, status_code=412)

    # The user belongs to the topic then we can start the scheduling
    v1_utils.verify_team_in_topic(user, topic_id)
    return topic_id, remoteci
Пример #15
0
def create_configuration(user, r_id):
    values_configuration = v1_utils.common_values_dict(user)
    values_configuration.update(
        schemas.rconfiguration.post(flask.request.json))
    values_configuration.update(flask.request.json)

    remoteci = v1_utils.verify_existence_and_get(r_id, _TABLE)

    if not user.is_in_team(remoteci['team_id']):
        raise auth.UNAUTHORIZED

    rconfiguration_id = values_configuration.get('id')

    with flask.g.db_conn.begin():
        try:
            # insert configuration
            query = _RCONFIGURATIONS.insert().\
                values(**values_configuration)
            flask.g.db_conn.execute(query)
            # insert join between rconfiguration and remoteci
            values_join = {
                'rconfiguration_id': rconfiguration_id,
                'remoteci_id': r_id}
            query = models.JOIN_REMOTECIS_RCONFIGURATIONS.insert().\
                values(**values_join)
            flask.g.db_conn.execute(query)
        except sa_exc.IntegrityError as ie:
            raise dci_exc.DCIException('Integrity Error: %s' % str(ie))

    return flask.Response(
        json.dumps({'rconfiguration': values_configuration}), 201,
        headers={'ETag': values_configuration['etag']},
        content_type='application/json'
    )
Пример #16
0
def put_meta(job_id, meta_id):
    """Modify a meta."""

    # get If-Match header
    if_match_etag = utils.check_and_get_etag(flask.request.headers)

    values = schemas.meta.put(flask.request.json)

    meta_retrieved = v1_utils.verify_existence_and_get(meta_id, _TABLE)

    if meta_retrieved['job_id'] != job_id:
        raise dci_exc.DCIException(
            "Meta '%s' is not associated to job '%s'." % (meta_id, job_id))

    values['etag'] = utils.gen_etag()
    where_clause = sql.and_(
        _TABLE.c.etag == if_match_etag,
        _TABLE.c.id == meta_id
    )
    query = _TABLE.update().where(where_clause).values(**values)

    result = flask.g.db_conn.execute(query)

    if not result.rowcount:
        raise dci_exc.DCIConflict('Meta', meta_id)

    return flask.Response(None, 204, headers={'ETag': values['etag']},
                          content_type='application/json')
Пример #17
0
def put_current_user(user):
    if_match_etag = utils.check_and_get_etag(flask.request.headers)
    values = schemas.current_user.put(flask.request.json)

    current_password = values['current_password']
    encrypted_password = user['password']
    if not auth.check_passwords_equal(current_password, encrypted_password):
        raise dci_exc.DCIException('current_password invalid')

    new_password = values.get('new_password')
    if new_password:
        encrypted_password = auth.hash_password(new_password)

    etag = utils.gen_etag()

    query = _TABLE.update().where(
        sql.and_(_TABLE.c.etag == if_match_etag,
                 _TABLE.c.id == user['id'])).values({
                     'etag':
                     etag,
                     'fullname':
                     values.get('fullname') or user['fullname'],
                     'email':
                     values.get('email') or user['email'],
                     'timezone':
                     values.get('timezone') or user['timezone'],
                     'password':
                     encrypted_password,
                 })

    flask.g.db_conn.execute(query)
    return flask.Response(None,
                          204,
                          headers={'ETag': etag},
                          content_type='application/json')
Пример #18
0
 def authenticate(self):
     headers = self.request.headers
     auth_request = AuthRequest(method=self.request.method,
                                endpoint=self.request.path,
                                payload=self.request.get_json(silent=True),
                                headers=headers,
                                params=self.request.args.to_dict(flat=True))
     hmac_signature = Signature(request=auth_request)
     self.identity = self.build_identity(auth_request.get_client_info())
     secret = getattr(self.identity, 'api_secret', '')
     if not hmac_signature.is_valid(secret):
         raise dci_exc.DCIException(
             'Authentication failed: signature invalid', status_code=401)
     if hmac_signature.is_expired():
         raise dci_exc.DCIException(
             'Authentication failed: signature expired', status_code=401)
     return True
Пример #19
0
def create_jobs(user):
    values = flask.request.json
    check_json_is_valid(create_job_schema, values)
    values.update(v1_utils.common_values_dict())

    components_ids = values.pop('components')

    if user.is_not_remoteci():
        raise dci_exc.DCIException('Only remoteci can create job')

    topic_id = values.get('topic_id')
    topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS)
    export_control.verify_access_to_topic(user, topic)
    previous_job_id = values.get('previous_job_id')
    if previous_job_id:
        v1_utils.verify_existence_and_get(previous_job_id, _TABLE)

    values.update({
        'status':
        'new',
        'remoteci_id':
        user.id,
        'topic_id':
        topic_id,
        'user_agent':
        flask.request.environ.get('HTTP_USER_AGENT'),
        'client_version':
        flask.request.environ.get('HTTP_CLIENT_VERSION'),
        'previous_job_id':
        previous_job_id,
        'team_id':
        user.teams_ids[0],
        'product_id':
        topic['product_id'],
        'duration':
        0
    })

    # create the job and feed the jobs_components table
    with flask.g.db_conn.begin():
        query = _TABLE.insert().values(**values)
        flask.g.db_conn.execute(query)

        jobs_components_to_insert = []
        for cmpt_id in components_ids:
            v1_utils.verify_existence_and_get(cmpt_id, models.COMPONENTS)
            jobs_components_to_insert.append({
                'job_id': values['id'],
                'component_id': cmpt_id
            })
        if jobs_components_to_insert:
            flask.g.db_conn.execute(models.JOIN_JOBS_COMPONENTS.insert(),
                                    jobs_components_to_insert)

    return flask.Response(json.dumps({'job': values}),
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Пример #20
0
def create_new_upgrade_job_from_an_existing_job(user):
    """Create a new job in the 'next topic' of the topic of
    the provided job_id."""
    values = flask.request.json
    check_json_is_valid(upgrade_job_schema, values)

    values.update({
        'id': utils.gen_uuid(),
        'created_at': get_utc_now().isoformat(),
        'updated_at': get_utc_now().isoformat(),
        'etag': utils.gen_etag(),
        'status': 'new'
    })

    original_job_id = values.pop('job_id')
    original_job = v1_utils.verify_existence_and_get(original_job_id,
                                                     models.JOBS)
    if user.is_not_in_team(original_job['team_id']) and user.is_not_epm():
        raise dci_exc.Unauthorized()

    # get the remoteci
    remoteci_id = str(original_job['remoteci_id'])
    remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS)
    values.update({'remoteci_id': remoteci_id})

    # get the associated topic
    topic_id = str(original_job['topic_id'])
    topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS)

    values.update({
        'user_agent':
        flask.request.environ.get('HTTP_USER_AGENT'),
        'client_version':
        flask.request.environ.get('HTTP_CLIENT_VERSION'),
    })

    next_topic_id = topic['next_topic_id']

    if not next_topic_id:
        raise dci_exc.DCIException("topic %s does not contains a next topic" %
                                   topic_id)
    topic = v1_utils.verify_existence_and_get(next_topic_id, models.TOPICS)
    product_id = topic['product_id']

    # instantiate a new job in the next_topic_id
    # todo(yassine): make possible the upgrade to choose specific components
    values = _build_job(product_id,
                        next_topic_id,
                        remoteci, [],
                        values,
                        previous_job_id=original_job_id)

    return flask.Response(json.dumps({'job': values}),
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Пример #21
0
def get_topic_by_id(user, topic_id):
    args = schemas.args(flask.request.args.to_dict())
    topic = v1_utils.verify_existence_and_get(topic_id, _TABLE)
    v1_utils.verify_team_in_topic(user, topic_id)
    if not auth.is_admin(user):
        if 'teams' in args['embed']:
            raise dci_exc.DCIException('embed=teams not authorized.',
                                       status_code=401)

    return base.get_resource_by_id(user, topic, _TABLE, _EMBED_MANY)
Пример #22
0
def _verify_existence_and_get_user(user_id):
    where_clause = _TABLE.c.id == user_id
    query = sql.select(_SELECT_WITHOUT_PASSWORD).where(where_clause)
    result = flask.g.db_conn.execute(query).fetchone()

    if result is None:
        raise dci_exc.DCIException('Resource "%s" not found.' % user_id,
                                   status_code=404)

    return result
Пример #23
0
def verify_user_in_team(user, team_id):
    """Verify that the user belongs to a given team. If the user is an
    admin then it belongs to all teams."""

    if auth.is_admin(user):
        return
    if not auth.is_in_team(user, team_id):
        raise dci_exc.DCIException('User\'s team does not belongs to '
                                   'team %s.' % team_id,
                                   status_code=412)
Пример #24
0
def verify_team_in_topic(user, topic_id):
    """Verify that the user's team does belongs to the given topic. If
    the user is an admin then it belongs to all topics.
    """
    if auth.is_admin(user):
        return
    if str(topic_id) not in user_topic_ids(user):
        raise dci_exc.DCIException('User team does not belongs to topic %s.' %
                                   topic_id,
                                   status_code=412)
Пример #25
0
    def _get_column(table, columns, name):
        payload = {
            'error': 'where key must have the following form '
            '"key:value"'
        }

        if '.' in name:
            subtable_name, name = name.split('.')
            table_obj = embeds.EMBED_STRING_TO_OBJECT[table.name]
            try:
                table = table_obj[subtable_name]
            except KeyError:
                payload = {'valid_keys': list(table_obj.keys())}
                raise dci_exc.DCIException(err_msg % name, payload=payload)
            columns = get_columns_name_with_objects(table)

        if name not in columns:
            payload = {'valid_keys': list(columns.keys())}
            raise dci_exc.DCIException(err_msg % name, payload=payload)
        return getattr(table.c, name)
Пример #26
0
    def authenticate(self):
        """Tries to authenticate a request using a signature as authentication
        mechanism.
        Sets self.identity to the authenticated entity for later use.
        """
        # Get headers and extract information

        client_info = self.get_client_info()
        their_signature = self.request.headers.get('DCI-Auth-Signature')

        identity = self.get_identity(client_info['type'], client_info['id'])
        if identity is None:
            raise dci_exc.DCIException(
                'Client %(type)s/%(id)s does not exist' % client_info,
                status_code=401)
        self.identity = identity

        if not self.verify_auth_signature(identity, client_info['timestamp'],
                                          their_signature):
            raise dci_exc.DCIException('Invalid signature.', status_code=401)
        return True
Пример #27
0
def get_last_components_by_type(component_types, topic_id, db_conn=None):
    """For each component type of a topic, get the last one."""
    db_conn = db_conn or flask.g.db_conn
    _components = []
    for ct in component_types:
        where_clause = sql.and_(models.COMPONENTS.c.type == ct,
                                models.COMPONENTS.c.topic_id == topic_id,
                                models.COMPONENTS.c.state == 'active')  # noqa
        query = (sql.select([models.COMPONENTS]).where(where_clause).order_by(
            sql.desc(models.COMPONENTS.c.created_at)))
        component = db_conn.execute(query).fetchone()

        if component is None:
            msg = 'Component of type "%s" not found or not exported.' % ct
            raise dci_exc.DCIException(msg, status_code=412)

        if component['id'] in _components:
            msg = ('Component types %s malformed: type %s duplicated.' %
                   (component_types, ct))
            raise dci_exc.DCIException(msg, status_code=412)
        _components.append(component)
    return _components
Пример #28
0
 def _get_embed_list(self, embed_joins):
     valid_embed = embed_joins.keys()
     embed_list = []
     for embed_elem in self._embeds:
         left = embed_elem.split('.')[0]
         if embed_elem not in valid_embed:
             raise dci_exc.DCIException(
                 'Invalid embed element %s' % embed_elem,
                 payload={'Valid elements': valid_embed})
         if left not in embed_list:
             embed_list.append(left)
         embed_list.append(embed_elem)
     return sorted(set(embed_list))
Пример #29
0
    def get_user_and_check_auth(self, username, password):
        """Check the combination username/password that is valid on the
        database.
        """
        constraint = sql.or_(models.USERS.c.name == username,
                             models.USERS.c.email == username)

        user = self.identity_from_db(models.USERS, constraint)
        if user is None:
            raise dci_exc.DCIException('User %s does not exists.' % username,
                                       status_code=401)

        return user, auth.check_passwords_equal(password, user.password)
Пример #30
0
    def authenticate(self):
        auth_header = self.request.headers.get('Authorization').split(' ')
        if len(auth_header) != 2:
            return False
        bearer, token = auth_header

        conf = dci_config.generate_conf()
        try:
            decoded_token = auth.decode_jwt(token, conf['SSO_PUBLIC_KEY'],
                                            conf['SSO_CLIENT_ID'])
        except jwt_exc.DecodeError:
            raise dci_exc.DCIException('Invalid JWT token.', status_code=401)
        except jwt_exc.ExpiredSignatureError:
            raise dci_exc.DCIException('JWT token expired, please refresh.',
                                       status_code=401)

        sso_username = decoded_token['username']
        self.identity = self._get_user_from_sso_username(sso_username)
        if self.identity is None:
            self.identity = self._create_user_and_get(decoded_token)
            if self.identity is None:
                return False