This commit is contained in:
Siwat Sirichai 2024-05-03 16:11:08 +07:00
parent 029fe23657
commit 1876580d86
911 changed files with 160008 additions and 2 deletions

View file

@ -0,0 +1,5 @@
/// <reference types="node" />
import * as crypto from "crypto";
export declare function getSigningAlgorithm(shortName?: string): string;
export declare function getDigestAlgorithm(shortName?: string): string;
export declare function getSigner(shortName?: string): crypto.Signer;

41
node_modules/passport-saml/lib/node-saml/algorithms.js generated vendored Normal file
View file

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSigner = exports.getDigestAlgorithm = exports.getSigningAlgorithm = void 0;
const crypto = require("crypto");
function getSigningAlgorithm(shortName) {
switch (shortName) {
case "sha256":
return "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
case "sha512":
return "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
case "sha1":
default:
return "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
}
}
exports.getSigningAlgorithm = getSigningAlgorithm;
function getDigestAlgorithm(shortName) {
switch (shortName) {
case "sha256":
return "http://www.w3.org/2001/04/xmlenc#sha256";
case "sha512":
return "http://www.w3.org/2001/04/xmlenc#sha512";
case "sha1":
default:
return "http://www.w3.org/2000/09/xmldsig#sha1";
}
}
exports.getDigestAlgorithm = getDigestAlgorithm;
function getSigner(shortName) {
switch (shortName) {
case "sha256":
return crypto.createSign("RSA-SHA256");
case "sha512":
return crypto.createSign("RSA-SHA512");
case "sha1":
default:
return crypto.createSign("RSA-SHA1");
}
}
exports.getSigner = getSigner;
//# sourceMappingURL=algorithms.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"algorithms.js","sourceRoot":"","sources":["../../src/node-saml/algorithms.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AAEjC,SAAgB,mBAAmB,CAAC,SAAkB;IACpD,QAAQ,SAAS,EAAE;QACjB,KAAK,QAAQ;YACX,OAAO,mDAAmD,CAAC;QAC7D,KAAK,QAAQ;YACX,OAAO,mDAAmD,CAAC;QAC7D,KAAK,MAAM,CAAC;QACZ;YACE,OAAO,4CAA4C,CAAC;KACvD;AACH,CAAC;AAVD,kDAUC;AAED,SAAgB,kBAAkB,CAAC,SAAkB;IACnD,QAAQ,SAAS,EAAE;QACjB,KAAK,QAAQ;YACX,OAAO,yCAAyC,CAAC;QACnD,KAAK,QAAQ;YACX,OAAO,yCAAyC,CAAC;QACnD,KAAK,MAAM,CAAC;QACZ;YACE,OAAO,wCAAwC,CAAC;KACnD;AACH,CAAC;AAVD,gDAUC;AAED,SAAgB,SAAS,CAAC,SAAkB;IAC1C,QAAQ,SAAS,EAAE;QACjB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC,KAAK,MAAM,CAAC;QACZ;YACE,OAAO,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;KACxC;AACH,CAAC;AAVD,8BAUC","sourcesContent":["import * as crypto from \"crypto\";\n\nexport function getSigningAlgorithm(shortName?: string): string {\n switch (shortName) {\n case \"sha256\":\n return \"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\";\n case \"sha512\":\n return \"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512\";\n case \"sha1\":\n default:\n return \"http://www.w3.org/2000/09/xmldsig#rsa-sha1\";\n }\n}\n\nexport function getDigestAlgorithm(shortName?: string): string {\n switch (shortName) {\n case \"sha256\":\n return \"http://www.w3.org/2001/04/xmlenc#sha256\";\n case \"sha512\":\n return \"http://www.w3.org/2001/04/xmlenc#sha512\";\n case \"sha1\":\n default:\n return \"http://www.w3.org/2000/09/xmldsig#sha1\";\n }\n}\n\nexport function getSigner(shortName?: string): crypto.Signer {\n switch (shortName) {\n case \"sha256\":\n return crypto.createSign(\"RSA-SHA256\");\n case \"sha512\":\n return crypto.createSign(\"RSA-SHA512\");\n case \"sha1\":\n default:\n return crypto.createSign(\"RSA-SHA1\");\n }\n}\n"]}

3
node_modules/passport-saml/lib/node-saml/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,3 @@
import type { CacheItem, CacheProvider } from "./inmemory-cache-provider";
import { SAML } from "./saml";
export { SAML, CacheItem, CacheProvider };

6
node_modules/passport-saml/lib/node-saml/index.js generated vendored Normal file
View file

@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SAML = void 0;
const saml_1 = require("./saml");
Object.defineProperty(exports, "SAML", { enumerable: true, get: function () { return saml_1.SAML; } });
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node-saml/index.ts"],"names":[],"mappings":";;;AACA,iCAA8B;AAErB,qFAFA,WAAI,OAEA","sourcesContent":["import type { CacheItem, CacheProvider } from \"./inmemory-cache-provider\";\nimport { SAML } from \"./saml\";\n\nexport { SAML, CacheItem, CacheProvider };\n"]}

View file

@ -0,0 +1,45 @@
/**
* Simple in memory cache provider. To be used to store state of requests that needs
* to be validated/checked when a response is received.
*
* This is the default implementation of a cache provider used by Passport-SAML. For
* multiple server instances/load balanced scenarios (I.e. the SAML request could have
* been generated from a different server/process handling the SAML response) this
* implementation will NOT be sufficient.
*
* The caller should provide their own implementation for a cache provider as defined
* in the config options for Passport-SAML.
* @param options
* @constructor
*/
export interface CacheItem {
value: string;
createdAt: number;
}
interface CacheProviderOptions {
keyExpirationPeriodMs: number;
}
export declare class CacheProvider {
cacheKeys: Record<string, CacheItem>;
options: CacheProviderOptions;
constructor(options: Partial<CacheProviderOptions>);
/**
* Store an item in the cache, using the specified key and value.
* Internally will keep track of the time the item was added to the cache
* @param id
* @param value
*/
saveAsync(key: string, value: string): Promise<CacheItem | null>;
/**
* Returns the value of the specified key in the cache
* @param id
* @returns {boolean}
*/
getAsync(key: string): Promise<string | null>;
/**
* Removes an item from the cache if it exists
* @param key
*/
removeAsync(key: string): Promise<string | null>;
}
export {};

View file

@ -0,0 +1,86 @@
"use strict";
/**
* Simple in memory cache provider. To be used to store state of requests that needs
* to be validated/checked when a response is received.
*
* This is the default implementation of a cache provider used by Passport-SAML. For
* multiple server instances/load balanced scenarios (I.e. the SAML request could have
* been generated from a different server/process handling the SAML response) this
* implementation will NOT be sufficient.
*
* The caller should provide their own implementation for a cache provider as defined
* in the config options for Passport-SAML.
* @param options
* @constructor
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheProvider = void 0;
class CacheProvider {
constructor(options) {
var _a;
this.cacheKeys = {};
this.options = {
...options,
keyExpirationPeriodMs: (_a = options === null || options === void 0 ? void 0 : options.keyExpirationPeriodMs) !== null && _a !== void 0 ? _a : 28800000,
};
// Expire old cache keys
const expirationTimer = setInterval(() => {
const nowMs = new Date().getTime();
const keys = Object.keys(this.cacheKeys);
keys.forEach((key) => {
if (nowMs >=
new Date(this.cacheKeys[key].createdAt).getTime() + this.options.keyExpirationPeriodMs) {
this.removeAsync(key);
}
});
}, this.options.keyExpirationPeriodMs);
// we only want this to run if the process is still open; it shouldn't hold the process open (issue #68)
expirationTimer.unref();
}
/**
* Store an item in the cache, using the specified key and value.
* Internally will keep track of the time the item was added to the cache
* @param id
* @param value
*/
async saveAsync(key, value) {
if (!this.cacheKeys[key]) {
this.cacheKeys[key] = {
createdAt: new Date().getTime(),
value: value,
};
return this.cacheKeys[key];
}
else {
return null;
}
}
/**
* Returns the value of the specified key in the cache
* @param id
* @returns {boolean}
*/
async getAsync(key) {
if (this.cacheKeys[key]) {
return this.cacheKeys[key].value;
}
else {
return null;
}
}
/**
* Removes an item from the cache if it exists
* @param key
*/
async removeAsync(key) {
if (this.cacheKeys[key]) {
delete this.cacheKeys[key];
return key;
}
else {
return null;
}
}
}
exports.CacheProvider = CacheProvider;
//# sourceMappingURL=inmemory-cache-provider.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"inmemory-cache-provider.js","sourceRoot":"","sources":["../../src/node-saml/inmemory-cache-provider.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAWH,MAAa,aAAa;IAIxB,YAAY,OAAsC;;QAChD,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QAEpB,IAAI,CAAC,OAAO,GAAG;YACb,GAAG,OAAO;YACV,qBAAqB,QAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,qBAAqB,mCAAI,QAAQ;SAClE,CAAC;QAEF,wBAAwB;QACxB,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACvC,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACnB,IACE,KAAK;oBACL,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,EACtF;oBACA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;iBACvB;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAEvC,wGAAwG;QACxG,eAAe,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,GAAW,EAAE,KAAa;QACxC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;YACxB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG;gBACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE;gBAC/B,KAAK,EAAE,KAAK;aACb,CAAC;YACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;SAC5B;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;YACvB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;SAClC;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,GAAW;QAC3B,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;YACvB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,GAAG,CAAC;SACZ;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;CACF;AAzED,sCAyEC","sourcesContent":["/**\n * Simple in memory cache provider. To be used to store state of requests that needs\n * to be validated/checked when a response is received.\n *\n * This is the default implementation of a cache provider used by Passport-SAML. For\n * multiple server instances/load balanced scenarios (I.e. the SAML request could have\n * been generated from a different server/process handling the SAML response) this\n * implementation will NOT be sufficient.\n *\n * The caller should provide their own implementation for a cache provider as defined\n * in the config options for Passport-SAML.\n * @param options\n * @constructor\n */\n\nexport interface CacheItem {\n value: string;\n createdAt: number;\n}\n\ninterface CacheProviderOptions {\n keyExpirationPeriodMs: number;\n}\n\nexport class CacheProvider {\n cacheKeys: Record<string, CacheItem>;\n options: CacheProviderOptions;\n\n constructor(options: Partial<CacheProviderOptions>) {\n this.cacheKeys = {};\n\n this.options = {\n ...options,\n keyExpirationPeriodMs: options?.keyExpirationPeriodMs ?? 28800000, // 8 hours,\n };\n\n // Expire old cache keys\n const expirationTimer = setInterval(() => {\n const nowMs = new Date().getTime();\n const keys = Object.keys(this.cacheKeys);\n keys.forEach((key) => {\n if (\n nowMs >=\n new Date(this.cacheKeys[key].createdAt).getTime() + this.options.keyExpirationPeriodMs\n ) {\n this.removeAsync(key);\n }\n });\n }, this.options.keyExpirationPeriodMs);\n\n // we only want this to run if the process is still open; it shouldn't hold the process open (issue #68)\n expirationTimer.unref();\n }\n\n /**\n * Store an item in the cache, using the specified key and value.\n * Internally will keep track of the time the item was added to the cache\n * @param id\n * @param value\n */\n async saveAsync(key: string, value: string): Promise<CacheItem | null> {\n if (!this.cacheKeys[key]) {\n this.cacheKeys[key] = {\n createdAt: new Date().getTime(),\n value: value,\n };\n return this.cacheKeys[key];\n } else {\n return null;\n }\n }\n\n /**\n * Returns the value of the specified key in the cache\n * @param id\n * @returns {boolean}\n */\n async getAsync(key: string): Promise<string | null> {\n if (this.cacheKeys[key]) {\n return this.cacheKeys[key].value;\n } else {\n return null;\n }\n }\n\n /**\n * Removes an item from the cache if it exists\n * @param key\n */\n async removeAsync(key: string): Promise<string | null> {\n if (this.cacheKeys[key]) {\n delete this.cacheKeys[key];\n return key;\n } else {\n return null;\n }\n }\n}\n"]}

View file

@ -0,0 +1,3 @@
import { SamlSigningOptions } from "./types";
export declare function signSamlPost(samlMessage: string, xpath: string, options: SamlSigningOptions): string;
export declare function signAuthnRequestPost(authnRequest: string, options: SamlSigningOptions): string;

View file

@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.signAuthnRequestPost = exports.signSamlPost = void 0;
const xml_1 = require("./xml");
const authnRequestXPath = '/*[local-name(.)="AuthnRequest" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
const issuerXPath = '/*[local-name(.)="Issuer" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:assertion"]';
function signSamlPost(samlMessage, xpath, options) {
return xml_1.signXml(samlMessage, xpath, { reference: xpath + issuerXPath, action: "after" }, options);
}
exports.signSamlPost = signSamlPost;
function signAuthnRequestPost(authnRequest, options) {
return signSamlPost(authnRequest, authnRequestXPath, options);
}
exports.signAuthnRequestPost = signAuthnRequestPost;
//# sourceMappingURL=saml-post-signing.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"saml-post-signing.js","sourceRoot":"","sources":["../../src/node-saml/saml-post-signing.ts"],"names":[],"mappings":";;;AACA,+BAAgC;AAEhC,MAAM,iBAAiB,GACrB,8FAA8F,CAAC;AACjG,MAAM,WAAW,GACf,yFAAyF,CAAC;AAE5F,SAAgB,YAAY,CAC1B,WAAmB,EACnB,KAAa,EACb,OAA2B;IAE3B,OAAO,aAAO,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,GAAG,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACnG,CAAC;AAND,oCAMC;AAED,SAAgB,oBAAoB,CAAC,YAAoB,EAAE,OAA2B;IACpF,OAAO,YAAY,CAAC,YAAY,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC;AAChE,CAAC;AAFD,oDAEC","sourcesContent":["import { SamlSigningOptions } from \"./types\";\nimport { signXml } from \"./xml\";\n\nconst authnRequestXPath =\n '/*[local-name(.)=\"AuthnRequest\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:protocol\"]';\nconst issuerXPath =\n '/*[local-name(.)=\"Issuer\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:assertion\"]';\n\nexport function signSamlPost(\n samlMessage: string,\n xpath: string,\n options: SamlSigningOptions\n): string {\n return signXml(samlMessage, xpath, { reference: xpath + issuerXPath, action: \"after\" }, options);\n}\n\nexport function signAuthnRequestPost(authnRequest: string, options: SamlSigningOptions): string {\n return signSamlPost(authnRequest, authnRequestXPath, options);\n}\n"]}

