Skip to content

Commit

Permalink
Merge branch 'master' into IOPLT-410_upgrade_appinsights_sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
gquadrati authored Apr 12, 2024
2 parents ff4de4b + fd6878f commit 2dad97c
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 15 deletions.
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [v13.3.0](https://github.com/pagopa/io-spid-commons/compare/v13.2.2...v13.3.0)
#### [v13.4.0](https://github.com/pagopa/io-spid-commons/compare/v13.3.0...v13.4.0)

- [#IOPID-1612, #IOPID-1513] SAMLResponse missing errorMessage [`#156`](https://github.com/pagopa/io-spid-commons/pull/156)

#### [v13.3.0](https://github.com/pagopa/io-spid-commons/compare/v13.3.0-RELEASE...v13.3.0)

> 1 December 2023
#### [v13.3.0-RELEASE](https://github.com/pagopa/io-spid-commons/compare/v13.2.2...v13.3.0-RELEASE)

> 1 December 2023
- [#IOPID-1156] Include additional params in doneCb, if any [`#153`](https://github.com/pagopa/io-spid-commons/pull/153)
- Bump version to 13.3.0 [skip ci] [`0918ab0`](https://github.com/pagopa/io-spid-commons/commit/0918ab0e7afe5e76ac9f4a3dd609f71444e34e4a)

#### [v13.2.2](https://github.com/pagopa/io-spid-commons/compare/v13.2.2-RELEASE...v13.2.2)

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pagopa/io-spid-commons",
"version": "13.3.0",
"version": "13.4.0",
"description": "Common code for integrating SPID authentication",
"repository": {
"type": "git",
Expand Down
97 changes: 85 additions & 12 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ import {
IApplicationConfig,
IServiceProviderConfig,
SamlConfig,
withSpid
withSpid,
} from "../";
import { DOMParser } from "@xmldom/xmldom";
import { IDPEntityDescriptor } from "../types/IDPEntityDescriptor";
import * as metadata from "../utils/metadata";
import { getSpidStrategyOption } from "../utils/middleware";
import { ERROR_SAML_RESPONSE_MISSING } from "../utils/samlUtils";

import {
mockCIEIdpMetadata,
mockCIETestIdpMetadata,
mockIdpMetadata,
mockTestenvIdpMetadata
mockTestenvIdpMetadata,
} from "../__mocks__/metadata";

const mockFetchIdpsMetadata = jest.spyOn(metadata, "fetchIdpsMetadata");
Expand Down Expand Up @@ -100,7 +102,7 @@ const appConfig: IApplicationConfig = {
loginPath: expectedLoginPath,
metadataPath,
sloPath: expectedSloPath,
spidLevelsWhitelist: ["SpidL2", "SpidL3"]
spidLevelsWhitelist: ["SpidL2", "SpidL3"],
};

const samlConfig: SamlConfig = {
Expand All @@ -114,15 +116,15 @@ const samlConfig: SamlConfig = {
issuer: "https://spid.agid.gov.it/cd",
logoutCallbackUrl: "http://localhost:3000/slo",
privateCert: samlKey,
validateInResponseTo: true
validateInResponseTo: true,
};

const serviceProviderConfig: IServiceProviderConfig = {
IDPMetadataUrl,
organization: {
URL: "https://example.com",
displayName: "Organization display name",
name: "Organization name"
name: "Organization name",
},
publicCert: samlCert,
requiredAttributes: {
Expand All @@ -132,16 +134,16 @@ const serviceProviderConfig: IServiceProviderConfig = {
"name",
"familyName",
"fiscalNumber",
"mobilePhone"
"mobilePhone",
],
name: "Required attrs"
name: "Required attrs",
},
spidCieUrl,
spidCieTestUrl,
spidTestEnvUrl,
strictResponseValidation: {
"http://localhost:8080": true
}
"http://localhost:8080": true,
},
};

const mockRedisClient = {} as RedisClientType;
Expand Down Expand Up @@ -186,7 +188,7 @@ describe("io-spid-commons withSpid", () => {
acs: async () =>
ResponsePermanentRedirect({ href: "/success?acs" } as ValidUrl),
logout: async () =>
ResponsePermanentRedirect({ href: "/success?logout" } as ValidUrl)
ResponsePermanentRedirect({ href: "/success?logout" } as ValidUrl),
})();
expect(mockFetchIdpsMetadata).toBeCalledTimes(4);
const emptySpidStrategyOption = getSpidStrategyOption(spid.app);
Expand Down Expand Up @@ -221,7 +223,7 @@ describe("io-spid-commons withSpid", () => {
...mockIdpMetadata,
...mockCIEIdpMetadata,
...mockCIETestIdpMetadata,
...mockTestenvIdpMetadata
...mockTestenvIdpMetadata,
});
});
it("should reject blacklisted spid levels", async () => {
Expand All @@ -236,10 +238,81 @@ describe("io-spid-commons withSpid", () => {
acs: async () =>
ResponsePermanentRedirect({ href: "/success?acs" } as ValidUrl),
logout: async () =>
ResponsePermanentRedirect({ href: "/success?logout" } as ValidUrl)
ResponsePermanentRedirect({ href: "/success?logout" } as ValidUrl),
})();
return request(spid.app)
.get(`${appConfig.loginPath}?authLevel=SpidL1`)
.expect(400);
});
});

describe("Custom errors", () => {
beforeEach(() => {
initMockFetchIDPMetadata();
});

it("during acs it should redirect to error if the request body is empty", async () => {
const app = express();
const spid = await withSpid({
appConfig,
samlConfig,
serviceProviderConfig,
redisClient: mockRedisClient as any,
app,
acs: async () =>
ResponsePermanentRedirect({ href: "/success?acs" } as ValidUrl),
logout: async () =>
ResponsePermanentRedirect({ href: "/success?logout" } as ValidUrl),
})();
const result = await request(spid.app)
.post(`${appConfig.assertionConsumerServicePath}`)
.set("Content-Type", "application/json")
.expect(302);

if (result.error !== false) fail();
expect(result.headers.location).toEqual(
expect.stringContaining(
`errorMessage=${encodeURI(ERROR_SAML_RESPONSE_MISSING)}`
)
);
});

it.each`
title | SAMLResponse
${"undefined"} | ${undefined}
${"null"} | ${null}
${"empty string"} | ${""}
`(
"during acs it should redirect to error if SAMLResponse is $title",
async ({ SAMLResponse }) => {
const app = express();
// needed to let app parse json body
app.use(express.json());
const spid = await withSpid({
appConfig,
samlConfig,
serviceProviderConfig,
redisClient: mockRedisClient as any,
app,
acs: async () =>
ResponsePermanentRedirect({ href: "/success?acs" } as ValidUrl),
logout: async () =>
ResponsePermanentRedirect({ href: "/success?logout" } as ValidUrl),
})();
const result = await request(spid.app)
.post(`${appConfig.assertionConsumerServicePath}`)
.set("Content-Type", "application/json")
.send({
SAMLResponse,
})
.expect(302);

if (result.error !== false) fail();
expect(result.headers.location).toEqual(
expect.stringContaining(
`errorMessage=${encodeURI(ERROR_SAML_RESPONSE_MISSING)}`
)
);
}
);
});
15 changes: 14 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
getXmlFromSamlResponse,
} from "./utils/saml";
import { getMetadataTamperer } from "./utils/saml";
import { ERROR_SAML_RESPONSE_MISSING } from "./utils/samlUtils";

