Exemplo n.º 1
0
def check_string(string: str,
                 name: str,
                 legal_characters: str = None,
                 max_len: int = None) -> None:
    '''
    Check that a string meets a set of criteria:
    - it is not None or whitespace only
    - (optional) it is less than some specified maximum length
    - (optional) it contains only legal characters.

    :param string: the string to test.
    :param name: the name of the string to be used in error messages.
    :param legal_characters: a regex character class that matches legal characters in the string.
        Typical examples are a-zA-Z_0-9, a-z, etc.
    :param max_len: the maximum length of the string.
    :raises MissingParameterError: if the string is None or whitespace only.
    :raises IllegalParameterError: if the string is too long or contains illegal characters.
    '''
    if not string or not string.strip():
        raise MissingParameterError(name)
    if max_len and len(string) > max_len:
        raise IllegalParameterError(
            '{} {} exceeds maximum length of {}'.format(name, string, max_len))
    if legal_characters:
        global _REGEX_CACHE
        if legal_characters not in _REGEX_CACHE:
            _REGEX_CACHE[legal_characters] = _re.compile('[^' +
                                                         legal_characters +
                                                         ']')
        match = _REGEX_CACHE[legal_characters].search(string)
        if match:
            raise IllegalParameterError(
                'Illegal character in {} {}: {}'.format(
                    name, string, match.group()))
Exemplo n.º 2
0
def test_authsource_init_fail():
    fail_authsource_init(None, MissingParameterError('authsource id'))
    fail_authsource_init('   \t    \n   ',
                         MissingParameterError('authsource id'))
    fail_authsource_init('abcdefghijklmnopqrstu', IllegalParameterError(
        'authsource id abcdefghijklmnopqrstu exceeds maximum length of 20'))
    fail_authsource_init('fooo1b&',
                         IllegalParameterError('Illegal character in authsource id fooo1b&: 1'))
Exemplo n.º 3
0
def test_namespace_id_init_fail():
    fail_namespace_id_init(None, MissingParameterError('namespace id'))
    fail_namespace_id_init('   \t    \n   ',
                           MissingParameterError('namespace id'))
    fail_namespace_id_init(
        'a' * 257,
        IllegalParameterError('namespace id ' + ('a' * 257) +
                              ' exceeds maximum length of 256'))
    fail_namespace_id_init(
        'fooo1b&_*',
        IllegalParameterError(
            'Illegal character in namespace id fooo1b&_*: &'))
Exemplo n.º 4
0
def _get_object_id_list_from_json(request) -> List[str]:
    # flask has a built in get_json() method but the errors it throws suck.
    body = json.loads(request.get_data())
    if not isinstance(body, dict):
        raise IllegalParameterError('Expected JSON mapping in request body')
    ids = body.get('ids')
    if not isinstance(ids, list):
        raise IllegalParameterError('Expected list at /ids in request body')
    if not ids:
        raise MissingParameterError('No ids supplied')
    for id_ in ids:
        if not id_ or not id_.strip():
            raise MissingParameterError('null or whitespace-only id in list')
    return ids
Exemplo n.º 5
0
 def get_mappings(ns):
     """ Find mappings. """
     ns_filter = request.args.get('namespace_filter')
     separate = request.args.get('separate')
     if ns_filter and ns_filter.strip():
         ns_filter = [NamespaceID(n.strip()) for n in ns_filter.split(',')]
     else:
         ns_filter = []
     ids = _get_object_id_list_from_json(request)
     if len(ids) > 1000:
         raise IllegalParameterError('A maximum of 1000 ids are allowed')
     ret = {}
     for id_ in ids:
         id_ = id_.strip()
         a, o = app.config[_APP].get_mappings(
             ObjectID(NamespaceID(ns), id_), ns_filter)
         if separate is not None:  # empty string if in query with no value
             ret[id_] = {
                 'admin': _objids_to_jsonable(a),
                 'other': _objids_to_jsonable(o)
             }
         else:
             a.update(o)
             ret[id_] = {'mappings': _objids_to_jsonable(a)}
     return flask.jsonify(ret)
