Skip to content

Commit b831eb7

Browse files
committed
refactor(api): move route
to identity-access-management bounded context
1 parent 9167a94 commit b831eb7

File tree

7 files changed

+186
-180
lines changed

7 files changed

+186
-180
lines changed

api/lib/application/authentication/oidc/index.js

-26
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,6 @@ const register = async function (server) {
3333

3434
server.route([
3535
...adminRoutes,
36-
{
37-
method: 'POST',
38-
path: '/api/oidc/user/check-reconciliation',
39-
config: {
40-
auth: false,
41-
validate: {
42-
payload: Joi.object({
43-
data: Joi.object({
44-
attributes: Joi.object({
45-
email: Joi.string().email().required(),
46-
password: Joi.string().required(),
47-
'identity-provider': Joi.string().required(),
48-
'authentication-key': Joi.string().required(),
49-
}),
50-
type: Joi.string(),
51-
}),
52-
}),
53-
},
54-
handler: oidcController.findUserForReconciliation,
55-
notes: [
56-
"- Cette route permet d'identifier un utilisateur Pix provenant de la double mire OIDC.\n" +
57-
"- Elle renvoie un objet contenant des informations sur l'utilisateur.",
58-
],
59-
tags: ['api', 'oidc'],
60-
},
61-
},
6236
{
6337
method: 'POST',
6438
path: '/api/oidc/user/reconcile',

api/src/identity-access-management/application/oidc-provider/oidc-provider.route.js

+26
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,30 @@ export const oidcProviderRoutes = [
106106
tags: ['identity-access-management', 'api', 'oidc'],
107107
},
108108
},
109+
{
110+
method: 'POST',
111+
path: '/api/oidc/user/check-reconciliation',
112+
config: {
113+
auth: false,
114+
validate: {
115+
payload: Joi.object({
116+
data: Joi.object({
117+
attributes: Joi.object({
118+
email: Joi.string().email().required(),
119+
password: Joi.string().required(),
120+
'identity-provider': Joi.string().required(),
121+
'authentication-key': Joi.string().required(),
122+
}),
123+
type: Joi.string(),
124+
}),
125+
}),
126+
},
127+
handler: (request, h) => oidcProviderController.findUserForReconciliation(request, h),
128+
notes: [
129+
"- Cette route permet d'identifier un utilisateur Pix provenant de la double mire OIDC.\n" +
130+
"- Elle renvoie un objet contenant des informations sur l'utilisateur.",
131+
],
132+
tags: ['identity-access-management', 'api', 'oidc'],
133+
},
134+
},
109135
];

api/tests/acceptance/application/authentication/oidc/check-reconciliation-route-post_test.js

-59
This file was deleted.

api/tests/identity-access-management/acceptance/application/oidc-provider.route.test.js

+53
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,57 @@ describe('Acceptance | Identity Access Management | Application | Route | oidc-p
501501
});
502502
});
503503
});
504+
505+
describe('POST /api/oidc/user/check-reconciliation', function () {
506+
context('when user has no oidc authentication method', function () {
507+
it('returns 200 HTTP status', async function () {
508+
// given
509+
const server = await createServer();
510+
databaseBuilder.factory.buildUser.withRawPassword({ email: '[email protected]', rawPassword: 'pix123' });
511+
await databaseBuilder.commit();
512+
513+
const idToken = jsonwebtoken.sign(
514+
{
515+
given_name: 'Brice',
516+
family_name: 'Glace',
517+
nonce: 'nonce',
518+
sub: 'some-user-unique-id',
519+
},
520+
'secret',
521+
);
522+
const userAuthenticationKey = await authenticationSessionService.save({
523+
sessionContent: { idToken },
524+
userInfo: {
525+
firstName: 'Brice',
526+
lastName: 'Glace',
527+
nonce: 'nonce',
528+
externalIdentityId: 'some-user-unique-id',
529+
},
530+
});
531+
532+
// when
533+
const response = await server.inject({
534+
method: 'POST',
535+
url: `/api/oidc/user/check-reconciliation`,
536+
payload: {
537+
data: {
538+
attributes: {
539+
540+
password: 'pix123',
541+
'identity-provider': 'OIDC_EXAMPLE_NET',
542+
'authentication-key': userAuthenticationKey,
543+
},
544+
},
545+
},
546+
});
547+
548+
// then
549+
expect(response.statusCode).to.equal(200);
550+
expect(response.result.data.attributes['full-name-from-pix']).to.exist;
551+
expect(response.result.data.attributes['full-name-from-external-identity-provider']).to.exist;
552+
expect(response.result.data.attributes['email']).to.exist;
553+
expect(response.result.data.attributes['authentication-methods']).to.exist;
554+
});
555+
});
556+
});
504557
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
AuthenticationKeyExpired,
3+
DifferentExternalIdentifierError,
4+
UserNotFoundError,
5+
} from '../../../../lib/domain/errors.js';
6+
import { oidcProviderController } from '../../../../src/identity-access-management/application/oidc-provider/oidc-provider.controller.js';
7+
import { identityAccessManagementRoutes } from '../../../../src/identity-access-management/application/routes.js';
8+
import { expect, HttpTestServer, sinon } from '../../../test-helper.js';
9+
10+
const routesUnderTest = identityAccessManagementRoutes[0];
11+
12+
describe('Integration | Identity Access Management | Application | Route | oidc-provider', function () {
13+
let httpTestServer;
14+
15+
beforeEach(async function () {
16+
httpTestServer = new HttpTestServer();
17+
httpTestServer.setupDeserialization();
18+
await httpTestServer.register(routesUnderTest);
19+
});
20+
21+
describe('POST /api/oidc/user/check-reconciliation', function () {
22+
context('error cases', function () {
23+
context('when user is not found', function () {
24+
it('returns a response with HTTP status code 404', async function () {
25+
// given
26+
sinon.stub(oidcProviderController, 'findUserForReconciliation').rejects(new UserNotFoundError());
27+
28+
// when
29+
const response = await httpTestServer.request('POST', '/api/oidc/user/check-reconciliation', {
30+
data: {
31+
attributes: {
32+
33+
password: 'pix123',
34+
'identity-provider': 'POLE_EMPLOI',
35+
'authentication-key': '123abc',
36+
},
37+
},
38+
});
39+
40+
// then
41+
expect(response.statusCode).to.equal(404);
42+
expect(response.result.errors[0].detail).to.equal('Ce compte est introuvable.');
43+
});
44+
});
45+
46+
context('when authentication key expired', function () {
47+
it('returns a response with HTTP status code 401', async function () {
48+
// given
49+
sinon.stub(oidcProviderController, 'findUserForReconciliation').rejects(new AuthenticationKeyExpired());
50+
51+
// when
52+
const response = await httpTestServer.request('POST', '/api/oidc/user/check-reconciliation', {
53+
data: {
54+
attributes: {
55+
56+
password: 'pix123',
57+
'identity-provider': 'POLE_EMPLOI',
58+
'authentication-key': '123abc',
59+
},
60+
},
61+
});
62+
63+
// then
64+
expect(response.statusCode).to.equal(401);
65+
expect(response.result.errors[0].detail).to.equal('This authentication key has expired.');
66+
});
67+
});
68+
69+
context('when external identity id and external identifier are different', function () {
70+
it('returns a response with HTTP status code 412', async function () {
71+
// given
72+
sinon
73+
.stub(oidcProviderController, 'findUserForReconciliation')
74+
.rejects(new DifferentExternalIdentifierError());
75+
76+
// when
77+
const response = await httpTestServer.request('POST', '/api/oidc/user/check-reconciliation', {
78+
data: {
79+
attributes: {
80+
81+
password: 'pix123',
82+
'identity-provider': 'POLE_EMPLOI',
83+
'authentication-key': '123abc',
84+
},
85+
},
86+
});
87+
88+
// then
89+
expect(response.statusCode).to.equal(409);
90+
expect(response.result.errors[0].detail).to.equal(
91+
"La valeur de l'externalIdentifier de la méthode de connexion ne correspond pas à celui reçu par le partenaire.",
92+
);
93+
});
94+
});
95+
});
96+
});
97+
});

api/tests/integration/application/authentication/oidc/index_test.js

-95
This file was deleted.

api/tests/tooling/server/http-test-server.js

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Hapi from '@hapi/hapi';
33
import { setupErrorHandling } from '../../../config/server-setup-error-handling.js';
44
import { authentication } from '../../../lib/infrastructure/authentication.js';
55
import { handleFailAction } from '../../../lib/validate.js';
6+
import { deserializer } from '../../../src/shared/infrastructure/serializers/jsonapi/deserializer.js';
67

78
const routesConfig = {
89
routes: {
@@ -56,6 +57,15 @@ class HttpTestServer {
5657
);
5758
this.hapiServer.auth.default(authentication.defaultStrategy);
5859
}
60+
61+
setupDeserialization() {
62+
this.hapiServer.ext('onPreHandler', async (request, h) => {
63+
if (request.payload?.data) {
64+
request.deserializedPayload = await deserializer.deserialize(request.payload);
65+
}
66+
return h.continue;
67+
});
68+
}
5969
}
6070

6171
export { HttpTestServer };

0 commit comments

Comments
 (0)