58
node_modules/passport-saml/lib/node-saml/saml.d.ts generated vendored Normal file
View file

@ -0,0 +1,58 @@
/// <reference types="node" />
import * as querystring from "querystring";
import { CacheProvider as InMemoryCacheProvider } from "./inmemory-cache-provider";
import { ParsedQs } from "qs";
import { SamlOptions } from "./types";
import { AuthenticateOptions, AuthorizeOptions, Profile, SamlConfig } from "../passport-saml/types";
interface NameID {
value: string | null;
format: string | null;
}
declare class SAML {
options: SamlOptions;
cacheProvider: InMemoryCacheProvider;
constructor(ctorOptions: SamlConfig);
initialize(ctorOptions: SamlConfig): SamlOptions;
private getCallbackUrl;
_generateUniqueID(): string;
private generateInstant;
private signRequest;
private generateAuthorizeRequestAsync;
_generateLogoutRequest(user: Profile): Promise<string>;
_generateLogoutResponse(logoutRequest: Profile): string;
_requestToUrlAsync(request: string | null | undefined, response: string | null, operation: string, additionalParameters: querystring.ParsedUrlQuery): Promise<string>;
_getAdditionalParams(RelayState: string, operation: string, overrideParams?: querystring.ParsedUrlQuery): querystring.ParsedUrlQuery;
getAuthorizeUrlAsync(RelayState: string, host: string | undefined, options: AuthorizeOptions): Promise<string>;
getAuthorizeFormAsync(RelayState: string, host?: string): Promise<string>;
getLogoutUrlAsync(user: Profile, RelayState: string, options: AuthenticateOptions & AuthorizeOptions): Promise<string>;
getLogoutResponseUrl(samlLogoutRequest: Profile, RelayState: string, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): void;
private getLogoutResponseUrlAsync;
_certToPEM(cert: string): string;
private certsToCheck;
validateSignature(fullXml: string, currentNode: Element, certs: string[]): boolean;
validatePostResponseAsync(container: Record<string, string>): Promise<{
profile?: Profile | null;
loggedOut?: boolean;
}>;
private validateInResponseTo;
validateRedirectAsync(container: ParsedQs, originalQuery: string | null): Promise<{
profile?: Profile | null;
loggedOut?: boolean;
}>;
private hasValidSignatureForRedirect;
private validateSignatureForRedirect;
private verifyLogoutRequest;
private verifyLogoutResponse;
private verifyIssuer;
private processValidlySignedAssertionAsync;
private checkTimestampsValidityError;
private checkAudienceValidityError;
validatePostRequestAsync(container: Record<string, string>): Promise<{
profile?: Profile;
loggedOut?: boolean;
}>;
_getNameIdAsync(self: SAML, doc: Node): Promise<NameID>;
generateServiceProviderMetadata(decryptionCert: string | null, signingCert?: string | null): string;
_keyToPEM(key: string | Buffer): typeof key extends string | Buffer ? string | Buffer : Error;
}
export { SAML };

1076
node_modules/passport-saml/lib/node-saml/saml.js generated vendored Normal file

File diff suppressed because it is too large Load diff

1
node_modules/passport-saml/lib/node-saml/saml.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

94
node_modules/passport-saml/lib/node-saml/types.d.ts generated vendored Normal file
View file

@ -0,0 +1,94 @@
/// <reference types="node" />
import type { CacheProvider } from "./inmemory-cache-provider";
export declare type SignatureAlgorithm = "sha1" | "sha256" | "sha512";
export interface SamlSigningOptions {
privateKey: string | Buffer;
signatureAlgorithm?: SignatureAlgorithm;
xmlSignatureTransforms?: string[];
digestAlgorithm?: string;
}
export declare const isValidSamlSigningOptions: (options: Partial<SamlSigningOptions>) => options is SamlSigningOptions;
export interface AudienceRestrictionXML {
Audience?: XMLObject[];
}
export declare type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];
export declare type XMLObject = {
[key: string]: XMLValue;
};
export declare type XMLInput = XMLObject;
export declare type XMLOutput = Record<string, any>;
export interface AuthorizeRequestXML {
"samlp:AuthnRequest": XMLInput;
}
export declare type CertCallback = (callback: (err: Error | null, cert?: string | string[]) => void) => void;
/**
* These are SAML options that must be provided to construct a new SAML Strategy
*/
export interface MandatorySamlOptions {
cert: string | string[] | CertCallback;
}
export interface SamlIDPListConfig {
entries: SamlIDPEntryConfig[];
getComplete?: string;
}
export interface SamlIDPEntryConfig {
providerId: string;
name?: string;
loc?: string;
}
export interface LogoutRequestXML {
"samlp:LogoutRequest": {
"saml:NameID": XMLInput;
[key: string]: XMLValue;
};
}
export interface ServiceMetadataXML {
EntityDescriptor: {
[key: string]: XMLValue;
SPSSODescriptor: XMLObject;
};
}
export declare type RacComparision = "exact" | "minimum" | "maximum" | "better";
interface SamlScopingConfig {
idpList?: SamlIDPListConfig[];
proxyCount?: number;
requesterId?: string[] | string;
}
/**
* The options required to use a SAML strategy
* These may be provided by means of defaults specified in the constructor
*/
export interface SamlOptions extends SamlSigningOptions, MandatorySamlOptions {
callbackUrl?: string;
path: string;
protocol?: string;
host: string;
entryPoint?: string;
issuer: string;
decryptionPvk?: string | Buffer;
additionalParams: Record<string, string>;
additionalAuthorizeParams: Record<string, string>;
identifierFormat?: string | null;
acceptedClockSkewMs: number;
attributeConsumingServiceIndex?: string;
disableRequestedAuthnContext: boolean;
authnContext: string[];
forceAuthn: boolean;
skipRequestCompression: boolean;
authnRequestBinding?: string;
racComparison: RacComparision;
providerName?: string;
passive: boolean;
idpIssuer?: string;
audience?: string;
scoping?: SamlScopingConfig;
wantAssertionsSigned?: boolean;
validateInResponseTo: boolean;
requestIdExpirationPeriodMs: number;
cacheProvider: CacheProvider;
logoutUrl: string;
additionalLogoutParams: Record<string, string>;
logoutCallbackUrl?: string;
disableRequestAcsUrl: boolean;
}
export {};

8
node_modules/passport-saml/lib/node-saml/types.js generated vendored Normal file
View file

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isValidSamlSigningOptions = void 0;
const isValidSamlSigningOptions = (options) => {
return options.privateKey != null;
};
exports.isValidSamlSigningOptions = isValidSamlSigningOptions;
//# sourceMappingURL=types.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/node-saml/types.ts"],"names":[],"mappings":";;;AAWO,MAAM,yBAAyB,GAAG,CACvC,OAAoC,EACL,EAAE;IACjC,OAAO,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;AACpC,CAAC,CAAC;AAJW,QAAA,yBAAyB,6BAIpC","sourcesContent":["import type { CacheProvider } from \"./inmemory-cache-provider\";\n\nexport type SignatureAlgorithm = \"sha1\" | \"sha256\" | \"sha512\";\n\nexport interface SamlSigningOptions {\n privateKey: string | Buffer;\n signatureAlgorithm?: SignatureAlgorithm;\n xmlSignatureTransforms?: string[];\n digestAlgorithm?: string;\n}\n\nexport const isValidSamlSigningOptions = (\n options: Partial<SamlSigningOptions>\n): options is SamlSigningOptions => {\n return options.privateKey != null;\n};\n\nexport interface AudienceRestrictionXML {\n Audience?: XMLObject[];\n}\n\nexport type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];\n\nexport type XMLObject = {\n [key: string]: XMLValue;\n};\n\nexport type XMLInput = XMLObject;\n\nexport type XMLOutput = Record<string, any>;\n\nexport interface AuthorizeRequestXML {\n \"samlp:AuthnRequest\": XMLInput;\n}\n\nexport type CertCallback = (\n callback: (err: Error | null, cert?: string | string[]) => void\n) => void;\n\n/**\n * These are SAML options that must be provided to construct a new SAML Strategy\n */\nexport interface MandatorySamlOptions {\n cert: string | string[] | CertCallback;\n}\n\nexport interface SamlIDPListConfig {\n entries: SamlIDPEntryConfig[];\n getComplete?: string;\n}\n\nexport interface SamlIDPEntryConfig {\n providerId: string;\n name?: string;\n loc?: string;\n}\n\nexport interface LogoutRequestXML {\n \"samlp:LogoutRequest\": {\n \"saml:NameID\": XMLInput;\n [key: string]: XMLValue;\n };\n}\n\nexport interface ServiceMetadataXML {\n EntityDescriptor: {\n [key: string]: XMLValue;\n SPSSODescriptor: XMLObject;\n };\n}\n\nexport type RacComparision = \"exact\" | \"minimum\" | \"maximum\" | \"better\";\n\ninterface SamlScopingConfig {\n idpList?: SamlIDPListConfig[];\n proxyCount?: number;\n requesterId?: string[] | string;\n}\n\n/**\n * The options required to use a SAML strategy\n * These may be provided by means of defaults specified in the constructor\n */\nexport interface SamlOptions extends SamlSigningOptions, MandatorySamlOptions {\n // Core\n callbackUrl?: string;\n path: string;\n protocol?: string;\n host: string;\n entryPoint?: string;\n issuer: string;\n decryptionPvk?: string | Buffer;\n\n // Additional SAML behaviors\n additionalParams: Record<string, string>;\n additionalAuthorizeParams: Record<string, string>;\n identifierFormat?: string | null;\n acceptedClockSkewMs: number;\n attributeConsumingServiceIndex?: string;\n disableRequestedAuthnContext: boolean;\n authnContext: string[];\n forceAuthn: boolean;\n skipRequestCompression: boolean;\n authnRequestBinding?: string;\n racComparison: RacComparision;\n providerName?: string;\n passive: boolean;\n idpIssuer?: string;\n audience?: string;\n scoping?: SamlScopingConfig;\n wantAssertionsSigned?: boolean;\n\n // InResponseTo Validation\n validateInResponseTo: boolean;\n requestIdExpirationPeriodMs: number;\n cacheProvider: CacheProvider;\n\n // Logout\n logoutUrl: string;\n additionalLogoutParams: Record<string, string>;\n logoutCallbackUrl?: string;\n\n // extras\n disableRequestAcsUrl: boolean;\n}\n"]}

View file

@ -0,0 +1,3 @@
import { SamlSigningOptions } from "./types";
export declare function assertRequired<T>(value: T | null | undefined, error?: string): T;
export declare function signXmlResponse(samlMessage: string, options: SamlSigningOptions): string;

19
node_modules/passport-saml/lib/node-saml/utility.js generated vendored Normal file
View file

@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.signXmlResponse = exports.assertRequired = void 0;
const xml_1 = require("./xml");
function assertRequired(value, error) {
if (value === undefined || value === null || (typeof value === "string" && value.length === 0)) {
throw new TypeError(error !== null && error !== void 0 ? error : "value does not exist");
}
else {
return value;
}
}
exports.assertRequired = assertRequired;
function signXmlResponse(samlMessage, options) {
const responseXpath = '//*[local-name(.)="Response" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
return xml_1.signXml(samlMessage, responseXpath, { reference: responseXpath, action: "append" }, options);
}
exports.signXmlResponse = signXmlResponse;
//# sourceMappingURL=utility.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"utility.js","sourceRoot":"","sources":["../../src/node-saml/utility.ts"],"names":[],"mappings":";;;AACA,+BAAgC;AAEhC,SAAgB,cAAc,CAAI,KAA2B,EAAE,KAAc;IAC3E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE;QAC9F,MAAM,IAAI,SAAS,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,sBAAsB,CAAC,CAAC;KACtD;SAAM;QACL,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAND,wCAMC;AAED,SAAgB,eAAe,CAAC,WAAmB,EAAE,OAA2B;IAC9E,MAAM,aAAa,GACjB,2FAA2F,CAAC;IAE9F,OAAO,aAAO,CACZ,WAAW,EACX,aAAa,EACb,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,EAC9C,OAAO,CACR,CAAC;AACJ,CAAC;AAVD,0CAUC","sourcesContent":["import { SamlSigningOptions } from \"./types\";\nimport { signXml } from \"./xml\";\n\nexport function assertRequired<T>(value: T | null | undefined, error?: string): T {\n if (value === undefined || value === null || (typeof value === \"string\" && value.length === 0)) {\n throw new TypeError(error ?? \"value does not exist\");\n } else {\n return value;\n }\n}\n\nexport function signXmlResponse(samlMessage: string, options: SamlSigningOptions): string {\n const responseXpath =\n '//*[local-name(.)=\"Response\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:protocol\"]';\n\n return signXml(\n samlMessage,\n responseXpath,\n { reference: responseXpath, action: \"append\" },\n options\n );\n}\n"]}

21
node_modules/passport-saml/lib/node-saml/xml.d.ts generated vendored Normal file
View file

@ -0,0 +1,21 @@
/// <reference types="node" />
import { SamlSigningOptions } from "./types";
export declare const xpath: {
selectAttributes: (node: Node, xpath: string) => Attr[];
selectElements: (node: Node, xpath: string) => Element[];
};
export declare const decryptXml: (xml: string, decryptionKey: string | Buffer) => Promise<string>;
/**
* This function checks that the |signature| is signed with a given |cert|.
*/
export declare const validateXmlSignatureForCert: (signature: Node, certPem: string, fullXml: string, currentNode: Element) => boolean;
interface XmlSignatureLocation {
reference: string;
action: "append" | "prepend" | "before" | "after";
}
export declare const signXml: (xml: string, xpath: string, location: XmlSignatureLocation, options: SamlSigningOptions) => string;
export declare const parseDomFromString: (xml: string) => Document;
export declare const parseXml2JsFromString: (xml: string | Buffer) => Promise<any>;
export declare const buildXml2JsObject: (rootName: string, xml: any) => string;
export declare const buildXmlBuilderObject: (xml: Record<string, any>, pretty: boolean) => string;
export {};

140
node_modules/passport-saml/lib/node-saml/xml.js generated vendored Normal file
View file

