saml-test-server 0.0.0-stage → 1.0.0
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.
- package/LICENSE +19 -0
- package/README.md +134 -2
- package/assets/idp-private-key.pem +27 -0
- package/assets/idp-public-cert.pem +20 -0
- package/dist/cli.js +106 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.js +2170 -0
- package/dist/index.js.map +1 -0
- package/dist/types/app.d.ts +16 -0
- package/dist/types/cli-program.d.ts +10 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/default-config.d.ts +12 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/log.d.ts +26 -0
- package/dist/types/options.d.ts +111 -0
- package/dist/types/profile-mapper.d.ts +10 -0
- package/dist/types/session.d.ts +36 -0
- package/dist/types/state.d.ts +49 -0
- package/dist/types/vendor/saml/encrypt.d.ts +16 -0
- package/dist/types/vendor/saml/index.d.ts +7 -0
- package/dist/types/vendor/saml/saml20.d.ts +47 -0
- package/dist/types/vendor/saml/sign.d.ts +30 -0
- package/dist/types/vendor/saml/utils.d.ts +18 -0
- package/dist/types/vendor/samlp/auth.d.ts +87 -0
- package/dist/types/vendor/samlp/constants.d.ts +30 -0
- package/dist/types/vendor/samlp/encoders.d.ts +5 -0
- package/dist/types/vendor/samlp/index.d.ts +14 -0
- package/dist/types/vendor/samlp/logout.d.ts +66 -0
- package/dist/types/vendor/samlp/metadata.d.ts +22 -0
- package/dist/types/vendor/samlp/profile-mapper.d.ts +38 -0
- package/dist/types/vendor/samlp/session-participants.d.ts +22 -0
- package/dist/types/vendor/samlp/signers.d.ts +43 -0
- package/dist/types/vendor/samlp/templates.d.ts +52 -0
- package/dist/types/vendor/samlp/trim-xml.d.ts +2 -0
- package/dist/types/vendor/samlp/utils.d.ts +55 -0
- package/dist/types/vendor/samlp/xml.d.ts +7 -0
- package/dist/types/views/AutoPostForm.d.ts +12 -0
- package/dist/types/views/ErrorPage.d.ts +8 -0
- package/dist/types/views/Layout.d.ts +4 -0
- package/dist/types/views/SettingsPage.d.ts +5 -0
- package/dist/types/views/UserPage.d.ts +20 -0
- package/dist/types/views/index.d.ts +5 -0
- package/package.json +58 -4
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ALGORITHMS } from './constants.js';
|
|
2
|
+
import { type XmlDocument } from './xml.js';
|
|
3
|
+
type SignatureAlgorithmName = keyof typeof ALGORITHMS.SIGNATURE;
|
|
4
|
+
type DigestAlgorithmName = keyof typeof ALGORITHMS.DIGEST;
|
|
5
|
+
export interface SigningOptions {
|
|
6
|
+
key: string | Buffer;
|
|
7
|
+
cert: string | Buffer;
|
|
8
|
+
signatureAlgorithm?: SignatureAlgorithmName;
|
|
9
|
+
digestAlgorithm?: DigestAlgorithmName;
|
|
10
|
+
/** XPath of the element to sign (default: `<LogoutRequest>`). */
|
|
11
|
+
reference?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ValidationOptions {
|
|
14
|
+
signingCert?: string | Buffer;
|
|
15
|
+
thumbprints?: string | string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function getSigAlg(options: {
|
|
18
|
+
signatureAlgorithm?: SignatureAlgorithmName;
|
|
19
|
+
}): string;
|
|
20
|
+
/** Adds an enveloped signature (placed after `<Issuer>`) to the root element. */
|
|
21
|
+
export declare function signXml(options: SigningOptions, xml: string): string;
|
|
22
|
+
export declare function certToPEM(cert: string | Buffer): string;
|
|
23
|
+
/**
|
|
24
|
+
* Validates the enveloped signature of the root element of `xml`.
|
|
25
|
+
*
|
|
26
|
+
* - If thumbprints are configured, the certificate embedded in `<KeyInfo>` is
|
|
27
|
+
* used and its thumbprint must match one of them.
|
|
28
|
+
* - Otherwise the configured `signingCert` is the only trusted key.
|
|
29
|
+
*
|
|
30
|
+
* @returns a list of validation errors (empty when the signature is valid)
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateXmlEmbeddedSignature(xml: XmlDocument, xmlString: string, options: ValidationOptions): string[];
|
|
33
|
+
/** Computes a detached signature (HTTP-Redirect binding) over `content`. */
|
|
34
|
+
export declare function sign(options: {
|
|
35
|
+
key: string | Buffer;
|
|
36
|
+
signatureAlgorithm?: SignatureAlgorithmName;
|
|
37
|
+
}, content: string): string;
|
|
38
|
+
/** Verifies a detached signature. `signatureAlgorithm` is the `SigAlg` URI. */
|
|
39
|
+
export declare function isValidContentAndSignature(content: string, signature: string, options: {
|
|
40
|
+
signingCert: string | Buffer;
|
|
41
|
+
signatureAlgorithm: string;
|
|
42
|
+
}): boolean;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface SamlResponseData {
|
|
2
|
+
id: string;
|
|
3
|
+
instant: string;
|
|
4
|
+
destination?: string;
|
|
5
|
+
inResponseTo?: string;
|
|
6
|
+
issuer: string;
|
|
7
|
+
samlStatusCode: string;
|
|
8
|
+
samlStatusMessage?: string;
|
|
9
|
+
/** Raw (already serialized) assertion XML. */
|
|
10
|
+
assertion?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function samlResponse(data: SamlResponseData): string;
|
|
13
|
+
export interface LogoutResponseData {
|
|
14
|
+
id: string;
|
|
15
|
+
instant: string;
|
|
16
|
+
destination?: string;
|
|
17
|
+
inResponseTo?: string;
|
|
18
|
+
issuer: string;
|
|
19
|
+
samlStatusCode: string;
|
|
20
|
+
samlStatusMessage?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function logoutResponse(data: LogoutResponseData): string;
|
|
23
|
+
export interface LogoutRequestData {
|
|
24
|
+
ID: string;
|
|
25
|
+
IssueInstant: string;
|
|
26
|
+
Issuer: string;
|
|
27
|
+
Destination?: string;
|
|
28
|
+
NameID: {
|
|
29
|
+
value?: string;
|
|
30
|
+
Format?: string;
|
|
31
|
+
NameQualifier?: string;
|
|
32
|
+
SPNameQualifier?: string;
|
|
33
|
+
SPProvidedID?: string;
|
|
34
|
+
};
|
|
35
|
+
SessionIndex?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function logoutRequest(data: LogoutRequestData): string;
|
|
38
|
+
export interface MetadataData {
|
|
39
|
+
issuer: string;
|
|
40
|
+
pem: string;
|
|
41
|
+
redirectEndpoint: string;
|
|
42
|
+
postEndpoint: string;
|
|
43
|
+
logoutEndpoints: {
|
|
44
|
+
redirect?: string;
|
|
45
|
+
post?: string;
|
|
46
|
+
};
|
|
47
|
+
claimTypes: Array<{
|
|
48
|
+
id: string;
|
|
49
|
+
displayName: string;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
export declare function metadata(data: MetadataData): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ElementType } from './constants.js';
|
|
2
|
+
import { type XmlDocument } from './xml.js';
|
|
3
|
+
/** Minimal, framework-agnostic view of an incoming HTTP request. */
|
|
4
|
+
export interface SamlHttpInput {
|
|
5
|
+
query: Record<string, string | undefined>;
|
|
6
|
+
body: Record<string, string | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export interface SigningCredentials {
|
|
9
|
+
cert?: string | Buffer;
|
|
10
|
+
thumbprints?: string | string[];
|
|
11
|
+
}
|
|
12
|
+
export interface ParseRequestOptions {
|
|
13
|
+
signingCert?: string | Buffer;
|
|
14
|
+
thumbprints?: string | string[];
|
|
15
|
+
relayState?: string;
|
|
16
|
+
signaturePath?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the credentials used to validate the signature of the incoming
|
|
19
|
+
* message from its issuer (and for logout requests, session index / NameID).
|
|
20
|
+
*/
|
|
21
|
+
getCredentials?: (issuer: string | undefined, sessionIndices: string[] | undefined, nameId: string | undefined) => SigningCredentials | undefined | Promise<SigningCredentials | undefined>;
|
|
22
|
+
}
|
|
23
|
+
interface ValidateOptions {
|
|
24
|
+
signingCert?: string | Buffer;
|
|
25
|
+
thumbprints?: string | string[];
|
|
26
|
+
deflate?: boolean;
|
|
27
|
+
relayState?: string;
|
|
28
|
+
signaturePath?: string;
|
|
29
|
+
}
|
|
30
|
+
/** Generates a random 20 character hexadecimal identifier. */
|
|
31
|
+
export declare function generateUniqueID(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Formats the given date in `xs:DateTime` format as per Core SAML "1.3.3 Time Values":
|
|
34
|
+
* UTC, no time zone component, millisecond precision.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatXmlDateTime(date: Date): string;
|
|
37
|
+
export declare function generateInstant(): string;
|
|
38
|
+
export declare function appendQueryString(initialUrl: string, query: Record<string, string>): string;
|
|
39
|
+
/**
|
|
40
|
+
* Decodes (base64, then optionally inflates) and parses a SAML request, and
|
|
41
|
+
* validates its signature when a signing credential is available.
|
|
42
|
+
*
|
|
43
|
+
* @returns the parsed DOM, or `undefined` when there is no SAML message
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseSamlRequest(input: SamlHttpInput, samlRequest: string | undefined, type: ElementType, options?: ParseRequestOptions): Promise<XmlDocument | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* Validates the signature of a SAML request/response received through the
|
|
48
|
+
* HTTP-POST binding (embedded XML signature) or HTTP-Redirect binding
|
|
49
|
+
* (detached `Signature` / `SigAlg` query parameters).
|
|
50
|
+
*
|
|
51
|
+
* @throws when the message is signed with an invalid signature, or unsigned
|
|
52
|
+
* while a signing certificate is configured.
|
|
53
|
+
*/
|
|
54
|
+
export declare function validateSignature(input: SamlHttpInput, elementType: ElementType, xml: XmlDocument, xmlString: string, options: ValidateOptions): void;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DOMParser } from '@xmldom/xmldom';
|
|
2
|
+
/** DOM node/document types produced by `@xmldom/xmldom`. */
|
|
3
|
+
export type XmlDocument = ReturnType<DOMParser['parseFromString']>;
|
|
4
|
+
export type XmlNode = NonNullable<XmlDocument['documentElement']>;
|
|
5
|
+
export declare function parseXml(xml: string): XmlDocument;
|
|
6
|
+
/** Evaluates an XPath expression and always returns an array of nodes. */
|
|
7
|
+
export declare function selectNodes(expression: string, node: unknown): XmlNode[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FC } from 'hono/jsx';
|
|
2
|
+
export interface AutoPostFormProps {
|
|
3
|
+
/** Form action (ACS / SLO URL of the Service Provider). */
|
|
4
|
+
url: string;
|
|
5
|
+
/** Name of the hidden field carrying the SAML message. */
|
|
6
|
+
field: string;
|
|
7
|
+
/** Base64 encoded SAML message. */
|
|
8
|
+
value: string;
|
|
9
|
+
relayState?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Page that immediately POSTs a SAML message to the Service Provider (HTTP-POST binding). */
|
|
12
|
+
export declare const AutoPostForm: FC<AutoPostFormProps>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FC } from 'hono/jsx';
|
|
2
|
+
import type { UserProfile } from '../default-config.js';
|
|
3
|
+
import { type IdpSettings } from '../state.js';
|
|
4
|
+
import type { ClaimMetadata } from '../vendor/samlp/index.js';
|
|
5
|
+
export interface AuthnRequestInfo {
|
|
6
|
+
relayState?: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
issuer?: string;
|
|
9
|
+
destination?: string;
|
|
10
|
+
acsUrl?: string;
|
|
11
|
+
forceAuthn?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface UserPageProps {
|
|
14
|
+
user: UserProfile;
|
|
15
|
+
sessionIndex?: string;
|
|
16
|
+
metadata: ClaimMetadata[];
|
|
17
|
+
authnRequest?: AuthnRequestInfo;
|
|
18
|
+
idp: IdpSettings;
|
|
19
|
+
}
|
|
20
|
+
export declare const UserPage: FC<UserPageProps>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saml-test-server",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Test SAML 2.0 Identity Provider (IdP) for E2E tests",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"saml",
|
|
10
|
+
"idp",
|
|
11
|
+
"e2e",
|
|
12
|
+
"hono"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=20"
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/types/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/types/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"saml-idp": "./dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"assets",
|
|
31
|
+
"LICENSE*"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"dev": "vite",
|
|
35
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
36
|
+
"prepare": "npm run build",
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"start": "node dist/cli.js",
|
|
39
|
+
"test": "vitest run"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@hono/node-server": "^1.19.0",
|
|
43
|
+
"@xmldom/xmldom": "^0.9.8",
|
|
44
|
+
"commander": "^14.0.0",
|
|
45
|
+
"hono": "^4.9.0",
|
|
46
|
+
"picocolors": "^1.1.1",
|
|
47
|
+
"xml-crypto": "^6.1.2",
|
|
48
|
+
"xml-encryption": "^3.1.0",
|
|
49
|
+
"xml-formatter": "^3.6.6",
|
|
50
|
+
"xml-name-validator": "^5.0.0",
|
|
51
|
+
"xpath": "^0.0.34"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@hono/vite-dev-server": "^0.20.0",
|
|
55
|
+
"@types/node": "^22.0.0",
|
|
56
|
+
"typescript": "^5.9.0",
|
|
57
|
+
"vite": "^7.0.0",
|
|
58
|
+
"vitest": "^5.0.4"
|
|
59
|
+
}
|
|
60
|
+
}
|