Пример #1
0
 def decorated(*args, **kwargs):
     token = request.headers.get("token")
     if not token:
         raise InvalidTokenError("Token is missing. Please login again")
     if not TokenService.decodeToken(token).get("group_id") == "2":
         raise InvalidTokenError("Token is invalid. Please login again")
     return fn(*args, **kwargs)
Пример #2
0
 def decorated(*args, **kwargs):
     token = request.headers.get("token")
     if not token:
         raise InvalidTokenError("Token is missing. Please login again")
     validity = TokenService.verifyToken(token)
     if not validity[0]:
         raise InvalidTokenError(validity[1])
     return fn(*args, **kwargs)
Пример #3
0
def _request_x5c(key_identifier: str, identity_provider_url: str) -> str:
    keys = requests.get(identity_provider_url)
    if not keys:
        raise InvalidTokenError(f"Identify provider cannot be reached: {keys.text}")
    keys = keys.json().get("keys", [])
    keys = {key["kid"]: key["x5c"][0] for key in keys}

    if key_identifier not in keys:
        raise InvalidTokenError(
            f"{key_identifier} is not a valid key identifier. Valid ones are {list(keys)}."
        )
    return keys[key_identifier]
Пример #4
0
    def get_jwk_for_token(self, token):
        unverified_header = jwt.get_unverified_header(token)

        try:
            token_kid = unverified_header['kid']
        except KeyError:
            raise InvalidTokenError("Key ID header parameter is missing")

        for jwk in self.get_jwk_set()['keys']:
            if jwk['kid'] == token_kid:
                return jwk

        raise InvalidTokenError("no key found")
Пример #5
0
 def decorated_function(*args, **kwargs):
     token = request.headers['authorization']
     if not token:
         raise InvalidTokenError('Invalid token')
     parts = token.split(' ')
     if len(parts) > 2:
         raise InvalidTokenError('Invalid token')
     [scheme, token] = parts
     if scheme.strip() != 'Bearer':
         raise InvalidSignatureError('Invalid token signature')
     try:
         jwt.decode(token, variables.SECRET_KEY)
         return func(*args, **kwargs)
     except DecodeError:
         raise DecodeError('Token could not be decoded')
Пример #6
0
def decode(jwt_token: str) -> (dict, dict):
    """
    Decode base64 encoded token and return JSON decoded header and body as a tuple.
    :raises InvalidTokenError
    """
    if not jwt_token:
        raise InvalidTokenError("JWT Token is mandatory.")

    if jwt_token.count(".") < 2:
        raise InvalidTokenError(
            "Invalid JWT Token (header, body and signature must be separated by dots)."
        )

    (jwt_header, jwt_body, jwt_signature) = jwt_token.split(".", maxsplit=2)

    return _to_json(jwt_header), _to_json(jwt_body)
Пример #7
0
def validate_user(email, password):
    """
    Validates user logging in

    :param email: user email
    :param password: user password
    :return: JSON web token
    """
    user = db.users.find_one({'email': email})

    if user is None:
        raise LookupError('User account not found')

    hashed = user['password'].encode('utf-8')

    if bcrypt.hashpw(password.encode('utf-8'), hashed) == hashed:
        try:
            token = jwt.encode({'_id': str(user['_id'])},
                               config.SECRET_KEY,
                               algorithm='HS256')
            return token
        except Exception:
            raise InvalidTokenError("Error creating JWToken")
    else:
        raise AssertionError("Incorrect password")
Пример #8
0
    def wrapper(*args, **kwargs):
        logger = getLogger("jwt")

        token = None
        if JWT_HEADER_KEY in request.headers:
            token = request.headers[JWT_HEADER_KEY]
        if not token:
            return abort(401)

        try:
            token_data = jwt.decode(token, os.environ.get("FLASK_SECRET"))
            user_id = token_data.get("userId")
            if not user_id:
                raise (InvalidKeyError("userId"))
            current_user = User.query.get(user_id)
            if not current_user:
                raise InvalidTokenError(
                    f"user not found for user_id {user_id}")
            expiration = token_data.get("expiration")
            if not expiration:
                raise (InvalidKeyError("expiration"))
            if datetime.strptime(expiration, "%Y-%m-%d") < datetime.now():
                return {"message": "Login expired"}, 401

            # survived the gauntlet!
            return func(*args, **kwargs)
        except (
                InvalidTokenError,
                InvalidKeyError,
        ) as e:
            logger.error(f"invalid auth: {e}")
            return abort(401)
