diff --git a/ruff.toml b/ruff.toml index 62e6457b0..3b563fd09 100644 --- a/ruff.toml +++ b/ruff.toml @@ -3,6 +3,6 @@ line-length = 120 target-version = "py310" [lint] -select = ["E", "F", "W", "I", "ASYNC", "UP", "FLY", "PERF", "FURB"] +select = ["E", "F", "W", "I", "ASYNC", "UP", "FLY", "PERF", "FURB", "ERA"] ignore = ["E501"] diff --git a/src/eduid/queue/db/change_event.py b/src/eduid/queue/db/change_event.py index bc4894c15..3952e76f0 100644 --- a/src/eduid/queue/db/change_event.py +++ b/src/eduid/queue/db/change_event.py @@ -55,7 +55,7 @@ class ChangeEvent: full_document: dict[str, Any] | None = None to: NS | None = None update_description: UpdateDescription | None = None - # Available in MongoDB >=4 + # Available in MongoDB >=4 # noqa: ERA001 # clusterTime # txnNumber # lsid diff --git a/src/eduid/satosa/entity_category/auth_server.py b/src/eduid/satosa/entity_category/auth_server.py index e9327729a..604e23679 100644 --- a/src/eduid/satosa/entity_category/auth_server.py +++ b/src/eduid/satosa/entity_category/auth_server.py @@ -23,6 +23,7 @@ SUNETAUTHSERVERv1: True, } +# ruff: noqa: ERA001 # These restrictions are parsed (and validated) into a list of saml2.assertion.EntityCategoryRule instances. RESTRICTIONS: list[dict[str, Any]] = [ # Example of conversion of some of the rules in RELEASE to this new format: diff --git a/src/eduid/scimapi/middleware.py b/src/eduid/scimapi/middleware.py index 121bf4c91..b87277abf 100644 --- a/src/eduid/scimapi/middleware.py +++ b/src/eduid/scimapi/middleware.py @@ -55,33 +55,9 @@ class ScimMiddleware(BaseMiddleware): async def dispatch(self, req: Request, call_next) -> Response: req = self.make_context_request(request=req, context_class=ScimApiContext) self.context.logger.debug(f"process_request: {req.method} {req.url.path}") - # TODO: fix me? is this needed? - # if req.method == 'POST': - # if req.path == '/login': - # if req.content_type != 'application/json': - # raise UnsupportedMediaTypeMalformed( - # detail=f'{req.content_type} is an unsupported media type for {req.path}' - # ) - # elif req.path == '/notifications': - # if req.content_type == 'text/plain; charset=UTF-8': - # # We know the body is json, set the correct content type - # req.content_type = 'application/json' - # elif req.content_type != 'application/scim+json': - # raise UnsupportedMediaTypeMalformed(detail=f'{req.content_type} is an unsupported media type') resp = await call_next(req) self.context.logger.debug(f"process_response: {req.method} {req.url.path}") - # Default to 'application/json' if responding with an error message - # if req_succeeded and resp.body: - # # candidates should be sorted by increasing desirability - # # preferred = request.client_prefers(('application/json', 'application/scim+json')) - # - # preferred = None - # self.context.logger.debug(f'Client prefers content-type {preferred}') - # if preferred is None: - # preferred = 'application/scim+json' - # self.context.logger.debug(f'Default content-type {preferred} used') - # resp.headers.content_type = preferred return resp diff --git a/src/eduid/scimapi/routers/invites.py b/src/eduid/scimapi/routers/invites.py index df2a7032d..9f375a8cb 100644 --- a/src/eduid/scimapi/routers/invites.py +++ b/src/eduid/scimapi/routers/invites.py @@ -72,83 +72,13 @@ async def on_put( raise BadRequest(detail="Invite completed and cannot be updated") invite_changed = False - profiles_changed = False if update_request.nutid_invite_v1.completed is not None: signup_invite = replace(signup_invite, completed_ts=update_request.nutid_invite_v1.completed) db_invite = replace(db_invite, completed=update_request.nutid_invite_v1.completed) invite_changed = True - # TODO: decide what can be updated - # # Update the invite - # invite_changed = False - # if SCIMSchema.NUTID_INVITE_V1 in update_request.schemas: - # name_in = ScimApiName(**update_request.nutid_invite_v1.name.dict(exclude_none=True)) - # emails_in = set(ScimApiEmail(**email.dict()) for email in update_request.nutid_invite_v1.emails) - # phone_numbers_in = set( - # ScimApiPhoneNumber(**number.dict()) for number in update_request.nutid_invite_v1.phone_numbers - # ) - # # external_id - # if update_request.external_id != db_invite.external_id: - # db_invite = replace(db_invite, external_id=update_request.external_id) - # invite_changed = True - # # preferred_language - # if update_request.nutid_invite_v1.preferred_language != db_invite.preferred_language: - # db_invite = replace(db_invite, preferred_language=update_request.nutid_invite_v1.preferred_language) - # invite_changed = True - # # name - # if name_in != db_invite.name: - # db_invite = replace(db_invite, name=name_in) - # invite_changed = True - # # emails - # if emails_in != set(db_invite.emails): - # db_invite = replace(db_invite, emails=list(emails_in)) - # invite_changed = True - # # phone_numbers - # if phone_numbers_in != set(db_invite.phone_numbers): - # db_invite = replace(db_invite, phone_numbers=list(phone_numbers_in)) - # invite_changed = True - # # nin - # if update_request.nutid_invite_v1.national_identity_number != db_invite.national_identity_number: - # db_invite = replace( - # db_invite, national_identity_number=update_request.nutid_invite_v1.national_identity_number - # ) - # invite_changed = True - # # finish_url - # if update_request.nutid_invite_v1.finish_url != db_invite.finish_url: - # db_invite = replace(db_invite, finish_url=update_request.nutid_invite_v1.finish_url) - # invite_changed = True - # # completed_ts - # if update_request.nutid_invite_v1.completed != db_invite.completed_ts: - # db_invite = replace(db_invite, completed_ts=update_request.nutid_invite_v1.completed) - # invite_changed = True - # - # profiles_changed = False - # if SCIMSchema.NUTID_USER_V1 in update_request.schemas and update_request.nutid_user_v1 is not None: - # - # # Look for changes in profiles - # for this in update_request.nutid_user_v1.profiles.keys(): - # if this not in db_invite.profiles: - # req.app.context.logger.info( - # f"Adding profile {this}/{update_request.nutid_user_v1.profiles[this]} to invite" - # ) - # profiles_changed = True - # elif update_request.nutid_user_v1.profiles[this].to_dict() != db_invite.profiles[this].to_dict(): - # req.app.context.logger.info(f"Profile {this}/{update_request.nutid_user_v1.profiles[this]} updated") - # profiles_changed = True - # else: - # req.app.context.logger.info(f"Profile {this}/{update_request.nutid_user_v1.profiles[this]} not changed") # noqa: E501 - # for this in db_invite.profiles.keys(): - # if this not in update_request.nutid_user_v1.profiles: - # req.app.context.logger.info(f"Profile {this}/{db_invite.profiles[this]} removed") - # profiles_changed = True - # - # if profiles_changed: - # for profile_name, profile in update_request.nutid_user_v1.profiles.items(): - # db_profile = ScimApiProfile(attributes=profile.attributes, data=profile.data) - # db_invite.profiles[profile_name] = db_profile - - if invite_changed or profiles_changed: + if invite_changed: save_invite( req=req, db_invite=db_invite, diff --git a/src/eduid/scimapi/routers/utils/groups.py b/src/eduid/scimapi/routers/utils/groups.py index b92709791..31a428ae4 100644 --- a/src/eduid/scimapi/routers/utils/groups.py +++ b/src/eduid/scimapi/routers/utils/groups.py @@ -53,10 +53,6 @@ def db_group_to_response(req: ContextRequest, resp: Response, db_group: ScimApiG resp.headers["Location"] = location resp.headers["ETag"] = make_etag(db_group.version) - # TODO: Needed? - # if SCIMSchema.NUTID_GROUP_V1 not in group.schemas and SCIMSchema.NUTID_GROUP_V1.value in dumped_group: - # # Serialization will always put the NUTID_GROUP_V1 in the dumped_group, even if there was no data - # del dumped_group[SCIMSchema.NUTID_GROUP_V1.value] req.app.context.logger.debug(f"Extra debug: Response:\n{group.model_dump_json(exclude_none=True, indent=2)}") return group diff --git a/src/eduid/scimapi/routers/utils/status.py b/src/eduid/scimapi/routers/utils/status.py index 64fbe2e0b..804026152 100644 --- a/src/eduid/scimapi/routers/utils/status.py +++ b/src/eduid/scimapi/routers/utils/status.py @@ -21,8 +21,7 @@ def check_mongo(req: ContextRequest, default_data_owner: str): def check_neo4j(req: ContextRequest, default_data_owner: str): group_db = req.app.context.get_groupdb(default_data_owner) try: - # TODO: Implement is_healthy - # db.is_healthy() + # TODO: Implement is_healthy, check if there is a better way for neo4j q = """ MATCH (n) RETURN count(*) as exists LIMIT 1 diff --git a/src/eduid/scimapi/testing.py b/src/eduid/scimapi/testing.py index 84d7ced98..2b2e11212 100644 --- a/src/eduid/scimapi/testing.py +++ b/src/eduid/scimapi/testing.py @@ -51,7 +51,6 @@ def _get_config(self) -> dict[str, Any]: "data_owners": {"eduid.se": {"db_name": "eduid_se"}}, "logging_config": { "loggers": { - #'eduid_groupdb': {'handlers': ['console'], 'level': 'DEBUG'}, "neo4j": {"handlers": ["console"], "level": "WARNING"}, "root": {"handlers": ["console"], "level": "DEBUG"}, }, diff --git a/src/eduid/scimapi/tests/test_notifications.py b/src/eduid/scimapi/tests/test_notifications.py index efda46237..fadf9d5e5 100644 --- a/src/eduid/scimapi/tests/test_notifications.py +++ b/src/eduid/scimapi/tests/test_notifications.py @@ -7,9 +7,6 @@ from eduid.scimapi.testing import ScimApiTestCase from eduid.userdb.scimapi import EventLevel -# from moto import mock_sns - - __author__ = "lundberg" diff --git a/src/eduid/scimapi/tests/test_sciminvite.py b/src/eduid/scimapi/tests/test_sciminvite.py index ae1e1ad05..d049e7d41 100644 --- a/src/eduid/scimapi/tests/test_sciminvite.py +++ b/src/eduid/scimapi/tests/test_sciminvite.py @@ -341,14 +341,6 @@ def _perform_search( resources = response.json().get("Resources") return resources - # def test_get_invites(self): - # for i in range(9): - # self.add_user(identifier=str(uuid4()), external_id=f'test-id-{i}', profiles={'test': self.test_profile}) - # parsed_response = self.client.get(url=f'/Users', headers=self.headers) - # self.assertEqual([SCIMSchema.API_MESSAGES_20_LIST_RESPONSE.value], parsed_response.json().get('schemas')) - # resources = parsed_response.json().get('Resources') - # self.assertEqual(self.userdb.db_count(), len(resources)) - def test_create_invite(self): req = { "schemas": [ diff --git a/src/eduid/scimapi/tests/test_scimuser.py b/src/eduid/scimapi/tests/test_scimuser.py index dc275d718..aad4f48c2 100644 --- a/src/eduid/scimapi/tests/test_scimuser.py +++ b/src/eduid/scimapi/tests/test_scimuser.py @@ -787,7 +787,6 @@ def _perform_search( class TestAsyncUserResource(IsolatedAsyncioTestCase, ScimApiTestCase): def setUp(self) -> None: super().setUp() - # ScimApiTestCase.setUp(self) self.async_client = AsyncClient(app=self.api, base_url="http://testserver") # create users self.user_count = 10 diff --git a/src/eduid/userdb/db/async_db.py b/src/eduid/userdb/db/async_db.py index 1412a69c4..2247d04a3 100644 --- a/src/eduid/userdb/db/async_db.py +++ b/src/eduid/userdb/db/async_db.py @@ -277,7 +277,7 @@ async def setup_indexes(self, indexes: Mapping[str, Any]) -> None: """ To update an index add a new item in indexes and remove the previous version. """ - # indexes={'index-name': {'key': [('key', 1)], 'param1': True, 'param2': False}, } + # indexes={'index-name': {'key': [('key', 1)], 'param1': True, 'param2': False}, } # noqa: ERA001 # http://docs.mongodb.org/manual/reference/method/db.collection.ensureIndex/ default_indexes = ["_id_"] # _id_ index can not be deleted from a mongo collection current_indexes = await self._coll.index_information() diff --git a/src/eduid/userdb/db/sync_db.py b/src/eduid/userdb/db/sync_db.py index 6393a9026..a34dfe9c9 100644 --- a/src/eduid/userdb/db/sync_db.py +++ b/src/eduid/userdb/db/sync_db.py @@ -302,7 +302,7 @@ def setup_indexes(self, indexes: Mapping[str, Any]) -> None: """ To update an index add a new item in indexes and remove the previous version. """ - # indexes={'index-name': {'key': [('key', 1)], 'param1': True, 'param2': False}, } + # indexes={'index-name': {'key': [('key', 1)], 'param1': True, 'param2': False}, } # noqa: ERA001 # http://docs.mongodb.org/manual/reference/method/db.collection.ensureIndex/ default_indexes = ["_id_"] # _id_ index can not be deleted from a mongo collection current_indexes = self._coll.index_information() diff --git a/src/eduid/userdb/orcid.py b/src/eduid/userdb/orcid.py index d74dba3ed..6caae3784 100644 --- a/src/eduid/userdb/orcid.py +++ b/src/eduid/userdb/orcid.py @@ -16,7 +16,7 @@ class OidcIdToken(Element): iss: str # Subject identifier sub: str - # Audience(s) + # Audience(s) # noqa: ERA001 aud: list[str] # Expiration time exp: int diff --git a/src/eduid/userdb/security/__init__.py b/src/eduid/userdb/security/__init__.py index cf581e014..7d1711f89 100644 --- a/src/eduid/userdb/security/__init__.py +++ b/src/eduid/userdb/security/__init__.py @@ -1,12 +1,7 @@ -from eduid.userdb.security.db import PasswordResetStateDB, SecurityUserDB -from eduid.userdb.security.state import PasswordResetEmailAndPhoneState, PasswordResetEmailState, PasswordResetState +from eduid.userdb.security.db import SecurityUserDB from eduid.userdb.security.user import SecurityUser __all__ = [ - "PasswordResetState", - "PasswordResetEmailState", - "PasswordResetEmailAndPhoneState", - "PasswordResetStateDB", "SecurityUser", "SecurityUserDB", ] diff --git a/src/eduid/userdb/security/db.py b/src/eduid/userdb/security/db.py index e05488a93..54e27ffe4 100644 --- a/src/eduid/userdb/security/db.py +++ b/src/eduid/userdb/security/db.py @@ -1,12 +1,6 @@ -import copy import logging -from collections.abc import Mapping -from typing import Any -from eduid.common.decorators import deprecated -from eduid.userdb.db import BaseDB, SaveResult, TUserDbDocument -from eduid.userdb.exceptions import MultipleDocumentsReturned -from eduid.userdb.security.state import PasswordResetEmailAndPhoneState, PasswordResetEmailState, PasswordResetState +from eduid.userdb.db import TUserDbDocument from eduid.userdb.security.user import SecurityUser from eduid.userdb.userdb import UserDB @@ -22,89 +16,3 @@ def __init__(self, db_uri: str, db_name: str = "eduid_security", collection: str @classmethod def user_from_dict(cls, data: TUserDbDocument) -> SecurityUser: return SecurityUser.from_dict(data) - - -# @deprecated("Remove once the password reset views are served from their own webapp") -class PasswordResetStateDB(BaseDB): - @deprecated("Remove once the password reset views are served from their own webapp") - def __init__(self, db_uri, db_name="eduid_security", collection="password_reset_data"): - super().__init__(db_uri, db_name, collection=collection) - - def get_state_by_email_code(self, email_code: str) -> PasswordResetState | None: - """ - Locate a state in the db given the state's email code. - - :param email_code: Code sent to the user - - :return: state, if found - - :raise self.MultipleDocumentsReturned: More than one document matches the search criteria - """ - spec = {"email_code.code": email_code} - states = list(self._get_documents_by_filter(spec)) - - if len(states) == 0: - return None - - if len(states) > 1: - raise MultipleDocumentsReturned(f"Multiple matching users for filter {filter!r}") - - return self.init_state(states[0]) - - def get_state_by_eppn(self, eppn: str) -> PasswordResetState | None: - """ - Locate a state in the db given the users eppn. - - :param eppn: Users unique eppn - - :return: state, if found - - :raise self.MultipleDocumentsReturned: More than one document matches the search criteria - """ - state = self._get_document_by_attr("eduPersonPrincipalName", eppn) - if state: - return self.init_state(state) - return None - - @staticmethod - def init_state( - data: Mapping[str, Any], - ) -> PasswordResetEmailState | PasswordResetEmailAndPhoneState | None: - _data = dict(copy.deepcopy(data)) # to not modify callers data - method = _data.pop("method", None) - if method == "email": - return PasswordResetEmailState.from_dict(_data) - if method == "email_and_phone": - return PasswordResetEmailAndPhoneState.from_dict(_data) - return None - - def save(self, state: PasswordResetState, is_in_database: bool) -> SaveResult: - """ - Save state to the database. - - :param state: The state to save - :param is_in_database: True if the state is already in the database. TODO: Remove when state have Meta. - """ - - data = state.to_dict() - # Remember what type of state this is, used when loading state above in init_state() - if isinstance(state, PasswordResetEmailAndPhoneState): - data["method"] = "email_and_phone" - elif isinstance(state, PasswordResetEmailState): - data["method"] = "email" - - if state.modified_ts is None: - # Remove old reset password state - old_state = self.get_state_by_eppn(state.eppn) - if old_state: - self.remove_state(old_state) - - spec: dict[str, Any] = {"eduPersonPrincipalName": state.eppn} - - result = self._save(state.to_dict(), spec, is_in_database=is_in_database) - state.modified_ts = result.ts - - return result - - def remove_state(self, state: PasswordResetState) -> None: - self.remove_document({"eduPersonPrincipalName": state.eppn}) diff --git a/src/eduid/userdb/security/state.py b/src/eduid/userdb/security/state.py deleted file mode 100644 index b2f1cc600..000000000 --- a/src/eduid/userdb/security/state.py +++ /dev/null @@ -1,90 +0,0 @@ -from __future__ import annotations - -import copy -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar - -import bson -from pydantic import BaseModel, ConfigDict, Field - -from eduid.userdb.db import TUserDbDocument -from eduid.userdb.security.element import CodeElement - -__author__ = "lundberg" - -from eduid.userdb.util import utc_now - -TPasswordResetStateSubclass = TypeVar("TPasswordResetStateSubclass", bound="PasswordResetState") - - -class PasswordResetState(BaseModel): - eppn: str = Field(alias="eduPersonPrincipalName") - state_id: bson.ObjectId = Field(default_factory=lambda: bson.ObjectId(), alias="_id") - created_ts: datetime.datetime = Field(default_factory=lambda: utc_now()) - modified_ts: datetime.datetime | None = None - extra_security: dict[str, Any] | None = None - generated_password: str | None = None - model_config = ConfigDict( - populate_by_name=True, validate_assignment=True, extra="forbid", arbitrary_types_allowed=True - ) - - # @deprecated("Remove once the password reset views are served from their own webapp") - # def __post_init__(self): - # self.reference = str(self.id) - - def __str__(self): - return f"" - - @property - def reference(self) -> str: - return str(self.state_id) - - def to_dict(self) -> TUserDbDocument: - """Convert state to a dict in eduid format, that can be used to reconstruct the state later.""" - data = self.dict(exclude_none=True) - data = self._to_dict_transform(data) - return TUserDbDocument(data) - - @classmethod - def from_dict(cls: type[TPasswordResetStateSubclass], data: Mapping[str, Any]) -> TPasswordResetStateSubclass: - _data = dict(copy.deepcopy(data)) # to not modify callers data - _data = cls._from_dict_transform(_data) - return cls(**_data) - - @classmethod - def _from_dict_transform(cls: type[TPasswordResetStateSubclass], data: dict[str, Any]) -> dict[str, Any]: - """ - Transform data received in eduid format into pythonic format. - """ - if "reference" in data: - data.pop("reference") - return data - - @classmethod - def _to_dict_transform(cls, data: dict[str, Any]) -> dict[str, Any]: - """ - Transform data kept in pythonic format into eduid format. - """ - data["eduPersonPrincipalName"] = data.pop("eppn") - data["_id"] = data.pop("state_id") - return data - - -class PasswordResetEmailState(PasswordResetState): - email_address: str - email_code: CodeElement - - -class PasswordResetEmailAndPhoneState(PasswordResetEmailState): - phone_number: str - phone_code: CodeElement - - @classmethod - def from_email_state( - cls, email_state: PasswordResetEmailState, phone_number: str, phone_code: str, application="security" - ) -> PasswordResetEmailAndPhoneState: - data = email_state.to_dict() - data["phone_number"] = phone_number - data["phone_code"] = CodeElement(created_by=application, code=phone_code) - return cls.from_dict(data=data) diff --git a/src/eduid/userdb/tests/test_credentials.py b/src/eduid/userdb/tests/test_credentials.py index 471b5d74f..35c01d8b2 100644 --- a/src/eduid/userdb/tests/test_credentials.py +++ b/src/eduid/userdb/tests/test_credentials.py @@ -15,11 +15,11 @@ __author__ = "lundberg" # {'passwords': { -# 'id': password_id, -# 'salt': salt, -# 'source': 'signup', -# 'created_ts': datetime.datetime.utcnow(), -# }} +# 'id': password_id, # noqa: ERA001 +# 'salt': salt, # noqa: ERA001 +# 'source': 'signup', # noqa: ERA001 +# 'created_ts': datetime.datetime.utcnow(), # noqa: ERA001 +# }} # noqa: ERA001 from eduid.userdb.credentials.password import Password _one_dict = { diff --git a/src/eduid/userdb/tests/test_u2f.py b/src/eduid/userdb/tests/test_u2f.py index db9108803..084698888 100644 --- a/src/eduid/userdb/tests/test_u2f.py +++ b/src/eduid/userdb/tests/test_u2f.py @@ -12,11 +12,11 @@ __author__ = "lundberg" # {'passwords': { -# 'id': password_id, -# 'salt': salt, -# 'source': 'signup', -# 'created_ts': datetime.datetime.utcnow(), -# }} +# 'id': password_id, # noqa: ERA001 +# 'salt': salt, # noqa: ERA001 +# 'source': 'signup', # noqa: ERA001 +# 'created_ts': datetime.datetime.utcnow(), # noqa: ERA001 +# }} # noqa: ERA001 _one_dict = { "version": "U2F_V2", diff --git a/src/eduid/userdb/util.py b/src/eduid/userdb/util.py index 4e3d5db95..df29d27bf 100644 --- a/src/eduid/userdb/util.py +++ b/src/eduid/userdb/util.py @@ -50,9 +50,8 @@ def format_dict_for_debug(data: Mapping[str, Any] | None) -> str | None: return json.dumps(data, indent=4, cls=EduidJSONEncoder) except Exception as e: - # Don't need the full exception logged here, just the summary (e.g. + # Don't need the full exception logged here, just the summary, e.g.: # TypeError: Object of type UUID is not JSON serializable - # ) # TODO: upgrade this debug to error once we've ridded userdb of all UUIDs logger.debug(f"Failed formatting document for debugging using JSON encoder: {repr(e)}") # We fail on encoding UUIDs used in some places. We want to turn the UUIDs into strings. diff --git a/src/eduid/vccs/server/log.py b/src/eduid/vccs/server/log.py index d2f8b79bf..6babb08df 100644 --- a/src/eduid/vccs/server/log.py +++ b/src/eduid/vccs/server/log.py @@ -22,26 +22,6 @@ def emit(self, record): def init_logging(): - # from eduid_common.api.logging import LocalContext, make_dictConfig - # local_context = LocalContext( - # app_debug=True, - # app_name='VCCS2', - # format='{asctime} | {levelname:7} | {name:35} | {message}', - # level='DEBUG', - # relative_time=True, - # ) - # logging_config = make_dictConfig(local_context) - # logging.config.dictConfig(logging_config) - - # logging.getLogger("uvicorn.access").handlers = [InterceptHandler()] - - # or _log in ['uvicorn', 'uvicorn.access', 'uvicorn.error', 'fastapi']: - # for _log in ['uvicorn.access']: - # _logger = logging.getLogger(_log) - # _logger.handlers = [InterceptHandler()] - # if '.' in _log: - # _logger.propagate = False - loguru_logger.remove() fmt = ( "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <7} | {module: <11}:" @@ -50,7 +30,6 @@ def init_logging(): loguru_logger.add(sys.stderr, format=fmt, level="DEBUG") loguru_logger.debug("Logging initialized") return loguru_logger - # return logging.getLogger('VCCS2') def audit_log(msg: str) -> None: diff --git a/src/eduid/webapp/authn/tests/saml2_settings.py b/src/eduid/webapp/authn/tests/saml2_settings.py index 337446124..176a09dba 100644 --- a/src/eduid/webapp/authn/tests/saml2_settings.py +++ b/src/eduid/webapp/authn/tests/saml2_settings.py @@ -34,12 +34,6 @@ }, # Do not check for signature during tests "want_response_signed": False, - # # This is commented to be compatible with simplesamlphp - # # attributes that this project need to identify a user - # 'required_attributes': ['uid'], - # - # # attributes that may be useful to have but not required - # 'optional_attributes': ['eduPersonAffiliation'], # in this section the list of IdPs we talk to are defined "idp": { # we do not need a WAYF service since there is diff --git a/src/eduid/webapp/authn/tests/test_authn.py b/src/eduid/webapp/authn/tests/test_authn.py index 4aa4bcec6..7aa6a2ad4 100644 --- a/src/eduid/webapp/authn/tests/test_authn.py +++ b/src/eduid/webapp/authn/tests/test_authn.py @@ -64,7 +64,6 @@ def update_config(self, config: dict[str, Any]) -> dict[str, Any]: saml_config = os.path.join(HERE, "saml2_settings.py") config.update( { - # "safe_relay_domain": "test.localhost", "saml2_login_redirect_url": "/", "saml2_logout_redirect_url": "/logged-out", "saml2_settings_module": saml_config, diff --git a/src/eduid/webapp/bankid/proofing.py b/src/eduid/webapp/bankid/proofing.py index 6abbdb581..5a449c86e 100644 --- a/src/eduid/webapp/bankid/proofing.py +++ b/src/eduid/webapp/bankid/proofing.py @@ -66,10 +66,6 @@ def verify_identity(self, user: User) -> VerifyUserResult: def identity_proofing_element(self, user: User) -> ProofingElementResult: if self.backdoor: proofing_version = "1999v1" - # TODO: Used to use these values when backdoor was in use, but is that really wise? - # issuer = 'https://idp.example.com/simplesaml/saml2/idp/metadata.php' - # authn_context = 'http://id.elegnamnden.se/loa/1.0/loa3' - # else: proofing_version = self.config.bankid_proofing_version diff --git a/src/eduid/webapp/bankid/tests/saml2_settings.py b/src/eduid/webapp/bankid/tests/saml2_settings.py index fd5d6ac23..9d471590f 100644 --- a/src/eduid/webapp/bankid/tests/saml2_settings.py +++ b/src/eduid/webapp/bankid/tests/saml2_settings.py @@ -35,12 +35,6 @@ }, # Do not check for signature during tests "want_response_signed": False, - # # This is commented to be compatible with simplesamlphp - # # attributes that this project need to identify a user - # 'required_attributes': ['uid'], - # - # # attributes that may be useful to have but not required - # 'optional_attributes': ['eduPersonAffiliation'], # in this section the list of IdPs we talk to are defined "idp": { # we do not need a WAYF service since there is diff --git a/src/eduid/webapp/bankid/views.py b/src/eduid/webapp/bankid/views.py index dbdc98a36..6b629b221 100644 --- a/src/eduid/webapp/bankid/views.py +++ b/src/eduid/webapp/bankid/views.py @@ -186,15 +186,6 @@ def _authn( assert isinstance(proofing_method, ProofingMethodSAML) # please mypy idp = proofing_method.idp - # TODO: We don't have any IdP that works for our automated tests - # if check_magic_cookie(current_app.conf): - # # set a test IdP with minimal interaction for the integration tests - # if current_app.conf.magic_cookie_idp: - # idp = current_app.conf.magic_cookie_idp - # current_app.logger.debug(f"Changed requested IdP due to magic cookie: {idp}") - # else: - # current_app.logger.error(f"Magic cookie is not supported for method {method}") - # return AuthnResult(error=BankIDMsg.method_not_available) authn_req = SP_AuthnRequest( frontend_action=_frontend_action, diff --git a/src/eduid/webapp/common/api/testing.py b/src/eduid/webapp/common/api/testing.py index 26d93916e..4718662e3 100644 --- a/src/eduid/webapp/common/api/testing.py +++ b/src/eduid/webapp/common/api/testing.py @@ -164,7 +164,6 @@ def tearDown(self): except Exception as exc: sys.stderr.write(f"Exception in tearDown: {exc!s}\n{exc!r}\n") traceback.print_exc() - # time.sleep(5) super(CommonTestCase, self).tearDown() # XXX reset redis @@ -313,9 +312,6 @@ def request_user_sync(self, private_user: User, app_name_override: str | None = user.meta.version = central_user.meta.version user.meta.is_in_database = True - # Make the new version in AM match the one in the private userdb - # user.meta.new_version = lambda: private_user.new_version - self.app.central_userdb.save(user) return True diff --git a/src/eduid/webapp/common/api/tests/test_decorators.py b/src/eduid/webapp/common/api/tests/test_decorators.py index 7817d8ee9..cc9218896 100644 --- a/src/eduid/webapp/common/api/tests/test_decorators.py +++ b/src/eduid/webapp/common/api/tests/test_decorators.py @@ -37,10 +37,6 @@ def flask_view(ret: FluxData) -> FluxData: class MarshalDecoratorTests(EduidAPITestCase): - # def setUp(self) -> None: - # self.app = EduIDBaseApp(__name__) - # self.app.register_blueprint(test_views) - app: DecoratorTestApp def load_app(self, config: Mapping[str, Any]) -> DecoratorTestApp: diff --git a/src/eduid/webapp/common/api/tests/test_nin_helpers.py b/src/eduid/webapp/common/api/tests/test_nin_helpers.py index 66c542cf5..f88eab1c3 100644 --- a/src/eduid/webapp/common/api/tests/test_nin_helpers.py +++ b/src/eduid/webapp/common/api/tests/test_nin_helpers.py @@ -56,7 +56,6 @@ def load_app(self, config: Mapping[str, Any]) -> HelpersTestApp: app for this test case. """ app = HelpersTestApp("testing", config) - # app.register_blueprint(test_views) return app diff --git a/src/eduid/webapp/common/authn/tests/test_fido_tokens.py b/src/eduid/webapp/common/authn/tests/test_fido_tokens.py index 4d89750e3..f002adfd3 100644 --- a/src/eduid/webapp/common/authn/tests/test_fido_tokens.py +++ b/src/eduid/webapp/common/authn/tests/test_fido_tokens.py @@ -61,12 +61,12 @@ def __init__(self, config: MockFidoConfig): SAMPLE_WEBAUTHN_REQUEST = { "credentialId": "i3KjBT0t5TPm693T9O0f4zyiwvdu9cY8BegCjiVvq_FS-ZmPcvXipFvHvD5CH6ZVRR3nsVsOla0Cad3fbtUA_Q", "authenticatorData": "3PcEcSYqagziJNECYxSBKMR01J4pmySHIPPDM-42YdMBAAAGNw", - # { - # "type":"webauthn.get", - # "challenge":"saoY-78kzDgV6mX5R2ixraC699jEU1cJTu7I9twUfJQ", - # "origin":"https://idp.eduid.docker", + # { # noqa: ERA001 + # "type":"webauthn.get", # noqa: ERA001 + # "challenge":"saoY-78kzDgV6mX5R2ixraC699jEU1cJTu7I9twUfJQ", # noqa: ERA001 + # "origin":"https://idp.eduid.docker", # noqa: ERA001 # "crossOrigin":false - # } + # } # noqa: ERA001 "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoic2FvWS03OGt6RGdWNm1YNVIyaXhyYUM2OTlqRVUxY0pU" "dTdJOXR3VWZKUSIsIm9yaWdpbiI6Imh0dHBzOi8vaWRwLmVkdWlkLmRvY2tlciIsImNyb3NzT3JpZ2luIjpmYWxzZX0", # This is a fake signature, we mock its verification below diff --git a/src/eduid/webapp/eidas/proofing.py b/src/eduid/webapp/eidas/proofing.py index f1dbcfd23..a9aa99ad1 100644 --- a/src/eduid/webapp/eidas/proofing.py +++ b/src/eduid/webapp/eidas/proofing.py @@ -166,10 +166,6 @@ def identity_proofing_element(self, user: User) -> ProofingElementResult: if self.backdoor: proofing_version = "1999v1" - # TODO: Used to use these values when backdoor was in use, but is that really wise? - # issuer = 'https://idp.example.com/simplesaml/saml2/idp/metadata.php' - # authn_context = 'http://id.elegnamnden.se/loa/1.0/loa3' - # issuer = "MAGIC COOKIE" authn_context = "MAGIC COOKIE" else: diff --git a/src/eduid/webapp/eidas/tests/saml2_settings.py b/src/eduid/webapp/eidas/tests/saml2_settings.py index fd5d6ac23..9d471590f 100644 --- a/src/eduid/webapp/eidas/tests/saml2_settings.py +++ b/src/eduid/webapp/eidas/tests/saml2_settings.py @@ -35,12 +35,6 @@ }, # Do not check for signature during tests "want_response_signed": False, - # # This is commented to be compatible with simplesamlphp - # # attributes that this project need to identify a user - # 'required_attributes': ['uid'], - # - # # attributes that may be useful to have but not required - # 'optional_attributes': ['eduPersonAffiliation'], # in this section the list of IdPs we talk to are defined "idp": { # we do not need a WAYF service since there is diff --git a/src/eduid/webapp/idp/app.py b/src/eduid/webapp/idp/app.py index b81e59214..53166f20c 100644 --- a/src/eduid/webapp/idp/app.py +++ b/src/eduid/webapp/idp/app.py @@ -27,8 +27,6 @@ def __init__(self, config: IdPConfig, **kwargs: Any) -> None: self.conf = config - # Init dbs - # self.private_userdb = IdPUserDB(self.conf.mongo_uri) # Initiate external modules self.babel = translation.init_babel(self) @@ -45,6 +43,7 @@ def __init__(self, config: IdPConfig, **kwargs: Any) -> None: self.authn_info_db = None + # Init dbs self.userdb = IdPUserDb(db_uri=config.mongo_uri) self.managed_account_db = ManagedAccountDB(config.mongo_uri) self.authn = idp_authn.IdPAuthn(config=config, userdb=self.userdb, managed_account_db=self.managed_account_db) diff --git a/src/eduid/webapp/idp/idp_saml.py b/src/eduid/webapp/idp/idp_saml.py index 194adfcb9..4d4f78644 100644 --- a/src/eduid/webapp/idp/idp_saml.py +++ b/src/eduid/webapp/idp/idp_saml.py @@ -352,10 +352,10 @@ def apply_binding(self, resp_args: ResponseArgs, relay_state: str, saml_response ) # _args is one of these pysaml2 dicts with HTML data, e.g.: # {'headers': [('Content-type', 'text/html')], - # 'data': '..., - # 'url': 'https://sp.example.edu/saml2/acs/', + # 'data': '..., # noqa: ERA001 + # 'url': 'https://sp.example.edu/saml2/acs/', # noqa: ERA001 # 'method': 'POST' - # } + # } # noqa: ERA001 return HttpArgs.from_pysaml2_dict(_args) diff --git a/src/eduid/webapp/idp/login.py b/src/eduid/webapp/idp/login.py index e3b09a754..482f68263 100644 --- a/src/eduid/webapp/idp/login.py +++ b/src/eduid/webapp/idp/login.py @@ -472,7 +472,7 @@ def _fticks_log(relying_party: str, authn_method: str, user_id: str) -> None: if not current_app.conf.fticks_secret_key: return # Default format string: - # 'F-TICKS/SWAMID/2.0#TS={ts}#RP={rp}#AP={ap}#PN={pn}#AM={am}#', + # 'F-TICKS/SWAMID/2.0#TS={ts}#RP={rp}#AP={ap}#PN={pn}#AM={am}#', # noqa: ERA001 _timestamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) _anon_userid = hmac.new( bytes(current_app.conf.fticks_secret_key, "ascii"), msg=bytes(user_id, "ascii"), digestmod=sha256 @@ -613,7 +613,6 @@ def get_ticket(info: SAMLQueryParams, binding: str | None) -> LoginContext | Non if info.request_ref not in session.idp.pending_requests: logger.debug(f"Ref {info.request_ref} not found in pending requests: {session.idp.pending_requests.keys()}") logger.debug(f"Extra debug, full pending requests: {session.idp.pending_requests}") - # raise RuntimeError(f'No pending request with ref {info.request_ref} found in session') return None pending = session.idp.pending_requests[info.request_ref] diff --git a/src/eduid/webapp/idp/tests/data/test_SSO_conf.py b/src/eduid/webapp/idp/tests/data/test_SSO_conf.py index 229fbf325..e18d7255e 100644 --- a/src/eduid/webapp/idp/tests/data/test_SSO_conf.py +++ b/src/eduid/webapp/idp/tests/data/test_SSO_conf.py @@ -20,7 +20,6 @@ key_path = os.path.join(here, "idp-public-snakeoil.key") cert_path = os.path.join(here, "idp-public-snakeoil.pem") -# attrmaps_path = os.path.join(here, '../../../attributemaps') idp_metadata_path = os.path.join(here, "idp_metadata.xml") swamid_sp_metadata_path = os.path.join(here, "swamid_sp_metadata.xml") coco_sp_metadata_path = os.path.join(here, "coco_sp_metadata.xml") @@ -89,7 +88,6 @@ }, "debug": True, "metadata": {"local": [swamid_sp_metadata_path, coco_sp_metadata_path, esi_coco_sp_metadata_path]}, - # "attribute_map_dir": attrmaps_path, "key_file": key_path, "cert_file": cert_path, "xmlsec_binary": xmlsec_path, diff --git a/src/eduid/webapp/idp/tests/test_SSO.py b/src/eduid/webapp/idp/tests/test_SSO.py index 206564c70..d09f66b1b 100644 --- a/src/eduid/webapp/idp/tests/test_SSO.py +++ b/src/eduid/webapp/idp/tests/test_SSO.py @@ -608,26 +608,6 @@ def test_get_login_refeds_mfa_fido_al2(self): assurance_profile=self.app.conf.swamid_assurance_profile_2, ) - def test_get_login_eduid_mfa_fido_swamid_al2(self): - """ - Test login with password and fido_swamid_al2 for verified user, request EDUID_MFA. - - Expect the response Authn to be EDUID_MFA, eduPersonAssurance AL1,Al2 - """ - user = self.get_user_set_nins(self.test_user.eppn, ["190101011234"]) - # user.credentials.add(_U2F_SWAMID_AL2) - out = self._get_login_response_authn( - user=user, - req_class_ref=EduidAuthnContextClass.EDUID_MFA, - credentials=["pw", "u2f"], - ) - self._check_login_response_authn( - authn_result=out, - message=IdPMsg.proceed, - accr=EduidAuthnContextClass.EDUID_MFA, - assurance_profile=self.app.conf.swamid_assurance_profile_2, - ) - def test_get_login_eduid_mfa_fido_swamid_al3(self): """ Test login with password and fido_swamid_al3 for verified user, request EDUID_MFA. diff --git a/src/eduid/webapp/letter_proofing/tests/test_app.py b/src/eduid/webapp/letter_proofing/tests/test_app.py index 5e53535c1..927d0daef 100644 --- a/src/eduid/webapp/letter_proofing/tests/test_app.py +++ b/src/eduid/webapp/letter_proofing/tests/test_app.py @@ -66,7 +66,7 @@ def load_app(self, config: dict[str, Any]) -> LetterProofingApp: def update_config(self, config: dict[str, Any]): config.update( { - # 'ekopost_debug_pdf': devnull, + # 'ekopost_debug_pdf': devnull, # set to file path if debugging # noqa: ERA001 "ekopost_api_uri": "http://localhost", "ekopost_api_user": "ekopost_user", "ekopost_api_pw": "secret", diff --git a/src/eduid/webapp/security/app.py b/src/eduid/webapp/security/app.py index 7379d8daf..df27d26ad 100644 --- a/src/eduid/webapp/security/app.py +++ b/src/eduid/webapp/security/app.py @@ -11,7 +11,7 @@ from eduid.userdb.authninfo import AuthnInfoDB from eduid.userdb.logs import ProofingLog from eduid.userdb.logs.db import FidoMetadataLog -from eduid.userdb.security import PasswordResetStateDB, SecurityUserDB +from eduid.userdb.security import SecurityUserDB from eduid.webapp.common.authn.middleware import AuthnBaseApp from eduid.webapp.security.settings.common import SecurityConfig @@ -29,7 +29,6 @@ def __init__(self, config: SecurityConfig, **kwargs): self.private_userdb = SecurityUserDB(config.mongo_uri) self.authninfo_db = AuthnInfoDB(config.mongo_uri) - self.password_reset_state_db = PasswordResetStateDB(config.mongo_uri) self.proofing_log = ProofingLog(config.mongo_uri) self.fido_metadata_log = FidoMetadataLog(config.mongo_uri) self.messagedb = MessageDB(config.mongo_uri) diff --git a/src/eduid/webapp/security/helpers.py b/src/eduid/webapp/security/helpers.py index 118c1dc49..468c1b024 100644 --- a/src/eduid/webapp/security/helpers.py +++ b/src/eduid/webapp/security/helpers.py @@ -278,7 +278,6 @@ def get_approved_security_keys() -> dict[str, Any]: user_verification_methods=user_verification_methods, key_protection=metadata_entry.metadata_statement.key_protection, description=metadata_entry.metadata_statement.description, - # icon=metadata_entry.metadata_statement.icon, ) parsed_entries.append(authenticator_info) diff --git a/src/eduid/webapp/security/views/security.py b/src/eduid/webapp/security/views/security.py index 950a659c7..5020d318d 100644 --- a/src/eduid/webapp/security/views/security.py +++ b/src/eduid/webapp/security/views/security.py @@ -84,12 +84,6 @@ def terminate_account(user: User): # revoke all user passwords revoke_all_credentials(security_user, vccs_url=current_app.conf.vccs_url) - # Skip removing old passwords from the user at this point as a password reset will do that anyway. - # This fixes the problem with loading users for a password reset as users without passwords triggers - # the UserHasNotCompletedSignup check in eduid-userdb. - # TODO: Needs a decision on how to handle unusable user passwords - # for p in security_user.credentials.filter(Password).to_list(): - # security_user.passwords.remove(p.key) # flag account as terminated security_user.terminated = utc_now() diff --git a/src/eduid/webapp/svipe_id/helpers.py b/src/eduid/webapp/svipe_id/helpers.py index daa2a1a05..f7ea2f600 100644 --- a/src/eduid/webapp/svipe_id/helpers.py +++ b/src/eduid/webapp/svipe_id/helpers.py @@ -70,7 +70,7 @@ class SvipeDocumentUserInfo(UserInfoBase): document_expiry_date: date = Field(alias="com.svipe:document_expiry_date") # Issuing Country: SWE document_issuing_country: str = Field(alias="com.svipe:document_issuing_country") - # Nationality: SWE + # Nationality: SWE # noqa: ERA001 document_nationality: str = Field(alias="com.svipe:document_nationality") document_number: str = Field(alias="com.svipe:document_number") # Document Type (standardized/english): Passport diff --git a/src/eduid/workers/msg/decorators.py b/src/eduid/workers/msg/decorators.py index 835ba5a24..0990dd7cb 100644 --- a/src/eduid/workers/msg/decorators.py +++ b/src/eduid/workers/msg/decorators.py @@ -41,8 +41,6 @@ def audit(*args, **kwargs): @classmethod def enable(cls, db_uri: str, db_name: str | None = None): - # if not isinstance(db_uri, str) or not db_uri: - # raise ValueError('Invalid db_uri passed to TransactionAudit') if isinstance(db_uri, str): cls.db_uri = db_uri if db_name is not None: diff --git a/src/eduid/workers/msg/tasks.py b/src/eduid/workers/msg/tasks.py index 53687e6b6..6e841e51b 100644 --- a/src/eduid/workers/msg/tasks.py +++ b/src/eduid/workers/msg/tasks.py @@ -491,11 +491,11 @@ def get_relations_to(self: MessageSender, identity_number: str, relative_nin: st result = [] # Entrys in relations['Relations']['Relation'] (a list) look like this: # - # { - # "RelationId" : { + # { # noqa: ERA001 + # "RelationId" : { # noqa: ERA001 # "NationalIdentityNumber" : "200001011234 # }, - # "RelationType" : "B", + # "RelationType" : "B", # noqa: ERA001 # "RelationStartDate" : "20000101" # }, #