diff --git a/keystone/models/revoke_model.py b/keystone/models/revoke_model.py index a036271746..38ccbf994e 100644 --- a/keystone/models/revoke_model.py +++ b/keystone/models/revoke_model.py @@ -159,12 +159,11 @@ def is_revoked(events, token_data): def matches(event, token_values): """See if the token matches the revocation event. - A brute force approach to checking. - Compare each attribute from the event with the corresponding - value from the token. If the event does not have a value for - the attribute, a match is still possible. If the event has a - value for the attribute, and it does not match the token, no match - is possible, so skip the remaining checks. + A brute force approach to checking. Compare each attribute from the event + with the corresponding value from the token. If the event does not have a + value for the attribute, a match is still possible. If the event has a + value for the attribute, and it does not match the token, no match is + possible, so skip the remaining checks. :param event: a RevokeEvent instance :param token_values: dictionary with set of values taken from the @@ -172,65 +171,143 @@ def matches(event, token_values): :returns: True if the token matches the revocation event, indicating the token has been revoked """ - # If any one check does not match, the whole token does - # not match the event. The numerous return False indicate - # that the token is still valid and short-circuits the - # rest of the logic. + # If any one check does not match, the whole token does not match the + # event. The numerous return False indicate that the token is still valid + # and short-circuits the rest of the logic. # The token has three attributes that can match the user_id. if event.user_id is not None and event.user_id not in ( token_values['user_id'], token_values['trustor_id'], token_values['trustee_id'],): + LOG.debug( + 'The user (id=%s) in the revocation event does not match any user ' + '(user_id=%s, trustor_id=%s, trustee_id=%s) in the token.', + event.user_id, + token_values['user_id'], + token_values['trustor_id'], + token_values['trustee_id']) return False # The token has two attributes that can match the domain_id. if event.domain_id is not None and event.domain_id not in( token_values['identity_domain_id'], token_values['assignment_domain_id'],): + LOG.debug( + 'The domain (id=%s) in the revocation event does not match any ' + 'domain (identity_domain_id=%s, assignment_domain_id=%s) in the ' + 'token.', + event.domain_id, + token_values['identity_domain_id'], + token_values['assignment_domain_id']) return False if event.domain_scope_id is not None and event.domain_scope_id not in ( token_values['assignment_domain_id'],): + LOG.debug( + 'The domain scope (id=%s) in the revocation event does not match ' + 'the domain scope (id=%s) in the token.', + event.domain_scope_id, + token_values['assignment_domain_id']) return False # If an event specifies an attribute name, but it does not match, the token # is not revoked. if event.project_id is not None and event.project_id not in ( token_values['project_id'],): + LOG.debug( + 'The project ID (%s) in the revocation event does not match the ' + 'project ID (%s) in the token.', + event.project_id, + token_values['project_id']) return False if event.expires_at is not None and event.expires_at not in ( token_values['expires_at'],): + LOG.debug( + 'The expiration (id=%s) in the revocation event does not match ' + 'the expiration (at=%s) of the token.', + event.expires_at, + token_values['expires_at']) return False if event.trust_id is not None and event.trust_id not in ( token_values['trust_id'],): + LOG.debug( + 'The trust (id=%s) in the revocation event does not match the ' + 'trust (id=%s) in the token.', + event.trust_id, + token_values['trust_id']) return False if event.consumer_id is not None and event.consumer_id not in ( token_values['consumer_id'],): + LOG.debug( + 'The OAuth consumer (id=%s) in the revocation event does not ' + 'match the OAuth consumer ID (id=%s) in the token.', + event.consumer_id, + token_values['consumer_id']) return False if event.access_token_id is not None and event.access_token_id not in ( token_values['access_token_id'],): + LOG.debug( + 'The OAuth access token (id=%s) in the revocation event does not ' + 'match the OAuth access token (id=%s) in the token.', + event.access_token_id, + token_values['access_token_id']) return False if event.audit_id is not None and event.audit_id not in ( token_values['audit_id'],): + LOG.debug( + 'The audit (id=%s) in the revocation event does not match the ' + 'audit (id=%s) in the token.', + event.audit_id, + token_values['audit_id']) return False if event.audit_chain_id is not None and event.audit_chain_id not in ( token_values['audit_chain_id'],): + LOG.debug( + 'The audit chain (id=%s) in the revocation event does not match ' + 'the audit chain (id=%s) in the token.', + event.audit_chain_id, + token_values['audit_chain_id']) return False if event.role_id is not None and event.role_id not in ( token_values['roles']): + if LOG.logger.getEffectiveLevel() <= log.DEBUG: + # The string formatting here needs to be conditional, so that the + # extra work can be skipped if DEBUG logs are not actually being + # written anywhere. + role_ids = ', '.join('id=%s' % x for x in token_values['roles']) + LOG.debug( + 'The role (id=%s) in the revocation event does not match any ' + 'of the roles (%s) in the token.', + event.role_id, + role_ids) return False if token_values['issued_at'] > event.issued_before: + LOG.debug( + 'The token was created (%s) after the revocation event was issued ' + '(%s).', + token_values['issued_at'], + event.issued_before) return False + if LOG.logger.getEffectiveLevel() <= log.DEBUG: + # The string formatting here needs to be conditional, so that the + # extra work can be skipped if DEBUG logs are not actually being + # written anywhere. + event_dict = event.to_dict() + attrs = ', '.join('='.join(item) for item in event_dict.items()) + LOG.debug( + 'All attributes (%s) in the revocation event are in the token.', + attrs, ) + return True