Skip to content

Commit

Permalink
feat(user): add certification routes
Browse files Browse the repository at this point in the history
  • Loading branch information
douglasduteil committed Feb 4, 2025
1 parent 0799802 commit 6649afd
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 1 deletion.
1 change: 1 addition & 0 deletions cypress/e2e/signin_with_certification_dirigeant/env.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DO_NOT_SEND_MAIL="True"
36 changes: 36 additions & 0 deletions cypress/e2e/signin_with_certification_dirigeant/fixtures.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
INSERT INTO users
(id, email, email_verified, email_verified_at, encrypted_password, created_at, updated_at,
given_name, family_name, phone_number, job, encrypted_totp_key, totp_key_verified_at, force_2fa)
VALUES
(1, '[email protected]', true, CURRENT_TIMESTAMP,
'$2a$10$kzY3LINL6..50Fy9shWCcuNlRfYq0ft5lS.KCcJ5PzrhlWfKK4NIO', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
'Jean', 'Certification', '0123456789', 'Dirigeant',
null, null, false);

INSERT INTO organizations
(id, siret, created_at, updated_at)
VALUES
(1, '21340126800130', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);

INSERT INTO users_organizations
(user_id, organization_id, is_external, verification_type, has_been_greeted)
VALUES
(1, 1, false, 'domain', true);

INSERT INTO oidc_clients
(client_name, client_id, client_secret, redirect_uris,
post_logout_redirect_uris, scope, client_uri, client_description,
userinfo_signed_response_alg, id_token_signed_response_alg,
authorization_signed_response_alg, introspection_signed_response_alg)
VALUES
('Oidc Test Client',
'standard_client_id',
'standard_client_secret',
ARRAY [
'http://localhost:4000/login-callback'
],
ARRAY []::varchar[],
'openid email profile organization',
'http://localhost:4000/',
'ProConnect test client. More info: https://github.com/numerique-gouv/proconnect-test-client.',
null, null, null, null);
26 changes: 26 additions & 0 deletions cypress/e2e/signin_with_certification_dirigeant/index.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
describe("sign-in with a client requiring certification dirigeant", () => {
beforeEach(() => {
cy.visit("http://localhost:4000");
cy.setRequestedAcrs([
"https://proconnect.gouv.fr/assurance/certification-dirigeant",
]);
});

it("should sign-in an return the right acr value", function () {
cy.get("button#custom-connection").click({ force: true });

cy.login("[email protected]");

cy.contains("Authentifier votre statut");
cy.contains("S’identifier avec").click();

cy.contains("Vous allez vous connecter en tant que ");
cy.contains("Jacintha Froment");
cy.contains("Continuer").click();
cy.contains("Continuer").click();

cy.contains(
'"acr": "https://proconnect.gouv.fr/assurance/certification-dirigeant"',
);
});
});
90 changes: 90 additions & 0 deletions src/controllers/user/certification-dirigeant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//

import type { NextFunction, Request, Response } from "express";
import { csrfToken } from "../../middlewares/csrf-protection";

//

export async function getCertificationDirigeantController(
req: Request,
res: Response,
next: NextFunction,
) {
try {
return res.render("user/certification-dirigeant", {
csrfToken: csrfToken(req),
pageTitle: "Certification dirigeant",
});
} catch (error) {
next(error);
}
}

export async function postCertificationDirigeantController(
_req: Request,
res: Response,
next: NextFunction,
) {
try {
return res.redirect("/users/certification-dirigeant/login-as");
} catch (error) {
next(error);
}
}

//

export async function getCertificationDirigeantLoginAsController(
req: Request,
res: Response,
next: NextFunction,
) {
try {
return res.render("user/certification-dirigeant-login-as", {
csrfToken: csrfToken(req),
pageTitle: "Se connecter en tant que",
});
} catch (error) {
next(error);
}
}

export async function postCertificationDirigeantLoginAsController(
_req: Request,
res: Response,
next: NextFunction,
) {
try {
return res.redirect("/users/certification-dirigeant/representing");
} catch (error) {
next(error);
}
}

//

export async function getCertificationDirigeantRepresentingController(
req: Request,
res: Response,
next: NextFunction,
) {
try {
const userOrganizations = [
{
id: "1",
siret: "12345678901234",
cached_libelle: "Organisation 1",
cached_adresse: "123 rue de la paix",
cached_libelle_activite_principale: "Activité principale 1",
},
];
return res.render("user/select-organization", {
csrfToken: csrfToken(req),
illustration: "illu-password.svg",
pageTitle: "Choisir une organisation",
userOrganizations,
});
} catch (error) {
next(error);
}
}
22 changes: 21 additions & 1 deletion src/middlewares/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,32 @@ export const checkUserIsVerifiedMiddleware = (
}
});

