class TestJWTKeyAuthentication(JWTAuthKeyTester): fixtures = ['base/addon_3615'] def setUp(self): super(TestJWTKeyAuthentication, self).setUp() self.factory = RequestFactory() self.auth = JWTKeyAuthentication() self.user = UserProfile.objects.get(email='*****@*****.**') def request(self, token): return self.factory.get('/', HTTP_AUTHORIZATION='JWT {}'.format(token)) def _create_token(self): api_key = self.create_api_key(self.user) return self.create_auth_token(api_key.user, api_key.key, api_key.secret) def test_get_user(self): user, _ = self.auth.authenticate(self.request(self._create_token())) assert user == self.user def test_unknown_issuer(self): api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['iss'] = 'non-existant-issuer' token = self.encode_token_payload(payload, api_key.secret) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == 'Unknown JWT iss (issuer).' def test_deleted_user(self): self.user.update(deleted=True) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(self._create_token())) assert ctx.exception.detail == 'User account is disabled.' def test_user_has_not_read_agreement(self): self.user.update(read_dev_agreement=None) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(self._create_token())) assert ctx.exception.detail == 'User has not read developer agreement.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_authentication_failed(self, jwt_decode_handler): jwt_decode_handler.side_effect = AuthenticationFailed with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Incorrect authentication credentials.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_expired_signature(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.ExpiredSignature with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Signature has expired.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_decoding_error(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.DecodeError with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Error decoding signature.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_invalid_token(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.InvalidTokenError with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Invalid JWT Token.' def test_refuse_refreshable_tokens(self): # We should not accept refreshable tokens. api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['orig_iat'] = timegm(payload['iat'].utctimetuple()) token = self.encode_token_payload(payload, api_key.secret) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == ( "API key based tokens are not refreshable, don't include " "`orig_iat` in their payload.") def test_cant_refresh_token(self): # Developers generate tokens, not us, they should not be refreshable, # the refresh implementation does not even know how to decode them. api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['orig_iat'] = timegm(payload['iat'].utctimetuple()) token = self.encode_token_payload(payload, api_key.secret) request = self.factory.post('/lol-refresh', {'token': token}) response = refresh_jwt_token(request) response.render() assert response.status_code == 400 data = json.loads(response.content) assert data == {'non_field_errors': ['Error decoding signature.']}
class TestJWTKeyAuthentication(JWTAuthKeyTester, TestCase): client_class = APITestClient def setUp(self): super(TestJWTKeyAuthentication, self).setUp() self.factory = RequestFactory() self.auth = JWTKeyAuthentication() self.user = user_factory(read_dev_agreement=datetime.now()) def request(self, token): return self.factory.get('/', HTTP_AUTHORIZATION='JWT {}'.format(token)) def _create_token(self, api_key=None): if api_key is None: api_key = self.create_api_key(self.user) return self.create_auth_token(api_key.user, api_key.key, api_key.secret) def test_get_user(self): core.set_remote_addr('15.16.23.42') user, _ = self.auth.authenticate(self.request(self._create_token())) assert user == self.user assert user.last_login_ip == '15.16.23.42' self.assertCloseToNow(user.last_login) def test_wrong_type_for_iat(self): api_key = self.create_api_key(self.user) # Manually create a broken payload where 'iat' is a string containing # a timestamp.. issued_at = int(time.mktime(datetime.utcnow().timetuple())) payload = { 'iss': api_key.key, 'iat': unicode(issued_at), 'exp': unicode(issued_at + settings.MAX_APIKEY_JWT_AUTH_TOKEN_LIFETIME), } token = self.encode_token_payload(payload, api_key.secret) core.set_remote_addr('1.2.3.4') with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == ( 'Wrong type for one or more keys in payload') def test_unknown_issuer(self): api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['iss'] = 'non-existant-issuer' token = self.encode_token_payload(payload, api_key.secret) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == 'Unknown JWT iss (issuer).' def test_deleted_user(self): in_the_past = self.days_ago(42) self.user.update(last_login_ip='48.15.16.23', last_login=in_the_past, deleted=True) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(self._create_token())) assert ctx.exception.detail == 'User account is disabled.' self.user.reload() assert self.user.last_login == in_the_past assert self.user.last_login_ip == '48.15.16.23' def test_user_has_not_read_agreement(self): self.user.update(read_dev_agreement=None) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(self._create_token())) assert ctx.exception.detail == 'User has not read developer agreement.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_authentication_failed(self, jwt_decode_handler): jwt_decode_handler.side_effect = AuthenticationFailed with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Incorrect authentication credentials.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_expired_signature(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.ExpiredSignature with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Signature has expired.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_decoding_error(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.DecodeError with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Error decoding signature.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_invalid_token(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.InvalidTokenError with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Invalid JWT Token.' def test_refuse_refreshable_tokens(self): # We should not accept refreshable tokens. api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['orig_iat'] = timegm(payload['iat'].utctimetuple()) token = self.encode_token_payload(payload, api_key.secret) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == ( "API key based tokens are not refreshable, don't include " "`orig_iat` in their payload.") def test_cant_refresh_token(self): # Developers generate tokens, not us, they should not be refreshable, # the refresh implementation does not even know how to decode them. api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['orig_iat'] = timegm(payload['iat'].utctimetuple()) token = self.encode_token_payload(payload, api_key.secret) request = self.factory.post('/lol-refresh', {'token': token}) response = refresh_jwt_token(request) response.render() assert response.status_code == 400 data = json.loads(response.content) assert data == {'non_field_errors': ['Error decoding signature.']}
class TestJWTKeyAuthentication(JWTAuthKeyTester, TestCase): client_class = APITestClient def setUp(self): super(TestJWTKeyAuthentication, self).setUp() self.factory = RequestFactory() self.auth = JWTKeyAuthentication() self.user = user_factory(read_dev_agreement=datetime.now()) def request(self, token): return self.factory.get('/', HTTP_AUTHORIZATION='JWT {}'.format(token)) def _create_token(self, api_key=None): if api_key is None: api_key = self.create_api_key(self.user) return self.create_auth_token(api_key.user, api_key.key, api_key.secret) def test_get_user(self): core.set_remote_addr('15.16.23.42') user, _ = self.auth.authenticate(self.request(self._create_token())) assert user == self.user assert user.last_login_ip == '15.16.23.42' self.assertCloseToNow(user.last_login) def test_wrong_type_for_iat(self): api_key = self.create_api_key(self.user) # Manually create a broken payload where 'iat' is a string containing # a timestamp.. issued_at = int(time.mktime(datetime.utcnow().timetuple())) payload = { 'iss': api_key.key, 'iat': unicode(issued_at), 'exp': unicode( issued_at + settings.MAX_APIKEY_JWT_AUTH_TOKEN_LIFETIME), } token = self.encode_token_payload(payload, api_key.secret) core.set_remote_addr('1.2.3.4') with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == ( 'Wrong type for one or more keys in payload') def test_unknown_issuer(self): api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['iss'] = 'non-existant-issuer' token = self.encode_token_payload(payload, api_key.secret) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == 'Unknown JWT iss (issuer).' def test_deleted_user(self): in_the_past = self.days_ago(42) self.user.update( last_login_ip='48.15.16.23', last_login=in_the_past, deleted=True) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(self._create_token())) assert ctx.exception.detail == 'User account is disabled.' self.user.reload() assert self.user.last_login == in_the_past assert self.user.last_login_ip == '48.15.16.23' def test_user_has_not_read_agreement(self): self.user.update(read_dev_agreement=None) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(self._create_token())) assert ctx.exception.detail == 'User has not read developer agreement.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_authentication_failed(self, jwt_decode_handler): jwt_decode_handler.side_effect = AuthenticationFailed with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Incorrect authentication credentials.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_expired_signature(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.ExpiredSignature with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Signature has expired.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_decoding_error(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.DecodeError with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Error decoding signature.' @mock.patch('olympia.api.jwt_auth.jwt_decode_handler') def test_decode_invalid_token(self, jwt_decode_handler): jwt_decode_handler.side_effect = jwt.InvalidTokenError with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request('whatever')) assert ctx.exception.detail == 'Invalid JWT Token.' def test_refuse_refreshable_tokens(self): # We should not accept refreshable tokens. api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['orig_iat'] = timegm(payload['iat'].utctimetuple()) token = self.encode_token_payload(payload, api_key.secret) with self.assertRaises(AuthenticationFailed) as ctx: self.auth.authenticate(self.request(token)) assert ctx.exception.detail == ( "API key based tokens are not refreshable, don't include " "`orig_iat` in their payload.") def test_cant_refresh_token(self): # Developers generate tokens, not us, they should not be refreshable, # the refresh implementation does not even know how to decode them. api_key = self.create_api_key(self.user) payload = self.auth_token_payload(self.user, api_key.key) payload['orig_iat'] = timegm(payload['iat'].utctimetuple()) token = self.encode_token_payload(payload, api_key.secret) request = self.factory.post('/lol-refresh', {'token': token}) response = refresh_jwt_token(request) response.render() assert response.status_code == 400 data = json.loads(response.content) assert data == {'non_field_errors': ['Error decoding signature.']}