def test_encode_invalid_access_token(self):
        # Check with non-serializable json
        with self.app.test_request_context():
            user_claims = datetime
            identity_claim = 'identity'
            with self.assertRaises(Exception):
                encode_access_token('user1',
                                    'secret',
                                    'HS256',
                                    timedelta(hours=1),
                                    True,
                                    user_claims,
                                    csrf=True,
                                    identity_claim=identity_claim)

            user_claims = {'foo': timedelta(hours=4)}
            with self.assertRaises(Exception):
                encode_access_token('user1',
                                    'secret',
                                    'HS256',
                                    timedelta(hours=1),
                                    True,
                                    user_claims,
                                    csrf=True,
                                    identity_claim=identity_claim)
    def test_encode_access_token(self):
        secret = 'super-totally-secret-key'
        algorithm = 'HS256'
        token_expire_delta = timedelta(minutes=5)
        user_claims = {'foo': 'bar'}
        identity_claim = 'identity'

        # Check with a fresh token
        with self.app.test_request_context():
            identity = 'user1'
            token = encode_access_token(identity, secret, algorithm, token_expire_delta,
                                        fresh=True, user_claims=user_claims, csrf=False,
                                        identity_claim=identity_claim)
            data = jwt.decode(token, secret, algorithms=[algorithm])
            self.assertIn('exp', data)
            self.assertIn('iat', data)
            self.assertIn('nbf', data)
            self.assertIn('jti', data)
            self.assertIn(identity_claim, data)
            self.assertIn('fresh', data)
            self.assertIn('type', data)
            self.assertIn('user_claims', data)
            self.assertNotIn('csrf', data)
            self.assertEqual(data[identity_claim], identity)
            self.assertEqual(data['fresh'], True)
            self.assertEqual(data['type'], 'access')
            self.assertEqual(data['user_claims'], user_claims)
            self.assertEqual(data['iat'], data['nbf'])
            now_ts = calendar.timegm(datetime.utcnow().utctimetuple())
            exp_seconds = data['exp'] - now_ts
            self.assertLessEqual(exp_seconds, 60 * 5)
            self.assertGreater(exp_seconds, 60 * 4)

            # Check with a non-fresh token
            identity = 12345  # identity can be anything json serializable
            token = encode_access_token(identity, secret, algorithm, token_expire_delta,
                                        fresh=False, user_claims=user_claims, csrf=True,
                                        identity_claim=identity_claim)
            data = jwt.decode(token, secret, algorithms=[algorithm])
            self.assertIn('exp', data)
            self.assertIn('iat', data)
            self.assertIn('nbf', data)
            self.assertIn('jti', data)
            self.assertIn(identity_claim, data)
            self.assertIn('fresh', data)
            self.assertIn('type', data)
            self.assertIn('user_claims', data)
            self.assertIn('csrf', data)
            self.assertEqual(data[identity_claim], identity)
            self.assertEqual(data['fresh'], False)
            self.assertEqual(data['type'], 'access')
            self.assertEqual(data['user_claims'], user_claims)
            self.assertEqual(data['iat'], data['nbf'])
            now_ts = calendar.timegm(datetime.utcnow().utctimetuple())
            exp_seconds = data['exp'] - now_ts
            self.assertLessEqual(exp_seconds, 60 * 5)
            self.assertGreater(exp_seconds, 60 * 4)
Beispiel #3
0
    def _create_access_token(self, identity, fresh=False, expires_delta=None,
                             user_claims=None, headers=None):
        if expires_delta is None:
            expires_delta = config.access_expires

        if user_claims is None:
            user_claims = self._user_claims_callback(identity)

        if headers is None:
            headers = self._jwt_additional_header_callback(identity)

        access_token = encode_access_token(
            identity=self._user_identity_callback(identity),
            secret=self._encode_key_callback(identity),
            algorithm=config.algorithm,
            expires_delta=expires_delta,
            fresh=fresh,
            user_claims=user_claims,
            csrf=config.csrf_protect,
            identity_claim_key=config.identity_claim_key,
            user_claims_key=config.user_claims_key,
            json_encoder=config.json_encoder,
            headers=headers,
            issuer=config.encode_issuer,
        )
        return access_token