@ -0,0 +1,140 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildXmlBuilderObject = exports.buildXml2JsObject = exports.parseXml2JsFromString = exports.parseDomFromString = exports.signXml = exports.validateXmlSignatureForCert = exports.decryptXml = exports.xpath = void 0;
const util = require("util");
const xmlCrypto = require("xml-crypto");
const xmlenc = require("xml-encryption");
const xmldom = require("xmldom");
const xml2js = require("xml2js");
const xmlbuilder = require("xmlbuilder");
const types_1 = require("./types");
const algorithms = require("./algorithms");
const selectXPath = (guard, node, xpath) => {
const result = xmlCrypto.xpath(node, xpath);
if (!guard(result)) {
throw new Error("invalid xpath return type");
}
return result;
};
const attributesXPathTypeGuard = (values) => {
return values.every((value) => {
if (typeof value != "object") {
return false;
}
return typeof value.nodeType === "number" && value.nodeType === value.ATTRIBUTE_NODE;
});
};
const elementsXPathTypeGuard = (values) => {
return values.every((value) => {
if (typeof value != "object") {
return false;
}
return typeof value.nodeType === "number" && value.nodeType === value.ELEMENT_NODE;
});
};
exports.xpath = {
selectAttributes: (node, xpath) => selectXPath(attributesXPathTypeGuard, node, xpath),
selectElements: (node, xpath) => selectXPath(elementsXPathTypeGuard, node, xpath),
};
const decryptXml = async (xml, decryptionKey) => util.promisify(xmlenc.decrypt).bind(xmlenc)(xml, { key: decryptionKey });
exports.decryptXml = decryptXml;
const normalizeNewlines = (xml) => {
// we can use this utility before passing XML to `xml-crypto`
// we are considered the XML processor and are responsible for newline normalization
// https://github.com/node-saml/passport-saml/issues/431#issuecomment-718132752
return xml.replace(/\r\n?/g, "\n");
};
const normalizeXml = (xml) => {
// we can use this utility to parse and re-stringify XML
// `DOMParser` will take care of normalization tasks, like replacing XML-encoded carriage returns with actual carriage returns
return exports.parseDomFromString(xml).toString();
};
/**
* This function checks that the |signature| is signed with a given |cert|.
*/
const validateXmlSignatureForCert = (signature, certPem, fullXml, currentNode) => {
const sig = new xmlCrypto.SignedXml();
sig.keyInfoProvider = {
file: "",
getKeyInfo: () => "<X509Data></X509Data>",
getKey: () => Buffer.from(certPem),
};
const signatureStr = normalizeNewlines(signature.toString());
sig.loadSignature(signatureStr);
// We expect each signature to contain exactly one reference to the top level of the xml we
// are validating, so if we see anything else, reject.
if (sig.references.length != 1)
return false;
const refUri = sig.references[0].uri;
const refId = refUri[0] === "#" ? refUri.substring(1) : refUri;
// If we can't find the reference at the top level, reject
const idAttribute = currentNode.getAttribute("ID") ? "ID" : "Id";
if (currentNode.getAttribute(idAttribute) != refId)
return false;
// If we find any extra referenced nodes, reject. (xml-crypto only verifies one digest, so
// multiple candidate references is bad news)
const totalReferencedNodes = exports.xpath.selectElements(currentNode.ownerDocument, "//*[@" + idAttribute + "='" + refId + "']");
if (totalReferencedNodes.length > 1) {
return false;
}
// normalize XML to replace XML-encoded carriage returns with actual carriage returns
fullXml = normalizeXml(fullXml);
fullXml = normalizeNewlines(fullXml);
return sig.checkSignature(fullXml);
};
exports.validateXmlSignatureForCert = validateXmlSignatureForCert;
const signXml = (xml, xpath, location, options) => {
var _a;
const defaultTransforms = [
"http://www.w3.org/2000/09/xmldsig#enveloped-signature",
"http://www.w3.org/2001/10/xml-exc-c14n#",
];
if (!xml)
throw new Error("samlMessage is required");
if (!location)
throw new Error("location is required");
if (!options)
throw new Error("options is required");
if (!types_1.isValidSamlSigningOptions(options))
throw new Error("options.privateKey is required");
const transforms = (_a = options.xmlSignatureTransforms) !== null && _a !== void 0 ? _a : defaultTransforms;
const sig = new xmlCrypto.SignedXml();
if (options.signatureAlgorithm != null) {
sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);
}
sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));
sig.signingKey = options.privateKey;
sig.computeSignature(xml, {
location,
});
return sig.getSignedXml();
};
exports.signXml = signXml;
const parseDomFromString = (xml) => {
return new xmldom.DOMParser().parseFromString(xml);
};
exports.parseDomFromString = parseDomFromString;
const parseXml2JsFromString = async (xml) => {
const parserConfig = {
explicitRoot: true,
explicitCharkey: true,
tagNameProcessors: [xml2js.processors.stripPrefix],
};
const parser = new xml2js.Parser(parserConfig);
return parser.parseStringPromise(xml);
};
exports.parseXml2JsFromString = parseXml2JsFromString;
const buildXml2JsObject = (rootName, xml) => {
const builderOpts = {
rootName,
headless: true,
};
return new xml2js.Builder(builderOpts).buildObject(xml);
};
exports.buildXml2JsObject = buildXml2JsObject;
const buildXmlBuilderObject = (xml, pretty) => {
const options = pretty ? { pretty: true, indent: " ", newline: "\n" } : {};
return xmlbuilder.create(xml).end(options);
};
exports.buildXmlBuilderObject = buildXmlBuilderObject;
//# sourceMappingURL=xml.js.map

1
node_modules/passport-saml/lib/node-saml/xml.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,5 @@
/// <reference types="node" />
import * as crypto from 'crypto';
export declare function getSigningAlgorithm(shortName: string): string;
export declare function getDigestAlgorithm(shortName: string): string;
export declare function getSigner(shortName: string): crypto.Signer;

View file

@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSigner = exports.getDigestAlgorithm = exports.getSigningAlgorithm = void 0;
const crypto = require("crypto");
function getSigningAlgorithm(shortName) {
switch (shortName) {
case 'sha256':
return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
case 'sha512':
return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
default:
return 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
}
}
exports.getSigningAlgorithm = getSigningAlgorithm;
function getDigestAlgorithm(shortName) {
switch (shortName) {
case 'sha256':
return 'http://www.w3.org/2001/04/xmlenc#sha256';
case 'sha512':
return 'http://www.w3.org/2001/04/xmlenc#sha512';
default:
return 'http://www.w3.org/2000/09/xmldsig#sha1';
}
}
exports.getDigestAlgorithm = getDigestAlgorithm;
function getSigner(shortName) {
switch (shortName) {
case 'sha256':
return crypto.createSign('RSA-SHA256');
case 'sha512':
return crypto.createSign('RSA-SHA512');
default:
return crypto.createSign('RSA-SHA1');
}
}
exports.getSigner = getSigner;
//# sourceMappingURL=algorithms.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"algorithms.js","sourceRoot":"","sources":["../../src/passport-saml/algorithms.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AAEjC,SAAgB,mBAAmB,CAAE,SAAiB;IACpD,QAAO,SAAS,EAAE;QAChB,KAAK,QAAQ;YACX,OAAO,mDAAmD,CAAC;QAC7D,KAAK,QAAQ;YACX,OAAO,mDAAmD,CAAC;QAC7D;YACE,OAAO,4CAA4C,CAAC;KACvD;AACH,CAAC;AATD,kDASC;AAED,SAAgB,kBAAkB,CAAE,SAAiB;IACnD,QAAO,SAAS,EAAE;QAChB,KAAK,QAAQ;YACX,OAAO,yCAAyC,CAAC;QACnD,KAAK,QAAQ;YACX,OAAO,yCAAyC,CAAC;QACnD;YACE,OAAO,wCAAwC,CAAC;KACnD;AACH,CAAC;AATD,gDASC;AAED,SAAgB,SAAS,CAAE,SAAiB;IAC1C,QAAO,SAAS,EAAE;QAChB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC;YACE,OAAO,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;KACxC;AACH,CAAC;AATD,8BASC","sourcesContent":["import * as crypto from 'crypto';\n\nexport function getSigningAlgorithm (shortName: string): string {\n switch(shortName) {\n case 'sha256':\n return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';\n case 'sha512':\n return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';\n default:\n return 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';\n }\n}\n\nexport function getDigestAlgorithm (shortName: string): string {\n switch(shortName) {\n case 'sha256':\n return 'http://www.w3.org/2001/04/xmlenc#sha256';\n case 'sha512':\n return 'http://www.w3.org/2001/04/xmlenc#sha512';\n default:\n return 'http://www.w3.org/2000/09/xmldsig#sha1';\n }\n}\n\nexport function getSigner (shortName: string): crypto.Signer {\n switch(shortName) {\n case 'sha256':\n return crypto.createSign('RSA-SHA256');\n case 'sha512':\n return crypto.createSign('RSA-SHA512');\n default:\n return crypto.createSign('RSA-SHA1');\n }\n}\n"]}

View file

@ -0,0 +1,6 @@
import type { CacheItem, CacheProvider } from './inmemory-cache-provider';
import { SAML } from './saml';
import Strategy = require('./strategy');
import MultiSamlStrategy = require('./multiSamlStrategy');
import type { Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest } from './types';
export { SAML, Strategy, MultiSamlStrategy, CacheItem, CacheProvider, Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest };

10
node_modules/passport-saml/lib/passport-saml/index.js generated vendored Normal file
View file

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiSamlStrategy = exports.Strategy = exports.SAML = void 0;
const saml_1 = require("./saml");
Object.defineProperty(exports, "SAML", { enumerable: true, get: function () { return saml_1.SAML; } });
const Strategy = require("./strategy");
exports.Strategy = Strategy;
const MultiSamlStrategy = require("./multiSamlStrategy");
exports.MultiSamlStrategy = MultiSamlStrategy;
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/passport-saml/index.ts"],"names":[],"mappings":";;;AACA,iCAA8B;AAKrB,qFALA,WAAI,OAKA;AAJb,uCAAwC;AAIzB,4BAAQ;AAHvB,yDAA0D;AAGjC,8CAAiB","sourcesContent":["import type { CacheItem, CacheProvider} from './inmemory-cache-provider';\nimport { SAML } from './saml';\nimport Strategy = require('./strategy');\nimport MultiSamlStrategy = require('./multiSamlStrategy');\nimport type { Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest } from './types';\n\nexport { SAML, Strategy, MultiSamlStrategy, CacheItem, CacheProvider, Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest };\n"]}

View file

@ -0,0 +1,45 @@
/**
* Simple in memory cache provider. To be used to store state of requests that needs
* to be validated/checked when a response is received.
*
* This is the default implementation of a cache provider used by Passport-SAML. For
* multiple server instances/load balanced scenarios (I.e. the SAML request could have
* been generated from a different server/process handling the SAML response) this
* implementation will NOT be sufficient.
*
* The caller should provide their own implementation for a cache provider as defined
* in the config options for Passport-SAML.
* @param options
* @constructor
*/
export interface CacheItem {
value: string;
createdAt: number;
}
interface CacheProviderOptions {
keyExpirationPeriodMs: number;
}
export declare class CacheProvider {
cacheKeys: Record<string, CacheItem>;
options: CacheProviderOptions;
constructor(options: Partial<CacheProviderOptions>);
/**
* Store an item in the cache, using the specified key and value.
* Internally will keep track of the time the item was added to the cache
* @param id
* @param value
*/
save(key: string, value: string, callback: (error: null, value: CacheItem | null) => void): void;
/**
* Returns the value of the specified key in the cache
* @param id
* @returns {boolean}
*/
get(key: string, callback: (key: string | null, value: string | null) => void): void;
/**
* Removes an item from the cache if it exists
* @param key
*/
remove(key: string, callback: (err: Error | null, key: string | null) => void): void;
}
export {};

View file

@ -0,0 +1,90 @@
"use strict";
/**
* Simple in memory cache provider. To be used to store state of requests that needs
* to be validated/checked when a response is received.
*
* This is the default implementation of a cache provider used by Passport-SAML. For
* multiple server instances/load balanced scenarios (I.e. the SAML request could have
* been generated from a different server/process handling the SAML response) this
* implementation will NOT be sufficient.
*
* The caller should provide their own implementation for a cache provider as defined
* in the config options for Passport-SAML.
* @param options
* @constructor
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheProvider = void 0;
class CacheProvider {
constructor(options) {
this.cacheKeys = {};
if (!options) {
options = {};
}
if (!options.keyExpirationPeriodMs) {
options.keyExpirationPeriodMs = 28800000; // 8 hours
}
this.options = options;
// Expire old cache keys
const expirationTimer = setInterval(() => {
const nowMs = new Date().getTime();
const keys = Object.keys(this.cacheKeys);
keys.forEach((key) => {
if (nowMs >= new Date(this.cacheKeys[key].createdAt).getTime() + this.options.keyExpirationPeriodMs) {
this.remove(key, () => undefined);
}
});
}, this.options.keyExpirationPeriodMs);
// we only want this to run if the process is still open; it shouldn't hold the process open (issue #68)
// (unref only introduced in node 0.9, so check whether we have it)
// Skip this in 0.10.34 due to https://github.com/joyent/node/issues/8900
if (expirationTimer.unref && process.version !== 'v0.10.34')
expirationTimer.unref();
}
/**
* Store an item in the cache, using the specified key and value.
* Internally will keep track of the time the item was added to the cache
* @param id
* @param value
*/
save(key, value, callback) {
if (!this.cacheKeys[key]) {
this.cacheKeys[key] = {
createdAt: new Date().getTime(),
value: value
};
callback(null, this.cacheKeys[key]);
}
else {
callback(null, null);
}
}
/**
* Returns the value of the specified key in the cache
* @param id
* @returns {boolean}
*/
get(key, callback) {
if (this.cacheKeys[key]) {
callback(null, this.cacheKeys[key].value);
}
else {
callback(null, null);
}
}
/**
* Removes an item from the cache if it exists
* @param key
*/
remove(key, callback) {
if (this.cacheKeys[key]) {
delete this.cacheKeys[key];
callback(null, key);
}
else {
callback(null, null);
}
}
}
exports.CacheProvider = CacheProvider;
//# sourceMappingURL=inmemory-cache-provider.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
import SamlStrategy = require('./strategy');
import type { Request } from 'express';
import { AuthenticateOptions, AuthorizeOptions, MultiSamlConfig, RequestWithUser, VerifyWithoutRequest, VerifyWithRequest } from './types';
declare class MultiSamlStrategy extends SamlStrategy {
_options: MultiSamlConfig;
constructor(options: MultiSamlConfig, verify: VerifyWithRequest | VerifyWithoutRequest);
authenticate(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions): void;
logout(req: RequestWithUser, callback: (err: Error | null, url?: string | null | undefined) => void): void;
/** @ts-expect-error typescript disallows changing method signature in a subclass */
generateServiceProviderMetadata(req: Request, decryptionCert: string | null, signingCert: string | null, callback: (err: Error | null, metadata?: string) => void): void;
}
export = MultiSamlStrategy;

