@tachybase/plugin-auth-saml 0.23.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.turbo/turbo-build.log +14 -0
  2. package/README.md +11 -0
  3. package/README.zh-CN.md +55 -0
  4. package/client.d.ts +2 -0
  5. package/client.js +1 -0
  6. package/dist/client/Options.d.ts +2 -0
  7. package/dist/client/SAMLButton.d.ts +5 -0
  8. package/dist/client/index.d.ts +5 -0
  9. package/dist/client/index.js +3 -0
  10. package/dist/client/locale/index.d.ts +3 -0
  11. package/dist/client/schemas/saml.d.ts +35 -0
  12. package/dist/constants.d.ts +2 -0
  13. package/dist/constants.js +31 -0
  14. package/dist/externalVersion.js +14 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +39 -0
  17. package/dist/locale/en-US.json +26 -0
  18. package/dist/locale/es-ES.json +22 -0
  19. package/dist/locale/fr-FR.json +22 -0
  20. package/dist/locale/ko_KR.json +29 -0
  21. package/dist/locale/pt-BR.json +22 -0
  22. package/dist/locale/zh-CN.json +29 -0
  23. package/dist/node_modules/@node-saml/node-saml/LICENSE +23 -0
  24. package/dist/node_modules/@node-saml/node-saml/lib/algorithms.d.ts +5 -0
  25. package/dist/node_modules/@node-saml/node-saml/lib/algorithms.js +41 -0
  26. package/dist/node_modules/@node-saml/node-saml/lib/crypto.d.ts +5 -0
  27. package/dist/node_modules/@node-saml/node-saml/lib/crypto.js +48 -0
  28. package/dist/node_modules/@node-saml/node-saml/lib/datetime.d.ts +13 -0
  29. package/dist/node_modules/@node-saml/node-saml/lib/datetime.js +27 -0
  30. package/dist/node_modules/@node-saml/node-saml/lib/index.d.ts +3 -0
  31. package/dist/node_modules/@node-saml/node-saml/lib/index.js +9 -0
  32. package/dist/node_modules/@node-saml/node-saml/lib/inmemory-cache-provider.d.ts +38 -0
  33. package/dist/node_modules/@node-saml/node-saml/lib/inmemory-cache-provider.js +100 -0
  34. package/dist/node_modules/@node-saml/node-saml/lib/metadata.d.ts +2 -0
  35. package/dist/node_modules/@node-saml/node-saml/lib/metadata.js +112 -0
  36. package/dist/node_modules/@node-saml/node-saml/lib/passport-saml-types.d.ts +8 -0
  37. package/dist/node_modules/@node-saml/node-saml/lib/passport-saml-types.js +3 -0
  38. package/dist/node_modules/@node-saml/node-saml/lib/saml-post-signing.d.ts +3 -0
  39. package/dist/node_modules/@node-saml/node-saml/lib/saml-post-signing.js +15 -0
  40. package/dist/node_modules/@node-saml/node-saml/lib/saml.d.ts +75 -0
  41. package/dist/node_modules/@node-saml/node-saml/lib/saml.js +1005 -0
  42. package/dist/node_modules/@node-saml/node-saml/lib/types.d.ts +219 -0
  43. package/dist/node_modules/@node-saml/node-saml/lib/types.js +21 -0
  44. package/dist/node_modules/@node-saml/node-saml/lib/utility.d.ts +5 -0
  45. package/dist/node_modules/@node-saml/node-saml/lib/utility.js +27 -0
  46. package/dist/node_modules/@node-saml/node-saml/lib/xml.d.ts +26 -0
  47. package/dist/node_modules/@node-saml/node-saml/lib/xml.js +234 -0
  48. package/dist/node_modules/@node-saml/node-saml/package.json +1 -0
  49. package/dist/server/actions/getAuthUrl.d.ts +2 -0
  50. package/dist/server/actions/getAuthUrl.js +35 -0
  51. package/dist/server/actions/metadata.d.ts +2 -0
  52. package/dist/server/actions/metadata.js +36 -0
  53. package/dist/server/actions/redirect.d.ts +2 -0
  54. package/dist/server/actions/redirect.js +49 -0
  55. package/dist/server/index.d.ts +1 -0
  56. package/dist/server/index.js +33 -0
  57. package/dist/server/migrations/20231008112900-update-autosignup.d.ts +6 -0
  58. package/dist/server/migrations/20231008112900-update-autosignup.js +52 -0
  59. package/dist/server/plugin.d.ts +11 -0
  60. package/dist/server/plugin.js +70 -0
  61. package/dist/server/saml-auth.d.ts +8 -0
  62. package/dist/server/saml-auth.js +110 -0
  63. package/dist/swagger/index.d.ts +137 -0
  64. package/dist/swagger/index.js +163 -0
  65. package/package.json +35 -0
  66. package/server.d.ts +2 -0
  67. package/server.js +1 -0
