Esempio n. 1
0
def test_protected_route_overruled_error():
    """ Configuring a protected route that would be overruled by a
    route in FORCED_ANONYMOUS_ROUTES should lead to a ProtectedRouteConflict
    """
    testsettings = TESTSETTINGS.copy()
    testsettings['PROTECTED'] = [('/foo/protected', ['*'], ['scope1'])]
    testsettings['FORCED_ANONYMOUS_ROUTES'] = ('/foo', )
    with pytest.raises(config.ProtectedRouteConflictError):
        reload_settings(testsettings)
        authorization_middleware(None)
Esempio n. 2
0
def test_protected_resource_syntax_error():
    invalid_entries = [
        ('foo', ),
        ('/foo', ),
        ('/foo', ['*']),
    ]
    for entry in invalid_entries:
        testsettings = TESTSETTINGS.copy()
        protected = []
        protected.append(entry)
        testsettings['PROTECTED'] = protected
        with pytest.raises(config.ProtectedRecourceSyntaxError):
            reload_settings(testsettings)
            authorization_middleware(None)
Esempio n. 3
0
def test_protected_resource_read_write_distinction(tokendata_scope1,
                                                   tokendata_scope2):
    testsettings = TESTSETTINGS.copy()
    testsettings['PROTECTED'] = [
        ('/read_write_distinction', ['GET', 'HEAD'], ['scope1']),
        ('/read_write_distinction', ['PATCH', 'PUT', 'POST',
                                     'DELETE'], ['scope2'])
    ]
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)

    request = create_request(tokendata_scope1, '4', 'Bearer',
                             '/read_write_distinction', 'GET')
    response = middleware(request)
    assert response.status_code == 200

    request = create_request(tokendata_scope1, '4', 'Bearer',
                             '/read_write_distinction', 'POST')
    response = middleware(request)
    assert response.status_code == 401
    assert 'insufficient_scope' in response['WWW-Authenticate']

    request = create_request(tokendata_scope2, '4', 'Bearer',
                             '/read_write_distinction', 'POST')
    response = middleware(request)
    assert response.status_code == 200
Esempio n. 4
0
def test_min_scope_multiple_sufficient(tokendata_two_scopes):
    """ Two scopes required, both of them in token """
    testsettings = TESTSETTINGS.copy()
    testsettings['MIN_SCOPE'] = ("scope1", "scope2")
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)
    request = create_request(tokendata_two_scopes, "4")
    response = middleware(request)
    assert response.status_code == 200
Esempio n. 5
0
def test_min_scope_as_string_insufficient(tokendata_scope1):
    """ MIN_SCOPE configured as string instead of tuple """
    testsettings = TESTSETTINGS.copy()
    testsettings['MIN_SCOPE'] = "scope1"
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)
    request = create_request_no_auth_header()
    response = middleware(request)
    assert response.status_code == 401
Esempio n. 6
0
def test_min_scope_sufficient(tokendata_scope1):
    """ scope1 is required, scope1 is in token """
    testsettings = TESTSETTINGS.copy()
    testsettings['MIN_SCOPE'] = ("scope1", )
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)
    request = create_request(tokendata_scope1, "4")
    response = middleware(request)
    assert response.status_code == 200
Esempio n. 7
0
def test_options_works_while_min_scope():
    testsettings = TESTSETTINGS.copy()
    testsettings['MIN_SCOPE'] = ("scope", )
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)
    empty_request = types.SimpleNamespace(META={}, path='/', method='OPTIONS')
    response = middleware(empty_request)
    assert response.status_code == 200
    with pytest.raises(Exception):
        response.is_authorized_for("scope1")
Esempio n. 8
0
def test_min_scope_multiple_insufficient(tokendata_scope1):
    """ Two scopes required, only one of them in token """
    testsettings = TESTSETTINGS.copy()
    testsettings['MIN_SCOPE'] = ("scope1", "scope2")
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)
    request = create_request(tokendata_scope1, "4")
    response = middleware(request)
    assert response.status_code == 401
    assert 'insufficient_scope' in response['WWW-Authenticate']
Esempio n. 9
0
def test_min_scope_insufficient():
    """ scope1 is required, request with no token """
    testsettings = TESTSETTINGS.copy()
    testsettings['MIN_SCOPE'] = ("scope1", )
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)
    request = create_request_no_auth_header()
    response = middleware(request)
    assert response.status_code == 401
    assert 'insufficient_scope' in response['WWW-Authenticate']
Esempio n. 10
0
def test_jwks_from_url(requests_mock, tokendata_two_scopes):
    """ Verify that loading keyset from url works, by checking that is_authorized_for
    method correctly evaluates that user has the scopes mentioned in the token data
    """
    jwks_url = "https://get.your.jwks.here/protocol/openid-connect/certs"
    requests_mock.get(jwks_url, text=json.dumps(JWKS1))
    reload_settings({'JWKS': None, 'JWKS_URL': jwks_url})
    middleware = authorization_middleware(lambda r: ok_response)
    request = create_request(tokendata_two_scopes, "4")
    middleware(request)
    assert request.is_authorized_for("scope1", "scope2")
Esempio n. 11
0
def test_forced_anonymous_routes():
    testsettings = TESTSETTINGS.copy()
    testsettings['FORCED_ANONYMOUS_ROUTES'] = ('/status', )
    testsettings['MIN_SCOPE'] = ("scope1", )
    reload_settings(testsettings)
    empty_request = types.SimpleNamespace(META={},
                                          path='/status/lala',
                                          method='GET')
    middleware = authorization_middleware(lambda r: ok_response)
    response = middleware(empty_request)
    assert response.status_code == 200
    with pytest.raises(Exception):
        response.is_authorized_for("scope1")
