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)
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
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, )
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
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
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)
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
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="退出登录成功")
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
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})
def custom_login(): config.token = tokens.encode_access_token('test', os.environ.get('MARVIN_SECRET'), 'HS256', False, True, 'user_claims', True, 'identity', 'user_claims')