Skip to content

Commit

Permalink
Merge pull request #637 from SUNET/lundberg_signup_fix
Browse files Browse the repository at this point in the history
error early if user is logged in during signup flow
  • Loading branch information
helylle authored Jun 17, 2024
2 parents d124178 + 3e3308b commit f3c090e
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 92 deletions.
16 changes: 16 additions & 0 deletions src/eduid/webapp/common/api/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ def require_eppn_decorator(*args: Any, **kwargs: Any) -> EduidViewReturnType:
return require_eppn_decorator


def require_not_logged_in(f: EduidRouteCallable) -> EduidRouteCallable:
"""
Decorator for views that require the user not to be logged in.
Because it can return a FluxData, this decorator must come after the MarshalWith decorator.
"""

@wraps(f)
def require_eppn_decorator(*args: Any, **kwargs: Any) -> EduidViewReturnType:
if session.common.is_logged_in:
return error_response(message=CommonMsg.logout_required)
return f(*args, **kwargs)

return require_eppn_decorator


TRequireUserResult = TypeVar("TRequireUserResult")


Expand Down
2 changes: 2 additions & 0 deletions src/eduid/webapp/common/api/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class CommonMsg(TranslatableMsg):
nin_invalid = "nin needs to be formatted as 18|19|20yymmddxxxx"
# Email address validation error
email_invalid = "email needs to be formatted according to RFC2822"
# user must log out
logout_required = "logout_required"
# TODO: These _should_ be unused now - check and remove
csrf_try_again = "csrf.try_again"
csrf_missing = "csrf.missing"
Expand Down
2 changes: 2 additions & 0 deletions src/eduid/webapp/common/api/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
"saml2": {"level": "WARNING"},
"xmlsec": {"level": "INFO"},
"urllib3": {"level": "INFO"},
"pymongo.serverSelection": {"level": "INFO"},
"pymongo.command": {"level": "INFO"},
"eduid.webapp.common.session": {"level": "INFO"},
"eduid.userdb.userdb.extra_debug": {"level": "INFO"},
"eduid.userdb.db.extra_debug": {"level": "INFO"},
Expand Down
8 changes: 7 additions & 1 deletion src/eduid/webapp/common/session/namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

class SessionNSBase(BaseModel, ABC):
def to_dict(self) -> dict[str, Any]:
return self.dict()
return self.model_dump()

@classmethod
def from_dict(cls: type[TSessionNSSubclass], data: Mapping[str, Any]) -> TSessionNSSubclass:
Expand All @@ -51,6 +51,12 @@ def _from_dict_transform(cls: type[SessionNSBase], data: Mapping[str, Any]) -> d
_data = deepcopy(data) # do not modify callers data
return dict(_data)

def clear(self):
"""
Clears all session namespace data.
"""
self.__dict__ = self.model_construct(_cls=self.__class__, field_set={}).__dict__


TSessionNSSubclass = TypeVar("TSessionNSSubclass", bound=SessionNSBase)

Expand Down
20 changes: 20 additions & 0 deletions src/eduid/webapp/common/session/tests/test_namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,26 @@ def test_to_dict_from_dict_with_timestamp(self):
assert second.idp.sso_cookie_val == first.idp.sso_cookie_val
assert second.idp.ts == first.idp.ts

def test_clear_namespace(self):
_meta = SessionMeta.new(app_secret="secret")
base_session = self.app.session_interface.manager.get_session(meta=_meta, new=True)
first = EduidSession(app=self.app, meta=_meta, base_session=base_session, new=True)
first.signup.email.address = "[email protected]"
first.signup.email.verification_code = "123456"
first.persist()
# load session again and clear it
base_session = self.app.session_interface.manager.get_session(meta=_meta, new=False)
second = EduidSession(self.app, _meta, base_session, new=False)
assert second.signup.email.address == "[email protected]"
assert second.signup.email.verification_code == "123456"
second.signup.clear()
second.signup.email.address = "[email protected]"
second.persist()
# load session one more time and make sure verification_code is empty
base_session = self.app.session_interface.manager.get_session(meta=_meta, new=False)
third = EduidSession(self.app, _meta, base_session, new=False)
assert third.signup.email.address == "[email protected]"
assert third.signup.email.verification_code is None

class TestAuthnNamespace(EduidAPITestCase):
app: SessionTestApp
Expand Down
Loading

0 comments on commit f3c090e

Please sign in to comment.