View file

@ -0,0 +1,58 @@
"use strict";
const saml = require("./saml");
const inmemory_cache_provider_1 = require("./inmemory-cache-provider");
const SamlStrategy = require("./strategy");
class MultiSamlStrategy extends SamlStrategy {
constructor(options, verify) {
if (!options || typeof options.getSamlOptions != 'function') {
throw new Error('Please provide a getSamlOptions function');
}
if (!options.requestIdExpirationPeriodMs) {
options.requestIdExpirationPeriodMs = 28800000; // 8 hours
}
if (!options.cacheProvider) {
options.cacheProvider = new inmemory_cache_provider_1.CacheProvider({ keyExpirationPeriodMs: options.requestIdExpirationPeriodMs });
}
super(options, verify);
this._options = options;
}
authenticate(req, options) {
this._options.getSamlOptions(req, (err, samlOptions) => {
if (err) {
return this.error(err);
}
const samlService = new saml.SAML({ ...this._options, ...samlOptions });
const strategy = Object.assign({}, this, { _saml: samlService });
Object.setPrototypeOf(strategy, this);
super.authenticate.call(strategy, req, options);
});
}
logout(req, callback) {
this._options.getSamlOptions(req, (err, samlOptions) => {
if (err) {
return callback(err);
}
const samlService = new saml.SAML(Object.assign({}, this._options, samlOptions));
const strategy = Object.assign({}, this, { _saml: samlService });
Object.setPrototypeOf(strategy, this);
super.logout.call(strategy, req, callback);
});
}
/** @ts-expect-error typescript disallows changing method signature in a subclass */
generateServiceProviderMetadata(req, decryptionCert, signingCert, callback) {
if (typeof callback !== 'function') {
throw new Error("Metadata can't be provided synchronously for MultiSamlStrategy.");
}
return this._options.getSamlOptions(req, (err, samlOptions) => {
if (err) {
return callback(err);
}
const samlService = new saml.SAML(Object.assign({}, this._options, samlOptions));
const strategy = Object.assign({}, this, { _saml: samlService });
Object.setPrototypeOf(strategy, this);
return callback(null, super.generateServiceProviderMetadata.call(strategy, decryptionCert, signingCert));
});
}
}
module.exports = MultiSamlStrategy;
//# sourceMappingURL=multiSamlStrategy.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
import { SAMLOptions } from './types';
export declare function signSamlPost(samlMessage: string, xpath: string, options: SAMLOptions): string;
export declare function signAuthnRequestPost(authnRequest: string, options: SAMLOptions): string;

View file

@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.signAuthnRequestPost = exports.signSamlPost = void 0;
const xml_crypto_1 = require("xml-crypto");
const algorithms = require("./algorithms");
const authnRequestXPath = '/*[local-name(.)="AuthnRequest" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
const issuerXPath = '/*[local-name(.)="Issuer" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:assertion"]';
const defaultTransforms = ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'];
function signSamlPost(samlMessage, xpath, options) {
if (!samlMessage)
throw new Error('samlMessage is required');
if (!xpath)
throw new Error('xpath is required');
if (!options) {
options = {};
}
if (options.privateCert) {
console.warn("options.privateCert has been deprecated; use options.privateKey instead.");
if (!options.privateKey) {
options.privateKey = options.privateCert;
}
}
if (!options.privateKey)
throw new Error('options.privateKey is required');
const transforms = options.xmlSignatureTransforms || defaultTransforms;
const sig = new xml_crypto_1.SignedXml();
if (options.signatureAlgorithm) {
sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);
}
sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));
sig.signingKey = options.privateKey;
sig.computeSignature(samlMessage, { location: { reference: xpath + issuerXPath, action: 'after' } });
return sig.getSignedXml();
}
exports.signSamlPost = signSamlPost;
function signAuthnRequestPost(authnRequest, options) {
return signSamlPost(authnRequest, authnRequestXPath, options);
}
exports.signAuthnRequestPost = signAuthnRequestPost;
//# sourceMappingURL=saml-post-signing.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"saml-post-signing.js","sourceRoot":"","sources":["../../src/passport-saml/saml-post-signing.ts"],"names":[],"mappings":";;;AAAA,2CAAuC;AACvC,2CAA2C;AAG3C,MAAM,iBAAiB,GAAG,8FAA8F,CAAC;AACzH,MAAM,WAAW,GAAG,yFAAyF,CAAC;AAC9G,MAAM,iBAAiB,GAAG,CAAE,uDAAuD,EAAE,yCAAyC,CAAE,CAAC;AAEjI,SAAgB,YAAY,CAAC,WAAmB,EAAE,KAAa,EAAE,OAAoB;IACnF,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,GAAG,EAAiB,CAAC;KAC7B;IAED,IAAI,OAAO,CAAC,WAAW,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QAEzF,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YACvB,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;SAC1C;KACF;IAED,IAAI,CAAC,OAAO,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAE3E,MAAM,UAAU,GAAG,OAAO,CAAC,sBAAsB,IAAI,iBAAiB,CAAC;IACvE,MAAM,GAAG,GAAG,IAAI,sBAAS,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,kBAAkB,EAAE;QAC9B,GAAG,CAAC,kBAAkB,GAAG,UAAU,CAAC,mBAAmB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACrF;IACD,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAC5F,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACpC,GAAG,CAAC,gBAAgB,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,GAAG,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,EAAC,CAAC,CAAC;IACpG,OAAO,GAAG,CAAC,YAAY,EAAE,CAAC;AAC5B,CAAC;AA1BD,oCA0BC;AAED,SAAgB,oBAAoB,CAAC,YAAoB,EAAE,OAAoB;IAC7E,OAAO,YAAY,CAAC,YAAY,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC;AAChE,CAAC;AAFD,oDAEC","sourcesContent":["import { SignedXml } from 'xml-crypto';\nimport * as algorithms from './algorithms';\nimport { SAMLOptions } from './types';\n\nconst authnRequestXPath = '/*[local-name(.)=\"AuthnRequest\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:protocol\"]';\nconst issuerXPath = '/*[local-name(.)=\"Issuer\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:assertion\"]';\nconst defaultTransforms = [ 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#' ];\n\nexport function signSamlPost(samlMessage: string, xpath: string, options: SAMLOptions) {\n if (!samlMessage) throw new Error('samlMessage is required');\n if (!xpath) throw new Error('xpath is required');\n if (!options) {\n options = {} as SAMLOptions;\n }\n\n if (options.privateCert) {\n console.warn(\"options.privateCert has been deprecated; use options.privateKey instead.\");\n\n if (!options.privateKey) {\n options.privateKey = options.privateCert;\n }\n }\n\n if (!options.privateKey) throw new Error('options.privateKey is required');\n\n const transforms = options.xmlSignatureTransforms || defaultTransforms;\n const sig = new SignedXml();\n if (options.signatureAlgorithm) {\n sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);\n }\n sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));\n sig.signingKey = options.privateKey;\n sig.computeSignature(samlMessage, { location: { reference: xpath + issuerXPath, action: 'after' }});\n return sig.getSignedXml();\n}\n\nexport function signAuthnRequestPost(authnRequest: string, options: SAMLOptions) {\n return signSamlPost(authnRequest, authnRequestXPath, options);\n}\n"]}

56
node_modules/passport-saml/lib/passport-saml/saml.d.ts generated vendored Normal file
View file

@ -0,0 +1,56 @@
/// <reference types="node" />
import * as xml2js from 'xml2js';
import * as crypto from 'crypto';
import * as querystring from 'querystring';
import { CacheProvider as InMemoryCacheProvider } from './inmemory-cache-provider';
import type { Request } from 'express';
import { ParsedQs } from 'qs';
import { AudienceRestrictionXML, AuthenticateOptions, AuthorizeOptions, Profile, RequestWithUser, SAMLOptions, XMLOutput } from './types';
declare class SAML {
options: SAMLOptions;
cacheProvider: InMemoryCacheProvider;
constructor(options: Partial<SAMLOptions>);
initialize(options: Partial<SAMLOptions>): SAMLOptions;
getProtocol(req: Request | {
headers?: undefined;
protocol?: undefined;
}): string;
getCallbackUrl(req: Request | {
headers?: undefined;
protocol?: undefined;
}): string;
generateUniqueID(): string;
generateInstant(): string;
signRequest(samlMessage: querystring.ParsedUrlQueryInput): void;
generateAuthorizeRequest(req: Request, isPassive: boolean, isHttpPostBinding: boolean, callback: (err: Error | null, request?: string) => void): void;
generateLogoutRequest(req: RequestWithUser): Promise<string>;
generateLogoutResponse(req: Request, logoutRequest: Profile): string;
requestToUrl(request: string | null | undefined, response: string | null, operation: string, additionalParameters: querystring.ParsedUrlQuery, callback: (err: Error | null, url?: string | null | undefined) => void): void;
getAdditionalParams(req: Request, operation: string, overrideParams?: querystring.ParsedUrlQuery): querystring.ParsedUrlQuery;
getAuthorizeUrl(req: Request, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): void;
getAuthorizeForm(req: Request, callback: (err: Error | null, data?: unknown) => void): void;
getLogoutUrl(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): Promise<void>;
getLogoutResponseUrl(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): void;
certToPEM(cert: string): string;
certsToCheck(): Promise<undefined | string[]>;
validateSignature(fullXml: string, currentNode: HTMLElement, certs: string[]): boolean;
validateSignatureForCert(signature: string | Node, cert: string, fullXml: string, currentNode: HTMLElement): boolean;
validatePostResponse(container: Record<string, string>, callback: (err: Error | null, profile?: Profile | null, loggedOut?: boolean) => void): void;
validateInResponseTo(inResponseTo: string | null): Promise<void>;
validateRedirect(container: ParsedQs, originalQuery: string | null, callback: (err: Error | null, profile?: Profile | null, loggedOut?: boolean) => void): void;
hasValidSignatureForRedirect(container: ParsedQs, originalQuery: string | null): Promise<boolean | void>;
validateSignatureForRedirect(urlString: crypto.BinaryLike, signature: string, alg: string, cert: string): boolean;
verifyLogoutRequest(doc: XMLOutput): void;
verifyLogoutResponse(doc: XMLOutput): Promise<boolean | void>;
verifyIssuer(samlMessage: XMLOutput): void;
processValidlySignedAssertion(xml: xml2js.convertableToString, samlResponseXml: string, inResponseTo: string, callback: (err: Error | null, profile?: Profile | undefined, loggedOut?: boolean | undefined) => void): void;
checkTimestampsValidityError(nowMs: number, notBefore: string, notOnOrAfter: string): Error | null;
checkAudienceValidityError(expectedAudience: string, audienceRestrictions: AudienceRestrictionXML[]): Error | null;
validatePostRequest(container: Record<string, string>, callback: (err: Error | null, profile?: Profile, loggedOut?: boolean) => void): void;
getNameID(self: SAML, doc: Node, callback: (err: Error | null, nameID?: XMLOutput) => void): void | Promise<void>;
generateServiceProviderMetadata(decryptionCert: string | null, signingCert?: string | null): string;
keyToPEM(key: crypto.KeyLike): crypto.KeyLike;
normalizeNewlines(xml: string): string;
normalizeXml(xml: string): string;
}
export { SAML };

1235
node_modules/passport-saml/lib/passport-saml/saml.js generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
import { Strategy as PassportStrategy } from 'passport-strategy';
import * as saml from './saml';
import { AuthenticateOptions, AuthorizeOptions, RequestWithUser, SamlConfig, VerifyWithoutRequest, VerifyWithRequest } from './types';
declare class Strategy extends PassportStrategy {
name: string;
_verify: VerifyWithRequest | VerifyWithoutRequest;
_saml: saml.SAML;
_passReqToCallback?: boolean;
_authnRequestBinding?: string;
constructor(options: SamlConfig, verify: VerifyWithRequest | VerifyWithoutRequest);
authenticate(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions): void;
logout(req: RequestWithUser, callback: (err: Error | null, url?: string | null) => void): void;
generateServiceProviderMetadata(decryptionCert: string | null, signingCert?: string | null): string;
}
export = Strategy;

View file

@ -0,0 +1,112 @@
"use strict";
const passport_strategy_1 = require("passport-strategy");
const saml = require("./saml");
const url = require("url");
class Strategy extends passport_strategy_1.Strategy {
constructor(options, verify) {
super();
if (typeof options == 'function') {
verify = options;
options = {};
}
if (!verify) {
throw new Error('SAML authentication strategy requires a verify function');
}
// Customizing the name can be useful to support multiple SAML configurations at the same time.
// Unlike other options, this one gets deleted instead of passed along.
if (options.name) {
this.name = options.name;
}
else {
this.name = 'saml';
}
this._verify = verify;
this._saml = new saml.SAML(options);
this._passReqToCallback = !!options.passReqToCallback;
this._authnRequestBinding = options.authnRequestBinding || 'HTTP-Redirect';
}
authenticate(req, options) {
options.samlFallback = options.samlFallback || 'login-request';
const validateCallback = (err, profile, loggedOut) => {
if (err) {
return this.error(err);
}
if (loggedOut) {
req.logout();
if (profile) {
req.samlLogoutRequest = profile;
return this._saml.getLogoutResponseUrl(req, options, redirectIfSuccess);
}
return this.pass();
}
const verified = (err, user, info) => {
if (err) {
return this.error(err);
}
if (!user) {
return this.fail(info, 401);
}
this.success(user, info);
};
if (this._passReqToCallback) {
this._verify(req, profile, verified);
}
else {
this._verify(profile, verified);
}
};
const redirectIfSuccess = (err, url) => {
if (err) {
this.error(err);
}
else {
this.redirect(url);
}
};
if (req.query && (req.query.SAMLResponse || req.query.SAMLRequest)) {
const originalQuery = url.parse(req.url).query;
this._saml.validateRedirect(req.query, originalQuery, validateCallback);
}
else if (req.body && req.body.SAMLResponse) {
this._saml.validatePostResponse(req.body, validateCallback);
}
else if (req.body && req.body.SAMLRequest) {
this._saml.validatePostRequest(req.body, validateCallback);
}
else {
const requestHandler = {
'login-request': () => {
if (this._authnRequestBinding === 'HTTP-POST') {
this._saml.getAuthorizeForm(req, (err, data) => {
if (err) {
this.error(err);
}
else {
const res = req.res;
res.send(data);
}
});
}
else { // Defaults to HTTP-Redirect
this._saml.getAuthorizeUrl(req, options, redirectIfSuccess);
}
},
'logout-request': () => {
this._saml.getLogoutUrl(req, options, redirectIfSuccess);
}
}[options.samlFallback];
if (typeof requestHandler !== 'function') {
return this.fail(401);
}
requestHandler();
}
}
logout(req, callback) {
this._saml.getLogoutUrl(req, {}, callback);
}
generateServiceProviderMetadata(decryptionCert, signingCert) {
return this._saml.generateServiceProviderMetadata(decryptionCert, signingCert);
}
}
module.exports = Strategy;
//# sourceMappingURL=strategy.js.map