@@ -0,0 +1,219 @@
1
+ /// <reference types="node" />
2
+ export declare type SignatureAlgorithm = "sha1" | "sha256" | "sha512";
3
+ export interface SamlSigningOptions {
4
+ privateKey: string | Buffer;
5
+ signatureAlgorithm?: SignatureAlgorithm;
6
+ xmlSignatureTransforms?: string[];
7
+ digestAlgorithm?: string;
8
+ }
9
+ export declare const isValidSamlSigningOptions: (options: Partial<SamlSigningOptions>) => options is SamlSigningOptions;
10
+ export interface AudienceRestrictionXML {
11
+ Audience?: XMLObject[];
12
+ }
13
+ export interface CacheItem {
14
+ value: string;
15
+ createdAt: number;
16
+ }
17
+ export interface CacheProvider {
18
+ saveAsync(key: string, value: string): Promise<CacheItem | null>;
19
+ getAsync(key: string): Promise<string | null>;
20
+ removeAsync(key: string | null): Promise<string | null>;
21
+ }
22
+ export declare type XMLValue = string | number | boolean | null | XMLObject | XMLValue[];
23
+ export declare type XMLObject = {
24
+ [key: string]: XMLValue;
25
+ };
26
+ export declare type XMLInput = XMLObject;
27
+ export declare type XMLOutput = Record<string, any>;
28
+ export declare type AuthorizeRequestXML = {
29
+ "samlp:AuthnRequest": XMLInput;
30
+ };
31
+ export declare type XmlJsObject = {
32
+ [key: string]: string | XmlJsObject | XmlJsObject[] | undefined;
33
+ $?: {
34
+ Value: string;
35
+ };
36
+ _?: string;
37
+ };
38
+ export declare type SamlResponseXmlJs = XmlJsObject & {
39
+ Response?: SamlAssertionXmlJs | SamlStatusXmlJs;
40
+ LogoutResponse?: unknown;
41
+ };
42
+ export declare type SamlRequestXmlJs = {
43
+ Request: unknown;
44
+ };
45
+ export declare type SamlAssertionXmlJs = {
46
+ Assertion: unknown;
47
+ };
48
+ export declare type SamlStatusXmlJs = {
49
+ Status: [
50
+ {
51
+ StatusCode: [XmlJsObject & {
52
+ StatusCode: [XmlJsObject];
53
+ }];
54
+ StatusMessage: [XmlJsObject];
55
+ }
56
+ ];
57
+ };
58
+ export declare type CertCallback = (callback: (err: Error | null, cert?: string | string[]) => void) => void;
59
+ /**
60
+ * These are SAML options that must be provided to construct a new SAML Strategy
61
+ */
62
+ export interface MandatorySamlOptions {
63
+ cert: string | string[] | CertCallback;
64
+ issuer: string;
65
+ }
66
+ export interface SamlIDPListConfig {
67
+ entries: SamlIDPEntryConfig[];
68
+ getComplete?: string;
69
+ }
70
+ export interface SamlIDPEntryConfig {
71
+ providerId: string;
72
+ name?: string;
73
+ loc?: string;
74
+ }
75
+ export declare type LogoutRequestXML = {
76
+ "samlp:LogoutRequest": {
77
+ "saml:NameID": XMLInput;
78
+ [key: string]: XMLValue;
79
+ };
80
+ };
81
+ export declare type ServiceMetadataXML = {
82
+ EntityDescriptor: {
83
+ [key: string]: XMLValue;
84
+ SPSSODescriptor: XMLObject;
85
+ };
86
+ };
87
+ export interface NameID {
88
+ value: string | null;
89
+ format: string | null;
90
+ }
91
+ export interface XmlSignatureLocation {
92
+ reference: string;
93
+ action: "append" | "prepend" | "before" | "after";
94
+ }
95
+ export declare type RacComparision = "exact" | "minimum" | "maximum" | "better";
96
+ interface SamlScopingConfig {
97
+ idpList?: SamlIDPListConfig[];
98
+ proxyCount?: number;
99
+ requesterId?: string[] | string;
100
+ }
101
+ export declare enum ValidateInResponseTo {
102
+ never = "never",
103
+ ifPresent = "ifPresent",
104
+ always = "always"
105
+ }
106
+ /**
107
+ * The options required to use a SAML strategy
108
+ * These may be provided by means of defaults specified in the constructor
109
+ */
110
+ export interface SamlOptions extends Partial<SamlSigningOptions>, MandatorySamlOptions {
111
+ callbackUrl?: string;
112
+ path: string;
113
+ protocol?: string;
114
+ host: string;
115
+ entryPoint?: string;
116
+ decryptionPvk?: string | Buffer;
117
+ additionalParams: Record<string, string>;
118
+ additionalAuthorizeParams: Record<string, string>;
119
+ identifierFormat: string | null;
120
+ allowCreate: boolean;
121
+ spNameQualifier?: string | null;
122
+ acceptedClockSkewMs: number;
123
+ attributeConsumingServiceIndex?: string;
124
+ disableRequestedAuthnContext: boolean;
125
+ authnContext: string[];
126
+ forceAuthn: boolean;
127
+ skipRequestCompression: boolean;
128
+ authnRequestBinding?: string;
129
+ racComparison: RacComparision;
130
+ providerName?: string;
131
+ passive: boolean;
132
+ idpIssuer?: string;
133
+ audience: string | false;
134
+ scoping?: SamlScopingConfig;
135
+ wantAssertionsSigned: boolean;
136
+ wantAuthnResponseSigned: boolean;
137
+ maxAssertionAgeMs: number;
138
+ generateUniqueId: () => string;
139
+ signMetadata: boolean;
140
+ validateInResponseTo: ValidateInResponseTo;
141
+ requestIdExpirationPeriodMs: number;
142
+ cacheProvider: CacheProvider;
143
+ logoutUrl: string;
144
+ additionalLogoutParams: Record<string, string>;
145
+ logoutCallbackUrl?: string;
146
+ disableRequestAcsUrl: boolean;
147
+ samlAuthnRequestExtensions?: Record<string, unknown>;
148
+ samlLogoutRequestExtensions?: Record<string, unknown>;
149
+ metadataContactPerson?: {
150
+ "@contactType": "technical" | "support" | "administrative" | "billing" | "other";
151
+ Extensions?: string;
152
+ Company?: string;
153
+ GivenName?: string;
154
+ SurName?: string;
155
+ EmailAddress?: [string];
156
+ TelephoneNumber?: [string];
157
+ }[];
158
+ metadataOrganization?: {
159
+ OrganizationName: {
160
+ "@xml:lang": string;
161
+ "#text": string;
162
+ }[];
163
+ OrganizationDisplayName: {
164
+ "@xml:lang": string;
165
+ "#text": string;
166
+ }[];
167
+ OrganizationURL: {
168
+ "@xml:lang": string;
169
+ "#text": string;
170
+ }[];
171
+ };
172
+ }
173
+ export interface GenerateServiceProviderMetadataParams {
174
+ decryptionCert?: string | null;
175
+ signingCerts?: string | string[] | null;
176
+ issuer: SamlOptions["issuer"];
177
+ callbackUrl: SamlOptions["callbackUrl"];
178
+ logoutCallbackUrl?: SamlOptions["logoutCallbackUrl"];
179
+ identifierFormat?: SamlOptions["identifierFormat"];
180
+ wantAssertionsSigned: SamlOptions["wantAssertionsSigned"];
181
+ decryptionPvk?: SamlOptions["decryptionPvk"];
182
+ privateKey?: SamlOptions["privateKey"];
183
+ signatureAlgorithm?: SamlOptions["signatureAlgorithm"];
184
+ xmlSignatureTransforms?: SamlOptions["xmlSignatureTransforms"];
185
+ digestAlgorithm?: SamlOptions["digestAlgorithm"];
186
+ signMetadata?: SamlOptions["signMetadata"];
187
+ metadataContactPerson?: SamlOptions["metadataContactPerson"];
188
+ metadataOrganization?: SamlOptions["metadataOrganization"];
189
+ generateUniqueId: SamlOptions["generateUniqueId"];
190
+ }
191
+ export interface StrategyOptions {
192
+ name?: string;
193
+ passReqToCallback?: boolean;
194
+ }
195
+ /**
196
+ * These options are availble for configuring a SAML strategy
197
+ */
198
+ export declare type SamlConfig = Partial<SamlOptions> & StrategyOptions & MandatorySamlOptions;
199
+ export interface Profile {
200
+ issuer: string;
201
+ sessionIndex?: string;
202
+ nameID: string;
203
+ nameIDFormat: string;
204
+ nameQualifier?: string;
205
+ spNameQualifier?: string;
206
+ ID?: string;
207
+ mail?: string;
208
+ email?: string;
209
+ ["urn:oid:0.9.2342.19200300.100.1.3"]?: string;
210
+ getAssertionXml?(): string;
211
+ getAssertion?(): Record<string, unknown>;
212
+ getSamlResponseXml?(): string;
213
+ [attributeName: string]: unknown;
214
+ }
215
+ export declare class ErrorWithXmlStatus extends Error {
216
+ readonly xmlStatus: string;
217
+ constructor(message: string, xmlStatus: string);
218
+ }
219
+ export {};
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorWithXmlStatus = exports.ValidateInResponseTo = exports.isValidSamlSigningOptions = void 0;
4
+ const isValidSamlSigningOptions = (options) => {
5
+ return options.privateKey != null;
6
+ };
7
+ exports.isValidSamlSigningOptions = isValidSamlSigningOptions;
8
+ var ValidateInResponseTo;
9
+ (function (ValidateInResponseTo) {
10
+ ValidateInResponseTo["never"] = "never";
11
+ ValidateInResponseTo["ifPresent"] = "ifPresent";
12
+ ValidateInResponseTo["always"] = "always";
13
+ })(ValidateInResponseTo = exports.ValidateInResponseTo || (exports.ValidateInResponseTo = {}));
14
+ class ErrorWithXmlStatus extends Error {
15
+ constructor(message, xmlStatus) {
16
+ super(message);
17
+ this.xmlStatus = xmlStatus;
18
+ }
19
+ }
20
+ exports.ErrorWithXmlStatus = ErrorWithXmlStatus;
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,5 @@
1
+ import { SamlSigningOptions } from "./types";
2
+ export declare function assertRequired<T>(value: T | null | undefined, error?: string): asserts value;
3
+ export declare function assertBooleanIfPresent<T>(value: T | null | undefined, error?: string): asserts value;
4
+ export declare function signXmlResponse(samlMessage: string, options: SamlSigningOptions): string;
5
+ export declare function signXmlMetadata(metadataXml: string, options: SamlSigningOptions): string;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.signXmlMetadata = exports.signXmlResponse = exports.assertBooleanIfPresent = exports.assertRequired = void 0;
4
+ const xml_1 = require("./xml");
5
+ function assertRequired(value, error) {
6
+ if (value === undefined || value === null || (typeof value === "string" && value.length === 0)) {
7
+ throw new TypeError(error !== null && error !== void 0 ? error : "value does not exist");
8
+ }
9
+ }
10
+ exports.assertRequired = assertRequired;
11
+ function assertBooleanIfPresent(value, error) {
12
+ if (value != null && typeof value != "boolean") {
13
+ throw new TypeError(error !== null && error !== void 0 ? error : "value is set but not boolean");
14
+ }
15
+ }
16
+ exports.assertBooleanIfPresent = assertBooleanIfPresent;
17
+ function signXmlResponse(samlMessage, options) {
18
+ const responseXpath = '//*[local-name(.)="Response" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
19
+ return (0, xml_1.signXml)(samlMessage, responseXpath, { reference: responseXpath, action: "append" }, options);
20
+ }
21
+ exports.signXmlResponse = signXmlResponse;
22
+ function signXmlMetadata(metadataXml, options) {
23
+ const metadataXpath = '//*[local-name(.)="EntityDescriptor" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:metadata"]';
24
+ return (0, xml_1.signXml)(metadataXml, metadataXpath, { reference: metadataXpath, action: "prepend" }, options);
25
+ }
26
+ exports.signXmlMetadata = signXmlMetadata;
27
+ //# sourceMappingURL=utility.js.map
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ import { NameID, SamlSigningOptions, XmlJsObject, XMLOutput, XmlSignatureLocation } from "./types";
3
+ export declare const xpath: {
4
+ selectAttributes: (node: Node, xpath: string) => Attr[];
5
+ selectElements: (node: Node, xpath: string) => Element[];
6
+ };
7
+ export declare const decryptXml: (xml: string, decryptionKey: string | Buffer) => Promise<string>;
8
+ /**
9
+ * This function checks that the |currentNode| in the |fullXml| document contains exactly 1 valid
10
+ * signature of the |currentNode|.
11
+ *
12
+ * See https://github.com/bergie/passport-saml/issues/19 for references to some of the attack
13
+ * vectors against SAML signature verification.
14
+ */
15
+ export declare const validateSignature: (fullXml: string, currentNode: Element, certs: string[]) => boolean;
16
+ /**
17
+ * This function checks that the |signature| is signed with a given |cert|.
18
+ */
19
+ export declare const validateXmlSignatureForCert: (signature: Node, certPem: string, fullXml: string, currentNode: Element) => boolean;
20
+ export declare const signXml: (xml: string, xpath: string, location: XmlSignatureLocation, options: SamlSigningOptions) => string;
21
+ export declare const parseDomFromString: (xml: string) => Promise<Document>;
22
+ export declare const parseXml2JsFromString: (xml: string | Buffer) => Promise<XmlJsObject>;
23
+ export declare const buildXml2JsObject: (rootName: string, xml: XmlJsObject) => string;
24
+ export declare const buildXmlBuilderObject: (xml: XMLOutput, pretty: boolean) => string;
25
+ export declare const promiseWithNameId: (nameid: Node) => Promise<NameID>;
26
+ export declare const getNameIdAsync: (doc: Node, decryptionPvk: string | Buffer | null) => Promise<NameID>;
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNameIdAsync = exports.promiseWithNameId = exports.buildXmlBuilderObject = exports.buildXml2JsObject = exports.parseXml2JsFromString = exports.parseDomFromString = exports.signXml = exports.validateXmlSignatureForCert = exports.validateSignature = exports.decryptXml = exports.xpath = void 0;
4
+ const util = require("util");
5
+ const xmlCrypto = require("xml-crypto");
6
+ const xmlenc = require("xml-encryption");
7
+ const xmldom = require("@xmldom/xmldom");
8
+ const xml2js = require("xml2js");
9
+ const xmlbuilder = require("xmlbuilder");
10
+ const types_1 = require("./types");
11
+ const algorithms = require("./algorithms");
12
+ const utility_1 = require("./utility");
13
+ const crypto_1 = require("./crypto");
14
+ const selectXPath = (guard, node, xpath) => {
15
+ const result = xmlCrypto.xpath(node, xpath);
16
+ if (!guard(result)) {
17
+ throw new Error("invalid xpath return type");
18
+ }
19
+ return result;
20
+ };
21
+ const attributesXPathTypeGuard = (values) => {
22
+ return values.every((value) => {
23
+ if (typeof value != "object") {
24
+ return false;
25
+ }
26
+ return typeof value.nodeType === "number" && value.nodeType === value.ATTRIBUTE_NODE;
27
+ });
28
+ };
29
+ const elementsXPathTypeGuard = (values) => {
30
+ return values.every((value) => {
31
+ if (typeof value != "object") {
32
+ return false;
33
+ }
34
+ return typeof value.nodeType === "number" && value.nodeType === value.ELEMENT_NODE;
35
+ });
36
+ };
37
+ exports.xpath = {
38
+ selectAttributes: (node, xpath) => selectXPath(attributesXPathTypeGuard, node, xpath),
39
+ selectElements: (node, xpath) => selectXPath(elementsXPathTypeGuard, node, xpath),
40
+ };
41
+ const decryptXml = async (xml, decryptionKey) => util.promisify(xmlenc.decrypt).bind(xmlenc)(xml, { key: decryptionKey });
42
+ exports.decryptXml = decryptXml;
43
+ /**
44
+ * we can use this utility before passing XML to `xml-crypto`
45
+ * we are considered the XML processor and are responsible for newline normalization
46
+ * https://github.com/node-saml/passport-saml/issues/431#issuecomment-718132752
47
+ */
48
+ const normalizeNewlines = (xml) => {
49
+ return xml.replace(/\r\n?/g, "\n");
50
+ };
51
+ /**
52
+ * This function checks that the |currentNode| in the |fullXml| document contains exactly 1 valid
53
+ * signature of the |currentNode|.
54
+ *
55
+ * See https://github.com/bergie/passport-saml/issues/19 for references to some of the attack
56
+ * vectors against SAML signature verification.
57
+ */
58
+ const validateSignature = (fullXml, currentNode, certs) => {
59
+ const xpathSigQuery = ".//*[" +
60
+ "local-name(.)='Signature' and " +
61
+ "namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#' and " +
62
+ "descendant::*[local-name(.)='Reference' and @URI='#" +
63
+ currentNode.getAttribute("ID") +
64
+ "']" +
65
+ "]";
66
+ const signatures = exports.xpath.selectElements(currentNode, xpathSigQuery);
67
+ // This function is expecting to validate exactly one signature, so if we find more or fewer
68
+ // than that, reject.
69
+ if (signatures.length !== 1) {
70
+ return false;
71
+ }
72
+ const xpathTransformQuery = ".//*[" +
73
+ "local-name(.)='Transform' and " +
74
+ "namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#' and " +
75
+ "ancestor::*[local-name(.)='Reference' and @URI='#" +
76
+ currentNode.getAttribute("ID") +
77
+ "']" +
78
+ "]";
79
+ const transforms = exports.xpath.selectElements(currentNode, xpathTransformQuery);
80
+ // Reject also XMLDSIG with more than 2 Transform
81
+ if (transforms.length > 2) {
82
+ // do not return false, throw an error so that it can be caught by tests differently
83
+ throw new Error("Invalid signature, too many transforms");
84
+ }
85
+ const signature = signatures[0];
86
+ return certs.some((certToCheck) => {
87
+ return (0, exports.validateXmlSignatureForCert)(signature, (0, crypto_1.certToPEM)(certToCheck), fullXml, currentNode);
88
+ });
89
+ };
90
+ exports.validateSignature = validateSignature;
91
+ /**
92
+ * This function checks that the |signature| is signed with a given |cert|.
93
+ */
94
+ const validateXmlSignatureForCert = (signature, certPem, fullXml, currentNode) => {
95
+ const sig = new xmlCrypto.SignedXml();
96
+ sig.keyInfoProvider = {
97
+ file: "",
98
+ getKeyInfo: () => "<X509Data></X509Data>",
99
+ getKey: () => Buffer.from(certPem),
100
+ };
101
+ sig.loadSignature(signature);
102
+ // We expect each signature to contain exactly one reference to the top level of the xml we
103
+ // are validating, so if we see anything else, reject.
104
+ if (sig.references.length != 1)
105
+ return false;
106
+ const refUri = sig.references[0].uri;
107
+ (0, utility_1.assertRequired)(refUri, "signature reference uri not found");
108
+ const refId = refUri[0] === "#" ? refUri.substring(1) : refUri;
109
+ // If we can't find the reference at the top level, reject
110
+ const idAttribute = currentNode.getAttribute("ID") ? "ID" : "Id";
111
+ if (currentNode.getAttribute(idAttribute) != refId)
112
+ return false;
113
+ // If we find any extra referenced nodes, reject. (xml-crypto only verifies one digest, so
114
+ // multiple candidate references is bad news)
115
+ const totalReferencedNodes = exports.xpath.selectElements(currentNode.ownerDocument, "//*[@" + idAttribute + "='" + refId + "']");
116
+ if (totalReferencedNodes.length > 1) {
117
+ return false;
118
+ }
119
+ fullXml = normalizeNewlines(fullXml);
120
+ return sig.checkSignature(fullXml);
121
+ };
122
+ exports.validateXmlSignatureForCert = validateXmlSignatureForCert;
123
+ const signXml = (xml, xpath, location, options) => {
124
+ var _a;
125
+ const defaultTransforms = [
126
+ "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
127
+ "http://www.w3.org/2001/10/xml-exc-c14n#",
128
+ ];
129
+ if (!xml)
130
+ throw new Error("samlMessage is required");
131
+ if (!location)
132
+ throw new Error("location is required");
133
+ if (!options)
134
+ throw new Error("options is required");
135
+ if (!(0, types_1.isValidSamlSigningOptions)(options))
136
+ throw new Error("options.privateKey is required");
137
+ const transforms = (_a = options.xmlSignatureTransforms) !== null && _a !== void 0 ? _a : defaultTransforms;
138
+ const sig = new xmlCrypto.SignedXml();
139
+ if (options.signatureAlgorithm != null) {
140
+ sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);
141
+ }
142
+ sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));
143
+ sig.signingKey = options.privateKey;
144
+ sig.computeSignature(xml, {
145
+ location,
146
+ });
147
+ return sig.getSignedXml();
148
+ };
149
+ exports.signXml = signXml;
150
+ const parseDomFromString = (xml) => {
151
+ return new Promise(function (resolve, reject) {
152
+ function errHandler(msg) {
153
+ return reject(new Error(msg));
154
+ }
155
+ const dom = new xmldom.DOMParser({
156
+ /**
157
+ * locator is always need for error position info
158
+ */
159
+ locator: {},
160
+ /**
161
+ * you can override the errorHandler for xml parser
162
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
163
+ */
164
+ errorHandler: {
165
+ error: errHandler,
166
+ fatalError: errHandler,
167
+ },
168
+ }).parseFromString(xml, "text/xml");
169
+ if (!Object.prototype.hasOwnProperty.call(dom, "documentElement")) {
170
+ return reject(new Error("Not a valid XML document"));
171
+ }
172
+ return resolve(dom);
173
+ });
174
+ };
175
+ exports.parseDomFromString = parseDomFromString;
176
+ const parseXml2JsFromString = async (xml) => {
177
+ const parserConfig = {
178
+ explicitRoot: true,
179
+ explicitCharkey: true,
180
+ tagNameProcessors: [xml2js.processors.stripPrefix],
181
+ };
182
+ const parser = new xml2js.Parser(parserConfig);
183
+ return parser.parseStringPromise(xml);
184
+ };
185
+ exports.parseXml2JsFromString = parseXml2JsFromString;
186
+ const buildXml2JsObject = (rootName, xml) => {
187
+ const builderOpts = {
188
+ rootName,
189
+ headless: true,
190
+ };
191
+ return new xml2js.Builder(builderOpts).buildObject(xml);
192
+ };
193
+ exports.buildXml2JsObject = buildXml2JsObject;
194
+ const buildXmlBuilderObject = (xml, pretty) => {
195
+ const options = pretty ? { pretty: true, indent: " ", newline: "\n" } : {};
196
+ return xmlbuilder.create(xml).end(options);
197
+ };
198
+ exports.buildXmlBuilderObject = buildXmlBuilderObject;
199
+ const promiseWithNameId = async (nameid) => {
200
+ const format = exports.xpath.selectAttributes(nameid, "@Format");
201
+ return {
202
+ value: nameid.textContent,
203
+ format: format && format[0] && format[0].nodeValue,
204
+ };
205
+ };
206
+ exports.promiseWithNameId = promiseWithNameId;
207
+ const getNameIdAsync = async (doc, decryptionPvk) => {
208
+ const nameIds = exports.xpath.selectElements(doc, "/*[local-name()='LogoutRequest']/*[local-name()='NameID']");
209
+ const encryptedIds = exports.xpath.selectElements(doc, "/*[local-name()='LogoutRequest']/*[local-name()='EncryptedID']");
210
+ if (nameIds.length + encryptedIds.length > 1) {
211
+ throw new Error("Invalid LogoutRequest");
212
+ }
213
+ if (nameIds.length === 1) {
214
+ return (0, exports.promiseWithNameId)(nameIds[0]);
215
+ }
216
+ if (encryptedIds.length === 1) {
217
+ (0, utility_1.assertRequired)(decryptionPvk, "No decryption key found getting name ID for encrypted SAML response");
218
+ const encryptedDatas = exports.xpath.selectElements(encryptedIds[0], "./*[local-name()='EncryptedData']");
219
+ if (encryptedDatas.length !== 1) {
220
+ throw new Error("Invalid LogoutRequest");
221
+ }
222
+ const encryptedDataXml = encryptedDatas[0].toString();
223
+ const decryptedXml = await (0, exports.decryptXml)(encryptedDataXml, decryptionPvk);
224
+ const decryptedDoc = await (0, exports.parseDomFromString)(decryptedXml);
225
+ const decryptedIds = exports.xpath.selectElements(decryptedDoc, "/*[local-name()='NameID']");
226
+ if (decryptedIds.length !== 1) {
227
+ throw new Error("Invalid EncryptedAssertion content");
228
+ }
229
+ return await (0, exports.promiseWithNameId)(decryptedIds[0]);
230
+ }
231
+ throw new Error("Missing SAML NameID");
232
+ };
233
+ exports.getNameIdAsync = getNameIdAsync;
234
+ //# sourceMappingURL=xml.js.map
@@ -0,0 +1 @@
1
+ {"name":"@node-saml/node-saml","version":"4.0.5","description":"SAML 2.0 implementation for Node.js","keywords":["saml","adfs","sso","shibboleth"],"repository":{"type":"git","url":"https://github.com/node-saml/node-saml.git"},"license":"MIT","author":{"name":"Henri Bergius","email":"henri.bergius@iki.fi","url":"http://bergie.iki.fi"},"contributors":["Michael Bosworth","Herbert Vojčík","Peter Loer","Mark Stosberg","Chris Barth","Andrii Kostenko","Andreas Zoellner"],"main":"./lib","files":["lib","README.md","LICENSE"],"scripts":{"build":"tsc","changelog":"gren changelog --override --generate --head master","lint":"eslint --ext .ts \"**/*.ts\" --cache && npm run prettier-check","lint-watch":"onchange -k -p 100 \"**/*.ts\" -- eslint {{file}}","lint:fix":"eslint --ext .ts --fix src && npm run prettier-format","prepare":"tsc","prettier-check":"prettier --config .prettierrc.json --check .","prettier-format":"prettier --config .prettierrc.json --write .","prettier-watch":"onchange -k -p 100 \".\" -- prettier --config .prettierrc.json --write {{file}}","prerelease":"git clean -xfd && npm ci && npm test && npm run build","release":"release-it","test":"npm run prettier-check && npm run lint && npm run tsc && nyc mocha","test-watch":"mocha --watch","tsc":"tsc","tsc-watch":"tsc --watch","watch":"concurrently --kill-others \"npm:*-watch\""},"dependencies":{"@types/debug":"^4.1.7","@types/passport":"^1.0.11","@types/xml-crypto":"^1.4.2","@types/xml-encryption":"^1.2.1","@types/xml2js":"^0.4.11","@xmldom/xmldom":"^0.8.6","debug":"^4.3.4","xml-crypto":"^3.0.1","xml-encryption":"^3.0.2","xml2js":"^0.5.0","xmlbuilder":"^15.1.1"},"devDependencies":{"@cjbarth/github-release-notes":"^3.0.0","@istanbuljs/nyc-config-typescript":"^1.0.2","@types/chai":"^4.3.3","@types/mocha":"^10.0.0","@types/node":"^14.18.33","@types/sinon":"^10.0.13","@typescript-eslint/eslint-plugin":"^5.45.0","@typescript-eslint/parser":"^5.43.0","body-parser":"^1.20.1","chai":"^4.3.6","choma":"^1.2.1","concurrently":"^7.6.0","eslint":"^8.29.0","eslint-config-prettier":"^8.5.0","eslint-plugin-deprecation":"^1.3.3","eslint-plugin-prettier":"^4.2.1","express":"^4.18.2","mocha":"^10.1.0","nyc":"^15.1.0","onchange":"^7.1.0","prettier":"^2.8.0","prettier-plugin-packagejson":"^2.3.0","release-it":"^15.5.0","sinon":"^14.0.1","ts-node":"^10.9.1","typescript":">=4.0.0 <4.9.0"},"engines":{"node":">= 14"},"publishConfig":{"access":"public"},"_lastModified":"2024-12-22T16:05:48.631Z"}
@@ -0,0 +1,2 @@
1
+ import { Context, Next } from '@tachybase/actions';
2
+ export declare const getAuthUrl: (ctx: Context, next: Next) => Promise<any>;
@@ -0,0 +1,35 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var getAuthUrl_exports = {};
19
+ __export(getAuthUrl_exports, {
20
+ getAuthUrl: () => getAuthUrl
21
+ });
22
+ module.exports = __toCommonJS(getAuthUrl_exports);
23
+ var import_node_saml = require("@node-saml/node-saml");
24
+ const getAuthUrl = async (ctx, next) => {
25
+ const { redirect = "" } = ctx.action.params.values || {};
26
+ const auth = ctx.auth;
27
+ const options = auth.getOptions();
28
+ const saml = new import_node_saml.SAML(options);
29
+ ctx.body = await saml.getAuthorizeUrlAsync(redirect, "", {});
30
+ return next();
31
+ };
32
+ // Annotate the CommonJS export names for ESM import in node:
33
+ 0 && (module.exports = {
34
+ getAuthUrl
35
+ });
@@ -0,0 +1,2 @@
1
+ import { Context, Next } from '@tachybase/actions';
2
+ export declare const metadata: (ctx: Context, next: Next) => Promise<any>;
@@ -0,0 +1,36 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var metadata_exports = {};
19
+ __export(metadata_exports, {
20
+ metadata: () => metadata
21
+ });
22
+ module.exports = __toCommonJS(metadata_exports);
23
+ var import_node_saml = require("@node-saml/node-saml");
24
+ const metadata = async (ctx, next) => {
25
+ const auth = ctx.auth;
26
+ const options = auth.getOptions();
27
+ const saml = new import_node_saml.SAML(options);
28
+ ctx.type = "text/xml";
29
+ ctx.body = saml.generateServiceProviderMetadata(options.cert);
30
+ ctx.withoutDataWrapping = true;
31
+ return next();
32
+ };
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ metadata
36
+ });
@@ -0,0 +1,2 @@
1
+ import { Context, Next } from '@tachybase/actions';
2
+ export declare const redirect: (ctx: Context, next: Next) => Promise<void>;