summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--keystone/tests/unit/test_v3_auth.py15
-rw-r--r--keystone/token/provider.py17
-rw-r--r--releasenotes/notes/token_expiration_to_match_application_credential-56d058355a9f240d.yaml10
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.