Skip to content

Commit ac60448

Browse files
committed
feat: acr can be used to force identity with IAL=2
1 parent bc4c527 commit ac60448

File tree

18 files changed

+467
-40
lines changed

18 files changed

+467
-40
lines changed

.github/workflows/end-to-end.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
- signin_from_standard_client
5151
- signin_with_email_verification_renewal
5252
- signin_with_magic_link
53+
- signin_with_right_acr
5354
- signin_with_totp
5455
- signup_entreprise_unipersonnelle
5556
- update_personal_information
@@ -95,6 +96,19 @@ jobs:
9596
MCP_PROVIDER: ${{ env.MONCOMPTEPRO_HOST }}
9697
MCP_SCOPES: openid email profile phone organizations
9798
STYLESHEET_URL: ""
99+
moncomptepro-acr-client:
100+
image: ghcr.io/numerique-gouv/moncomptepro-test-client
101+
ports:
102+
- 4003:3000
103+
env:
104+
SITE_TITLE: moncomptepro-acr-client
105+
HOST: http://localhost:4003
106+
MCP_CLIENT_ID: acr_client_id
107+
MCP_CLIENT_SECRET: acr_client_secret
108+
MCP_PROVIDER: ${{ env.MONCOMPTEPRO_HOST }}
109+
MCP_SCOPES: openid email profile organization
110+
ACR_VALUE_FOR_2FA: urn:dinum:ac:classes:consistency-checked
111+
STYLESHEET_URL: ""
98112
redis:
99113
image: redis:7.2
100114
ports:

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,21 @@ d’usurpations d’identités liés aux attaques par _phishing_ par exemple.
155155

156156
Vous pouvez tester la cinématique via le lien suivant : https://test.moncomptepro.beta.gouv.fr/#force-2fa
157157

158-
Pour ce faire, vous devez passer les paramètres `claims={"id_token":{"acr":{"essential":true,value:"https://refeds.org/profile/mfa"}}}` comme suit :
158+
Pour ce faire, vous devez passer les paramètres `claims={"id_token":{"acr":{"essential":true,value:"urn:dinum:ac:classes:consistency-checked-2fa"}}}` comme suit :
159159

160160
https://app-sandbox.moncomptepro.beta.gouv.fr/oauth/authorize?client_id=client_id&scope=openid%20email%20profile%20organization&response_type=code&redirect_uri=https%3A%2F%2Ftest.moncomptepro.beta.gouv.fr%2Flogin-callback&claims=%7B%22id_token%22%3A%7B%22acr%22%3A%7B%22essential%22%3Atrue%2C%22value%22%3A%22https%3A%2F%2Frefeds.org%2Fprofile%2Fmfa%22%7D%7D%7D
161161

162162
Les valeurs `acr` utilisées par ProConnect Identité sont les suivantes :
163163

164-
- `eidas1` authentification simple facteur avec une identité de niveau faible.
165-
- `https://refeds.org/profile/mfa` authentification par double facteur sans preuve d’identité particulière.
164+
- `eidas1` authentification simple facteur avec une identité de niveau faible ;
165+
- `urn:dinum:ac:classes:self-asserted` : identité déclarative ;
166+
- `urn:dinum:ac:classes:self-asserted-2fa` : identité déclarative ;
167+
- `urn:dinum:ac:classes:consistency-checked` : identité déclarative + un des tests de cohérence suivant :
168+
- contrôle du référencement du nom de domaine
169+
- code à usage unique envoyé par courrier postal au siège social
170+
- code à usage unique envoyé par email à l'adresse de contact référencée dans un annuaire de référence
171+
- identité du dirigeant d'association conforme
172+
- `urn:dinum:ac:classes:consistency-checked-2fa` : `urn:dinum:ac:classes:consistency-checked` + authentification à double facteur
166173

