예제 #1
0
 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)
예제 #2
0
 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)
예제 #3
0
 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,
     )
예제 #4
0
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"))
예제 #5
0
 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",
     )
예제 #6
0
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}"
예제 #7
0
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
예제 #8
0
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}"