File diff suppressed because one or more lines are too long

125
node_modules/passport-saml/lib/passport-saml/types.d.ts generated vendored Normal file
View file

@ -0,0 +1,125 @@
import type * as express from 'express';
import * as passport from 'passport';
import type { CacheProvider } from './inmemory-cache-provider';
export declare type CertCallback = (callback: (err: Error | null, cert?: string | string[]) => void) => void;
export interface AuthenticateOptions extends passport.AuthenticateOptions {
additionalParams?: Record<string, any>;
}
export interface AuthorizeOptions extends AuthenticateOptions {
samlFallback?: 'login-request' | 'logout-request';
}
export interface SAMLOptions {
callbackUrl: string;
path: string;
protocol: string;
host: string;
entryPoint: string;
issuer: string;
/** @deprecated use privateKey field instead */
privateCert?: string;
privateKey: string;
cert: string | string[] | CertCallback;
decryptionPvk: string;
signatureAlgorithm: 'sha1' | 'sha256' | 'sha512';
additionalParams: Record<string, string>;
additionalAuthorizeParams: Record<string, string>;
identifierFormat: string;
acceptedClockSkewMs: number;
attributeConsumingServiceIndex: string | null;
disableRequestedAuthnContext: boolean;
authnContext: string | string[];
forceAuthn: boolean;
skipRequestCompression: boolean;
/** @deprecated use racComparison field instead */
RACComparison?: 'exact' | 'minimum' | 'maximum' | 'better';
racComparison: 'exact' | 'minimum' | 'maximum' | 'better';
providerName: string;
passive: boolean;
idpIssuer: string;
audience: string;
scoping: SamlScopingConfig;
validateInResponseTo: boolean;
requestIdExpirationPeriodMs: number;
cacheProvider: CacheProvider;
logoutUrl: string;
additionalLogoutParams: Record<string, string>;
logoutCallbackUrl: string;
xmlSignatureTransforms: string[];
digestAlgorithm: string;
/** @deprecated use disableRequestAcsUrl field instead */
disableRequestACSUrl?: boolean;
disableRequestAcsUrl: boolean;
}
export declare type SamlConfig = Partial<SAMLOptions> & StrategyOptions;
interface StrategyOptions {
name?: string;
passReqToCallback?: boolean;
authnRequestBinding?: string;
}
export interface SamlScopingConfig {
idpList?: SamlIDPListConfig[];
proxyCount?: number;
requesterId?: string[];
}
export declare type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];
export declare type XMLObject = {
[key: string]: XMLValue;
};
export declare type XMLInput = XMLObject;
export interface AuthorizeRequestXML {
'samlp:AuthnRequest': XMLInput;
}
export interface LogoutRequestXML {
'samlp:LogoutRequest': {
'saml:NameID': XMLInput;
[key: string]: XMLValue;
};
}
export interface ServiceMetadataXML {
EntityDescriptor: {
[key: string]: XMLValue;
SPSSODescriptor: XMLObject;
};
}
export interface AudienceRestrictionXML {
Audience?: XMLObject[];
}
export declare type XMLOutput = Record<string, any>;
export interface SamlIDPListConfig {
entries: SamlIDPEntryConfig[];
getComplete?: string;
}
export interface SamlIDPEntryConfig {
providerId: string;
name?: string;
loc?: string;
}
export declare type Profile = {
issuer?: string;
sessionIndex?: string;
nameID?: string;
nameIDFormat?: string;
nameQualifier?: string;
spNameQualifier?: string;
ID?: string;
mail?: string;
email?: string;
['urn:oid:0.9.2342.19200300.100.1.3']?: string;
getAssertionXml(): string;
getAssertion(): Record<string, unknown>;
getSamlResponseXml(): string;
} & {
[attributeName: string]: unknown;
};
export interface RequestWithUser extends express.Request {
samlLogoutRequest: any;
user?: Profile;
}
export declare type VerifiedCallback = (err: Error | null, user?: Record<string, unknown>, info?: Record<string, unknown>) => void;
export declare type VerifyWithRequest = (req: express.Request, profile: Profile | null | undefined, done: VerifiedCallback) => void;
export declare type VerifyWithoutRequest = (profile: Profile | null | undefined, done: VerifiedCallback) => void;
export declare type SamlOptionsCallback = (err: Error | null, samlOptions?: SamlConfig) => void;
export interface MultiSamlConfig extends SamlConfig {
getSamlOptions(req: express.Request, callback: SamlOptionsCallback): void;
}
export {};

View file

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/passport-saml/types.ts"],"names":[],"mappings":"","sourcesContent":["import type * as express from 'express';\nimport * as passport from 'passport';\nimport type { CacheProvider } from './inmemory-cache-provider';\n\nexport type CertCallback = (callback: (err: Error | null, cert?: string | string[]) => void) => void;\n\nexport interface AuthenticateOptions extends passport.AuthenticateOptions {\n additionalParams?: Record<string, any>;\n}\n\nexport interface AuthorizeOptions extends AuthenticateOptions {\n samlFallback?: 'login-request' | 'logout-request';\n}\n\nexport interface SAMLOptions {\n // Core\n callbackUrl: string;\n path: string;\n protocol: string;\n host: string;\n entryPoint: string;\n issuer: string;\n /** @deprecated use privateKey field instead */\n privateCert?: string;\n privateKey: string;\n cert: string | string[] | CertCallback;\n decryptionPvk: string;\n signatureAlgorithm: 'sha1' | 'sha256' | 'sha512';\n\n // Additional SAML behaviors\n additionalParams: Record<string, string>;\n additionalAuthorizeParams: Record<string, string>;\n identifierFormat: string;\n acceptedClockSkewMs: number;\n attributeConsumingServiceIndex: string | null;\n disableRequestedAuthnContext: boolean;\n authnContext: string | string[];\n forceAuthn: boolean;\n skipRequestCompression: boolean;\n /** @deprecated use racComparison field instead */\n RACComparison?: 'exact' | 'minimum' | 'maximum' | 'better';\n racComparison: 'exact' | 'minimum' | 'maximum' | 'better';\n providerName: string;\n passive: boolean;\n idpIssuer: string;\n audience: string;\n scoping : SamlScopingConfig;\n\n // InResponseTo Validation\n validateInResponseTo: boolean;\n requestIdExpirationPeriodMs: number;\n cacheProvider: CacheProvider;\n\n // Logout\n logoutUrl: string;\n additionalLogoutParams: Record<string, string>;\n logoutCallbackUrl: string;\n\n // extras\n xmlSignatureTransforms: string[];\n digestAlgorithm: string;\n /** @deprecated use disableRequestAcsUrl field instead */\n disableRequestACSUrl?: boolean;\n disableRequestAcsUrl: boolean;\n}\n\nexport type SamlConfig = Partial<SAMLOptions> & StrategyOptions\n\ninterface StrategyOptions {\n name?: string;\n passReqToCallback?: boolean;\n authnRequestBinding?: string;\n}\n\nexport interface SamlScopingConfig {\n idpList?: SamlIDPListConfig[];\n proxyCount?: number;\n requesterId?: string[];\n}\n\nexport type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];\n\nexport type XMLObject = {\n [key: string]: XMLValue;\n};\n\nexport type XMLInput = XMLObject;\n\nexport interface AuthorizeRequestXML {\n 'samlp:AuthnRequest': XMLInput;\n}\n\nexport interface LogoutRequestXML {\n 'samlp:LogoutRequest': {\n 'saml:NameID': XMLInput;\n [key: string]: XMLValue;\n };\n}\n\nexport interface ServiceMetadataXML {\n EntityDescriptor: {\n [key: string]: XMLValue;\n SPSSODescriptor: XMLObject;\n };\n}\n\nexport interface AudienceRestrictionXML {\n Audience?: XMLObject[];\n}\n\nexport type XMLOutput = Record<string, any>;\n\nexport interface SamlIDPListConfig {\n entries: SamlIDPEntryConfig[];\n getComplete?: string;\n}\n\nexport interface SamlIDPEntryConfig {\n providerId: string;\n name?: string;\n loc?: string;\n}\n\nexport type Profile = {\n issuer?: string;\n sessionIndex?: string;\n nameID?: string;\n nameIDFormat?: string;\n nameQualifier?: string;\n spNameQualifier?: string;\n ID?: string;\n mail?: string; // InCommon Attribute urn:oid:0.9.2342.19200300.100.1.3\n email?: string; // `mail` if not present in the assertion\n ['urn:oid:0.9.2342.19200300.100.1.3']?: string;\n getAssertionXml(): string; // get the raw assertion XML\n getAssertion(): Record<string, unknown>; // get the assertion XML parsed as a JavaScript object\n getSamlResponseXml(): string; // get the raw SAML response XML\n } & {\n [attributeName: string]: unknown; // arbitrary `AttributeValue`s\n };\n\n export interface RequestWithUser extends express.Request {\n samlLogoutRequest: any;\n user?: Profile\n}\n\nexport type VerifiedCallback = (err: Error | null, user?: Record<string, unknown>, info?: Record<string, unknown>) => void;\n\nexport type VerifyWithRequest = (req: express.Request, profile: Profile | null | undefined, done: VerifiedCallback) => void;\n\nexport type VerifyWithoutRequest = (profile: Profile | null | undefined, done: VerifiedCallback) => void;\n\nexport type SamlOptionsCallback = (err: Error | null, samlOptions?: SamlConfig) => void;\n\nexport interface MultiSamlConfig extends SamlConfig {\n getSamlOptions(req: express.Request, callback: SamlOptionsCallback): void;\n}\n"]}

View file

@ -0,0 +1,4 @@
import { SamlSigningOptions } from "./types";
export declare function assertRequired<T>(value: T | null | undefined, error?: string): T;
export declare function signXml(samlMessage: string, xpath: string, options: SamlSigningOptions): string;
export declare function signXmlResponse(samlMessage: string, options: SamlSigningOptions): string;

View file

@ -0,0 +1,47 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.signXmlResponse = exports.signXml = exports.assertRequired = void 0;
const xml_crypto_1 = require("xml-crypto");
const algorithms = require("./algorithms");
function assertRequired(value, error) {
if (value === undefined || value === null || (typeof value === "string" && value.length === 0)) {
throw new TypeError(error !== null && error !== void 0 ? error : "value does not exist");
}
else {
return value;
}
}
exports.assertRequired = assertRequired;
function signXml(samlMessage, xpath, options) {
const defaultTransforms = [
"http://www.w3.org/2000/09/xmldsig#enveloped-signature",
"http://www.w3.org/2001/10/xml-exc-c14n#",
];
if (!samlMessage)
throw new Error("samlMessage is required");
if (!xpath)
throw new Error("xpath is required");
if (!options) {
options = {};
}
if (!options.privateKey)
throw new Error("options.privateKey is required");
const transforms = options.xmlSignatureTransforms || defaultTransforms;
const sig = new xml_crypto_1.SignedXml();
if (options.signatureAlgorithm) {
sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);
}
sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));
sig.signingKey = options.privateKey;
sig.computeSignature(samlMessage, {
location: { reference: xpath, action: "append" },
});
return sig.getSignedXml();
}
exports.signXml = signXml;
function signXmlResponse(samlMessage, options) {
const responseXpath = '//*[local-name(.)="Response" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
return signXml(samlMessage, responseXpath, options);
}
exports.signXmlResponse = signXmlResponse;
//# sourceMappingURL=utility.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"utility.js","sourceRoot":"","sources":["../../src/passport-saml/utility.ts"],"names":[],"mappings":";;;AAAA,2CAAuC;AAEvC,2CAA2C;AAE3C,SAAgB,cAAc,CAAI,KAA2B,EAAE,KAAc;IAC3E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE;QAC9F,MAAM,IAAI,SAAS,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,sBAAsB,CAAC,CAAC;KACtD;SAAM;QACL,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAND,wCAMC;AAED,SAAgB,OAAO,CAAC,WAAmB,EAAE,KAAa,EAAE,OAA2B;IACrF,MAAM,iBAAiB,GAAG;QACxB,uDAAuD;QACvD,yCAAyC;KAC1C,CAAC;IAEF,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,GAAG,EAAwB,CAAC;KACpC;IAED,IAAI,CAAC,OAAO,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAE3E,MAAM,UAAU,GAAG,OAAO,CAAC,sBAAsB,IAAI,iBAAiB,CAAC;IACvE,MAAM,GAAG,GAAG,IAAI,sBAAS,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,kBAAkB,EAAE;QAC9B,GAAG,CAAC,kBAAkB,GAAG,UAAU,CAAC,mBAAmB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACrF;IACD,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAC5F,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACpC,GAAG,CAAC,gBAAgB,CAAC,WAAW,EAAE;QAChC,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE;KACjD,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,YAAY,EAAE,CAAC;AAC5B,CAAC;AA1BD,0BA0BC;AAED,SAAgB,eAAe,CAAC,WAAmB,EAAE,OAA2B;IAC9E,MAAM,aAAa,GACjB,2FAA2F,CAAC;IAE9F,OAAO,OAAO,CAAC,WAAW,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC;AALD,0CAKC","sourcesContent":["import { SignedXml } from \"xml-crypto\";\nimport { SamlSigningOptions } from \"./types\";\nimport * as algorithms from \"./algorithms\";\n\nexport function assertRequired<T>(value: T | null | undefined, error?: string): T {\n if (value === undefined || value === null || (typeof value === \"string\" && value.length === 0)) {\n throw new TypeError(error ?? \"value does not exist\");\n } else {\n return value;\n }\n}\n\nexport function signXml(samlMessage: string, xpath: string, options: SamlSigningOptions): string {\n const defaultTransforms = [\n \"http://www.w3.org/2000/09/xmldsig#enveloped-signature\",\n \"http://www.w3.org/2001/10/xml-exc-c14n#\",\n ];\n\n if (!samlMessage) throw new Error(\"samlMessage is required\");\n if (!xpath) throw new Error(\"xpath is required\");\n if (!options) {\n options = {} as SamlSigningOptions;\n }\n\n if (!options.privateKey) throw new Error(\"options.privateKey is required\");\n\n const transforms = options.xmlSignatureTransforms || defaultTransforms;\n const sig = new SignedXml();\n if (options.signatureAlgorithm) {\n sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);\n }\n sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));\n sig.signingKey = options.privateKey;\n sig.computeSignature(samlMessage, {\n location: { reference: xpath, action: \"append\" },\n });\n\n return sig.getSignedXml();\n}\n\nexport function signXmlResponse(samlMessage: string, options: SamlSigningOptions): string {\n const responseXpath =\n '//*[local-name(.)=\"Response\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:protocol\"]';\n\n return signXml(samlMessage, responseXpath, options);\n}\n"]}