Пример #9
0
    def _validate_claims(self, payload, options, audience=None, issuer=None, leeway=0, **kwargs):
        if options.get("exp_max_s") is not None:
            if "verify_expiration" in kwargs and not kwargs.get("verify_expiration"):
                raise ValueError("exp_max_s option implies verify_expiration")

            options["verify_exp"] = True

        # Do all of the other checks
        super(_StrictJWT, self)._validate_claims(
            payload, options, audience, issuer, leeway, **kwargs
        )

        now = timegm(datetime.utcnow().utctimetuple())
        self._reject_future_iat(payload, now, leeway)

        if "exp" in payload and options.get("exp_max_s") is not None:
            # Validate that the expiration was not more than exp_max_s seconds after the issue time
            # or in the absence of an issue time, more than exp_max_s in the future from now

            # This will work because the parent method already checked the type of exp
            expiration = datetime.utcfromtimestamp(int(payload["exp"]))
            max_signed_s = options.get("exp_max_s")

            start_time = datetime.utcnow()
            if "iat" in payload:
                start_time = datetime.utcfromtimestamp(int(payload["iat"]))

            if expiration > start_time + timedelta(seconds=max_signed_s):
                raise InvalidTokenError(
                    "Token was signed for more than %s seconds from %s", max_signed_s, start_time
                )
Пример #10
0
def decode_jwt_token(token):
    unverified_header = jwt.get_unverified_header(token)
    unverified_claims = jwt.decode(token, verify=False)

    if unverified_header.get(claims.KEY_ID):
        unverified_key_id = six.text_type(unverified_header.get(claims.KEY_ID))
    else:
        unverified_key_id = None

    if claims.ISSUER not in unverified_claims:
        raise MissingRequiredClaimError(claims.ISSUER)

    unverified_issuer = six.text_type(unverified_claims[claims.ISSUER])

    if api_settings.ACCEPTED_ISSUERS is not None and unverified_issuer not in api_settings.ACCEPTED_ISSUERS:
        raise InvalidIssuerError('Invalid issuer')

    public_key, key_id = get_public_key_and_key_id(issuer=unverified_issuer, key_id=unverified_key_id)

    options = {
        'verify_exp': api_settings.VERIFY_EXPIRATION,
        'verify_aud': True,
        'verify_iss': True,
    }

    payload = jwt.decode(
        jwt=token,
        key=public_key,
        verify=api_settings.VERIFY_SIGNATURE,
        algorithms=api_settings.DECODE_ALGORITHMS or [api_settings.ENCODE_ALGORITHM],
        options=options,
        leeway=api_settings.EXPIRATION_LEEWAY,
        audience=api_settings.IDENTITY,
        issuer=unverified_issuer,
    )

    if payload.get(claims.TOKEN) not in (claims.TOKEN_SESSION, claims.TOKEN_AUTHORIZATION):
        raise InvalidTokenError('Unknown token type')
    if payload.get(claims.ISSUER) != api_settings.IDENTITY and payload.get(claims.TOKEN) != claims.TOKEN_AUTHORIZATION:
        raise InvalidTokenError('Only authorization tokens are accepted from other issuers')
    if not payload.get(claims.SESSION_ID):
        raise MissingRequiredClaimError('Session ID is missing.')
    if not payload.get(claims.USER_ID):
        raise MissingRequiredClaimError('User ID is missing.')

    return payload
Пример #11
0
def validate_jwt_token(token, user=None):
    """
    Validate the given auth/refresh JWT token for given user. It run all
    security checks to invalidate token if required like
    1. User is not active
    2. Password reset of user

    :param token:
    :param user:
    :return: an user instance
    """
    # TODO : refactor this method
    # it's unverified payload
    payload = jwt.decode(token, None, False)
    username = jwt_get_username_from_payload_handler(payload)

    if username is None:
        raise InvalidTokenError(
            "'username' field value in token payload is null or not set")

    if user is None:
        from src.apis.models.user import User
        try:
            user = User.objects.get_by_natural_key(username)
        except User.DoesNotExist:
            raise InvalidTokenError(f"No user found for username '{username}'")

    if getattr(user, "username") != username:
        raise InvalidTokenError(
            "'username' in token payload and subject user instance is not "
            "matched")

    # ----------- 1) User account is set inactive ---------------------------
    if not user.is_active:
        raise InvalidTokenError("Invalid token")

    # ----------- 2) User changed password ----------------------------------
    # Invalidate the token, if user's password is changed after token is
    # issued
    token_iat = payload.get("orig_iat")  # time is in epoch
    # user_password_changed_at = dt_to_epoch(user.last_password_change)
    # if user_password_changed_at and user_password_changed_at > token_iat:
    #     raise InvalidTokenError("Invalid token")

    return user
def test_should_return_401_if_load_account_by_id_raise_jwt_exception(
        mock_load: MagicMock, mock_get_collection: MagicMock,
        sut: AuthMiddleware):
    mock_load.side_effect = InvalidTokenError()
    mock_get_collection.return_value = mongomock.MongoClient().db.collection
    http_response = sut.handle(
        HttpRequest(headers={"x-access-token": "any_token"}, body=None))
    assert http_response.status_code == 401
    assert http_response.body["message"] == "Unauthorized"
