def test_create_jwt_token_no_secret_no_algorithm(settings: SettingsWrapper): """Test create_jwt_token function by trying to create a JWT token with no secret and algorithm set. Args: settings (SettingsWrapper): Fixture for django settings """ settings.SAML2_AUTH = {"JWT_SECRET": None, "JWT_ALGORITHM": None} with pytest.raises(SAMLAuthError) as exc_info: create_jwt_token("*****@*****.**") assert str(exc_info.value ) == "Cannot create JWT token. Specify secret and algorithm."
def test_decode_jwt_token_success(): """Test decode_jwt_token function by verifying if the newly created JWT token using create_jwt_token function is valid.""" jwt_token = create_jwt_token("*****@*****.**") user_id = decode_jwt_token(jwt_token) assert user_id == "*****@*****.**"
def sp_initiated_login(request: HttpRequest) -> HttpResponseRedirect: # User must be created first by the IdP-initiated SSO (acs) if request.method == "GET": if request.GET.get("token"): user_id = decode_jwt_token(request.GET.get("token")) saml_client = get_saml_client(get_assertion_url(request), acs, user_id) jwt_token = create_jwt_token(user_id) _, info = saml_client.prepare_for_authenticate( sign=False, relay_state=jwt_token) redirect_url = dict(info["headers"]).get("Location", "") if not redirect_url: return HttpResponseRedirect( get_reverse([denied, "denied", "django_saml2_auth:denied"])) return HttpResponseRedirect(redirect_url) else: raise SAMLAuthError("Request method is not supported.", extra={ "exc_type": Exception, "error_code": INVALID_REQUEST_METHOD, "reason": "Request method is not supported.", "status_code": 404 })
def acs(request: HttpRequest): """Assertion Consumer Service is SAML terminology for the location at a ServiceProvider that accepts <samlp:Response> messages (or SAML artifacts) for the purpose of establishing a session based on an assertion. Assertion is a signed authentication request from identity provider (IdP) to acs endpoint. Args: request (HttpRequest): Incoming request from identity provider (IdP) for authentication Exceptions: SAMLAuthError: The target user is inactive. Returns: HttpResponseRedirect: Redirect to various endpoints: denied, welcome or next_url (e.g. the front-end app) Notes: https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService """ authn_response = decode_saml_response(request, acs) user = extract_user_identity(authn_response.get_identity()) next_url = request.session.get("login_next_url") or get_default_next_url() # If RelayState params is passed, it is a JWT token that identifies the user trying to login # via sp_initiated_login endpoint relay_state = request.POST.get("RelayState") if relay_state: redirected_user_id = decode_jwt_token(relay_state) # This prevents users from entering an email on the SP, but use a different email on IdP if get_user_id(user) != redirected_user_id: raise SAMLAuthError("The user identifier doesn't match.", extra={ "exc_type": ValueError, "error_code": USER_MISMATCH, "reason": "User identifier mismatch.", "status_code": 403 }) is_new_user, target_user = get_or_create_user(user) before_login_trigger = dictor(settings.SAML2_AUTH, "TRIGGER.BEFORE_LOGIN") if before_login_trigger: run_hook(before_login_trigger, user) request.session.flush() use_jwt = settings.SAML2_AUTH.get("USE_JWT", False) if use_jwt and target_user.is_active: # Create a new JWT token for IdP-initiated login (acs) jwt_token = create_jwt_token(target_user.email) # Use JWT auth to send token to frontend query = f"?token={jwt_token}" frontend_url = settings.SAML2_AUTH.get("FRONTEND_URL", next_url) return HttpResponseRedirect(frontend_url + query) if target_user.is_active: model_backend = "django.contrib.auth.backends.ModelBackend" login(request, target_user, model_backend) after_login_trigger = dictor(settings.SAML2_AUTH, "TRIGGER.AFTER_LOGIN") if after_login_trigger: run_hook(after_login_trigger, request.session, user) else: raise SAMLAuthError("The target user is inactive.", extra={ "exc_type": Exception, "error_code": INACTIVE_USER, "reason": "User is inactive.", "status_code": 500 }) if is_new_user: try: return render(request, "django_saml2_auth/welcome.html", {"user": request.user}) except TemplateDoesNotExist: return HttpResponseRedirect(next_url) else: return HttpResponseRedirect(next_url)
def test_create_jwt_token_success(): """Test create_jwt_token function to verify JWT token generation.""" jwt_token = create_jwt_token("*****@*****.**") assert isinstance(jwt_token, str) assert "." in jwt_token assert jwt_token.count(".") == 2