Exemplo n.º 6
0
def test_object_id_init_fail():
    ns = NamespaceID('foo')
    fail_object_id_init(None, 'o', TypeError('namespace_id cannot be None'))
    fail_object_id_init(ns, None, MissingParameterError('data id'))
    fail_object_id_init(ns, '   \t   \n    ', MissingParameterError('data id'))
    fail_object_id_init(
        ns, 'a' * 1001,
        IllegalParameterError('data id ' + ('a' * 1001) +
                              ' exceeds maximum length of 1000'))
Exemplo n.º 7
0
def test_check_string_fail():
    fail_check_string(None, 'foo', None, None, MissingParameterError('foo'))
    fail_check_string('   \t   \n   ', 'foo', None, None,
                      MissingParameterError('foo'))
    fail_check_string(
        'bar', 'foo', None, 2,
        IllegalParameterError('foo bar exceeds maximum length of 2'))
    fail_check_string(
        'b_ar&_1', 'foo', 'a-z_', None,
        IllegalParameterError('Illegal character in foo b_ar&_1: &'))

    # this is reaching into the implementation which is very naughty but I don't see a good way
    # to check the cache is actually working otherwise
    assert arg_check._REGEX_CACHE['a-z_'].pattern == '[^a-z_]'

    # test with cache
    fail_check_string(
        'b_ar&_1', 'foo', 'a-z_', None,
        IllegalParameterError('Illegal character in foo b_ar&_1: &'))
Exemplo n.º 8
0
 def remove_mapping(admin_ns, other_ns):
     """ Remove a mapping. """
     authsource, token = _get_auth(request)
     ids = _get_object_id_dict_from_json(request)
     if len(ids) > 10000:
         raise IllegalParameterError('A maximum of 10000 ids are allowed')
     for id_ in ids:
         app.config[_APP].remove_mapping(
             authsource, token, ObjectID(NamespaceID(admin_ns),
                                         id_.strip()),
             ObjectID(NamespaceID(other_ns), ids[id_].strip()))
     return ('', 204)
Exemplo n.º 9
0
def _get_object_id_dict_from_json(request) -> Dict[str, str]:
    # flask has a built in get_json() method but the errors it throws suck.
    ids = json.loads(request.get_data())
    if not isinstance(ids, dict):
        raise IllegalParameterError('Expected JSON mapping in request body')
    if not ids:
        raise MissingParameterError('No ids supplied')
    for id_ in ids:
        # json keys must be strings
        if not id_.strip():
            raise MissingParameterError('whitespace only key in input JSON')
        val = ids[id_]
        if not isinstance(val, str):
            raise IllegalParameterError(
                'value for key {} in input JSON is not string: {}'.format(
                    id_, val))
        if not val.strip():
            raise MissingParameterError(
                'value for key {} in input JSON is whitespace only'.format(
                    id_))
    return ids
Exemplo n.º 10
0
 def set_namespace_params(namespace):
     """ Change settings on a namespace. """
     authsource, token = _get_auth(request)
     pubmap = request.args.get('publicly_mappable')
     if pubmap:  # expand later if more settings are allowed
         if pubmap not in [_TRUE, _FALSE]:
             raise IllegalParameterError(
                 "Expected value of 'true' or 'false' for publicly_mappable"
             )
         app.config[_APP].set_namespace_publicly_mappable(
             authsource, token, NamespaceID(namespace), pubmap == _TRUE)
     else:
         raise MissingParameterError('No settings provided.')
     return ('', 204)
Exemplo n.º 11
0
def _get_auth(request,
              required=True) -> Tuple[Optional[AuthsourceID], Optional[Token]]:
    """
    :returns None if required is False and there is no authorization header.
    :raises NoTokenError: if required is True and there's no authorization header.
    :raises InvalidTokenError: if the authorization header is malformed.
    :raises IllegalParameterError: if the authsource is illegal.
    """
    auth = request.headers.get('Authorization')
    if not auth:
        if required:
            raise NoTokenError()
        return (None, None)
    auth = auth.strip().split()
    if len(auth) != 2:
        raise IllegalParameterError('Expected authsource and token in header.')
    return AuthsourceID(auth[0]), Token(auth[1])