14
node_modules/passport-saml/lib/passport-saml/xml.d.ts generated vendored Normal file
View file

@ -0,0 +1,14 @@
/// <reference types="node" />
export declare const xpath: {
selectAttributes: (node: Node, xpath: string) => Attr[];
selectElements: (node: Node, xpath: string) => Element[];
};
export declare const decryptXml: (xml: string, decryptionKey: string | Buffer) => Promise<string>;
/**
* This function checks that the |signature| is signed with a given |cert|.
*/
export declare const validateXmlSignatureForCert: (signature: Node, certPem: string, fullXml: string, currentNode: Element) => boolean;
export declare const parseDomFromString: (xml: string) => Document;
export declare const parseXml2JsFromString: (xml: string | Buffer) => Promise<any>;
export declare const buildXml2JsObject: (rootName: string, xml: any) => string;
export declare const buildXmlBuilderObject: (xml: Record<string, any>, pretty: boolean) => string;

104
node_modules/passport-saml/lib/passport-saml/xml.js generated vendored Normal file
View file

@ -0,0 +1,104 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildXmlBuilderObject = exports.buildXml2JsObject = exports.parseXml2JsFromString = exports.parseDomFromString = exports.validateXmlSignatureForCert = exports.decryptXml = exports.xpath = void 0;
const util = require("util");
const xmlCrypto = require("xml-crypto");
const xmlenc = require("xml-encryption");
const xmldom = require("xmldom");
const xml2js = require("xml2js");
const xmlbuilder = require("xmlbuilder");
const selectXPath = (guard, node, xpath) => {
const result = xmlCrypto.xpath(node, xpath);
if (!guard(result)) {
throw new Error("invalid xpath return type");
}
return result;
};
const attributesXPathTypeGuard = (values) => {
return values.every((value) => {
if (typeof value != "object") {
return false;
}
return typeof value.nodeType === "number" && value.nodeType === value.ATTRIBUTE_NODE;
});
};
const elementsXPathTypeGuard = (values) => {
return values.every((value) => {
if (typeof value != "object") {
return false;
}
return typeof value.nodeType === "number" && value.nodeType === value.ELEMENT_NODE;
});
};
exports.xpath = {
selectAttributes: (node, xpath) => selectXPath(attributesXPathTypeGuard, node, xpath),
selectElements: (node, xpath) => selectXPath(elementsXPathTypeGuard, node, xpath),
};
const decryptXml = async (xml, decryptionKey) => util.promisify(xmlenc.decrypt).bind(xmlenc)(xml, { key: decryptionKey });
exports.decryptXml = decryptXml;
const normalizeNewlines = (xml) => {
// we can use this utility before passing XML to `xml-crypto`
// we are considered the XML processor and are responsible for newline normalization
// https://github.com/node-saml/passport-saml/issues/431#issuecomment-718132752
return xml.replace(/\r\n?/g, "\n");
};
/**
* This function checks that the |signature| is signed with a given |cert|.
*/
const validateXmlSignatureForCert = (signature, certPem, fullXml, currentNode) => {
const sig = new xmlCrypto.SignedXml();
sig.keyInfoProvider = {
file: "",
getKeyInfo: () => "<X509Data></X509Data>",
getKey: () => Buffer.from(certPem),
};
const signatureStr = normalizeNewlines(signature.toString());
sig.loadSignature(signatureStr);
// We expect each signature to contain exactly one reference to the top level of the xml we
// are validating, so if we see anything else, reject.
if (sig.references.length != 1)
return false;
const refUri = sig.references[0].uri;
const refId = refUri[0] === "#" ? refUri.substring(1) : refUri;
// If we can't find the reference at the top level, reject
const idAttribute = currentNode.getAttribute("ID") ? "ID" : "Id";
if (currentNode.getAttribute(idAttribute) != refId)
return false;
// If we find any extra referenced nodes, reject. (xml-crypto only verifies one digest, so
// multiple candidate references is bad news)
const totalReferencedNodes = exports.xpath.selectElements(currentNode.ownerDocument, "//*[@" + idAttribute + "='" + refId + "']");
if (totalReferencedNodes.length > 1) {
return false;
}
fullXml = normalizeNewlines(fullXml);
return sig.checkSignature(fullXml);
};
exports.validateXmlSignatureForCert = validateXmlSignatureForCert;
const parseDomFromString = (xml) => {
return new xmldom.DOMParser().parseFromString(xml);
};
exports.parseDomFromString = parseDomFromString;
const parseXml2JsFromString = async (xml) => {
const parserConfig = {
explicitRoot: true,
explicitCharkey: true,
tagNameProcessors: [xml2js.processors.stripPrefix],
};
const parser = new xml2js.Parser(parserConfig);
return parser.parseStringPromise(xml);
};
exports.parseXml2JsFromString = parseXml2JsFromString;
const buildXml2JsObject = (rootName, xml) => {
const builderOpts = {
rootName,
headless: true,
};
return new xml2js.Builder(builderOpts).buildObject(xml);
};
exports.buildXml2JsObject = buildXml2JsObject;
const buildXmlBuilderObject = (xml, pretty) => {
const options = pretty ? { pretty: true, indent: " ", newline: "\n" } : {};
return xmlbuilder.create(xml).end(options);
};
exports.buildXmlBuilderObject = buildXmlBuilderObject;
//# sourceMappingURL=xml.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,5 @@
/// <reference types="node" />
import * as crypto from 'crypto';
export declare function getSigningAlgorithm(shortName: string): string;
export declare function getDigestAlgorithm(shortName: string): string;
export declare function getSigner(shortName: string): crypto.Signer;

View file

@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSigner = exports.getDigestAlgorithm = exports.getSigningAlgorithm = void 0;
const crypto = require("crypto");
function getSigningAlgorithm(shortName) {
switch (shortName) {
case 'sha256':
return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
case 'sha512':
return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
default:
return 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
}
}
exports.getSigningAlgorithm = getSigningAlgorithm;
function getDigestAlgorithm(shortName) {
switch (shortName) {
case 'sha256':
return 'http://www.w3.org/2001/04/xmlenc#sha256';
case 'sha512':
return 'http://www.w3.org/2001/04/xmlenc#sha512';
default:
return 'http://www.w3.org/2000/09/xmldsig#sha1';
}
}
exports.getDigestAlgorithm = getDigestAlgorithm;
function getSigner(shortName) {
switch (shortName) {
case 'sha256':
return crypto.createSign('RSA-SHA256');
case 'sha512':
return crypto.createSign('RSA-SHA512');
default:
return crypto.createSign('RSA-SHA1');
}
}
exports.getSigner = getSigner;
//# sourceMappingURL=algorithms.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"algorithms.js","sourceRoot":"","sources":["../../../src/passport-saml/algorithms.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AAEjC,SAAgB,mBAAmB,CAAE,SAAiB;IACpD,QAAO,SAAS,EAAE;QAChB,KAAK,QAAQ;YACX,OAAO,mDAAmD,CAAC;QAC7D,KAAK,QAAQ;YACX,OAAO,mDAAmD,CAAC;QAC7D;YACE,OAAO,4CAA4C,CAAC;KACvD;AACH,CAAC;AATD,kDASC;AAED,SAAgB,kBAAkB,CAAE,SAAiB;IACnD,QAAO,SAAS,EAAE;QAChB,KAAK,QAAQ;YACX,OAAO,yCAAyC,CAAC;QACnD,KAAK,QAAQ;YACX,OAAO,yCAAyC,CAAC;QACnD;YACE,OAAO,wCAAwC,CAAC;KACnD;AACH,CAAC;AATD,gDASC;AAED,SAAgB,SAAS,CAAE,SAAiB;IAC1C,QAAO,SAAS,EAAE;QAChB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC;YACE,OAAO,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;KACxC;AACH,CAAC;AATD,8BASC","sourcesContent":["import * as crypto from 'crypto';\n\nexport function getSigningAlgorithm (shortName: string): string {\n switch(shortName) {\n case 'sha256':\n return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';\n case 'sha512':\n return 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';\n default:\n return 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';\n }\n}\n\nexport function getDigestAlgorithm (shortName: string): string {\n switch(shortName) {\n case 'sha256':\n return 'http://www.w3.org/2001/04/xmlenc#sha256';\n case 'sha512':\n return 'http://www.w3.org/2001/04/xmlenc#sha512';\n default:\n return 'http://www.w3.org/2000/09/xmldsig#sha1';\n }\n}\n\nexport function getSigner (shortName: string): crypto.Signer {\n switch(shortName) {\n case 'sha256':\n return crypto.createSign('RSA-SHA256');\n case 'sha512':\n return crypto.createSign('RSA-SHA512');\n default:\n return crypto.createSign('RSA-SHA1');\n }\n}\n"]}

View file

@ -0,0 +1,6 @@
import type { CacheItem, CacheProvider } from './inmemory-cache-provider';
import { SAML } from './saml';
import Strategy = require('./strategy');
import MultiSamlStrategy = require('./multiSamlStrategy');
import type { Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest } from './types';
export { SAML, Strategy, MultiSamlStrategy, CacheItem, CacheProvider, Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest };

View file

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiSamlStrategy = exports.Strategy = exports.SAML = void 0;
const saml_1 = require("./saml");
Object.defineProperty(exports, "SAML", { enumerable: true, get: function () { return saml_1.SAML; } });
const Strategy = require("./strategy");
exports.Strategy = Strategy;
const MultiSamlStrategy = require("./multiSamlStrategy");
exports.MultiSamlStrategy = MultiSamlStrategy;
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/passport-saml/index.ts"],"names":[],"mappings":";;;AACA,iCAA8B;AAKrB,qFALA,WAAI,OAKA;AAJb,uCAAwC;AAIzB,4BAAQ;AAHvB,yDAA0D;AAGjC,8CAAiB","sourcesContent":["import type { CacheItem, CacheProvider} from './inmemory-cache-provider';\nimport { SAML } from './saml';\nimport Strategy = require('./strategy');\nimport MultiSamlStrategy = require('./multiSamlStrategy');\nimport type { Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest } from './types';\n\nexport { SAML, Strategy, MultiSamlStrategy, CacheItem, CacheProvider, Profile, SamlConfig, VerifiedCallback, VerifyWithRequest, VerifyWithoutRequest };\n"]}

View file

@ -0,0 +1,45 @@
/**
* Simple in memory cache provider. To be used to store state of requests that needs
* to be validated/checked when a response is received.
*
* This is the default implementation of a cache provider used by Passport-SAML. For
* multiple server instances/load balanced scenarios (I.e. the SAML request could have
* been generated from a different server/process handling the SAML response) this
* implementation will NOT be sufficient.
*
* The caller should provide their own implementation for a cache provider as defined
* in the config options for Passport-SAML.
* @param options
* @constructor
*/
export interface CacheItem {
value: string;
createdAt: number;
}
interface CacheProviderOptions {
keyExpirationPeriodMs: number;
}
export declare class CacheProvider {
cacheKeys: Record<string, CacheItem>;
options: CacheProviderOptions;
constructor(options: Partial<CacheProviderOptions>);
/**
* Store an item in the cache, using the specified key and value.
* Internally will keep track of the time the item was added to the cache
* @param id
* @param value
*/
save(key: string, value: string, callback: (error: null, value: CacheItem | null) => void): void;
/**
* Returns the value of the specified key in the cache
* @param id
* @returns {boolean}
*/
get(key: string, callback: (key: string | null, value: string | null) => void): void;
/**
* Removes an item from the cache if it exists
* @param key
*/
remove(key: string, callback: (err: Error | null, key: string | null) => void): void;
}
export {};

View file