Beispiel #4
0
def make_token(username, secret_key, lifetime, claims):
    """
    Produce a JWT for access to the API.
    Parameters
    ----------
    username : str
        Name of user to issue token for.
    secret_key : str
        Secret used to sign the token.
    lifetime : timedelta
        Time for which the token is valid.
    claims : dict
        User claims. Query types this token will allow access to, and type of access allowed.
    """
    return encode_access_token(
        identity=username,
        secret=secret_key,
        algorithm="HS256",
        expires_delta=lifetime,
        fresh=True,
        user_claims=claims,
        csrf=False,
        identity_claim_key="identity",
        user_claims_key="user_claims",
        json_encoder=JSONEncoder,
    )
Beispiel #5
0
    def create_access_token(self, identity, fresh=False, expires_delta=None):
        """
        Creates a new access token

        :param identity: The identity of this token. This can be any data that is
                         json serializable. It can also be an object, in which case
                         you can use the user_identity_loader to define a function
                         that will be called to pull a json serializable identity
                         out of this object. This is useful so you don't need to
                         query disk twice, once for initially finding the identity
                         in your login endpoint, and once for setting addition data
                         in the JWT via the user_claims_loader
        :param fresh: If this token should be marked as fresh, and can thus access
                      fresh_jwt_required protected endpoints. Defaults to False
        :param expires_delta: A datetime.timedelta for how long this token should
                              last before it expires. If this is None, it will
                              use the 'JWT_ACCESS_TOKEN_EXPIRES` config value
        :return: A new access token
        """
        if expires_delta is None:
            expires_delta = config.access_expires

        access_token = encode_access_token(
            identity=self._user_identity_callback(identity),
            secret=config.encode_key,
            algorithm=config.algorithm,
            expires_delta=expires_delta,
            fresh=fresh,
            user_claims=self._user_claims_callback(identity),
            csrf=config.csrf_protect)
        return access_token
Beispiel #6
0
    def create_access_token(self, identity, fresh=False):
        """
        Creates a new access token

        :param identity: The identity of this token. This can be any data that is
                         json serializable. It can also be an object, in which case
                         you can use the user_identity_loader to define a function
                         that will be called to pull a json serializable identity
                         out of this object. This is useful so you don't need to
                         query disk twice, once for initially finding the identity
                         in your login endpoint, and once for setting addition data
                         in the JWT via the user_claims_loader
        :param fresh: If this token should be marked as fresh, and can thus access
                      fresh_jwt_required protected endpoints. Defaults to False
        :return: A new access token
        """
        access_token = encode_access_token(
            identity=self._user_identity_callback(identity),
            secret=config.encode_key,
            algorithm=config.algorithm,
            expires_delta=config.access_expires,
            fresh=fresh,
            user_claims=self._user_claims_callback(identity),
            csrf=config.csrf_protect)
        if config.blacklist_enabled and config.blacklist_access_tokens:
            decoded_token = decode_jwt(access_token,
                                       config.decode_key,
                                       config.algorithm,
                                       csrf=config.csrf_protect)
            store_token(decoded_token, revoked=False)
        return access_token