Пример #13
0
def get(json_body: dict, key: str, description: str = None) -> str:
    """
    Return value for a given key stored in JSON body.

    :raises InvalidTokenError in case key does not exists.
    """
    value = json_body.get(key)
    if value is None:
        raise InvalidTokenError(
            f"No {description if description else key} in JSON body.")
    return value
Пример #14
0
def decode_jwt_token(token):
    unverified_header = jwt.get_unverified_header(token)
    unverified_claims = jwt.decode(token, verify=False)

    if unverified_header.get(claims.KEY_ID):
        unverified_key_id = str(unverified_header.get(claims.KEY_ID))
    else:
        unverified_key_id = None

    if claims.ISSUER not in unverified_claims:
        raise MissingRequiredClaimError(claims.ISSUER)

    unverified_issuer = str(unverified_claims[claims.ISSUER])

    if api_settings.ACCEPTED_ISSUERS is not None and unverified_issuer not in api_settings.ACCEPTED_ISSUERS:
        raise InvalidIssuerError("Invalid issuer")

    public_key, key_id = get_public_key_and_key_id(issuer=unverified_issuer,
                                                   key_id=unverified_key_id)

    options = {
        "verify_exp": api_settings.VERIFY_EXPIRATION,
        "verify_iss": api_settings.VERIFY_ISSUER,
        "verify_aud": api_settings.VERIFY_AUDIENCE,
    }

    payload = jwt.decode(
        jwt=token,
        key=public_key,
        verify=api_settings.VERIFY_SIGNATURE,
        algorithms=api_settings.DECODE_ALGORITHMS
        or [api_settings.ENCODE_ALGORITHM],
        options=options,
        leeway=api_settings.EXPIRATION_LEEWAY,
        audience=api_settings.IDENTITY,
        issuer=unverified_issuer,
    )

    if payload.get(claims.TOKEN) not in (claims.TOKEN_SESSION,
                                         claims.TOKEN_AUTHORIZATION):
        raise InvalidTokenError("Unknown token type")
    if not payload.get(claims.SESSION_ID):
        raise MissingRequiredClaimError("Session ID is missing.")
    if not payload.get(claims.USER_ID):
        raise MissingRequiredClaimError("User ID is missing.")

    return payload
Пример #15
0
    def do_GET(self):
        if self.path == "/healthz":
            self.send_response(200)
            self.send_header("Content-type", "text/plain")
            self.end_headers()
            return

        try:
            authorization = self.headers.get("authorization")
            auth_header = authorization.split()

            if auth_header[0].lower() != 'bearer' or len(auth_header) == 1:
                self.end_headers()
                return

            token = auth_header[1]

            decoded = jwt.decode(
                token,
                public_key,
                audience=url + '/resources',
                issuer=url,
                algorithms=['RS256'])  #, options={'verify_exp': False})

            scope_claims = decoded['scope']
            if valid_scopes:
                if not any(val in scope_claims for val in valid_scopes):
                    raise InvalidTokenError('Invalid scope ' +
                                            str(scope_claims) + ' not in ' +
                                            str(valid_scopes))

            self.send_response(200)
            self.send_header("Content-type", "text/plain")

            for key, value in decoded.items():
                self.send_header("X-JWT-" + key, str(value))

            self.end_headers()

            self.wfile.write(bytes(str(decoded), "utf8"))
        except Exception as e:
            self.send_response(401)
            self.end_headers()
            self.wfile.write(bytes(str(e), "utf8"))
        return
Пример #16
0
    def __init__(self, api, app=None):
        '''
        :param api: Instance of a flask_restplus Api that has been associated with app
        :param app: Instance of flask application or blueprint
        '''
        self.api = api
        super(self.__class__, self).__init__(app)

        # https://github.com/vimalloc/flask-jwt-extended/issues/86
        self._set_error_handler_callbacks(api)

        # As a result of https://github.com/noirbizarre/flask-restplus/issues/421 we must register
        # the invalid token error handler for each sub-class of jwt.exceptions.InvalidTokenError
        def handle_invalid_token_error(e):
            return self._invalid_token_callback(str(e))

        for subclass in InvalidTokenError.__subclasses__():
            (api.errorhandler(subclass))(handle_invalid_token_error)

        # Override default error callbacks
        self.expired_token_loader(expired_token_callback)
        self.invalid_token_loader(invalid_token_callback)
        self.unauthorized_loader(unauthorized_callback)
Пример #17
0
 def verify_sub(self, sub):
     if sub is None:
         raise InvalidTokenError('invalid sub')
     return True
Пример #18
0
 def verify_jti(self, jti):
     if jti is None:
         raise InvalidTokenError('invalid jti')
     return True
Пример #19
0
def get_jwk(kid, jwks):
    for jwk in jwks.get('keys', []):
        if jwk.get('kid') == kid:
            return jwk
    raise InvalidTokenError('JWK not found for kid={0}'.format(kid, str(jwks)))