Merge lp:~facundo/canonical-identity-provider/refuse-refresh-password-changed into lp:canonical-identity-provider/release

Proposed by Facundo Batista
Status: Merged
Approved by: Facundo Batista
Approved revision: no longer in the source branch.
Merged at revision: 1418
Proposed branch: lp:~facundo/canonical-identity-provider/refuse-refresh-password-changed
Merge into: lp:canonical-identity-provider/release
Prerequisite: lp:~facundo/canonical-identity-provider/add-password-changed-timestamp
Diff against target: 74 lines (+29/-3)
2 files modified
src/identityprovider/auth.py (+10/-3)
src/identityprovider/tests/test_auth.py (+19/-0)
To merge this branch: bzr merge lp:~facundo/canonical-identity-provider/refuse-refresh-password-changed
Reviewer Review Type Date Requested Status
Matias Bordese (community) Approve
Daniel Manrique (community) Approve
Review via email: mp+289938@code.launchpad.net

Commit message

Check if account's password changed before refreshing the macaroon.

Description of the change

Check if account's password changed before refreshing the macaroon.

To post a comment you must log in.
Revision history for this message
Daniel Manrique (roadmr) wrote :

The test, I think, is not really doing what we expect it to do. See longish comment below and I think we have some fixing to do :(

review: Needs Fixing
Revision history for this message
Matias Bordese (matiasb) :
Revision history for this message
Facundo Batista (facundo) wrote :

Answered a comment, pushed the fix for the other.

Revision history for this message
Daniel Manrique (roadmr) wrote :

Looks OK to me, Matías suggested another way to achieve the None value using update(), your choice on which one to use.

I'd still prefer a more explicit check than "just run this and ensure it didn't exception out" but am OK if you think this is reasonable.

I'll +1 in case you want to merge as is, or if you want to apply the update() change.

review: Approve
Revision history for this message
Daniel Manrique (roadmr) wrote :

Thanks for the assert.

review: Approve
Revision history for this message
Matias Bordese (matiasb) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/identityprovider/auth.py'
--- src/identityprovider/auth.py 2016-03-22 14:04:53 +0000
+++ src/identityprovider/auth.py 2016-03-23 18:07:17 +0000
@@ -46,6 +46,8 @@
4646
47logger = logging.getLogger(__name__)47logger = logging.getLogger(__name__)
4848
49MACAROON_TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%M:%S.%f'
50
4951
50class BCrypt13PasswordHasher(BCryptPasswordHasher):52class BCrypt13PasswordHasher(BCryptPasswordHasher):
51 rounds = 1353 rounds = 13
@@ -541,12 +543,12 @@
541 d.add_first_party_caveat(service_location + '|account|' + account_info)543 d.add_first_party_caveat(service_location + '|account|' + account_info)
542544
543 # add timestamp values545 # add timestamp values
544 now_string = now().strftime('%Y-%m-%dT%H:%M:%S.%f')546 now_string = now().strftime(MACAROON_TIMESTAMP_FORMAT)
545 if last_auth is None:547 if last_auth is None:
546 last_auth = now_string548 last_auth = now_string
547 if expires is None:549 if expires is None:
548 expires_ts = now() + datetime.timedelta(seconds=settings.MACAROON_TTL)550 expires_ts = now() + datetime.timedelta(seconds=settings.MACAROON_TTL)
549 expires = expires_ts.strftime('%Y-%m-%dT%H:%M:%S.%f')551 expires = expires_ts.strftime(MACAROON_TIMESTAMP_FORMAT)
550552
551 d.add_first_party_caveat(service_location + '|valid_since|' + now_string)553 d.add_first_party_caveat(service_location + '|valid_since|' + now_string)
552 d.add_first_party_caveat(service_location + '|last_auth|' + last_auth)554 d.add_first_party_caveat(service_location + '|last_auth|' + last_auth)
@@ -608,10 +610,15 @@
608 except:610 except:
609 raise AuthenticationError("Not verifying macaroons")611 raise AuthenticationError("Not verifying macaroons")
610612
611 # verify that the account is still fine613 # verify that the account is still active and password didn't change
612 account = Account.objects.active_by_openid(info_holder['openid'])614 account = Account.objects.active_by_openid(info_holder['openid'])
613 if account is None:615 if account is None:
614 raise AccountDeactivated()616 raise AccountDeactivated()
617 if account.accountpassword.date_changed is not None:
618 last_auth_ts = datetime.datetime.strptime(info_holder['last_auth'],
619 MACAROON_TIMESTAMP_FORMAT)
620 if account.accountpassword.date_changed > last_auth_ts:
621 raise AuthenticationError("Password changed")
615622
616 # create the new discharge macaroon with same location, key and623 # create the new discharge macaroon with same location, key and
617 # identifier than it's original 3rd-party caveat (so they can624 # identifier than it's original 3rd-party caveat (so they can
618625
=== modified file 'src/identityprovider/tests/test_auth.py'
--- src/identityprovider/tests/test_auth.py 2016-03-22 19:47:29 +0000
+++ src/identityprovider/tests/test_auth.py 2016-03-23 18:07:17 +0000
@@ -1161,6 +1161,25 @@
1161 self.root_macaroon.serialize(),1161 self.root_macaroon.serialize(),
1162 self.discharge_macaroon.serialize())1162 self.discharge_macaroon.serialize())
11631163
1164 def test_password_changed(self):
1165 self.account.set_password("a new password")
1166 self.assertRaises(AuthenticationError, refresh_macaroons,
1167 self.root_macaroon.serialize(),
1168 self.discharge_macaroon.serialize())
1169
1170 def test_password_with_no_datetime(self):
1171 # simulate an "old" account password (before we started to keep the
1172 # changed date); note that I'm bypassing the AccountPassword save(),
1173 # which will update the attribute that I want in Null! (and we confirm
1174 # that in the assert)
1175 self.account.accountpassword.date_changed = None
1176 super(AccountPassword, self.account.accountpassword).save()
1177 assert self.account.accountpassword.date_changed is None
1178
1179 # check that auths ok
1180 refresh_macaroons(self.root_macaroon.serialize(),
1181 self.discharge_macaroon.serialize())
1182
1164 def test_proper_refreshing(self):1183 def test_proper_refreshing(self):
1165 old_discharge = self.discharge_macaroon # just rename for readability1184 old_discharge = self.discharge_macaroon # just rename for readability
1166 service_location = settings.MACAROON_SERVICE_LOCATION1185 service_location = settings.MACAROON_SERVICE_LOCATION