Beispiel #7
0
    def test_bad_tokens(self):
        # Test expired access token
        response = self.client.post('/auth/login')
        data = json.loads(response.get_data(as_text=True))
        access_token = data['access_token']
        status_code, data = self._jwt_get('/protected', access_token)
        self.assertEqual(status_code, 200)
        self.assertIn('msg', data)
        time.sleep(2)
        status_code, data = self._jwt_get('/protected', access_token)
        self.assertEqual(status_code, 401)
        self.assertIn('msg', data)

        # Test expired refresh token
        response = self.client.post('/auth/login')
        data = json.loads(response.get_data(as_text=True))
        refresh_token = data['refresh_token']
        status_code, data = self._jwt_post('/auth/refresh', refresh_token)
        self.assertEqual(status_code, 200)
        self.assertIn('access_token', data)
        self.assertNotIn('msg', data)
        time.sleep(2)
        status_code, data = self._jwt_post('/auth/refresh', refresh_token)
        self.assertEqual(status_code, 401)
        self.assertNotIn('access_token', data)
        self.assertIn('msg', data)

        # Test Bogus token
        auth_header = "Bearer {}".format('this_is_totally_an_access_token')
        response = self.client.get('/protected', headers={'Authorization': auth_header})
        data = json.loads(response.get_data(as_text=True))
        status_code = response.status_code
        self.assertEqual(status_code, 422)
        self.assertIn('msg', data)

        # Test token that was signed with a different key
        with self.app.test_request_context():
            token = encode_access_token('foo', 'newsecret', 'HS256',
                                        timedelta(minutes=5), True, {}, csrf=False)
        auth_header = "Bearer {}".format(token)
        response = self.client.get('/protected', headers={'Authorization': auth_header})
        data = json.loads(response.get_data(as_text=True))
        status_code = response.status_code
        self.assertEqual(status_code, 422)
        self.assertIn('msg', data)

        # Test with valid token that is missing required claims
        now = datetime.utcnow()
        token_data = {'exp': now + timedelta(minutes=5)}
        encoded_token = jwt.encode(token_data, self.app.config['SECRET_KEY'],
                                   self.app.config['JWT_ALGORITHM']).decode('utf-8')
        auth_header = "Bearer {}".format(encoded_token)
        response = self.client.get('/protected', headers={'Authorization': auth_header})
        data = json.loads(response.get_data(as_text=True))
        status_code = response.status_code
        self.assertEqual(status_code, 422)
        self.assertIn('msg', data)
 def test_optional_jwt_with_different_algorithm(self):
     self.app.config['JWT_ALGORITHM'] = 'HS256'
     self.app.secret_key = 'test_secret'
     access_token = encode_access_token(identity='bobdobbs',
                                        secret='test_secret',
                                        algorithm='HS512',
                                        expires_delta=timedelta(minutes=5),
                                        fresh=True,
                                        user_claims={},
                                        csrf=False)
     status, data = self._jwt_get('/partially-protected', access_token)
     self.assertEqual(status, 422)
     self.assertIn('msg', data)
    def test_encode_access_token__no_user_claims(self):
        '''
        To make JWT shorter, do not add `user_claims` if empty.
        '''
        secret = 'super-totally-secret-key'
        algorithm = 'HS256'
        token_expire_delta = timedelta(minutes=5)
        identity_claim = 'sub'

        # `user_claims` is empty dict
        with self.app.test_request_context():
            identity = 'user1'
            token = encode_access_token(identity,
                                        secret,
                                        algorithm,
                                        token_expire_delta,
                                        fresh=False,
                                        user_claims={},
                                        csrf=False,
                                        identity_claim=identity_claim)

            data = jwt.decode(token, secret, algorithms=[algorithm])
            self.assertNotIn('user_claims', data)

        # `user_claims` is None
        with self.app.test_request_context():
            identity = 'user1'
            token = encode_access_token(identity,
                                        secret,
                                        algorithm,
                                        token_expire_delta,
                                        fresh=False,
                                        user_claims=None,
                                        csrf=False,
                                        identity_claim=identity_claim)

            data = jwt.decode(token, secret, algorithms=[algorithm])
            self.assertNotIn('user_claims', data)
Beispiel #10
0
    def _create_access_token(self, identity, fresh=False, expires_delta=None):
        if expires_delta is None:
            expires_delta = config.access_expires

        access_token = encode_access_token(
            identity=self._user_identity_callback(identity),
            secret=config.encode_key,
            algorithm=config.algorithm,
            expires_delta=expires_delta,
            fresh=fresh,
            user_claims=self._user_claims_callback(identity),
            csrf=config.csrf_protect,
            identity_claim=config.identity_claim)
        return access_token