Esempio n. 12
0
def test_unknown_kid(tokendata_two_scopes):
    """
    Verify that a token signed with an unknown key results in an "invalid_token" response
    """
    # Create a request with a token signed with a key from JWKS2
    reload_settings({
        'JWKS': json.dumps(JWKS2),
    })
    request = create_request(tokendata_two_scopes, "6")
    # Instantiate the middleware with JWKS1
    reload_settings({
        'JWKS': json.dumps(JWKS1),
    })
    middleware = authorization_middleware(lambda r: ok_response)
    response = middleware(request)
    assert response.status_code == 401
    assert 'WWW-Authenticate' in response
    assert 'invalid_token' in response['WWW-Authenticate']
Esempio n. 13
0
def test_reload_jwks_from_url(requests_mock, tokendata_two_scopes):
    """ It is possible that the IdP rotates the keys. In that case the new keyset
    needs to be fetched from the JWKS url to be able to verify signed tokens.
    """
    jwks_url = "https://get.your.jwks.here/protocol/openid-connect/certs"

    # Create a request with a token signed with a key from JWKS2
    requests_mock.get(jwks_url, text=json.dumps(JWKS2))
    reload_settings({'JWKS': None, 'JWKS_URL': jwks_url})
    assert requests_mock.call_count == 1
    request = create_request(tokendata_two_scopes, "6")
    # Instantiate the middleware with JWKS1
    requests_mock.get(jwks_url, text=json.dumps(JWKS1))
    reload_settings({
        'JWKS': None,
        'JWKS_URL': jwks_url,
        'MIN_INTERVAL_KEYSET_UPDATE':
        0  # Set update interval to 0 secs for the test
    })
    assert requests_mock.call_count == 2
    middleware = authorization_middleware(lambda r: ok_response)
    """
    Process a request with the middleware. The middleware should now:
    - refetch the keyset from jwks_url
    - receive and load JWKS1
    - still not recognize the kid
    - respond with an invalid_token response
    """
    response = middleware(request)
    assert requests_mock.call_count == 3
    assert response.status_code == 401
    assert 'WWW-Authenticate' in response
    assert 'invalid_token' in response['WWW-Authenticate']
    """
    Mock requests so jwks_url returns JWKS2 and do the same request again.
    The middleware should now:
    - refetch the keyset from jwks_url again
    - receive and load JWKS2
    - successfully verify the signature of the token
    """
    requests_mock.get(jwks_url, text=json.dumps(JWKS2))
    middleware(request)
    assert requests_mock.call_count == 4
    assert request.is_authorized_for("scope1", "scope2")
Esempio n. 14
0
def test_protected_resources_all_methods(tokendata_scope1,
                                         tokendata_two_scopes):
    testsettings = TESTSETTINGS.copy()
    testsettings['PROTECTED'] = [
        ('/one_scope_required', ['*'], ['scope1']),
        ('/two_scopes_required', ['*'], ['scope1', 'scope2']),
    ]
    reload_settings(testsettings)
    middleware = authorization_middleware(lambda r: ok_response)

    # a token with scope1 gives access via all methods
    # to the one_scope_required route
    for method in ('GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'):
        request = create_request(tokendata_scope1, '4', 'Bearer',
                                 '/one_scope_required', method)
        response = middleware(request)
        assert request.is_authorized_for('scope1')
        assert response.status_code == 200

    # a token with only scope1 does not give access to two_scopes_required route
    request = create_request(tokendata_scope1, '4', 'Bearer',
                             '/two_scopes_required', 'GET')
    response = middleware(request)
    assert response.status_code == 401
    assert 'insufficient_scope' in response['WWW-Authenticate']

    # a token with scope1 and scope2 gives access to two_scopes_required route
    request = create_request(tokendata_two_scopes, '4', 'Bearer',
                             '/two_scopes_required', 'GET')
    response = middleware(request)
    assert response.status_code == 200

    # OPTIONS method should be allowed without auth header, even with methods: *
    request = create_request_no_auth_header('one_scope_required', 'OPTIONS')
    response = middleware(request)
    assert response.status_code == 200
Esempio n. 15
0
def middleware():
    reload_settings(TESTSETTINGS)
    return authorization_middleware(lambda r: ok_response)
Esempio n. 16
0
def test_empty_scopes_error():
    testsettings = TESTSETTINGS.copy()
    testsettings['PROTECTED'] = [('/foo/protected', ['*'], [])]
    with pytest.raises(config.NoRequiredScopesError):
        reload_settings(testsettings)
        authorization_middleware(None)
Esempio n. 17
0
def test_bad_jwks():
    with pytest.raises(config.AuthzConfigurationError):
        reload_settings({'JWKS': 'iamnotajwks'})
        authorization_middleware(None)
Esempio n. 18
0
def test_unknown_config_param():
    testsettings = TESTSETTINGS.copy()
    testsettings['lalaland'] = 'oscar'
    with pytest.raises(config.AuthzConfigurationError):
        reload_settings(testsettings)
        authorization_middleware(None)
Esempio n. 19
0
def test_missing_conf():
    with pytest.raises(config.AuthzConfigurationError):
        authorization_middleware(None)