@ -0,0 +1,90 @@
"use strict";
/**
* Simple in memory cache provider. To be used to store state of requests that needs
* to be validated/checked when a response is received.
*
* This is the default implementation of a cache provider used by Passport-SAML. For
* multiple server instances/load balanced scenarios (I.e. the SAML request could have
* been generated from a different server/process handling the SAML response) this
* implementation will NOT be sufficient.
*
* The caller should provide their own implementation for a cache provider as defined
* in the config options for Passport-SAML.
* @param options
* @constructor
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheProvider = void 0;
class CacheProvider {
constructor(options) {
this.cacheKeys = {};
if (!options) {
options = {};
}
if (!options.keyExpirationPeriodMs) {
options.keyExpirationPeriodMs = 28800000; // 8 hours
}
this.options = options;
// Expire old cache keys
const expirationTimer = setInterval(() => {
const nowMs = new Date().getTime();
const keys = Object.keys(this.cacheKeys);
keys.forEach((key) => {
if (nowMs >= new Date(this.cacheKeys[key].createdAt).getTime() + this.options.keyExpirationPeriodMs) {
this.remove(key, () => undefined);
}
});
}, this.options.keyExpirationPeriodMs);
// we only want this to run if the process is still open; it shouldn't hold the process open (issue #68)
// (unref only introduced in node 0.9, so check whether we have it)
// Skip this in 0.10.34 due to https://github.com/joyent/node/issues/8900
if (expirationTimer.unref && process.version !== 'v0.10.34')
expirationTimer.unref();
}
/**
* Store an item in the cache, using the specified key and value.
* Internally will keep track of the time the item was added to the cache
* @param id
* @param value
*/
save(key, value, callback) {
if (!this.cacheKeys[key]) {
this.cacheKeys[key] = {
createdAt: new Date().getTime(),
value: value
};
callback(null, this.cacheKeys[key]);
}
else {
callback(null, null);
}
}
/**
* Returns the value of the specified key in the cache
* @param id
* @returns {boolean}
*/
get(key, callback) {
if (this.cacheKeys[key]) {
callback(null, this.cacheKeys[key].value);
}
else {
callback(null, null);
}
}
/**
* Removes an item from the cache if it exists
* @param key
*/
remove(key, callback) {
if (this.cacheKeys[key]) {
delete this.cacheKeys[key];
callback(null, key);
}
else {
callback(null, null);
}
}
}
exports.CacheProvider = CacheProvider;
//# sourceMappingURL=inmemory-cache-provider.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
import SamlStrategy = require('./strategy');
import type { Request } from 'express';
import { AuthenticateOptions, AuthorizeOptions, MultiSamlConfig, RequestWithUser, VerifyWithoutRequest, VerifyWithRequest } from './types';
declare class MultiSamlStrategy extends SamlStrategy {
_options: MultiSamlConfig;
constructor(options: MultiSamlConfig, verify: VerifyWithRequest | VerifyWithoutRequest);
authenticate(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions): void;
logout(req: RequestWithUser, callback: (err: Error | null, url?: string | null | undefined) => void): void;
/** @ts-expect-error typescript disallows changing method signature in a subclass */
generateServiceProviderMetadata(req: Request, decryptionCert: string | null, signingCert: string | null, callback: (err: Error | null, metadata?: string) => void): void;
}
export = MultiSamlStrategy;

View file

@ -0,0 +1,58 @@
"use strict";
const saml = require("./saml");
const inmemory_cache_provider_1 = require("./inmemory-cache-provider");
const SamlStrategy = require("./strategy");
class MultiSamlStrategy extends SamlStrategy {
constructor(options, verify) {
if (!options || typeof options.getSamlOptions != 'function') {
throw new Error('Please provide a getSamlOptions function');
}
if (!options.requestIdExpirationPeriodMs) {
options.requestIdExpirationPeriodMs = 28800000; // 8 hours
}
if (!options.cacheProvider) {
options.cacheProvider = new inmemory_cache_provider_1.CacheProvider({ keyExpirationPeriodMs: options.requestIdExpirationPeriodMs });
}
super(options, verify);
this._options = options;
}
authenticate(req, options) {
this._options.getSamlOptions(req, (err, samlOptions) => {
if (err) {
return this.error(err);
}
const samlService = new saml.SAML({ ...this._options, ...samlOptions });
const strategy = Object.assign({}, this, { _saml: samlService });
Object.setPrototypeOf(strategy, this);
super.authenticate.call(strategy, req, options);
});
}
logout(req, callback) {
this._options.getSamlOptions(req, (err, samlOptions) => {
if (err) {
return callback(err);
}
const samlService = new saml.SAML(Object.assign({}, this._options, samlOptions));
const strategy = Object.assign({}, this, { _saml: samlService });
Object.setPrototypeOf(strategy, this);
super.logout.call(strategy, req, callback);
});
}
/** @ts-expect-error typescript disallows changing method signature in a subclass */
generateServiceProviderMetadata(req, decryptionCert, signingCert, callback) {
if (typeof callback !== 'function') {
throw new Error("Metadata can't be provided synchronously for MultiSamlStrategy.");
}
return this._options.getSamlOptions(req, (err, samlOptions) => {
if (err) {
return callback(err);
}
const samlService = new saml.SAML(Object.assign({}, this._options, samlOptions));
const strategy = Object.assign({}, this, { _saml: samlService });
Object.setPrototypeOf(strategy, this);
return callback(null, super.generateServiceProviderMetadata.call(strategy, decryptionCert, signingCert));
});
}
}
module.exports = MultiSamlStrategy;
//# sourceMappingURL=multiSamlStrategy.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
import { SAMLOptions } from './types';
export declare function signSamlPost(samlMessage: string, xpath: string, options: SAMLOptions): string;
export declare function signAuthnRequestPost(authnRequest: string, options: SAMLOptions): string;

View file

@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.signAuthnRequestPost = exports.signSamlPost = void 0;
const xml_crypto_1 = require("xml-crypto");
const algorithms = require("./algorithms");
const authnRequestXPath = '/*[local-name(.)="AuthnRequest" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
const issuerXPath = '/*[local-name(.)="Issuer" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:assertion"]';
const defaultTransforms = ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'];
function signSamlPost(samlMessage, xpath, options) {
if (!samlMessage)
throw new Error('samlMessage is required');
if (!xpath)
throw new Error('xpath is required');
if (!options) {
options = {};
}
if (options.privateCert) {
console.warn("options.privateCert has been deprecated; use options.privateKey instead.");
if (!options.privateKey) {
options.privateKey = options.privateCert;
}
}
if (!options.privateKey)
throw new Error('options.privateKey is required');
const transforms = options.xmlSignatureTransforms || defaultTransforms;
const sig = new xml_crypto_1.SignedXml();
if (options.signatureAlgorithm) {
sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);
}
sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));
sig.signingKey = options.privateKey;
sig.computeSignature(samlMessage, { location: { reference: xpath + issuerXPath, action: 'after' } });
return sig.getSignedXml();
}
exports.signSamlPost = signSamlPost;
function signAuthnRequestPost(authnRequest, options) {
return signSamlPost(authnRequest, authnRequestXPath, options);
}
exports.signAuthnRequestPost = signAuthnRequestPost;
//# sourceMappingURL=saml-post-signing.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"saml-post-signing.js","sourceRoot":"","sources":["../../../src/passport-saml/saml-post-signing.ts"],"names":[],"mappings":";;;AAAA,2CAAuC;AACvC,2CAA2C;AAG3C,MAAM,iBAAiB,GAAG,8FAA8F,CAAC;AACzH,MAAM,WAAW,GAAG,yFAAyF,CAAC;AAC9G,MAAM,iBAAiB,GAAG,CAAE,uDAAuD,EAAE,yCAAyC,CAAE,CAAC;AAEjI,SAAgB,YAAY,CAAC,WAAmB,EAAE,KAAa,EAAE,OAAoB;IACnF,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,GAAG,EAAiB,CAAC;KAC7B;IAED,IAAI,OAAO,CAAC,WAAW,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QAEzF,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YACvB,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;SAC1C;KACF;IAED,IAAI,CAAC,OAAO,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAE3E,MAAM,UAAU,GAAG,OAAO,CAAC,sBAAsB,IAAI,iBAAiB,CAAC;IACvE,MAAM,GAAG,GAAG,IAAI,sBAAS,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,kBAAkB,EAAE;QAC9B,GAAG,CAAC,kBAAkB,GAAG,UAAU,CAAC,mBAAmB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACrF;IACD,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAC5F,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACpC,GAAG,CAAC,gBAAgB,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,GAAG,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,EAAC,CAAC,CAAC;IACpG,OAAO,GAAG,CAAC,YAAY,EAAE,CAAC;AAC5B,CAAC;AA1BD,oCA0BC;AAED,SAAgB,oBAAoB,CAAC,YAAoB,EAAE,OAAoB;IAC7E,OAAO,YAAY,CAAC,YAAY,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC;AAChE,CAAC;AAFD,oDAEC","sourcesContent":["import { SignedXml } from 'xml-crypto';\nimport * as algorithms from './algorithms';\nimport { SAMLOptions } from './types';\n\nconst authnRequestXPath = '/*[local-name(.)=\"AuthnRequest\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:protocol\"]';\nconst issuerXPath = '/*[local-name(.)=\"Issuer\" and namespace-uri(.)=\"urn:oasis:names:tc:SAML:2.0:assertion\"]';\nconst defaultTransforms = [ 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#' ];\n\nexport function signSamlPost(samlMessage: string, xpath: string, options: SAMLOptions) {\n if (!samlMessage) throw new Error('samlMessage is required');\n if (!xpath) throw new Error('xpath is required');\n if (!options) {\n options = {} as SAMLOptions;\n }\n\n if (options.privateCert) {\n console.warn(\"options.privateCert has been deprecated; use options.privateKey instead.\");\n\n if (!options.privateKey) {\n options.privateKey = options.privateCert;\n }\n }\n\n if (!options.privateKey) throw new Error('options.privateKey is required');\n\n const transforms = options.xmlSignatureTransforms || defaultTransforms;\n const sig = new SignedXml();\n if (options.signatureAlgorithm) {\n sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);\n }\n sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));\n sig.signingKey = options.privateKey;\n sig.computeSignature(samlMessage, { location: { reference: xpath + issuerXPath, action: 'after' }});\n return sig.getSignedXml();\n}\n\nexport function signAuthnRequestPost(authnRequest: string, options: SAMLOptions) {\n return signSamlPost(authnRequest, authnRequestXPath, options);\n}\n"]}

View file

@ -0,0 +1,56 @@
/// <reference types="node" />
import * as xml2js from 'xml2js';
import * as crypto from 'crypto';
import * as querystring from 'querystring';
import { CacheProvider as InMemoryCacheProvider } from './inmemory-cache-provider';
import type { Request } from 'express';
import { ParsedQs } from 'qs';
import { AudienceRestrictionXML, AuthenticateOptions, AuthorizeOptions, Profile, RequestWithUser, SAMLOptions, XMLOutput } from './types';
declare class SAML {
options: SAMLOptions;
cacheProvider: InMemoryCacheProvider;
constructor(options: Partial<SAMLOptions>);
initialize(options: Partial<SAMLOptions>): SAMLOptions;
getProtocol(req: Request | {
headers?: undefined;
protocol?: undefined;
}): string;
getCallbackUrl(req: Request | {
headers?: undefined;
protocol?: undefined;
}): string;
generateUniqueID(): string;
generateInstant(): string;
signRequest(samlMessage: querystring.ParsedUrlQueryInput): void;
generateAuthorizeRequest(req: Request, isPassive: boolean, isHttpPostBinding: boolean, callback: (err: Error | null, request?: string) => void): void;
generateLogoutRequest(req: RequestWithUser): Promise<string>;
generateLogoutResponse(req: Request, logoutRequest: Profile): string;
requestToUrl(request: string | null | undefined, response: string | null, operation: string, additionalParameters: querystring.ParsedUrlQuery, callback: (err: Error | null, url?: string | null | undefined) => void): void;
getAdditionalParams(req: Request, operation: string, overrideParams?: querystring.ParsedUrlQuery): querystring.ParsedUrlQuery;
getAuthorizeUrl(req: Request, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): void;
getAuthorizeForm(req: Request, callback: (err: Error | null, data?: unknown) => void): void;
getLogoutUrl(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): Promise<void>;
getLogoutResponseUrl(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions, callback: (err: Error | null, url?: string | null) => void): void;
certToPEM(cert: string): string;
certsToCheck(): Promise<undefined | string[]>;
validateSignature(fullXml: string, currentNode: HTMLElement, certs: string[]): boolean;
validateSignatureForCert(signature: string | Node, cert: string, fullXml: string, currentNode: HTMLElement): boolean;
validatePostResponse(container: Record<string, string>, callback: (err: Error | null, profile?: Profile | null, loggedOut?: boolean) => void): void;
validateInResponseTo(inResponseTo: string | null): Promise<void>;
validateRedirect(container: ParsedQs, originalQuery: string | null, callback: (err: Error | null, profile?: Profile | null, loggedOut?: boolean) => void): void;
hasValidSignatureForRedirect(container: ParsedQs, originalQuery: string | null): Promise<boolean | void>;
validateSignatureForRedirect(urlString: crypto.BinaryLike, signature: string, alg: string, cert: string): boolean;
verifyLogoutRequest(doc: XMLOutput): void;
verifyLogoutResponse(doc: XMLOutput): Promise<boolean | void>;
verifyIssuer(samlMessage: XMLOutput): void;
processValidlySignedAssertion(xml: xml2js.convertableToString, samlResponseXml: string, inResponseTo: string, callback: (err: Error | null, profile?: Profile | undefined, loggedOut?: boolean | undefined) => void): void;
checkTimestampsValidityError(nowMs: number, notBefore: string, notOnOrAfter: string): Error | null;
checkAudienceValidityError(expectedAudience: string, audienceRestrictions: AudienceRestrictionXML[]): Error | null;
validatePostRequest(container: Record<string, string>, callback: (err: Error | null, profile?: Profile, loggedOut?: boolean) => void): void;
getNameID(self: SAML, doc: Node, callback: (err: Error | null, nameID?: XMLOutput) => void): void | Promise<void>;
generateServiceProviderMetadata(decryptionCert: string | null, signingCert?: string | null): string;
keyToPEM(key: crypto.KeyLike): crypto.KeyLike;
normalizeNewlines(xml: string): string;
normalizeXml(xml: string): string;
}
export { SAML };

1235
node_modules/passport-saml/lib/src/passport-saml/saml.js generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
import { Strategy as PassportStrategy } from 'passport-strategy';
import * as saml from './saml';
import { AuthenticateOptions, AuthorizeOptions, RequestWithUser, SamlConfig, VerifyWithoutRequest, VerifyWithRequest } from './types';
declare class Strategy extends PassportStrategy {
name: string;
_verify: VerifyWithRequest | VerifyWithoutRequest;
_saml: saml.SAML;
_passReqToCallback?: boolean;
_authnRequestBinding?: string;
constructor(options: SamlConfig, verify: VerifyWithRequest | VerifyWithoutRequest);
authenticate(req: RequestWithUser, options: AuthenticateOptions & AuthorizeOptions): void;
logout(req: RequestWithUser, callback: (err: Error | null, url?: string | null) => void): void;
generateServiceProviderMetadata(decryptionCert: string | null, signingCert?: string | null): string;
}
export = Strategy;

View file