167174
## 3. 👋 Contribuer à ProConnect Identité
168175

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DO_NOT_SEND_MAIL="True"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
INSERT INTO users
2+
(id, email, email_verified, email_verified_at, encrypted_password, created_at, updated_at,
3+
given_name, family_name, phone_number, job, encrypted_totp_key, totp_key_verified_at, force_2fa)
4+
VALUES
5+
(1, 'ial2-aal2@yopmail.com', true, CURRENT_TIMESTAMP,
6+
'$2a$10$kzY3LINL6..50Fy9shWCcuNlRfYq0ft5lS.KCcJ5PzrhlWfKK4NIO', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
7+
'Jean', 'IAL2 AAL2', '0123456789', 'Sbire',
8+
'kuOSXGk68H2B3pYnph0uyXAHrmpbWaWyX/iX49xVaUc=.VMPBZSO+eAng7mjS.cI2kRY9rwhXchcKiiaMZIg==',
9+
CURRENT_TIMESTAMP, false
10+
),
11+
(2, 'ial1-aal2@yopmail.com', true, CURRENT_TIMESTAMP,
12+
'$2a$10$kzY3LINL6..50Fy9shWCcuNlRfYq0ft5lS.KCcJ5PzrhlWfKK4NIO', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
13+
'Jean', 'IAL1 AAL2', '0123456789', 'Sbire',
14+
'kuOSXGk68H2B3pYnph0uyXAHrmpbWaWyX/iX49xVaUc=.VMPBZSO+eAng7mjS.cI2kRY9rwhXchcKiiaMZIg==',
15+
CURRENT_TIMESTAMP, false
16+
),
17+
(3, 'ial2-aal1@yopmail.com', true, CURRENT_TIMESTAMP,
18+
'$2a$10$kzY3LINL6..50Fy9shWCcuNlRfYq0ft5lS.KCcJ5PzrhlWfKK4NIO', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
19+
'Jean', 'IAL2 AAL1', '0123456789', 'Sbire',
20+
null, null, false),
21+
(4, 'ial1-aal1@yopmail.com', true, CURRENT_TIMESTAMP,
22+
'$2a$10$kzY3LINL6..50Fy9shWCcuNlRfYq0ft5lS.KCcJ5PzrhlWfKK4NIO', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
23+
'Jean', 'IAL1 AAL1', '0123456789', 'Sbire',
24+
null, null, false);
25+
26+
INSERT INTO organizations
27+
(id, siret, created_at, updated_at)
28+
VALUES
29+
(1, '21340126800130', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
30+
31+
INSERT INTO users_organizations
32+
(user_id, organization_id, is_external, verification_type, has_been_greeted)
33+
VALUES
34+
(1, 1, false, 'domain', true),
35+
(2, 1, false, null, true),
36+
(3, 1, false, 'domain', true),
37+
(4, 1, false, null, true);
38+
39+
INSERT INTO oidc_clients
40+
(client_name, client_id, client_secret, redirect_uris,
41+
post_logout_redirect_uris, scope, client_uri, client_description,
42+
userinfo_signed_response_alg, id_token_signed_response_alg,
43+
authorization_signed_response_alg, introspection_signed_response_alg)
44+
VALUES
45+
('Oidc Test Client',
46+
'acr_client_id',
47+
'acr_client_secret',
48+
ARRAY [
49+
'http://localhost:4003/login-callback'
50+
],
51+
ARRAY [
52+
'http://localhost:4003/'
53+
],
54+
'openid email profile organization',
55+
'http://localhost:4003/',
56+
'MonComptePro test client. More info: https://github.com/numerique-gouv/moncomptepro-test-client.',
57+
null, 'RS256', null, null);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
3+
describe("sign-in with a client requiring consistency-checked identity", () => {
4+
it("should sign-in an return the right acr value", function () {
5+
cy.visit("http://localhost:4003");
6+
cy.get("button#force-2fa").click();
7+
8+
cy.login("ial2-aal1@yopmail.com");
9+
10+
cy.contains('"acr": "urn:dinum:ac:classes:consistency-checked"');
11+
});
12+
it("should return an error with ial1", function () {
13+
cy.visit("http://localhost:4003");
14+
cy.get("button#force-2fa").click();
15+
16+
cy.login("ial1-aal1@yopmail.com");
17+
18+
cy.contains("access_denied (none of the requested ACRs could be obtained)");
19+
});
20+
21+
// TODO add tests:
22+
// - log with a client requiring consistency-checked and consistency-checked-mfa
23+
// - with a consistency checked user and MFA => see the right acr returned
24+
// - with a self-asserted user and MFA => see an error
25+
// - log with a client not requiring any acr
26+
// - with a self-asserted user => see acr self-asserted
27+
// - with a consistency checked user => see acr consistency-checked
28+
// - log with acr_values=eidas1 and ENABLE_FIXED_ACR=True
29+
// - with all type of acr => see the right acr
30+
// these tests required the mcp-test-client to be modifiable like fc-mock
31+
});

cypress/e2e/signin_with_totp/index.cy.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ describe("sign-in with TOTP on untrusted browser", () => {
1414

1515
cy.login("unused2@yopmail.com");
1616

17-
cy.contains("Vérifier votre email");
17+
// TODO get browser enrollment code
18+
19+
cy.contains("moncomptepro-standard-client");
1820
});
1921

2022
it("should sign-in with password and TOTP when forced by SP", function () {
@@ -26,6 +28,25 @@ describe("sign-in with TOTP on untrusted browser", () => {
2628
cy.contains('"amr": [\n "pwd",\n "totp",\n "mfa"\n ],');
2729
});
2830

31+
it("should only show totp step when already logged", function () {
32+
cy.visit("http://localhost:4000");
33+
cy.get("button.proconnect-button").click();
34+
35+
cy.login("unused2@yopmail.com");
36+
37+
// TODO get browser enrollment code
38+
39+
cy.contains("moncomptepro-standard-client");
40+
41+
cy.get("button#force-2fa").click();
42+
43+
cy.contains("merci de valider votre deuxième étape de connexion");
44+
45+
cy.fillTotpFields();
46+
47+
cy.contains('"amr": [\n "pwd",\n "totp",\n "mfa"\n ],');
48+
});
49+
2950
it("should trigger totp rate limiting", function () {
3051
cy.visit("/users/start-sign-in");
3152

docker-compose.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ services:
6767
STYLESHEET_URL:
6868
network_mode: "host"
6969

70+
moncomptepro-acr-client:
71+
image: ghcr.io/numerique-gouv/moncomptepro-test-client
72+
environment:
73+
PORT: 4003
74+
SITE_TITLE: moncomptepro-acr-client
75+
HOST: http://localhost:4003
76+
MCP_CLIENT_ID: acr_client_id
77+
MCP_CLIENT_SECRET: acr_client_secret
78+
MCP_PROVIDER: http://localhost:3000
79+
MCP_SCOPES: openid email profile organization
80+
ACR_VALUE_FOR_2FA: urn:dinum:ac:classes:consistency-checked
81+
STYLESHEET_URL:
82+
network_mode: "host"
83+
7084
maildev:
7185
image: soulteary/maildev
7286
network_mode: "host"

src/config/env.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export const {
2828
ACCESS_LOG_PATH,
2929
API_AUTH_PASSWORD,
3030
API_AUTH_USERNAME,
31+
ACR_VALUE_FOR_IAL1_AAL1,
32+
ACR_VALUE_FOR_IAL1_AAL2,
33+
ACR_VALUE_FOR_IAL2_AAL1,
34+
ACR_VALUE_FOR_IAL2_AAL2,
3135
BREVO_API_KEY,
3236
CRISP_BASE_URL,
3337
CRISP_IDENTIFIER,

src/config/env.zod.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ export const secretEnvSchema = z.object({
5252

5353
export const paramsEnvSchema = z.object({
5454
ACCESS_LOG_PATH: z.string().optional(),
55+
ACR_VALUE_FOR_IAL1_AAL1: z
56+
.string()
57+
.default("urn:dinum:ac:classes:self-asserted"),
58+
ACR_VALUE_FOR_IAL1_AAL2: z
59+
.string()
60+
.default("urn:dinum:ac:classes:self-asserted-2fa"),
61+
ACR_VALUE_FOR_IAL2_AAL1: z
62+
.string()
63+
.default("urn:dinum:ac:classes:consistency-checked"),
64+
ACR_VALUE_FOR_IAL2_AAL2: z
65+
.string()
66+
.default("urn:dinum:ac:classes:consistency-checked-2fa"),
5567
DEPLOY_ENV: z.enum(["preview", "production", "sandbox"]).default("preview"),
5668
DIRTY_DS_REDIRECTION_URL: z
5769
.string()

src/config/oidc-provider-configuration.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import epochTime from "../services/epoch-time";
55
import { findAccount } from "../services/oidc-account-adapter";
66
import policy from "../services/oidc-policy";
77
import { renderWithEjsLayout } from "../services/renderer";
8+
import {
9+
ACR_VALUE_FOR_IAL1_AAL1,
10+
ACR_VALUE_FOR_IAL1_AAL2,
11+
ACR_VALUE_FOR_IAL2_AAL1,
12+
ACR_VALUE_FOR_IAL2_AAL2,
13+
} from "./env";
814

915
//
1016

@@ -13,7 +19,13 @@ export const oidcProviderConfiguration = ({
1319
shortTokenTtlInSeconds = 10 * 60,
1420
tokenTtlInSeconds = 60 * 60,
1521
}): Configuration => ({
16-
acrValues: ["eidas1", "https://refeds.org/profile/mfa"],
22+
acrValues: [
23+
"eidas1",
24+
ACR_VALUE_FOR_IAL1_AAL1,
25+
ACR_VALUE_FOR_IAL1_AAL2,
26+
ACR_VALUE_FOR_IAL2_AAL1,
27+
ACR_VALUE_FOR_IAL2_AAL2,
28+
],
1729
claims: {
1830
amr: null,
1931
// claims definitions can be found here: https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims

0 commit comments

Comments
 (0)