def validate_signed_grant(auth_header): """ Validates a signed grant as found inside an auth header and returns whether it points to a valid grant. """ if not auth_header: return ValidateResult(AuthKind.signed_grant, missing=True) # Try to parse the token from the header. normalized = [part.strip() for part in auth_header.split(" ") if part] if normalized[0].lower() != "token" or len(normalized) != 2: logger.debug("Not a token: %s", auth_header) return ValidateResult(AuthKind.signed_grant, missing=True) # Check that it starts with the expected prefix. if not normalized[1].startswith(SIGNATURE_PREFIX): logger.debug("Not a signed grant token: %s", auth_header) return ValidateResult(AuthKind.signed_grant, missing=True) # Decrypt the grant. encrypted = normalized[1][len(SIGNATURE_PREFIX) :] ser = SecureCookieSessionInterface().get_signing_serializer(app) try: token_data = ser.loads(encrypted, max_age=app.config["SIGNED_GRANT_EXPIRATION_SEC"]) except BadSignature: logger.warning("Signed grant could not be validated: %s", encrypted) return ValidateResult( AuthKind.signed_grant, error_message="Signed grant could not be validated" ) logger.debug("Successfully validated signed grant with data: %s", token_data) return ValidateResult(AuthKind.signed_grant, signed_data=token_data)
def validate_oauth_token(token): """ Validates the specified OAuth token, returning whether it points to a valid OAuth token. """ validated = model.oauth.validate_access_token(token) if not validated: logger.warning("OAuth access token could not be validated: %s", token) return ValidateResult( AuthKind.oauth, error_message="OAuth access token could not be validated") if validated.expires_at <= datetime.utcnow(): logger.warning("OAuth access with an expired token: %s", token) return ValidateResult(AuthKind.oauth, error_message="OAuth access token has expired") # Don't allow disabled users to login. if not validated.authorized_user.enabled: return ValidateResult( AuthKind.oauth, error_message="Granter of the oauth access token is disabled") # We have a valid token scope_set = scopes_from_scope_string(validated.scope) logger.debug("Successfully validated oauth access token with scope: %s", scope_set) return ValidateResult(AuthKind.oauth, oauthtoken=validated)
def test_apply_context(get_entity, entity_kind, app): assert get_authenticated_context() is None entity = get_entity() args = {} args[entity_kind] = entity result = ValidateResult(AuthKind.basic, **args) result.apply_to_context() expected_user = entity if entity_kind == 'user' or entity_kind == 'robot' else None if entity_kind == 'oauthtoken': expected_user = entity.authorized_user if entity_kind == 'appspecifictoken': expected_user = entity.user expected_token = entity if entity_kind == 'token' else None expected_oauth = entity if entity_kind == 'oauthtoken' else None expected_appspecifictoken = entity if entity_kind == 'appspecifictoken' else None expected_grant = entity if entity_kind == 'signed_data' else None assert get_authenticated_context().authed_user == expected_user assert get_authenticated_context().token == expected_token assert get_authenticated_context().oauthtoken == expected_oauth assert get_authenticated_context( ).appspecifictoken == expected_appspecifictoken assert get_authenticated_context().signed_data == expected_grant
def validate_bearer_auth(auth_header): """ Validates an OAuth token found inside a basic auth `Bearer` token, returning whether it points to a valid OAuth token. """ if not auth_header: return ValidateResult(AuthKind.oauth, missing=True) normalized = [part.strip() for part in auth_header.split(' ') if part] if normalized[0].lower() != 'bearer' or len(normalized) != 2: logger.debug('Got invalid bearer token format: %s', auth_header) return ValidateResult(AuthKind.oauth, missing=True) (_, oauth_token) = normalized return validate_oauth_token(oauth_token)
def test_valid_app_specific_token(app): user = model.user.get_user("devtable") app_specific_token = model.appspecifictoken.create_token(user, "some token") full_token = model.appspecifictoken.get_full_token_string(app_specific_token) token = _token(APP_SPECIFIC_TOKEN_USERNAME, full_token) result = validate_basic_auth(token) assert result == ValidateResult(AuthKind.basic, appspecifictoken=app_specific_token)
def test_unicode(app): result, kind = validate_credentials("someusername", "some₪code") assert kind == CredentialKind.user assert not result.auth_valid assert result == ValidateResult( AuthKind.credentials, error_message="Invalid Username or Password" )
def test_valid_oauth(app): user = model.user.get_user("devtable") app = model.oauth.list_applications_for_org(model.user.get_user_or_org("buynlarge"))[0] oauth_token, code = model.oauth.create_user_access_token(user, app.client_id, "repo:read") token = _token(OAUTH_TOKEN_USERNAME, code) result = validate_basic_auth(token) assert result == ValidateResult(AuthKind.basic, oauthtoken=oauth_token)
def test_invalid_app_specific_token_code(app): user = model.user.get_user("devtable") app_specific_token = model.appspecifictoken.create_token(user, "some token") full_token = app_specific_token.token_name + "something" result, kind = validate_credentials(APP_SPECIFIC_TOKEN_USERNAME, full_token) assert kind == CredentialKind.app_specific_token assert result == ValidateResult(AuthKind.credentials, error_message="Invalid token")
def test_invalid_unicode_robot(app): token = "“4JPCOLIVMAY32Q3XGVPHC4CBF8SKII5FWNYMASOFDIVSXTC5I5NBU”" result, kind = validate_credentials("devtable+somerobot", token) assert kind == CredentialKind.robot assert not result.auth_valid msg = "Could not find robot with specified username" assert result == ValidateResult(AuthKind.credentials, error_message=msg)
def test_valid_app_specific_token(app): user = model.user.get_user("devtable") app_specific_token = model.appspecifictoken.create_token(user, "some token") full_token = model.appspecifictoken.get_full_token_string(app_specific_token) result, kind = validate_credentials(APP_SPECIFIC_TOKEN_USERNAME, full_token) assert kind == CredentialKind.app_specific_token assert result == ValidateResult(AuthKind.credentials, appspecifictoken=app_specific_token)
def test_valid_token(app): access_token = model.token.create_delegate_token("devtable", "simple", "sometoken") result, kind = validate_credentials(ACCESS_TOKEN_USERNAME, access_token.get_code()) assert kind == CredentialKind.token assert result == ValidateResult(AuthKind.credentials, token=access_token)
def test_invalid_unicode_2(app): token = "“4JPCOLIVMAY32Q3XGVPHC4CBF8SKII5FWNYMASOFDIVSXTC5I5NBU”".encode("utf-8") header = "basic " + b64encode(b"devtable+somerobot:%s" % token).decode("ascii") result = validate_basic_auth(header) assert result == ValidateResult( AuthKind.basic, error_message="Could not find robot with username: devtable+somerobot and supplied password.", )
def test_invalid_unicode_3(app): token = "sometoken" header = "basic " + b64encode("“devtable+somerobot”:%s" % token) result = validate_basic_auth(header) assert result == ValidateResult( AuthKind.basic, error_message="Could not find robot with specified username", )
def test_invalid_unicode_3(app): token = "sometoken" auth = "“devtable+somerobot”:" + token auth = auth.encode("utf-8") header = "basic " + b64encode(auth).decode("ascii") result = validate_basic_auth(header) assert result == ValidateResult( AuthKind.basic, error_message="Could not find robot with specified username", )
def test_unicode_robot(app): robot, _ = model.user.create_robot("somerobot", model.user.get_user("devtable")) result, kind = validate_credentials(robot.username, "some₪code") assert kind == CredentialKind.robot assert not result.auth_valid msg = "Could not find robot with username: devtable+somerobot and supplied password." assert result == ValidateResult(AuthKind.credentials, error_message=msg)
def test_invalid_unicode_2(app): token = '“4JPCOLIVMAY32Q3XGVPHC4CBF8SKII5FWNYMASOFDIVSXTC5I5NBU”' header = 'basic ' + b64encode('devtable+somerobot:%s' % token) result = validate_basic_auth(header) assert result == ValidateResult( AuthKind.basic, error_message= 'Could not find robot with username: devtable+somerobot and supplied password.' )
def test_valid_oauth(app): user = model.user.get_user("devtable") app = model.oauth.list_applications_for_org( model.user.get_user_or_org("buynlarge"))[0] oauth_token, code = model.oauth.create_access_token_for_testing( user, app.client_id, "repo:read") result, kind = validate_credentials(OAUTH_TOKEN_USERNAME, code) assert kind == CredentialKind.oauth_token assert result == ValidateResult(AuthKind.oauth, oauthtoken=oauth_token)
def test_invalid_unicode_robot_2(app): user = model.user.get_user("devtable") robot, password = model.user.create_robot("somerobot", user) token = "“4JPCOLIVMAY32Q3XGVPHC4CBF8SKII5FWNYMASOFDIVSXTC5I5NBU”" result, kind = validate_credentials("devtable+somerobot", token) assert kind == CredentialKind.robot assert not result.auth_valid msg = "Could not find robot with username: devtable+somerobot and supplied password." assert result == ValidateResult(AuthKind.credentials, error_message=msg)
def validate_basic_auth(auth_header): """ Validates the specified basic auth header, returning whether its credentials point to a valid user or token. """ if not auth_header: return ValidateResult(AuthKind.basic, missing=True) logger.debug("Attempt to process basic auth header") # Parse the basic auth header. assert isinstance(auth_header, basestring) credentials, err = _parse_basic_auth_header(auth_header) if err is not None: logger.debug("Got invalid basic auth header: %s", auth_header) return ValidateResult(AuthKind.basic, missing=True) auth_username, auth_password_or_token = credentials result, _ = validate_credentials(auth_username, auth_password_or_token) return result.with_kind(AuthKind.basic)
def test_valid_robot_for_disabled_user(app): user = model.user.get_user("devtable") user.enabled = False user.save() robot, password = model.user.create_robot("somerobot", user) result, kind = validate_credentials(robot.username, password) assert kind == CredentialKind.robot err = "This user has been disabled. Please contact your administrator." assert result == ValidateResult(AuthKind.credentials, error_message=err)
def test_valid_grant(): header = 'token ' + generate_signed_token({'a': 'b'}, {'c': 'd'}) expected = ValidateResult(AuthKind.signed_grant, signed_data={ 'grants': { 'a': 'b', }, 'user_context': { 'c': 'd' }, }) assert validate_signed_grant(header) == expected
def test_valid_app_specific_token_for_disabled_user(app): user = model.user.get_user("devtable") user.enabled = False user.save() app_specific_token = model.appspecifictoken.create_token(user, "some token") full_token = model.appspecifictoken.get_full_token_string(app_specific_token) result, kind = validate_credentials(APP_SPECIFIC_TOKEN_USERNAME, full_token) assert kind == CredentialKind.app_specific_token err = "This user has been disabled. Please contact your administrator." assert result == ValidateResult(AuthKind.credentials, error_message=err)
def test_valid_grant(): header = "token " + generate_signed_token({"a": "b"}, {"c": "d"}) expected = ValidateResult( AuthKind.signed_grant, signed_data={ "grants": { "a": "b", }, "user_context": {"c": "d"}, }, ) assert validate_signed_grant(header) == expected
def validate_session_cookie(auth_header_unusued=None): """ Attempts to load a user from a session cookie. """ if current_user.is_anonymous: return ValidateResult(AuthKind.cookie, missing=True) try: # Attempt to parse the user uuid to make sure the cookie has the right value type UUID(current_user.get_id()) except ValueError: logger.debug('Got non-UUID for session cookie user: %s', current_user.get_id()) return ValidateResult(AuthKind.cookie, error_message='Invalid session cookie format') logger.debug('Loading user from cookie: %s', current_user.get_id()) db_user = current_user.db_user() if db_user is None: return ValidateResult(AuthKind.cookie, error_message='Could not find matching user') # Don't allow disabled users to login. if not db_user.enabled: logger.debug('User %s in session cookie is disabled', db_user.username) return ValidateResult(AuthKind.cookie, error_message='User account is disabled') # Don't allow organizations to "login". if db_user.organization: logger.debug('User %s in session cookie is in-fact organization', db_user.username) return ValidateResult(AuthKind.cookie, error_message='Cannot login to organization') return ValidateResult(AuthKind.cookie, user=db_user)
def test_valid_token(app): access_token = model.token.create_delegate_token("devtable", "simple", "sometoken") token = _token(ACCESS_TOKEN_USERNAME, access_token.get_code()) result = validate_basic_auth(token) assert result == ValidateResult(AuthKind.basic, token=access_token)
def test_valid_robot(app): robot, password = model.user.create_robot("somerobot", model.user.get_user("devtable")) token = _token(robot.username, password) result = validate_basic_auth(token) assert result == ValidateResult(AuthKind.basic, robot=robot)
def test_valid_user(app): token = _token("devtable", "password") result = validate_basic_auth(token) assert result == ValidateResult(AuthKind.basic, user=model.user.get_user("devtable"))
from auth.credentials import (ACCESS_TOKEN_USERNAME, OAUTH_TOKEN_USERNAME, APP_SPECIFIC_TOKEN_USERNAME) from auth.validateresult import AuthKind, ValidateResult from data import model from test.fixtures import * def _token(username, password): assert isinstance(username, basestring) assert isinstance(password, basestring) return 'basic ' + b64encode('%s:%s' % (username, password)) @pytest.mark.parametrize('token, expected_result', [ ('', ValidateResult(AuthKind.basic, missing=True)), ('someinvalidtoken', ValidateResult(AuthKind.basic, missing=True)), ('somefoobartoken', ValidateResult(AuthKind.basic, missing=True)), ('basic ', ValidateResult(AuthKind.basic, missing=True)), ('basic some token', ValidateResult(AuthKind.basic, missing=True)), ('basic sometoken', ValidateResult(AuthKind.basic, missing=True)), (_token(APP_SPECIFIC_TOKEN_USERNAME, 'invalid'), ValidateResult(AuthKind.basic, error_message='Invalid token')), (_token(ACCESS_TOKEN_USERNAME, 'invalid'), ValidateResult(AuthKind.basic, error_message='Invalid access token')), (_token(OAUTH_TOKEN_USERNAME, 'invalid'), ValidateResult( AuthKind.basic, error_message='OAuth access token could not be validated')), (_token('devtable', 'invalid'), ValidateResult(AuthKind.basic,
def test_invalid_unicode(app): token = "\xebOH" header = "basic " + b64encode(token) result = validate_basic_auth(header) assert result == ValidateResult(AuthKind.basic, missing=True)
from auth.validateresult import AuthKind, ValidateResult from data import model from test.fixtures import * def _token(username, password): assert isinstance(username, basestring) assert isinstance(password, basestring) return "basic " + b64encode("%s:%s" % (username, password)) @pytest.mark.parametrize( "token, expected_result", [ ("", ValidateResult(AuthKind.basic, missing=True)), ("someinvalidtoken", ValidateResult(AuthKind.basic, missing=True)), ("somefoobartoken", ValidateResult(AuthKind.basic, missing=True)), ("basic ", ValidateResult(AuthKind.basic, missing=True)), ("basic some token", ValidateResult(AuthKind.basic, missing=True)), ("basic sometoken", ValidateResult(AuthKind.basic, missing=True)), ( _token(APP_SPECIFIC_TOKEN_USERNAME, "invalid"), ValidateResult(AuthKind.basic, error_message="Invalid token"), ), ( _token(ACCESS_TOKEN_USERNAME, "invalid"), ValidateResult(AuthKind.basic, error_message="Invalid access token"), ), (