// assertion consumer service express handler
export type AssertionConsumerServiceT<T extends Record<string, unknown>> = (
Expand Down Expand Up @@ -132,8 +133,20 @@ export const withSpidAuthMiddleware =
res: express.Response,
next: express.NextFunction
): void => {
const maybeDoc = getXmlFromSamlResponse(req.body);
// in case the SAMLResponse is missing
// we redirect the user to a specific error
if (O.isNone(maybeDoc)) {
logger.error(
"Spid Authentication|Authentication Error|ERROR=%s|ISSUER=UNKNOWN",
ERROR_SAML_RESPONSE_MISSING
);
return res.redirect(
clientErrorRedirectionUrl +
`?errorMessage=${ERROR_SAML_RESPONSE_MISSING}`
);
}
passport.authenticate("spid", async (err: unknown, user: unknown) => {
const maybeDoc = getXmlFromSamlResponse(req.body);
const issuer = pipe(
maybeDoc,
O.chain(getSamlIssuer),
Expand Down
1 change: 1 addition & 0 deletions src/utils/samlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const cleanCert = (cert: string): string =>
.replace(/-+END CERTIFICATE-+\r?\n?/, "")
.replace(/\r\n/g, "\n");

export const ERROR_SAML_RESPONSE_MISSING = "Missing SAMLResponse in ACS";
const SAMLResponse = t.type({
SAMLResponse: t.string,
});
Expand Down

0 comments on commit 2dad97c

Please sign in to comment.