Reference
shared.iam.abac ¶
access_policy ¶
AccessPolicy ¶
Bases: ABC
Define an Access Based Access Control (ABAC) policy
__init_subclass__ ¶
Source code in shared/iam/abac/access_policy.py
do_evaluate
classmethod
¶
Source code in shared/iam/abac/access_policy.py
enforce
classmethod
¶
evaluate
abstractmethod
classmethod
¶
AccessPolicyError ¶
Bases: IamException, Forbidden
PolicyEnforcedCallable ¶
enforce_policy ¶
Evaluate one or more policies and raise PermissionError if any of them fails
Source code in shared/iam/abac/access_policy.py
enforce_policy_before_request ¶
or_ ¶
Create a disjunction (OR) of multiple policies
Source code in shared/iam/abac/access_policy.py
backoffice ¶
BackofficePermissionAccessPolicy ¶
permitted_for
classmethod
¶
Source code in shared/iam/abac/backoffice.py
shared.iam.auth_context ¶
model ¶
AuthContext
dataclass
¶
AuthContext(
id=uuid.uuid4(),
_real_principal=None,
_effective_principal=None,
_delegate_principal=None,
session_id=None,
session_scopes=set(),
impersonation_mode=None,
cloudflare_zerotrust_identity=None,
cloudflare_ray_id=None,
cloudflare_ip_country=None,
)
Keeps track of all the authentication context i.e. who is logged in, on whose behalf, with which scope(s), etc. Parts of it are persisted in TransactionAuthContext for our audit trail.
NEVER EVER create an AuthContext on your own - only access it via current_auth_context
__post_init__ ¶
Source code in shared/iam/auth_context/model.py
cloudflare_ip_country
class-attribute
instance-attribute
¶
The 2-letter ISO country code from Cloudflare's geo IP (CF-IPCountry header)
cloudflare_ray_id
class-attribute
instance-attribute
¶
The Cloudflare Ray ID - unique identifier for the request
cloudflare_zerotrust_identity
class-attribute
instance-attribute
¶
The Cloudflare ZeroTrust user identity: https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/application-token/#user-identity ⧉
delegate_principal
property
¶
Get the (optional) principal who is performing the action on behalf of the real principal
delegate_principal_as ¶
Get the (optional) principal who is performing the action on behalf of the real principal, cast as a specific class This will raise an exception if the actual type is not the one expected
Source code in shared/iam/auth_context/model.py
effective_principal
property
¶
Get the principal who is the subject of the action, i.e. the actor or an impersonated user This will raise an exception if it's not set You need to call is_authenticated or is_anonymous to guard against this
effective_principal_as ¶
Get the principal who is the subject of the action, i.e. the actor or an impersonated user, cast as a specific class This will raise an exception if the principal is not set or if the actual type is not the one expected You need to call is_authenticated or is_anonymous to guard against this
Source code in shared/iam/auth_context/model.py
from_dict
classmethod
¶
Source code in shared/iam/auth_context/model.py
has_backoffice_permissions ¶
For now we only check the permissions of the real principal, i.e. the actor - as there is no impersonation / delegation on backoffice
Source code in shared/iam/auth_context/model.py
real_principal
property
¶
Get the actual principal or 'actor', i.e. who is performing the action This will raise an exception if it's not set You need to call is_authenticated or is_anonymous to guard against this
real_principal_as ¶
Get the actual principal or 'actor', i.e. who is performing the action, cast as a specific class This will raise an exception if the principal is not set or if the actual type is not the one expected This will raise an exception if it's not set You need to call is_authenticated or is_anonymous to guard against this
Source code in shared/iam/auth_context/model.py
to_dict ¶
Source code in shared/iam/auth_context/model.py
providers ¶
anonymous ¶
AnonymousAuthContextProvider ¶
Bases: AuthContextProvider
AuthContextProvider for anonymous users.
If not explicitly added to the auth context providers chain, anonymous requests will be denied. WARNING: this currently cannot be used in a chain with other providers because it ALWAYS handles the request whereas one and only one provider in a chain is allowed to do it (they must be mutually exclusive) This is because some "anonymous" endpoints actually check e.g. authorization headers so we can't exclude them here This should be solved once all "anonymous" endpoints that actually perform authentication are moved to a proper auth provider context
set_auth_context_from_request ¶
base ¶
AuthContextProvider ¶
Bases: ABC
Base class for auth context providers
An auth context provider is responsible for extracting the authentication context from the request
get_auth_principal_from_email
staticmethod
¶
Source code in shared/iam/auth_context/providers/base.py
set_auth_context_from_request
abstractmethod
¶
dev ¶
DevAuthContextProvider ¶
Bases: AuthContextProvider
Source code in shared/iam/auth_context/providers/dev.py
set_auth_context_from_request ¶
Source code in shared/iam/auth_context/providers/dev.py
helpers ¶
set_auth_context_from_provider_chain ¶
Source code in shared/iam/auth_context/providers/helpers.py
set_auth_context_from_provider_chain_before_request ¶
Source code in shared/iam/auth_context/providers/helpers.py
service_account ¶
ServiceAccountAuthContextProvider ¶
Bases: AuthContextProvider
Source code in shared/iam/auth_context/providers/service_account.py
get_email_from_access_token ¶
Source code in shared/iam/auth_context/providers/service_account.py
set_auth_context_from_request ¶
Source code in shared/iam/auth_context/providers/service_account.py
will_handle_request ¶
Source code in shared/iam/auth_context/providers/service_account.py
webhook ¶
WebhookAuthContextProvider ¶
WebhookAuthContextProvider(
auth_type,
header_name,
secret_name_config_key,
auth_principal_type,
auth_principal_email,
)
Bases: AuthContextProvider
Validate a webhook payload and set a static principal value in the authentication context
Typically the principal would be a specific service account corresponding to the 3rd party sending the payload
Source code in shared/iam/auth_context/providers/webhook.py
set_auth_context_from_request ¶
Source code in shared/iam/auth_context/providers/webhook.py
zero_trust ¶
ZeroTrustAuthContextProvider ¶
Bases: AuthContextProvider
Source code in shared/iam/auth_context/providers/zero_trust.py
set_auth_context_from_request ¶
Source code in shared/iam/auth_context/providers/zero_trust.py
will_handle_request ¶
shared.iam.auth_principal ¶
AuthPrincipal ¶
Base mixin for all user models which are allowed to authenticate on our apps, i.e. both users (frontoffice) and Alan admins (backoffice) Principals can be individual people, computers, or services - any entity that can be authenticated.
principal_name
abstractmethod
property
¶
A name that uniquely identifies this principal
shared.iam.authenticatable ¶
Authenticatable ¶
Bases: AlanModelWithPrivacyMode, LangMixin
auth_token ¶
Source code in shared/iam/authenticatable.py
authentication_id ¶
Source code in shared/iam/authenticatable.py
create_session_tokens_and_make_response ¶
create_session_tokens_and_make_response(
refresh_token_type,
code=None,
initial_response_dict=None,
)
Source code in shared/iam/authenticatable.py
email ¶
Source code in shared/iam/authenticatable.py
email_address_conflict_filter
classmethod
¶
first_name ¶
Source code in shared/iam/authenticatable.py
generate_global_password_reset_email
classmethod
¶
Generate a password reset email through our identity provider
Attributes:
| Name | Type | Description |
|---|---|---|
email |
str
|
The email address of the user to trigger a password reset |
client_id |
str
|
Identity provider client ID (e.g. "alan-mobile-prod", "fr-web-prod") |
redirect_uri |
str | None
|
The URI to redirect to after performing password reset |
Source code in shared/iam/authenticatable.py
generate_password_reset_token
classmethod
¶
Generate a password reset token (legacy). This option is deprecated as we are progressively using Keycloak for this. Cf. See Authenticatable.generate_global_password_reset_email
Note: If a user doesn't have an auth identity, it gets created before generating the password reset token.
Attributes:
| Name | Type | Description |
|---|---|---|
email |
str
|
The email address of the user to generate a password reset token for |
Source code in shared/iam/authenticatable.py
get_by_token
classmethod
¶
keycloak_id ¶
Source code in shared/iam/authenticatable.py
last_name ¶
Source code in shared/iam/authenticatable.py
parse_token
classmethod
¶
Parse the access token and return the user, session-id and issued-at timestamp if valid (or all None if invalid)
Source code in shared/iam/authenticatable.py
refresh_session_tokens ¶
Source code in shared/iam/authenticatable.py
revoke_all_tokens ¶
Source code in shared/iam/authenticatable.py
set_cookie_and_make_response ¶
Source code in shared/iam/authenticatable.py
set_session_cookie ¶
Source code in shared/iam/authenticatable.py
validate_email_address ¶
Source code in shared/iam/authenticatable.py
validate_names ¶
validate_refresh_tokens ¶
Source code in shared/iam/authenticatable.py
verification_error
staticmethod
¶
verify_keycloak_access_token
classmethod
¶
Source code in shared/iam/authenticatable.py
verify_refresh_token
staticmethod
¶
Source code in shared/iam/authenticatable.py
shared.iam.authorization ¶
AlanerAdminStrategy ¶
Bases: BaseAuthorizationStrategy
Used for authorization on resources only accessible by Alaners (like marmot, flask-admin, etc.)
Source code in shared/iam/authorization.py
authorize ¶
Source code in shared/iam/authorization.py
ensure_custom_authorization
class-attribute
instance-attribute
¶
AuthenticatedStrategy ¶
Bases: BaseAuthorizationStrategy
Source code in shared/iam/authorization.py
AuthenticatedWithCustomAuthorizationStrategy ¶
Bases: AuthenticatedStrategy
Source code in shared/iam/authorization.py
BaseAuthorizationStrategy ¶
Bases: ABC
Source code in shared/iam/authorization.py
authenticator ¶
authorize
abstractmethod
¶
Source code in shared/iam/authorization.py
ensure_custom_authorization
class-attribute
instance-attribute
¶
OpenStrategy ¶
Bases: AuthenticatedStrategy
Source code in shared/iam/authorization.py
OwnerOnlyStrategy ¶
Bases: BaseAuthorizationStrategy
Strategy that delegates authorization to the owner_only strategy provided by the controller it applies to.
Source code in shared/iam/authorization.py
authorize ¶
Source code in shared/iam/authorization.py
ensure_custom_authorization
class-attribute
instance-attribute
¶
owner_bypass_permitted_for
instance-attribute
¶
admin_can_access_sensitive_company ¶
Source code in shared/iam/authorization.py
admin_can_access_sensitive_user ¶
Source code in shared/iam/authorization.py
check_is_owner ¶
Source code in shared/iam/authorization.py
custom_authorization ¶
This decorator is used to wrap custom authorization functions that are used in the context of AuthenticatedWithCustomAuthorizationStrategy.
Source code in shared/iam/authorization.py
shared.iam.bearer_token_auth ¶
BearerTokenAuth ¶
Bases: HTTPTokenAuth
Bearer token authentication
This class authenticates a request based on the presence of a valid Bearer token.
Handling of deep links to backend endpoints¶
Normally, a request without a bearer token is simply rejected as unauthenticated. This happens in particular when an endpoint is browsed directly from a browser (through a deep link to the endpoint).
If an endpoint is marked as allowing deep links, instead of rejecting requests without a token, we redirect them to a special route in the front-end, which will allow the user to authenticate, and then make the same request again, this time with a proper token, and present the result to the user.
Source code in shared/iam/bearer_token_auth.py
restrict_location_for_alaner_admin
instance-attribute
¶
verify_token ¶
Source code in shared/iam/bearer_token_auth.py
shared.iam.cookie_token_auth ¶
CookieTokenAuth ¶
Source code in shared/iam/cookie_token_auth.py
login_required ¶
Source code in shared/iam/cookie_token_auth.py
shared.iam.data ¶
shared.iam.enum ¶
shared.iam.exceptions ¶
IamException ¶
Base class for IAM exceptions
RestrictAlanEmployeeInvalid ¶
Bases: Forbidden, IamException
Error: Token validated, but invalid user (cannot recover, show Forbidden 403)
Source code in shared/iam/exceptions.py
RestrictAlanerAdminExceptionNotFound ¶
RestrictInvalidToken ¶
Bases: Forbidden, IamException
Warning: Invalid token which is expired or malformed (can recover, restart authentication cinematic)
Source code in shared/iam/exceptions.py
RestrictToAlmerysExceptionNotFound ¶
RestrictToPermissionsExceptionForbidden ¶
RestrictToPermissionsExceptionNotFound ¶
RestrictToWhitelistedIpsNotFound ¶
RestrictToZerotrustAuthenticatedUserNotFound ¶
shared.iam.gdpr ¶
AMPLITUDE_ENDPOINT
module-attribute
¶
AMPLITUDE_HEADERS
module-attribute
¶
gdpr_erasure ¶
Source code in shared/iam/gdpr.py
remove_tracking ¶
Source code in shared/iam/gdpr.py
shared.iam.global_authorization ¶
GlobalAuthorizationStrategies ¶
Bases: IsomorphicAuthorizationStrategies
Source code in shared/iam/global_authorization.py
IsomorphicAuthorizationStrategies ¶
not_implemented_strategy ¶
shared.iam.google_auth ¶
GOOGLE_OAUTH_USER_INFO_URL
module-attribute
¶
get_client_config ¶
Returns the client config for the OAuth call.
The values nees to be taken from config (current_config.get("ADMIN_OAUTH_CLIENT_ID")).
For all environments (acceptance, prod, etc.) from AWS secrets
This also needs to match the Google Console configuration.
Source code in shared/iam/google_auth.py
get_response_unauthorized_access_employee ¶
Returns a 403 response for invalid alan employee
Source code in shared/iam/google_auth.py
get_response_unauthorized_service_account ¶
Returns a 403 response for invalid service account
Source code in shared/iam/google_auth.py
google_auth_login_required ¶
Use as annotation to require google auth login for this endpoint.
If the user isn't logged in (no token in session), this method returns a redirect
to the google auth URL. The given permitted_for will also validate the user
permission. This is used for backend admin URLs (not frontend admin URLs).
If auth_only is True, only require authentication. If auth_only is False, user must have at least one of the permissions from permitted_for. (I.e. this will always fail if permitted_for is empty and auth_only is False).
Source code in shared/iam/google_auth.py
make_token_for_credentials ¶
Returns a JWT token from the given google credentials, returns None if the employee is not found
Uses the credentials token to query user info url (needs the userinfo.email scope), then loads the alan employee and user for return.
Raises HTTPError: 401 Client Error: Unauthorized for url if an invalid credential token is provided. This
error is recoverable (restart the oauth cinematic).
Raises RestrictAlanEmployeeInvalid: if the alan employee is not found or invalid. This error is NOT recoverable (show 403).
Source code in shared/iam/google_auth.py
redirect_to_authorize ¶
Returns the redirect to the authorize URL and add the next location to the session. The user
will be redirected back to the given url at the end of the authentication cinematic. Most of
the time, request.url is sufficient for the url value.
Source code in shared/iam/google_auth.py
shared.iam.headers ¶
IMPERSONATION_MODE_HEADER
module-attribute
¶
InvalidAccessToken ¶
Bases: Exception
claims_to_be_alaner_admin ¶
get_access_token ¶
Source code in shared/iam/headers.py
shared.iam.helpers ¶
ImpersonationMode ¶
Bases: Enum
service_account_delegation
class-attribute
instance-attribute
¶
A special type of impersonation used by the API Proxy system. Refer to the following documentation for more information:
Note that, under this impersonation mode, X-ALAN-IMPERSONATED-USER will contain an Alaner email instead of the user ID.
block_request_if_user_blocked ¶
Block request if user is registered as blocked in Datadog.
Will raise a 403 Forbidden error if user is blocked.
Blocked users can be viewed in Datadog: https://app.datadoghq.eu/security/appsec/denylist ⧉
Source code in shared/iam/helpers.py
can_actor_bypass_permissions ¶
current_auth_context
module-attribute
¶
delete_cookie ¶
get_user_cls ¶
is_alaner_admin ¶
is_impersonated ¶
is_oauth_enabled ¶
reset_auth_context ¶
reset_auth_globals ¶
restrict_to_alaner_admin ¶
Restrict endpoints reserved for super admins.
This should be kept for endpoints that expect only super admins.
Source code in shared/iam/helpers.py
restrict_to_local_machine ¶
Restrict endpoints to localhost only.
Source code in shared/iam/helpers.py
restrict_to_privileged_request ¶
Source code in shared/iam/helpers.py
set_auth_context ¶
set_auth_context(
real_principal,
effective_principal=None,
impersonation_mode=None,
session_id=None,
cloudflare_zerotrust_identity=None,
)
Source code in shared/iam/helpers.py
set_auth_context_from_dict ¶
set_auth_globals_for_alaner_admin_user ¶
Source code in shared/iam/helpers.py
set_auth_globals_for_impersonated_user ¶
set_auth_globals_for_impersonated_user(
actor,
impersonated_user,
impersonation_mode=ImpersonationMode.read_only,
)
Source code in shared/iam/helpers.py
set_auth_globals_for_regular_user ¶
Source code in shared/iam/helpers.py
set_auth_globals_from_saved_values ¶
Source code in shared/iam/helpers.py
shared.iam.http_token_auth ¶
HTTPTokenAuth ¶
Bases: HTTPTokenAuth
Source code in shared/iam/http_token_auth.py
shared.iam.keycloak ¶
KeycloakAdminWithErrorHandling ¶
Bases: KeycloakAdmin
Overrides KeycloakAdmin methods to handle errors. The admin client raises exceptions after fetching the server using a generic function So we can't use the decorator directly on core methods for fetching data, we need to override each high-level method we use.
KeycloakBusinessError ¶
Bases: BaseErrorCode
These errors are expected to occur due to user actions in normal application operations, and do not constitute technical errors requiring specific attention/remediation by Alan Eng. HTTP_ERRORS: list of Keycloak server http statuses that we can map as Keycloak Business Error
These errors:
- don't trigger Sentry. See: https://github.com/alan-eu/alan-apps/blob/538fb56cf374fc1a0719668e0d70e5359edbde91/backend/shared/helpers/sentry/setup.py#L71 ⧉
- Are caught by our Flask controllers => views will return an HTTP 4XX (and not a 500), see https://github.com/alan-eu/alan-apps/blob/538fb56cf374fc1a0719668e0d70e5359edbde91/backend/shared/api/helpers.py#L132 ⧉
- NB: You can pass http_code=<your_code> to additional_args to change the HTTP status code returned to the client.
Source code in shared/iam/keycloak.py
KeycloakUser ¶
build_login_url ¶
Build a login URL depending on client ID. It uses either the front end URL or deep link URL as base URL. :param client_id: a str representing the Keycloak client :param email: a str representing the email address for login :return: the login URL
Source code in shared/iam/keycloak.py
get_admin_client ¶
Source code in shared/iam/keycloak.py
get_user_from_access_token ¶
Source code in shared/iam/keycloak.py
with_keycloak_error_handling ¶
Source code in shared/iam/keycloak.py
shared.iam.login_form_auth ¶
LoginFormAuth ¶
Inspired by flask_httpauth (https://github.com/miguelgrinberg/Flask-HTTPAuth ⧉).
Source code in shared/iam/login_form_auth.py
authenticate ¶
Source code in shared/iam/login_form_auth.py
custom_error_handler ¶
error_handler ¶
Source code in shared/iam/login_form_auth.py
login_required ¶
login_required_mind ¶
shared.iam.monitoring ¶
KEYCLOAK_ALAN_REALM_ID
module-attribute
¶
TrackedKeycloakEventType ¶
track_keycloak_event_in_datadog ¶
Track Keycloak events in our API as we don't have a built-in provider for Keycloak. Tracked: Login success / Login failure
Example of events: 1. Login success: { "time": 1734544774538, "type": "LOGIN", "realmId": "e5c69b4c-7d1a-4fc1-bf3f-e90d812fee64", "clientId": "fr-web-dev", "userId": "abc", "sessionId": "def", "ipAddress": "1.1.1.1", "details": { "auth_method": "openid-connect", "token_id": "ghi", "grant_type": "password", "refresh_token_type": "Refresh", "scope": "profile email openid", "refresh_token_id": "mno", "client_auth_method": "client-secret", "username": "toto@alan.eu" } }
-
Login failure: { "time": 1734546787082, "type": "LOGIN_ERROR", "realmId": "e5c69b4c-7d1a-4fc1-bf3f-e90d812fee64", "clientId": "fr-web-dev", "ipAddress": "1.1.1.1", "error": "user_not_found", "details": { "auth_method": "openid-connect", "grant_type": "password", "client_auth_method": "client-secret", "username": "toto@alan.eu" } }
-
Update credential / password: { "time": 1734548799123, "type": "UPDATE_CREDENTIAL", "realmId": "e5c69b4c-7d1a-4fc1-bf3f-e90d812fee64", "clientId": "fr-web-dev", "userId": "abc", "ipAddress": "1.1.1.1", "details": { "auth_method": "openid-connect", "code_id": "def", "credential_type": "password", "custom_required_action": "UPDATE_PASSWORD", "redirect_uri": "http://localhost:4001/login?email=toto%40alan.eu ⧉", "remember_me": "false", "response_mode": "query", "response_type": "code", "username": "toto@alan.eu" } }
-
Update credential / password error: { "time": 1734548799123, "type": "UPDATE_CREDENTIAL_ERROR", "realmId": "e5c69b4c-7d1a-4fc1-bf3f-e90d812fee64", "clientId": "fr-web-dev", "userId": "abc", "ipAddress": "1.1.1.1", "error": "password_missing", "details": { "auth_method": "openid-connect", "code_id": "def", "credential_type": "password", "custom_required_action": "UPDATE_PASSWORD", "redirect_uri": "http://localhost:4001/login?email=toto%40alan.eu ⧉", "remember_me": "false", "response_mode": "query", "response_type": "code", "username": "toto@alan.eu" } }
-
User disabled by temporary lockout:
{ "type": "USER_DISABLED_BY_TEMPORARY_LOCKOUT", "realmId": "e5c69b4c-7d1a-4fc1-bf3f-e90d812fee64", "realmName": "alan", "clientId": "null", "userId": "9e23c536-c22f-45c5-8c0d-bc985cb7cd9f", "ipAddress": "2a0d:e487:138f:3f9e:8e:d53c:4016:f0cb", "reason": "brute_force_attack detected", "not_before": "2025-10-02T13:06:34", "num_failures": "5" }
If Keycloak events' schema changes, let this function fail, so we can update it.
Source code in shared/iam/monitoring.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
shared.iam.openid_connect ¶
AsymmetricKeyTargetUsage ¶
ClaimBucket ¶
OpenIdConnectTokenExchangeResponse
dataclass
¶
PKCE_CODE_CACHE_EXPIRATION_TIME
module-attribute
¶
======================== OpenID Connect 1.0 Authorization Code flow ========================
Hard specs: https://openid.net/specs/openid-connect-core-1_0.html ⧉
Overview:
{ Identification Provider } { Human } { Alan Mobile } { Alan Backend } { Identification Provider }
{ Frontend } { Member } { App } { Server } { Backend }
| | | | |
| |>--1."login with"--| | |
| | |>---2./get_authorization_url----| |
|--------------------(redirected)-------------<|-3. url with signed claims req-<| |
|>-4.Provider login prompt-| | | |
|------5.Identifies-------<| | | |
|>-------------6.Redirect w/ auth code------(pass)------------------------------| |
| | | |>---7.signed token request---|
| | | |-----8.ID+Access tokens-----<|
| | |
exchange_code_for_tokens ¶
Exchange an authorization code for an ID token and an access token.
Source code in shared/iam/openid_connect.py
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | |
get_authorization_url ¶
get_authorization_url(
id_provider_root_url,
client_id,
redirect_uri,
scope,
state,
claims=None,
ui_locales=None,
)
Build an authorization request URL, to be opened on the member's device to authenticate with the identification provider.
Source code in shared/iam/openid_connect.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | |
get_userinfo ¶
Retrieve OpenID user info for the previously agreed claims.
Source code in shared/iam/openid_connect.py
shared.iam.passwords ¶
This module is a shallow implementation of the frontend password strength estimation library zxcvbn. It provides functions to evaluate password strength and determine if a password meets a minimum strength requirement.
Source: frontend/shared/password-utils/index.ts
get_password_score ¶
Evaluate the strength of a password using zxcvbn.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
password
|
str
|
The password to evaluate |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The strength score of the password (0-4) |
Source code in shared/iam/passwords.py
is_password_strong_enough ¶
Check if the password meets the minimum strength requirement.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
password
|
str
|
The password to check |
required |
shared.iam.permissions ¶
alaner_admin_has_permission ¶
Return True if current actor has at least one of the given permissions
Source code in shared/iam/permissions.py
get_actor_permissions ¶
Return the permissions of the current actor.
WARNING, don't use this to check permissions. We have a strict policy, instead use alaner_admin_has_permission so that it is appropriately logged.
Source code in shared/iam/permissions.py
get_alan_employees_with_permission ¶
this should not be used to test whether a particular User has a given permission, because:
- it's not efficient, as we loop over all users
- it doesn't call
permissions_intersectswhich tracks permission checks
Source code in shared/iam/permissions.py
get_roles ¶
has_permission ¶
Return True if given user has at least one of the given permissions
Source code in shared/iam/permissions.py
is_alaner_admin_with_permissions_or_raise ¶
Return True if current actor (which must be an Alaner admin) has one of the listed permissions
Raise a missing permission error if the user is authenticated as an Alaner admin but does not have the required permissions.
Source code in shared/iam/permissions.py
is_authenticated_actor_with_permissions_or_raise ¶
Return True if current actor (which must be an Alaner admin) has one of the listed permissions
Raise a missing permission error if the user is authenticated as an Alaner admin but does not have the required permissions.
Source code in shared/iam/permissions.py
permissions_intersects ¶
Return True if the given two Sets of permissions intersect.
The first Set is the requested permissions, the second the available permissions. Properly logs the check. Can receive an entity and stack level for improved logging
Source code in shared/iam/permissions.py
permitted_for ¶
Source code in shared/iam/permissions.py
raise_missing_permission_error ¶
Source code in shared/iam/permissions.py
shared.iam.scim_api ¶
AlanEmployeeIdentity
dataclass
¶
GenericScimAdapter ¶
Generic SCIM adapter for all apps but BE, CA, ES and FR
create_app_user ¶
Source code in shared/iam/scim_api.py
create_scim_user ¶
Source code in shared/iam/scim_api.py
delete_scim_user ¶
Source code in shared/iam/scim_api.py
get_all_scim_users ¶
Source code in shared/iam/scim_api.py
get_scim_user ¶
Source code in shared/iam/scim_api.py
get_scim_users_data ¶
Source code in shared/iam/scim_api.py
get_user_data ¶
Source code in shared/iam/scim_api.py
update_scim_user ¶
Source code in shared/iam/scim_api.py
ScimEmailSchema ¶
ScimErrorSchema ¶
ScimUserCountryDataSchema ¶
ScimUserCreateSchema ¶
ScimUserOutputSchema ¶
Bases: ScimUserEditSchema
ScimUsersListSchema ¶
ScimUsersQueryArgSchema ¶
current_alan_employees ¶
Bases: MethodView
get ¶
Source code in shared/iam/scim_api.py
post ¶
Source code in shared/iam/scim_api.py
get_alan_employee_cls ¶
Get the Alan employee class.
Source code in shared/iam/scim_api.py
get_scim_adapter ¶
record ¶
Record callback to store the adapter instance.
Source code in shared/iam/scim_api.py
scim_api_error_handler ¶
Source code in shared/iam/scim_api.py
scim_auth_required ¶
Source code in shared/iam/scim_api.py
scim_blueprint
module-attribute
¶
shared.iam.sensitive_data_mixin ¶
shared.iam.token_auth ¶
TokenAuth ¶
Token authentication
This class authenticates a request based on - the presence of a valid token passed in a Bearer authorization header for mobile requests - the presence of a valid token passed in a cookie for web requests
Source code in shared/iam/token_auth.py
bearer_token_auth
instance-attribute
¶
bearer_token_auth = BearerTokenAuth(
optional=optional,
allow_deep_link=allow_deep_link,
restrict_location_for_alaner_admin=restrict_location_for_alaner_admin,
)
cookie_token_auth
instance-attribute
¶
is_client_authenticating_with_cookie ¶
login_required ¶
Source code in shared/iam/token_auth.py
shared.iam.token_auth_helpers ¶
get_alaner_admin_user_from_claims ¶
Returns the User from the JWT token claims, none if not found or not from authorized location. This method is used for admin URLs only.
Raises RestrictInvalidToken: if claims are missing (warning)
Raises RestrictAlanEmployeeInvalid: if the alan employee is unauthorized (error)
Source code in shared/iam/token_auth_helpers.py
get_alaner_admin_user_from_token ¶
get_authenticated_user_from_email ¶
Return the User from the given email, if the user is an alan employee, is currently active, and connected from an authorized location. This method is used for admin URLs only.
Raises RestrictAlanEmployeeInvalid: if not the case
Source code in shared/iam/token_auth_helpers.py
get_authenticated_user_from_id ¶
Return the User from the given id, if the user is an alan employee, is currently active, and connected from an authorized location. This method is used for admin URLs only.
Raises RestrictAlanEmployeeInvalid: if not the case
Source code in shared/iam/token_auth_helpers.py
get_claims_from_token ¶
Returns the claims from the JWT token, none if invalid token or expired. This method is used for admin URLs only. The claims do not contain the signature, and do so not constitute sensitive credentials.
Source code in shared/iam/token_auth_helpers.py
make_token ¶
Source code in shared/iam/token_auth_helpers.py
make_token_for_id ¶
Returns the JWT token for the given user id, with an expiration time at 23:00 (cutoff) or the next day at 23:00 if we're 1 hour before the cutoff. This method is used for admin URLs only.
Source code in shared/iam/token_auth_helpers.py
shared.iam.tracking ¶
events ¶
publish_user_session_ended ¶
Source code in shared/iam/tracking/events.py
publish_user_session_refreshed ¶
Source code in shared/iam/tracking/events.py
publish_user_session_started ¶
Source code in shared/iam/tracking/events.py
traits ¶
AuthProfileTraits ¶
Bases: UserTraits['Authenticatable']
Source code in shared/services/segment/base.py
get_attributes ¶
Return authentication-relevant attributes from the authenticatable user.
Source code in shared/iam/tracking/traits.py
shared.iam.user_auth ¶
validate_at_hash ¶
Validates at_hash (access token hash) claim stored in the ID token against the access token itself. Described here: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowTokenValidation ⧉ To do this, we use the same function used by authlib to generate the at_hash and compare the result.