Beispiel #11
0
def logout():
    # csrf_token = session.get('csrf_token')
    # session.clear()
    # session['csrf_token'] = csrf_token
    jti = get_raw_jwt()['jti']
    username = get_jwt_identity()
    jwt_manager = _get_jwt_manager()
    access_token = encode_access_token(identity=jwt_manager._user_identity_callback(username),
            secret='revoked-secret',
            algorithm=config.algorithm,
            expires_delta=None,
            fresh=False,
            user_claims=jwt_manager._user_claims_callback(username),
            csrf=config.csrf_protect,
            identity_claim_key=config.identity_claim_key,
            user_claims_key=config.user_claims_key,
            json_encoder=config.json_encoder)
    # revoked_store.set(jti, 'true')
    return jsonify(errno=RET.OK, access_token=access_token,errmsg="退出登录成功")
Beispiel #12
0
    def _create_access_token(self,
                             identity,
                             extra_info_for_claims={},
                             fresh=False,
                             expires_delta=None):
        if expires_delta is None:
            expires_delta = config.access_expires

        access_token = encode_access_token(
            identity=self._user_identity_callback(identity),
            secret=self._encode_key_callback(identity),
            algorithm=config.algorithm,
            expires_delta=expires_delta,
            fresh=fresh,
            user_claims=self._user_claims_callback(identity,
                                                   extra_info_for_claims),
            csrf=config.csrf_protect,
            identity_claim_key=config.identity_claim_key,
            user_claims_key=config.user_claims_key,
            json_encoder=config.json_encoder)
        return access_token
Beispiel #13
0
def add_token(server):
    """
    Generate a new token for a server.

    Parameters
    ----------
    server: int
        ID of the server.

    Notes
    -----
    Expects json with "name", "expiry" and "claims" keys, where "name" is a string,
    expiry is a datetime string of the form ""%Y-%m-%dT%H:%M:%S.%fZ" (e.g. 2018-01-01T00:00:00.0Z),
    and claims is a nested dict of the form {<claim_name>:{<right_name>:<bool>}}.

    Responds with a json object {"token":<token_string>, "id":<token_id>}.

    """
    server = Server.query.filter(Server.id == server).first_or_404()
    json = request.get_json()
    print(json)
    if "name" not in json:
        raise InvalidUsage("No name.", payload={"bad_field": "name"})
    expiry = datetime.datetime.strptime(json["expiry"], "%Y-%m-%dT%H:%M:%S.%fZ")
    lifetime = expiry - datetime.datetime.now()
    latest_lifetime = current_user.latest_token_expiry(server)
    if expiry > latest_lifetime:
        raise InvalidUsage("Token lifetime too long", payload={"bad_field": "expiry"})
    allowed_claims = current_user.allowed_claims(server)
    print(allowed_claims)
    for claim, rights in json["claims"].items():
        if claim not in allowed_claims:
            raise Unauthorized(f"You do not have access to {claim} on {server.name}")
        for right, setting in rights["permissions"].items():
            if setting and not allowed_claims[claim]["permissions"][right]:
                raise Unauthorized(
                    f"You do not have access to {claim}:{right} on {server.name}"
                )
        for agg_unit in rights["spatial_aggregation"]:
            if agg_unit not in allowed_claims[claim]["spatial_aggregation"]:
                raise Unauthorized(
                    f"You do not have access to {claim} at {agg_unit} on {server.name}"
                )
    token_string = encode_access_token(
        identity=current_user.username,
        secret=server.secret_key,
        algorithm="HS256",
        expires_delta=lifetime,
        fresh=True,
        user_claims=json["claims"],
        csrf=False,
        identity_claim_key="identity",
        user_claims_key="user_claims",
        json_encoder=JSONEncoder,
    )
    token = Token(
        name=json["name"],
        token=token_string,
        expires=expiry,
        owner=current_user,
        server=server,
    )
    db.session.add(token)
    db.session.commit()
    return jsonify({"token": token_string, "id": token.id})
Beispiel #14
0
def custom_login():
    config.token = tokens.encode_access_token('test',
                                              os.environ.get('MARVIN_SECRET'),
                                              'HS256', False, True,
                                              'user_claims', True, 'identity',
                                              'user_claims')