@ -0,0 +1,112 @@
"use strict";
const passport_strategy_1 = require("passport-strategy");
const saml = require("./saml");
const url = require("url");
class Strategy extends passport_strategy_1.Strategy {
constructor(options, verify) {
super();
if (typeof options == 'function') {
verify = options;
options = {};
}
if (!verify) {
throw new Error('SAML authentication strategy requires a verify function');
}
// Customizing the name can be useful to support multiple SAML configurations at the same time.
// Unlike other options, this one gets deleted instead of passed along.
if (options.name) {
this.name = options.name;
}
else {
this.name = 'saml';
}
this._verify = verify;
this._saml = new saml.SAML(options);
this._passReqToCallback = !!options.passReqToCallback;
this._authnRequestBinding = options.authnRequestBinding || 'HTTP-Redirect';
}
authenticate(req, options) {
options.samlFallback = options.samlFallback || 'login-request';
const validateCallback = (err, profile, loggedOut) => {
if (err) {
return this.error(err);
}
if (loggedOut) {
req.logout();
if (profile) {
req.samlLogoutRequest = profile;
return this._saml.getLogoutResponseUrl(req, options, redirectIfSuccess);
}
return this.pass();
}
const verified = (err, user, info) => {
if (err) {
return this.error(err);
}
if (!user) {
return this.fail(info, 401);
}
this.success(user, info);
};
if (this._passReqToCallback) {
this._verify(req, profile, verified);
}
else {
this._verify(profile, verified);
}
};
const redirectIfSuccess = (err, url) => {
if (err) {
this.error(err);
}
else {
this.redirect(url);
}
};
if (req.query && (req.query.SAMLResponse || req.query.SAMLRequest)) {
const originalQuery = url.parse(req.url).query;
this._saml.validateRedirect(req.query, originalQuery, validateCallback);
}
else if (req.body && req.body.SAMLResponse) {
this._saml.validatePostResponse(req.body, validateCallback);
}
else if (req.body && req.body.SAMLRequest) {
this._saml.validatePostRequest(req.body, validateCallback);
}
else {
const requestHandler = {
'login-request': () => {
if (this._authnRequestBinding === 'HTTP-POST') {
this._saml.getAuthorizeForm(req, (err, data) => {
if (err) {
this.error(err);
}
else {
const res = req.res;
res.send(data);
}
});
}
else { // Defaults to HTTP-Redirect
this._saml.getAuthorizeUrl(req, options, redirectIfSuccess);
}
},
'logout-request': () => {
this._saml.getLogoutUrl(req, options, redirectIfSuccess);
}
}[options.samlFallback];
if (typeof requestHandler !== 'function') {
return this.fail(401);
}
requestHandler();
}
}
logout(req, callback) {
this._saml.getLogoutUrl(req, {}, callback);
}
generateServiceProviderMetadata(decryptionCert, signingCert) {
return this._saml.generateServiceProviderMetadata(decryptionCert, signingCert);
}
}
module.exports = Strategy;
//# sourceMappingURL=strategy.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,125 @@
import type * as express from 'express';
import * as passport from 'passport';
import type { CacheProvider } from './inmemory-cache-provider';
export declare type CertCallback = (callback: (err: Error | null, cert?: string | string[]) => void) => void;
export interface AuthenticateOptions extends passport.AuthenticateOptions {
additionalParams?: Record<string, any>;
}
export interface AuthorizeOptions extends AuthenticateOptions {
samlFallback?: 'login-request' | 'logout-request';
}
export interface SAMLOptions {
callbackUrl: string;
path: string;
protocol: string;
host: string;
entryPoint: string;
issuer: string;
/** @deprecated use privateKey field instead */
privateCert?: string;
privateKey: string;
cert: string | string[] | CertCallback;
decryptionPvk: string;
signatureAlgorithm: 'sha1' | 'sha256' | 'sha512';
additionalParams: Record<string, string>;
additionalAuthorizeParams: Record<string, string>;
identifierFormat: string;
acceptedClockSkewMs: number;
attributeConsumingServiceIndex: string | null;
disableRequestedAuthnContext: boolean;
authnContext: string | string[];
forceAuthn: boolean;
skipRequestCompression: boolean;
/** @deprecated use racComparison field instead */
RACComparison?: 'exact' | 'minimum' | 'maximum' | 'better';
racComparison: 'exact' | 'minimum' | 'maximum' | 'better';
providerName: string;
passive: boolean;
idpIssuer: string;
audience: string;
scoping: SamlScopingConfig;
validateInResponseTo: boolean;
requestIdExpirationPeriodMs: number;
cacheProvider: CacheProvider;
logoutUrl: string;
additionalLogoutParams: Record<string, string>;
logoutCallbackUrl: string;
xmlSignatureTransforms: string[];
digestAlgorithm: string;
/** @deprecated use disableRequestAcsUrl field instead */
disableRequestACSUrl?: boolean;
disableRequestAcsUrl: boolean;
}
export declare type SamlConfig = Partial<SAMLOptions> & StrategyOptions;
interface StrategyOptions {
name?: string;
passReqToCallback?: boolean;
authnRequestBinding?: string;
}
export interface SamlScopingConfig {
idpList?: SamlIDPListConfig[];
proxyCount?: number;
requesterId?: string[];
}
export declare type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];
export declare type XMLObject = {
[key: string]: XMLValue;
};
export declare type XMLInput = XMLObject;
export interface AuthorizeRequestXML {
'samlp:AuthnRequest': XMLInput;
}
export interface LogoutRequestXML {
'samlp:LogoutRequest': {
'saml:NameID': XMLInput;
[key: string]: XMLValue;
};
}
export interface ServiceMetadataXML {
EntityDescriptor: {
[key: string]: XMLValue;
SPSSODescriptor: XMLObject;
};
}
export interface AudienceRestrictionXML {
Audience?: XMLObject[];
}
export declare type XMLOutput = Record<string, any>;
export interface SamlIDPListConfig {
entries: SamlIDPEntryConfig[];
getComplete?: string;
}
export interface SamlIDPEntryConfig {
providerId: string;
name?: string;
loc?: string;
}
export declare type Profile = {
issuer?: string;
sessionIndex?: string;
nameID?: string;
nameIDFormat?: string;
nameQualifier?: string;
spNameQualifier?: string;
ID?: string;
mail?: string;
email?: string;
['urn:oid:0.9.2342.19200300.100.1.3']?: string;
getAssertionXml(): string;
getAssertion(): Record<string, unknown>;
getSamlResponseXml(): string;
} & {
[attributeName: string]: unknown;
};
export interface RequestWithUser extends express.Request {
samlLogoutRequest: any;
user?: Profile;
}
export declare type VerifiedCallback = (err: Error | null, user?: Record<string, unknown>, info?: Record<string, unknown>) => void;
export declare type VerifyWithRequest = (req: express.Request, profile: Profile | null | undefined, done: VerifiedCallback) => void;
export declare type VerifyWithoutRequest = (profile: Profile | null | undefined, done: VerifiedCallback) => void;
export declare type SamlOptionsCallback = (err: Error | null, samlOptions?: SamlConfig) => void;
export interface MultiSamlConfig extends SamlConfig {
getSamlOptions(req: express.Request, callback: SamlOptionsCallback): void;
}
export {};

View file

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/passport-saml/types.ts"],"names":[],"mappings":"","sourcesContent":["import type * as express from 'express';\nimport * as passport from 'passport';\nimport type { CacheProvider } from './inmemory-cache-provider';\n\nexport type CertCallback = (callback: (err: Error | null, cert?: string | string[]) => void) => void;\n\nexport interface AuthenticateOptions extends passport.AuthenticateOptions {\n additionalParams?: Record<string, any>;\n}\n\nexport interface AuthorizeOptions extends AuthenticateOptions {\n samlFallback?: 'login-request' | 'logout-request';\n}\n\nexport interface SAMLOptions {\n // Core\n callbackUrl: string;\n path: string;\n protocol: string;\n host: string;\n entryPoint: string;\n issuer: string;\n /** @deprecated use privateKey field instead */\n privateCert?: string;\n privateKey: string;\n cert: string | string[] | CertCallback;\n decryptionPvk: string;\n signatureAlgorithm: 'sha1' | 'sha256' | 'sha512';\n\n // Additional SAML behaviors\n additionalParams: Record<string, string>;\n additionalAuthorizeParams: Record<string, string>;\n identifierFormat: string;\n acceptedClockSkewMs: number;\n attributeConsumingServiceIndex: string | null;\n disableRequestedAuthnContext: boolean;\n authnContext: string | string[];\n forceAuthn: boolean;\n skipRequestCompression: boolean;\n /** @deprecated use racComparison field instead */\n RACComparison?: 'exact' | 'minimum' | 'maximum' | 'better';\n racComparison: 'exact' | 'minimum' | 'maximum' | 'better';\n providerName: string;\n passive: boolean;\n idpIssuer: string;\n audience: string;\n scoping : SamlScopingConfig;\n\n // InResponseTo Validation\n validateInResponseTo: boolean;\n requestIdExpirationPeriodMs: number;\n cacheProvider: CacheProvider;\n\n // Logout\n logoutUrl: string;\n additionalLogoutParams: Record<string, string>;\n logoutCallbackUrl: string;\n\n // extras\n xmlSignatureTransforms: string[];\n digestAlgorithm: string;\n /** @deprecated use disableRequestAcsUrl field instead */\n disableRequestACSUrl?: boolean;\n disableRequestAcsUrl: boolean;\n}\n\nexport type SamlConfig = Partial<SAMLOptions> & StrategyOptions\n\ninterface StrategyOptions {\n name?: string;\n passReqToCallback?: boolean;\n authnRequestBinding?: string;\n}\n\nexport interface SamlScopingConfig {\n idpList?: SamlIDPListConfig[];\n proxyCount?: number;\n requesterId?: string[];\n}\n\nexport type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];\n\nexport type XMLObject = {\n [key: string]: XMLValue;\n};\n\nexport type XMLInput = XMLObject;\n\nexport interface AuthorizeRequestXML {\n 'samlp:AuthnRequest': XMLInput;\n}\n\nexport interface LogoutRequestXML {\n 'samlp:LogoutRequest': {\n 'saml:NameID': XMLInput;\n [key: string]: XMLValue;\n };\n}\n\nexport interface ServiceMetadataXML {\n EntityDescriptor: {\n [key: string]: XMLValue;\n SPSSODescriptor: XMLObject;\n };\n}\n\nexport interface AudienceRestrictionXML {\n Audience?: XMLObject[];\n}\n\nexport type XMLOutput = Record<string, any>;\n\nexport interface SamlIDPListConfig {\n entries: SamlIDPEntryConfig[];\n getComplete?: string;\n}\n\nexport interface SamlIDPEntryConfig {\n providerId: string;\n name?: string;\n loc?: string;\n}\n\nexport type Profile = {\n issuer?: string;\n sessionIndex?: string;\n nameID?: string;\n nameIDFormat?: string;\n nameQualifier?: string;\n spNameQualifier?: string;\n ID?: string;\n mail?: string; // InCommon Attribute urn:oid:0.9.2342.19200300.100.1.3\n email?: string; // `mail` if not present in the assertion\n ['urn:oid:0.9.2342.19200300.100.1.3']?: string;\n getAssertionXml(): string; // get the raw assertion XML\n getAssertion(): Record<string, unknown>; // get the assertion XML parsed as a JavaScript object\n getSamlResponseXml(): string; // get the raw SAML response XML\n } & {\n [attributeName: string]: unknown; // arbitrary `AttributeValue`s\n };\n\n export interface RequestWithUser extends express.Request {\n samlLogoutRequest: any;\n user?: Profile\n}\n\nexport type VerifiedCallback = (err: Error | null, user?: Record<string, unknown>, info?: Record<string, unknown>) => void;\n\nexport type VerifyWithRequest = (req: express.Request, profile: Profile | null | undefined, done: VerifiedCallback) => void;\n\nexport type VerifyWithoutRequest = (profile: Profile | null | undefined, done: VerifiedCallback) => void;\n\nexport type SamlOptionsCallback = (err: Error | null, samlOptions?: SamlConfig) => void;\n\nexport interface MultiSamlConfig extends SamlConfig {\n getSamlOptions(req: express.Request, callback: SamlOptionsCallback): void;\n}\n"]}

1
node_modules/passport-saml/lib/test.d.ts generated vendored Normal file
View file

@ -0,0 +1 @@
export {};

22
node_modules/passport-saml/lib/test.js generated vendored Normal file
View file

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const passport = require("passport");
const passport_saml_1 = require("./passport-saml");
function findByEmail(email, cb) {
cb(null);
}
passport.use(new passport_saml_1.Strategy({
path: "/login/callback",
entryPoint: "https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php",
issuer: "passport-saml",
}, function (profile, done) {
if (profile != null && typeof profile.email === "string") {
findByEmail(profile.email, function (err, user) {
if (err) {
return done(err);
}
return done(null, user);
});
}
}));
//# sourceMappingURL=test.js.map

1
node_modules/passport-saml/lib/test.js.map generated vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"test.js","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":";;AAAA,qCAAqC;AACrC,mDAA2D;AAG3D,SAAS,WAAW,CAAC,KAAa,EAAE,EAAoB;IACtD,EAAE,CAAC,IAAI,CAAC,CAAC;AACX,CAAC;AAED,QAAQ,CAAC,GAAG,CACV,IAAI,wBAAY,CACd;IACE,IAAI,EAAE,iBAAiB;IACvB,UAAU,EACR,8DAA8D;IAChE,MAAM,EAAE,eAAe;CACxB,EACD,UAAU,OAAmC,EAAE,IAAsB;IACnE,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE;QACxD,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,EAAE,IAAI;YAC5C,IAAI,GAAG,EAAE;gBACP,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;aAClB;YACD,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;KACJ;AACH,CAAC,CACF,CACF,CAAC","sourcesContent":["import * as passport from \"passport\";\nimport { Strategy as SamlStrategy } from \"./passport-saml\";\nimport { Profile, VerifiedCallback } from \"./passport-saml/types\";\n\nfunction findByEmail(email: string, cb: VerifiedCallback) {\n cb(null);\n}\n\npassport.use(\n new SamlStrategy(\n {\n path: \"/login/callback\",\n entryPoint:\n \"https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php\",\n issuer: \"passport-saml\",\n },\n function (profile: Profile | null | undefined, done: VerifiedCallback) {\n if (profile != null && typeof profile.email === \"string\") {\n findByEmail(profile.email, function (err, user) {\n if (err) {\n return done(err);\n }\n return done(null, user);\n });\n }\n }\n )\n);\n"]}