-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c746310
commit 57ce38b
Showing
18 changed files
with
686 additions
and
229 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. | ||
# | ||
# This software is licensed under the Apache License, Version 2.0 (the | ||
# "License") as published by the Apache Software Foundation. | ||
# | ||
# You may not use this file except in compliance with the License. You may | ||
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
|
||
from .resync_session_and_fetch_mfa_info import handle_resync_session_and_fetch_mfa_info_api # type: ignore |
153 changes: 153 additions & 0 deletions
153
supertokens_python/recipe/multifactorauth/api/implementation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
# Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. | ||
# | ||
# This software is licensed under the Apache License, Version 2.0 (the | ||
# "License") as published by the Apache Software Foundation. | ||
# | ||
# You may not use this file except in compliance with the License. You may | ||
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING, Any, Dict, List, Union | ||
|
||
from supertokens_python.recipe.session import SessionContainer | ||
from supertokens_python.recipe.multifactorauth.utils import ( | ||
update_and_get_mfa_related_info_in_session, | ||
) | ||
from supertokens_python.recipe.multitenancy.asyncio import get_tenant | ||
from ..multi_factor_auth_claim import MultiFactorAuthClaim | ||
from supertokens_python.asyncio import get_user | ||
from supertokens_python.recipe.session.exceptions import ( | ||
InvalidClaimsError, | ||
SuperTokensSessionError, | ||
UnauthorisedError, | ||
) | ||
|
||
if TYPE_CHECKING: | ||
from supertokens_python.recipe.multifactorauth.interfaces import ( | ||
APIInterface, | ||
APIOptions, | ||
) | ||
|
||
from supertokens_python.types import GeneralErrorResponse | ||
from ..interfaces import ( | ||
APIInterface, | ||
APIOptions, | ||
NextFactors, | ||
ResyncSessionAndFetchMFAInfoPUTOkResult, | ||
) | ||
|
||
|
||
class APIImplementation(APIInterface): | ||
async def resync_session_and_fetch_mfa_info_put( | ||
self, | ||
api_options: APIOptions, | ||
session: SessionContainer, | ||
user_context: Dict[str, Any], | ||
) -> Union[ResyncSessionAndFetchMFAInfoPUTOkResult, GeneralErrorResponse]: | ||
session_user = await get_user(session.get_user_id(), user_context) | ||
|
||
if session_user is None: | ||
raise UnauthorisedError( | ||
"Session user not found", | ||
) | ||
|
||
mfa_info = await update_and_get_mfa_related_info_in_session( | ||
input_session=session, | ||
user_context=user_context, | ||
) | ||
factors_setup_for_user = ( | ||
await api_options.recipe_implementation.get_factors_setup_for_user( | ||
user=session_user, | ||
user_context=user_context, | ||
) | ||
) | ||
tenant_info = await get_tenant( | ||
session.get_tenant_id(user_context), user_context | ||
) | ||
if tenant_info is None: | ||
raise UnauthorisedError( | ||
"Tenant not found", | ||
) | ||
all_available_secondary_factors = ( | ||
await api_options.recipe_instance.get_all_available_secondary_factor_ids( | ||
tenant_info | ||
) | ||
) | ||
|
||
factors_allowed_to_setup: List[str] = [] | ||
|
||
async def get_factors_set_up_for_user(): | ||
return factors_setup_for_user | ||
|
||
async def get_mfa_requirements_for_auth(): | ||
return mfa_info.mfa_requirements_for_auth | ||
|
||
for factor_id in all_available_secondary_factors: | ||
try: | ||
await api_options.recipe_implementation.assert_allowed_to_setup_factor_else_throw_invalid_claim_error( | ||
session=session, | ||
factor_id=factor_id, | ||
factors_set_up_for_user=get_factors_set_up_for_user, | ||
mfa_requirements_for_auth=get_mfa_requirements_for_auth, | ||
user_context=user_context, | ||
) | ||
factors_allowed_to_setup.append(factor_id) | ||
except SuperTokensSessionError as err: | ||
if not isinstance(err, InvalidClaimsError): | ||
raise err | ||
|
||
next_set_of_unsatisfied_factors = ( | ||
MultiFactorAuthClaim.get_next_set_of_unsatisfied_factors( | ||
mfa_info.completed_factors, mfa_info.mfa_requirements_for_auth | ||
) | ||
) | ||
|
||
get_emails_for_factors_result = ( | ||
await api_options.recipe_instance.get_emails_for_factors( | ||
session_user, session.get_recipe_user_id(user_context) | ||
) | ||
) | ||
get_phone_numbers_for_factors_result = ( | ||
await api_options.recipe_instance.get_phone_numbers_for_factors( | ||
session_user, session.get_recipe_user_id(user_context) | ||
) | ||
) | ||
if ( | ||
get_emails_for_factors_result.status == "UNKNOWN_SESSION_RECIPE_USER_ID" | ||
or get_phone_numbers_for_factors_result.status | ||
== "UNKNOWN_SESSION_RECIPE_USER_ID" | ||
): | ||
raise UnauthorisedError( | ||
"User no longer associated with the session", | ||
) | ||
|
||
next_factors = [ | ||
factor_id | ||
for factor_id in next_set_of_unsatisfied_factors.factor_ids | ||
if factor_id in factors_allowed_to_setup | ||
or factor_id in factors_setup_for_user | ||
] | ||
|
||
if ( | ||
len(next_factors) == 0 | ||
and len(next_set_of_unsatisfied_factors.factor_ids) != 0 | ||
): | ||
raise Exception( | ||
f"The user is required to complete secondary factors they are not allowed to " | ||
f"({', '.join(next_set_of_unsatisfied_factors.factor_ids)}), likely because of configuration issues." | ||
) | ||
return ResyncSessionAndFetchMFAInfoPUTOkResult( | ||
factors=NextFactors( | ||
next=next_factors, | ||
already_setup=factors_setup_for_user, | ||
allowed_to_setup=factors_allowed_to_setup, | ||
), | ||
emails=get_emails_for_factors_result.factor_id_to_emails_map, | ||
phone_numbers=get_phone_numbers_for_factors_result.factor_id_to_phone_number_map, | ||
) |
52 changes: 52 additions & 0 deletions
52
supertokens_python/recipe/multifactorauth/api/resync_session_and_fetch_mfa_info.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. | ||
# | ||
# This software is licensed under the Apache License, Version 2.0 (the | ||
# "License") as published by the Apache Software Foundation. | ||
# | ||
# You may not use this file except in compliance with the License. You may | ||
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING, Any, Dict | ||
|
||
if TYPE_CHECKING: | ||
from ..interfaces import ( | ||
APIOptions, | ||
APIInterface, | ||
) | ||
|
||
from supertokens_python.utils import send_200_response | ||
|
||
from supertokens_python.recipe.session.asyncio import get_session | ||
|
||
|
||
async def handle_resync_session_and_fetch_mfa_info_api( | ||
tenant_id: str, | ||
api_implementation: APIInterface, | ||
api_options: APIOptions, | ||
user_context: Dict[str, Any], | ||
): | ||
if api_implementation.disable_resync_session_and_fetch_mfa_info_put is True: | ||
return None | ||
|
||
session = await get_session( | ||
api_options.request, | ||
override_global_claim_validators=lambda _, __, ___: [], | ||
user_context=user_context, | ||
) | ||
|
||
assert session is not None | ||
|
||
response = await api_implementation.resync_session_and_fetch_mfa_info_put( | ||
api_options, | ||
session, | ||
user_context, | ||
) | ||
|
||
return send_200_response(response.to_json(), api_options.response) |
Oops, something went wrong.