export const checkUserHasPersonalInformationsMiddleware = (
export const checkUserNeedCertificationDirigeantMiddleware = (
req: Request,
res: Response,
next: NextFunction,
) =>
checkUserIsVerifiedMiddleware(req, res, async (error) => {
try {
if (error) return next(error);

console.log("Loooooooooool");
console.trace();

if (1) return res.redirect("/users/certification-dirigeant");

return next();
} catch (error) {
next(error);
}
});

export const checkUserHasPersonalInformationsMiddleware = (
req: Request,
res: Response,
next: NextFunction,
) =>
checkUserNeedCertificationDirigeantMiddleware(req, res, async (error) => {
try {
if (error) return next(error);

Expand Down
42 changes: 42 additions & 0 deletions src/routers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import {
} from "../controllers/organization";
import { postSignInWithAuthenticatorAppController } from "../controllers/totp";
import { get2faSignInController } from "../controllers/user/2fa-sign-in";
import {
getCertificationDirigeantController,
getCertificationDirigeantLoginAsController,
getCertificationDirigeantRepresentingController,
postCertificationDirigeantController,
postCertificationDirigeantLoginAsController,
} from "../controllers/user/certification-dirigeant";
import { postDeleteUserController } from "../controllers/user/delete";
import { postCancelModerationAndRedirectControllerFactory } from "../controllers/user/edit-moderation";
import { issueSessionOrRedirectController } from "../controllers/user/issue-session-or-redirect";
Expand Down Expand Up @@ -418,6 +425,41 @@ export const userRouter = () => {
postDeleteUserController,
);

userRouter.get(
"/certification-dirigeant",
rateLimiterMiddleware,
csrfProtectionMiddleware,
getCertificationDirigeantController,
);

userRouter.post(
"/certification-dirigeant",
rateLimiterMiddleware,
csrfProtectionMiddleware,
postCertificationDirigeantController,
);

userRouter.get(
"/certification-dirigeant/login-as",
rateLimiterMiddleware,
csrfProtectionMiddleware,
getCertificationDirigeantLoginAsController,
);

userRouter.post(
"/certification-dirigeant/login-as",
rateLimiterMiddleware,
csrfProtectionMiddleware,
postCertificationDirigeantLoginAsController,
);

userRouter.get(
"/certification-dirigeant/representing",
rateLimiterMiddleware,
csrfProtectionMiddleware,
getCertificationDirigeantRepresentingController,
);

return userRouter;
};

Expand Down
24 changes: 24 additions & 0 deletions src/views/user/certification-dirigeant-login-as.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div>
<h2 class="fr-h2">Vous allez vous connecter en tant que :</h2>
<center>
<h1 class="fr-h3 blue-france">Jacintha Froment</h1>
</center>

<form action="/users/certification-dirigeant/login-as" method="post">
<input type="hidden" name="_csrf" value="<%= csrfToken; %>" />

<fieldset class="fr-fieldset" aria-labelledby="agreement">
<div class="fr-fieldset__element">
<div class="fr-checkbox-group">
<input name="agreement" id="agreement" type="checkbox" />
<label class="fr-label" for="agreement">
J'accepte que FranceConnect transmette mes données au service pour
me connecter
</label>
</div>
</div>
</fieldset>

<button class="fr-btn" type="submit">Continuer</button>
</form>
</div>
28 changes: 28 additions & 0 deletions src/views/user/certification-dirigeant.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div>
<h1 class="fr-h3">Authentifier votre statut</h1>

<p>
Vous pouvez authentifier instantanément votre statut de dirigeant grâce à
FranceConnect.
</p>

<form action="/users/certification-dirigeant" method="post">
<input type="hidden" name="_csrf" value="<%= csrfToken; %>" />

<div class="fr-connect-group">
<button class="fr-connect">
<span class="fr-connect__login">S’identifier avec</span>
<span class="fr-connect__brand">FranceConnect</span>
</button>
<p>
<a
href="https://franceconnect.gouv.fr/"
target="_blank"
rel="noopener"
title="Qu’est-ce que FranceConnect ? - nouvelle fenêtre"
>Qu’est-ce que FranceConnect ?</a
>
</p>
</div>
</form>
</div>

0 comments on commit 6649afd

Please sign in to comment.