diff --git a/src/onegov/user/auth/core.py b/src/onegov/user/auth/core.py index 3907834143..2148789476 100644 --- a/src/onegov/user/auth/core.py +++ b/src/onegov/user/auth/core.py @@ -1,7 +1,9 @@ import morepath from datetime import datetime -from itsdangerous import URLSafeSerializer, BadSignature +from itsdangerous import URLSafeSerializer, BadData +from itsdangerous.encoding import base64_encode, base64_decode +from secrets import token_bytes from onegov.core.utils import relative_url from onegov.user import log @@ -368,21 +370,33 @@ def new_signup_token( requested amount of uses is allowed. """ - return self.signup_token_serializer.dumps({ + serializer = self.signup_token_serializer + serialized = serializer.dumps({ 'role': role, 'max_uses': max_uses, 'expires': int(datetime.utcnow().timestamp()) + max_age }) + assert serializer.salt is not None + encoded_salt = base64_encode(serializer.salt).decode('ascii') + return f'{serialized}.{encoded_salt}' @property def signup_token_serializer(self) -> URLSafeSerializer: assert self.signup_token_secret - return URLSafeSerializer(self.signup_token_secret, salt='signup') + return URLSafeSerializer( + self.signup_token_secret, + salt=token_bytes(16) + ) def decode_signup_token(self, token: str) -> 'SignupToken | None': try: - return self.signup_token_serializer.loads(token) - except BadSignature: + serialized, _, encoded_salt = token.rpartition('.') + if not serialized: + # the separator wasn't part of the token + return None + salt = base64_decode(encoded_salt) + return self.signup_token_serializer.loads(serialized, salt=salt) + except BadData: return None @property