diff options
-rw-r--r-- | keystone/tests/unit/test_v3_auth.py | 15 | ||||
-rw-r--r-- | keystone/token/provider.py | 17 | ||||
-rw-r--r-- | releasenotes/notes/token_expiration_to_match_application_credential-56d058355a9f240d.yaml | 10 |
3 files changed, 42 insertions, 0 deletions
diff --git a/keystone/tests/unit/test_v3_auth.py b/keystone/tests/unit/test_v3_auth.py index e710634d0..cf456518a 100644 --- a/keystone/tests/unit/test_v3_auth.py +++ b/keystone/tests/unit/test_v3_auth.py @@ -5577,6 +5577,21 @@ class ApplicationCredentialAuth(test_v3.RestfulTestCase): self.v3_create_token(auth_data, expected_status=http.client.UNAUTHORIZED) + def test_application_credential_expiration_limits_token_expiration(self): + expires_at = datetime.datetime.utcnow() + datetime.timedelta(minutes=1) + app_cred = self._make_app_cred(expires=expires_at) + app_cred_ref = self.app_cred_api.create_application_credential( + app_cred) + auth_data = self.build_authentication_request( + app_cred_id=app_cred_ref['id'], secret=app_cred_ref['secret']) + resp = self.v3_create_token(auth_data, + expected_status=http.client.CREATED) + token = resp.headers.get('X-Subject-Token') + future = datetime.datetime.utcnow() + datetime.timedelta(minutes=2) + with freezegun.freeze_time(future): + self._validate_token(token, + expected_status=http.client.UNAUTHORIZED) + def test_application_credential_fails_when_user_deleted(self): app_cred = self._make_app_cred() app_cred_ref = self.app_cred_api.create_application_credential( diff --git a/keystone/token/provider.py b/keystone/token/provider.py index 2ea4d7e08..b14b0f34e 100644 --- a/keystone/token/provider.py +++ b/keystone/token/provider.py @@ -267,6 +267,23 @@ class Manager(manager.Manager): default_expire_time(), subsecond=True ) + # NOTE(d34dh0r53): If this token is being issued with an application + # credential and the application credential expires before the token + # we need to set the token expiration to be the same as the application + # credential. See CVE-2022-2447 for more information. + if app_cred_id is not None: + app_cred_api = PROVIDERS.application_credential_api + app_cred = app_cred_api.get_application_credential( + token.application_credential_id) + token_time = timeutils.normalize_time( + timeutils.parse_isotime(token.expires_at)) + if (app_cred['expires_at'] is not None) and ( + token_time > app_cred['expires_at']): + token.expires_at = app_cred['expires_at'].isoformat() + LOG.debug('Resetting token expiration to the application' + ' credential expiration: %s', + app_cred['expires_at'].isoformat()) + token_id, issued_at = self.driver.generate_id_and_issued_at(token) token.mint(token_id, issued_at) diff --git a/releasenotes/notes/token_expiration_to_match_application_credential-56d058355a9f240d.yaml b/releasenotes/notes/token_expiration_to_match_application_credential-56d058355a9f240d.yaml new file mode 100644 index 000000000..d37073a9d --- /dev/null +++ b/releasenotes/notes/token_expiration_to_match_application_credential-56d058355a9f240d.yaml @@ -0,0 +1,10 @@ +--- +security: + - | + [`bug 1992183 <https://bugs.launchpad.net/keystone/+bug/1992183>`_] + [`CVE-2022-2447 <http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-2447>`_] + Tokens issued with application credentials will now have their expiration + validated against that of the application credential. If the application + credential expires before the token the token's expiration will be set to + the same expiration as the application credential. Otherwise the token + will use the configured value. |