def test_generate_sha256_hash(self): hash_123 = "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3" hash_123salt = ( "81d40d94fee4fb4eeb1a21bb7adb93c06aad35b929c1a2b024ae33b3a9b79e23" ) self.assertRaises(TypeError, generate_sha256_hash, "123") self.assertEqual(generate_sha256_hash("123".encode()), hash_123) self.assertEqual(generate_sha256_hash("123".encode("utf-8")), hash_123) self.assertEqual( generate_sha256_hash("123".encode() + "salt".encode()), hash_123salt ) self.assertEqual(generate_sha256_hash("123salt".encode()), hash_123salt) self.assertEqual(len(generate_sha256_hash("123salt".encode())), 64)
def setUp(self): self.client = Client() self.aidant = AidantFactory() self.client.force_login(self.aidant) self.epoch_date = DATE.timestamp() self.connection = Connection.objects.create( demarches=["argent", "papiers"], duree_keyword="SHORT", state="test_state", connection_type="FS", nonce="test_nonce", id=1, expires_on=DATE + timedelta(minutes=5), aidant=self.aidant, organisation=self.aidant.organisation, ) Connection.objects.create( state="test_another_state", connection_type="FS", nonce="test_another_nonce", id=2, ) self.usager_sub_fc = "123" self.usager_sub = generate_sha256_hash( f"{self.usager_sub_fc}{settings.FC_AS_FI_HASH_SALT}".encode()) self.usager = UsagerFactory(given_name="Joséphine", sub=self.usager_sub)
def setUp(self): self.usager_sub_fc = "123" self.usager_sub = generate_sha256_hash( f"{self.usager_sub_fc}{settings.FC_AS_FI_HASH_SALT}".encode()) self.usager = UsagerFactory(given_name="Joséphine", sub=self.usager_sub) self.aidant = AidantFactory() self.connection = Connection.objects.create( access_token="mock_access_token", aidant=self.aidant, )
def generate_attestation_hash(aidant, usager, demarches, expiration_date): demarches.sort() attestation_data = { "aidant_id": aidant.id, "creation_date": date.today().isoformat(), "demarches_list": ",".join(demarches), "expiration_date": expiration_date.date().isoformat(), "organisation_id": aidant.organisation.id, "template_hash": generate_file_sha256_hash(settings.MANDAT_TEMPLATE_PATH), "usager_sub": usager.sub, } sorted_attestation_data = dict(sorted(attestation_data.items())) attestation_string = ";".join( str(x) for x in list(sorted_attestation_data.values())) attestation_string_with_salt = attestation_string + settings.ATTESTATION_SALT return generate_sha256_hash(attestation_string_with_salt.encode("utf-8"))
def setUpTestData(cls): cls.usager_sub_fc = "123" cls.usager_sub = generate_sha256_hash( f"{cls.usager_sub_fc}{settings.FC_AS_FI_HASH_SALT}".encode()) cls.usager = UsagerFactory(given_name="Joséphine", sub=cls.usager_sub) cls.aidant = AidantFactory() cls.connection = Connection.objects.create( access_token="mock_access_token", aidant=cls.aidant, organisation=cls.aidant.organisation, ) cls.connection_with_phone = Connection.objects.create( access_token="mock_access_token_with_phone", aidant=cls.aidant, organisation=cls.aidant.organisation, user_phone="0 800 840 800", )
def get_user_info(connection: Connection) -> tuple: fc_base = settings.FC_AS_FS_BASE_URL fc_user_info = python_request.get( f"{fc_base}/userinfo?schema=openid", headers={"Authorization": f"Bearer {connection.access_token}"}, ) user_info = fc_user_info.json() if user_info.get("birthplace") == "": user_info["birthplace"] = None usager_sub = generate_sha256_hash( f"{user_info['sub']}{settings.FC_AS_FI_HASH_SALT}".encode()) try: usager = Usager.objects.get(sub=usager_sub) if usager.email != user_info.get("email"): usager.email = user_info.get("email") usager.save() Journal.log_update_email_usager(aidant=connection.aidant, usager=usager) return usager, None except Usager.DoesNotExist: try: usager = Usager.objects.create( given_name=user_info.get("given_name"), family_name=user_info.get("family_name"), birthdate=user_info.get("birthdate"), gender=user_info.get("gender"), birthplace=user_info.get("birthplace"), birthcountry=user_info.get("birthcountry"), sub=usager_sub, email=user_info.get("email"), ) return usager, None except IntegrityError as e: log.error("Error happened in Recap") log.error(e) return None, f"The FranceConnect ID is not complete: {e}"
def token(request): if request.method == "GET": return HttpResponse("You did a GET on a POST only route") client_secret = request.POST.get("client_secret") try: hash_client_secret = generate_sha256_hash(client_secret.encode()) except AttributeError: return HttpResponseBadRequest() parameters = { "code": request.POST.get("code"), "grant_type": request.POST.get("grant_type"), "redirect_uri": request.POST.get("redirect_uri"), "client_id": request.POST.get("client_id"), "hash_client_secret": hash_client_secret, } EXPECTED_STATIC_PARAMETERS = { "grant_type": "authorization_code", "redirect_uri": settings.FC_AS_FI_CALLBACK_URL, "client_id": settings.FC_AS_FI_ID, "hash_client_secret": settings.HASH_FC_AS_FI_SECRET, } error, message = check_request_parameters(parameters, EXPECTED_STATIC_PARAMETERS, "token") if error: return (HttpResponseBadRequest() if message == "missing parameter" else HttpResponseForbidden()) code_hash = make_password(parameters["code"], settings.FC_AS_FI_HASH_SALT) try: connection = Connection.objects.get(code=code_hash) if connection.is_expired: log.info("connection has expired at token") return render(request, "408.html", status=408) except ObjectDoesNotExist: log.info("403: /token No connection corresponds to the code") log.info(parameters["code"]) return HttpResponseForbidden() id_token = { # The audience, the Client ID of your Auth0 Application "aud": settings.FC_AS_FI_ID, # The expiration time. in the format "seconds since epoch" # TODO Check if 10 minutes is not too much "exp": int(time.time()) + settings.FC_CONNECTION_AGE, # The issued at time "iat": int(time.time()), # The issuer, the URL of your Auth0 tenant "iss": settings.HOST, # The unique identifier of the user "sub": connection.usager.sub, "nonce": connection.nonce, } encoded_id_token = jwt.encode(id_token, client_secret, algorithm="HS256") access_token = token_urlsafe(64) connection.access_token = make_password(access_token, settings.FC_AS_FI_HASH_SALT) connection.save() response = { "access_token": access_token, "expires_in": 3600, "id_token": encoded_id_token, "refresh_token": _mock_refresh_token(), "token_type": "Bearer", } definite_response = JsonResponse(response) return definite_response
def get_user_info(connection: Connection) -> tuple: fc_base = settings.FC_AS_FS_BASE_URL fc_user_info = python_request.get( f"{fc_base}/userinfo?schema=openid", headers={"Authorization": f"Bearer {connection.access_token}"}, ) user_info = fc_user_info.json() user_phone = connection.user_phone if len( connection.user_phone) > 0 else None if user_info.get("birthplace") == "": user_info["birthplace"] = None user_sub = user_info.get("sub") if not user_sub: return None, "Unable to find sub in FC user info" usager_sub = generate_sha256_hash( f"{user_sub}{settings.FC_AS_FI_HASH_SALT}".encode()) try: usager = Usager.objects.get(sub=usager_sub) if usager.email != user_info.get("email"): usager.email = user_info.get("email") usager.save() Journal.log_update_email_usager(aidant=connection.aidant, usager=usager) if user_phone is not None and usager.phone != user_phone: usager.phone = user_phone Journal.log_update_phone_usager(aidant=connection.aidant, usager=usager) usager.save() if not usager.preferred_username and user_info.get( "preferred_username"): usager.preferred_username = user_info.get("preferred_username") usager.save() return usager, None except Usager.DoesNotExist: kwargs = { "given_name": user_info.get("given_name"), "family_name": user_info.get("family_name"), "birthdate": user_info.get("birthdate"), "gender": user_info.get("gender"), "birthplace": user_info.get("birthplace"), "birthcountry": user_info.get("birthcountry"), "preferred_username": user_info.get("preferred_username"), "sub": usager_sub, "email": user_info.get("email"), } if user_phone is not None: kwargs["phone"] = user_phone try: usager = Usager.objects.create(**kwargs) return usager, None except IntegrityError as e: log.error("Error happened in Recap") log.error(e) return None, f"The FranceConnect ID is not complete: {e}"