@mcp-abap-adt/auth-providers 2.2.2 → 3.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/CHANGELOG.md +88 -0
- package/README.md +231 -13
- package/dist/__tests__/integration/stand/formLogin.d.ts +68 -0
- package/dist/__tests__/integration/stand/formLogin.d.ts.map +1 -0
- package/dist/__tests__/integration/stand/formLogin.js +194 -0
- package/dist/auth/callbackServer.js +2 -2
- package/dist/auth/passcodeAuth.d.ts +25 -0
- package/dist/auth/passcodeAuth.d.ts.map +1 -0
- package/dist/auth/passcodeAuth.js +62 -0
- package/dist/auth/samlBearerAssertion.d.ts +24 -0
- package/dist/auth/samlBearerAssertion.d.ts.map +1 -0
- package/dist/auth/samlBearerAssertion.js +101 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/providers/Saml2BearerProvider.d.ts.map +1 -1
- package/dist/providers/Saml2BearerProvider.js +4 -1
- package/dist/providers/UaaPasscodeProvider.d.ts +43 -0
- package/dist/providers/UaaPasscodeProvider.d.ts.map +1 -0
- package/dist/providers/UaaPasscodeProvider.js +86 -0
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -3
- package/dist/strategies/index.d.ts +1 -1
- package/dist/strategies/index.d.ts.map +1 -1
- package/dist/strategies/index.js +2 -1
- package/dist/strategies/manualStrategies.d.ts +7 -0
- package/dist/strategies/manualStrategies.d.ts.map +1 -1
- package/dist/strategies/manualStrategies.js +21 -0
- package/package.json +10 -5
- package/bin/auth-device-flow.ts +0 -114
- package/dist/auth/deviceFlowAuth.d.ts +0 -43
- package/dist/auth/deviceFlowAuth.d.ts.map +0 -1
- package/dist/auth/deviceFlowAuth.js +0 -168
- package/dist/providers/DeviceFlowProvider.d.ts +0 -32
- package/dist/providers/DeviceFlowProvider.d.ts.map +0 -1
- package/dist/providers/DeviceFlowProvider.js +0 -86
|
@@ -163,8 +163,8 @@ async function runCallbackScope(options, routes, use) {
|
|
|
163
163
|
setTimeout(() => {
|
|
164
164
|
if (finished)
|
|
165
165
|
return;
|
|
166
|
-
// Grace expired —
|
|
167
|
-
//
|
|
166
|
+
// Grace expired — an active connection may simply be stuck. Force it,
|
|
167
|
+
// bounded.
|
|
168
168
|
server.closeIdleConnections?.();
|
|
169
169
|
server.closeAllConnections?.();
|
|
170
170
|
for (const socket of sockets)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The UAA one-time passcode exchange — what `cf login --sso` does.
|
|
3
|
+
*
|
|
4
|
+
* The user opens `<uaa>/passcode` in any browser, logs in however the
|
|
5
|
+
* identity zone lets them (SSO, a corporate IdP, MFA), and copies the
|
|
6
|
+
* "Temporary Authentication Code" shown there. That code is exchanged here
|
|
7
|
+
* through the password grant, with `passcode` in place of a username and
|
|
8
|
+
* password. It is a UAA extension, not an RFC; XSUAA inherits it.
|
|
9
|
+
*
|
|
10
|
+
* UAA hands the request to its passcode filter chain only when its Accept
|
|
11
|
+
* header names JSON (`passcodeTokenMatcher` accepts `application/json` or
|
|
12
|
+
* `application/x-www-form-urlencoded`). Otherwise it falls through to the
|
|
13
|
+
* ordinary password grant, which answers `invalid_client: No password
|
|
14
|
+
* supplied` — what a bare `fetch`, which sends `*\/*`, gets. axios's default
|
|
15
|
+
* Accept happens to include `application/json`; the header is set explicitly
|
|
16
|
+
* so the exchange does not depend on an HTTP client's defaults.
|
|
17
|
+
*/
|
|
18
|
+
import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
|
|
19
|
+
export interface PasscodeTokens {
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken?: string;
|
|
22
|
+
expiresIn?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function exchangePasscode(uaaUrl: string, clientId: string, clientSecret: string | undefined, passcode: string, logger?: ILogger): Promise<PasscodeTokens>;
|
|
25
|
+
//# sourceMappingURL=passcodeAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passcodeAuth.d.ts","sourceRoot":"","sources":["../../src/auth/passcodeAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAG9D,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The UAA one-time passcode exchange — what `cf login --sso` does.
|
|
4
|
+
*
|
|
5
|
+
* The user opens `<uaa>/passcode` in any browser, logs in however the
|
|
6
|
+
* identity zone lets them (SSO, a corporate IdP, MFA), and copies the
|
|
7
|
+
* "Temporary Authentication Code" shown there. That code is exchanged here
|
|
8
|
+
* through the password grant, with `passcode` in place of a username and
|
|
9
|
+
* password. It is a UAA extension, not an RFC; XSUAA inherits it.
|
|
10
|
+
*
|
|
11
|
+
* UAA hands the request to its passcode filter chain only when its Accept
|
|
12
|
+
* header names JSON (`passcodeTokenMatcher` accepts `application/json` or
|
|
13
|
+
* `application/x-www-form-urlencoded`). Otherwise it falls through to the
|
|
14
|
+
* ordinary password grant, which answers `invalid_client: No password
|
|
15
|
+
* supplied` — what a bare `fetch`, which sends `*\/*`, gets. axios's default
|
|
16
|
+
* Accept happens to include `application/json`; the header is set explicitly
|
|
17
|
+
* so the exchange does not depend on an HTTP client's defaults.
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.exchangePasscode = exchangePasscode;
|
|
24
|
+
const axios_1 = __importDefault(require("axios"));
|
|
25
|
+
async function exchangePasscode(uaaUrl, clientId, clientSecret, passcode, logger) {
|
|
26
|
+
const tokenUrl = `${uaaUrl.replace(/\/+$/, '')}/oauth/token`;
|
|
27
|
+
const params = new URLSearchParams();
|
|
28
|
+
params.append('grant_type', 'password');
|
|
29
|
+
params.append('passcode', passcode);
|
|
30
|
+
logger?.info('[UAA] Exchanging passcode for token', { tokenUrl });
|
|
31
|
+
// A public client — `cf` is one — authenticates with an empty secret.
|
|
32
|
+
const basic = Buffer.from(`${clientId}:${clientSecret ?? ''}`).toString('base64');
|
|
33
|
+
let response;
|
|
34
|
+
try {
|
|
35
|
+
response = await axios_1.default.post(tokenUrl, params.toString(), {
|
|
36
|
+
headers: {
|
|
37
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
38
|
+
Accept: 'application/json',
|
|
39
|
+
Authorization: `Basic ${basic}`,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// UAA says why in the body — "Invalid passcode" for a mistyped or
|
|
45
|
+
// already spent code — which is what the user needs to read.
|
|
46
|
+
if (axios_1.default.isAxiosError(error) && error.response) {
|
|
47
|
+
const body = error.response.data;
|
|
48
|
+
const reason = body?.error_description ?? body?.error ?? 'no reason given';
|
|
49
|
+
throw new Error(`Passcode exchange failed (${error.response.status}): ${reason}`);
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
const data = response.data;
|
|
54
|
+
if (!data?.access_token) {
|
|
55
|
+
throw new Error('Passcode exchange returned no access_token');
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
accessToken: data.access_token,
|
|
59
|
+
refreshToken: data.refresh_token,
|
|
60
|
+
expiresIn: data.expires_in,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the SAML 2.0 bearer grant accepts, from what a SAML login delivers.
|
|
3
|
+
*
|
|
4
|
+
* RFC 7522 §2.1: the `assertion` parameter is a single SAML 2.0 Assertion,
|
|
5
|
+
* base64url-encoded. An interactive login delivers something else — the
|
|
6
|
+
* identity provider's whole `samlp:Response`, in standard base64 — and a
|
|
7
|
+
* token endpoint that follows the RFC refuses it: Cloud Foundry UAA answers
|
|
8
|
+
* 401 to a Response in either encoding. So the Assertion is taken out of the
|
|
9
|
+
* Response here and re-encoded.
|
|
10
|
+
*
|
|
11
|
+
* The Assertion is serialised as an element of its own, and every namespace
|
|
12
|
+
* declaration it inherited from the Response is copied onto it first. A
|
|
13
|
+
* serializer would add back only the prefixes used in element and attribute
|
|
14
|
+
* names; a prefix used only inside a value — `xsi:type="xs:string"` — would be
|
|
15
|
+
* lost, leaving a QName that no longer resolves. Copying all of them keeps the
|
|
16
|
+
* Assertion's in-scope namespaces exactly what they were. Its signature, over
|
|
17
|
+
* exclusive canonical XML, still verifies: canonicalisation renders a
|
|
18
|
+
* namespace where it is used, or where the signature's InclusiveNamespaces
|
|
19
|
+
* names it, not where it was declared. A signature over the Response alone does not
|
|
20
|
+
* survive the cut; the token endpoint then refuses the Assertion, as it
|
|
21
|
+
* would any unsigned one.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toBearerAssertion(payload: string): string;
|
|
24
|
+
//# sourceMappingURL=samlBearerAssertion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"samlBearerAssertion.d.ts","sourceRoot":"","sources":["../../src/auth/samlBearerAssertion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmDzD"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* What the SAML 2.0 bearer grant accepts, from what a SAML login delivers.
|
|
4
|
+
*
|
|
5
|
+
* RFC 7522 §2.1: the `assertion` parameter is a single SAML 2.0 Assertion,
|
|
6
|
+
* base64url-encoded. An interactive login delivers something else — the
|
|
7
|
+
* identity provider's whole `samlp:Response`, in standard base64 — and a
|
|
8
|
+
* token endpoint that follows the RFC refuses it: Cloud Foundry UAA answers
|
|
9
|
+
* 401 to a Response in either encoding. So the Assertion is taken out of the
|
|
10
|
+
* Response here and re-encoded.
|
|
11
|
+
*
|
|
12
|
+
* The Assertion is serialised as an element of its own, and every namespace
|
|
13
|
+
* declaration it inherited from the Response is copied onto it first. A
|
|
14
|
+
* serializer would add back only the prefixes used in element and attribute
|
|
15
|
+
* names; a prefix used only inside a value — `xsi:type="xs:string"` — would be
|
|
16
|
+
* lost, leaving a QName that no longer resolves. Copying all of them keeps the
|
|
17
|
+
* Assertion's in-scope namespaces exactly what they were. Its signature, over
|
|
18
|
+
* exclusive canonical XML, still verifies: canonicalisation renders a
|
|
19
|
+
* namespace where it is used, or where the signature's InclusiveNamespaces
|
|
20
|
+
* names it, not where it was declared. A signature over the Response alone does not
|
|
21
|
+
* survive the cut; the token endpoint then refuses the Assertion, as it
|
|
22
|
+
* would any unsigned one.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.toBearerAssertion = toBearerAssertion;
|
|
26
|
+
const xmldom_1 = require("@xmldom/xmldom");
|
|
27
|
+
const SAML_ASSERTION_NS = 'urn:oasis:names:tc:SAML:2.0:assertion';
|
|
28
|
+
const SAML_PROTOCOL_NS = 'urn:oasis:names:tc:SAML:2.0:protocol';
|
|
29
|
+
function toBearerAssertion(payload) {
|
|
30
|
+
// Node's base64 decoder accepts both alphabets, so this reads either.
|
|
31
|
+
const xml = Buffer.from(payload.trim(), 'base64').toString('utf8');
|
|
32
|
+
if (!xml.trimStart().startsWith('<')) {
|
|
33
|
+
throw new Error('SAML bearer payload is not base64-encoded XML');
|
|
34
|
+
}
|
|
35
|
+
let root;
|
|
36
|
+
try {
|
|
37
|
+
root = new xmldom_1.DOMParser().parseFromString(xml, 'text/xml').documentElement;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new Error(`SAML bearer payload is not well-formed XML: ${error instanceof Error ? error.message : String(error)}`);
|
|
41
|
+
}
|
|
42
|
+
if (isElement(root, SAML_ASSERTION_NS, 'Assertion')) {
|
|
43
|
+
return Buffer.from(xml, 'utf8').toString('base64url');
|
|
44
|
+
}
|
|
45
|
+
if (!isElement(root, SAML_PROTOCOL_NS, 'Response')) {
|
|
46
|
+
throw new Error('SAML bearer payload is neither a SAML Response nor an Assertion');
|
|
47
|
+
}
|
|
48
|
+
const children = childElements(root);
|
|
49
|
+
const assertions = children.filter((e) => isElement(e, SAML_ASSERTION_NS, 'Assertion'));
|
|
50
|
+
if (assertions.length === 0) {
|
|
51
|
+
if (children.some((e) => isElement(e, SAML_ASSERTION_NS, 'EncryptedAssertion'))) {
|
|
52
|
+
throw new Error('SAML Response carries only an EncryptedAssertion; encrypted Assertions are not supported');
|
|
53
|
+
}
|
|
54
|
+
throw new Error('SAML Response carries no Assertion');
|
|
55
|
+
}
|
|
56
|
+
if (assertions.length > 1) {
|
|
57
|
+
throw new Error(`SAML Response carries ${assertions.length} Assertions; a bearer grant takes one`);
|
|
58
|
+
}
|
|
59
|
+
const assertion = assertions[0];
|
|
60
|
+
declareInheritedNamespaces(assertion);
|
|
61
|
+
const serialized = new xmldom_1.XMLSerializer().serializeToString(assertion);
|
|
62
|
+
return Buffer.from(serialized, 'utf8').toString('base64url');
|
|
63
|
+
}
|
|
64
|
+
function isElement(node, namespace, localName) {
|
|
65
|
+
return (!!node && node.namespaceURI === namespace && node.localName === localName);
|
|
66
|
+
}
|
|
67
|
+
const XMLNS_NS = 'http://www.w3.org/2000/xmlns/';
|
|
68
|
+
const isNamespaceDeclaration = (name) => name === 'xmlns' || name.startsWith('xmlns:');
|
|
69
|
+
/**
|
|
70
|
+
* Copies onto `element` every namespace declaration in scope from its
|
|
71
|
+
* ancestors that it does not make itself. Ancestors are walked innermost
|
|
72
|
+
* first, so the nearest declaration of a prefix wins, as it did in place.
|
|
73
|
+
*/
|
|
74
|
+
function declareInheritedNamespaces(element) {
|
|
75
|
+
const declared = new Set();
|
|
76
|
+
for (let i = 0; i < element.attributes.length; i++) {
|
|
77
|
+
const name = element.attributes.item(i)?.name;
|
|
78
|
+
if (name && isNamespaceDeclaration(name))
|
|
79
|
+
declared.add(name);
|
|
80
|
+
}
|
|
81
|
+
for (let ancestor = element.parentNode; ancestor && ancestor.nodeType === 1; ancestor = ancestor.parentNode) {
|
|
82
|
+
const attributes = ancestor.attributes;
|
|
83
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
84
|
+
const attribute = attributes.item(i);
|
|
85
|
+
if (attribute &&
|
|
86
|
+
isNamespaceDeclaration(attribute.name) &&
|
|
87
|
+
!declared.has(attribute.name)) {
|
|
88
|
+
element.setAttributeNS(XMLNS_NS, attribute.name, attribute.value);
|
|
89
|
+
declared.add(attribute.name);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function childElements(parent) {
|
|
95
|
+
const out = [];
|
|
96
|
+
for (let n = parent.firstChild; n; n = n.nextSibling) {
|
|
97
|
+
if (n.nodeType === 1)
|
|
98
|
+
out.push(n);
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,10 +9,10 @@ export type { OidcCallbackResult } from './auth/oidcBrowserAuth';
|
|
|
9
9
|
export { withOidcCallbackServer } from './auth/oidcBrowserAuth';
|
|
10
10
|
export { withSamlCallbackServer } from './auth/saml2Auth';
|
|
11
11
|
export { BrowserAuthError, RefreshError, ServiceKeyError, SessionDataError, TokenProviderError, ValidationError, } from './errors/TokenProviderErrors';
|
|
12
|
-
export type { AuthorizationCodeProviderConfig, ClientCredentialsProviderConfig,
|
|
13
|
-
export { AuthorizationCodeProvider, BaseTokenProvider, ClientCredentialsProvider,
|
|
12
|
+
export type { AuthorizationCodeProviderConfig, ClientCredentialsProviderConfig, OidcBrowserProviderConfig, OidcDeviceFlowProviderConfig, OidcPasswordProviderConfig, OidcTokenExchangeProviderConfig, Saml2BearerProviderConfig, Saml2PureProviderConfig, UaaPasscodeProviderConfig, } from './providers';
|
|
13
|
+
export { AuthorizationCodeProvider, BaseTokenProvider, ClientCredentialsProvider, OidcBrowserProvider, OidcDeviceFlowProvider, OidcPasswordProvider, OidcTokenExchangeProvider, Saml2BearerProvider, Saml2PureProvider, UaaPasscodeProvider, } from './providers';
|
|
14
14
|
export { SsoProviderFactory } from './sso/SsoProviderFactory';
|
|
15
15
|
export type { SsoProviderConfig, SsoProviderInstance } from './sso/types';
|
|
16
16
|
export type { BrowserCallbackStrategyOptions, CallbackStrategyOptions, ExternalCodeStrategyOptions, ManualStrategyOptions, StaticCodeStrategyOptions, } from './strategies';
|
|
17
|
-
export { asOidcResult, BrowserCallbackStrategy, browserCallbackStrategy, DEFAULT_CALLBACK_PORT, DEFAULT_LOGIN_TIMEOUT_MS, externalCodeStrategy, manualPasteStrategy, manualSamlResponseStrategy, oidcCallbackStrategy, samlCallbackStrategy, staticCodeStrategy, } from './strategies';
|
|
17
|
+
export { asOidcResult, BrowserCallbackStrategy, browserCallbackStrategy, DEFAULT_CALLBACK_PORT, DEFAULT_LOGIN_TIMEOUT_MS, externalCodeStrategy, manualPasscodeStrategy, manualPasteStrategy, manualSamlResponseStrategy, oidcCallbackStrategy, samlCallbackStrategy, staticCodeStrategy, } from './strategies';
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,GAChB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,+BAA+B,EAC/B,+BAA+B,EAC/B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,GAChB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,+BAA+B,EAC/B,+BAA+B,EAC/B,yBAAyB,EACzB,4BAA4B,EAC5B,0BAA0B,EAC1B,+BAA+B,EAC/B,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC1E,YAAY,EACV,8BAA8B,EAC9B,uBAAuB,EACvB,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,0BAA0B,EAC1B,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Provides token providers
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.staticCodeStrategy = exports.samlCallbackStrategy = exports.oidcCallbackStrategy = exports.manualSamlResponseStrategy = exports.manualPasteStrategy = exports.externalCodeStrategy = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.DEFAULT_CALLBACK_PORT = exports.browserCallbackStrategy = exports.BrowserCallbackStrategy = exports.asOidcResult = exports.SsoProviderFactory = exports.Saml2PureProvider = exports.Saml2BearerProvider = exports.OidcTokenExchangeProvider = exports.OidcPasswordProvider = exports.OidcDeviceFlowProvider = exports.OidcBrowserProvider = exports.
|
|
9
|
+
exports.staticCodeStrategy = exports.samlCallbackStrategy = exports.oidcCallbackStrategy = exports.manualSamlResponseStrategy = exports.manualPasteStrategy = exports.manualPasscodeStrategy = exports.externalCodeStrategy = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.DEFAULT_CALLBACK_PORT = exports.browserCallbackStrategy = exports.BrowserCallbackStrategy = exports.asOidcResult = exports.SsoProviderFactory = exports.UaaPasscodeProvider = exports.Saml2PureProvider = exports.Saml2BearerProvider = exports.OidcTokenExchangeProvider = exports.OidcPasswordProvider = exports.OidcDeviceFlowProvider = exports.OidcBrowserProvider = exports.ClientCredentialsProvider = exports.BaseTokenProvider = exports.AuthorizationCodeProvider = exports.ValidationError = exports.TokenProviderError = exports.SessionDataError = exports.ServiceKeyError = exports.RefreshError = exports.BrowserAuthError = exports.withSamlCallbackServer = exports.withOidcCallbackServer = exports.withBrowserCallbackServer = void 0;
|
|
10
10
|
// Callback server factories — "take the transport this package gives".
|
|
11
11
|
var callbackServer_1 = require("./auth/callbackServer");
|
|
12
12
|
Object.defineProperty(exports, "withBrowserCallbackServer", { enumerable: true, get: function () { return callbackServer_1.withBrowserCallbackServer; } });
|
|
@@ -27,13 +27,13 @@ var providers_1 = require("./providers");
|
|
|
27
27
|
Object.defineProperty(exports, "AuthorizationCodeProvider", { enumerable: true, get: function () { return providers_1.AuthorizationCodeProvider; } });
|
|
28
28
|
Object.defineProperty(exports, "BaseTokenProvider", { enumerable: true, get: function () { return providers_1.BaseTokenProvider; } });
|
|
29
29
|
Object.defineProperty(exports, "ClientCredentialsProvider", { enumerable: true, get: function () { return providers_1.ClientCredentialsProvider; } });
|
|
30
|
-
Object.defineProperty(exports, "DeviceFlowProvider", { enumerable: true, get: function () { return providers_1.DeviceFlowProvider; } });
|
|
31
30
|
Object.defineProperty(exports, "OidcBrowserProvider", { enumerable: true, get: function () { return providers_1.OidcBrowserProvider; } });
|
|
32
31
|
Object.defineProperty(exports, "OidcDeviceFlowProvider", { enumerable: true, get: function () { return providers_1.OidcDeviceFlowProvider; } });
|
|
33
32
|
Object.defineProperty(exports, "OidcPasswordProvider", { enumerable: true, get: function () { return providers_1.OidcPasswordProvider; } });
|
|
34
33
|
Object.defineProperty(exports, "OidcTokenExchangeProvider", { enumerable: true, get: function () { return providers_1.OidcTokenExchangeProvider; } });
|
|
35
34
|
Object.defineProperty(exports, "Saml2BearerProvider", { enumerable: true, get: function () { return providers_1.Saml2BearerProvider; } });
|
|
36
35
|
Object.defineProperty(exports, "Saml2PureProvider", { enumerable: true, get: function () { return providers_1.Saml2PureProvider; } });
|
|
36
|
+
Object.defineProperty(exports, "UaaPasscodeProvider", { enumerable: true, get: function () { return providers_1.UaaPasscodeProvider; } });
|
|
37
37
|
// SSO factory
|
|
38
38
|
var SsoProviderFactory_1 = require("./sso/SsoProviderFactory");
|
|
39
39
|
Object.defineProperty(exports, "SsoProviderFactory", { enumerable: true, get: function () { return SsoProviderFactory_1.SsoProviderFactory; } });
|
|
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "browserCallbackStrategy", { enumerable: true, ge
|
|
|
45
45
|
Object.defineProperty(exports, "DEFAULT_CALLBACK_PORT", { enumerable: true, get: function () { return strategies_1.DEFAULT_CALLBACK_PORT; } });
|
|
46
46
|
Object.defineProperty(exports, "DEFAULT_LOGIN_TIMEOUT_MS", { enumerable: true, get: function () { return strategies_1.DEFAULT_LOGIN_TIMEOUT_MS; } });
|
|
47
47
|
Object.defineProperty(exports, "externalCodeStrategy", { enumerable: true, get: function () { return strategies_1.externalCodeStrategy; } });
|
|
48
|
+
Object.defineProperty(exports, "manualPasscodeStrategy", { enumerable: true, get: function () { return strategies_1.manualPasscodeStrategy; } });
|
|
48
49
|
Object.defineProperty(exports, "manualPasteStrategy", { enumerable: true, get: function () { return strategies_1.manualPasteStrategy; } });
|
|
49
50
|
Object.defineProperty(exports, "manualSamlResponseStrategy", { enumerable: true, get: function () { return strategies_1.manualSamlResponseStrategy; } });
|
|
50
51
|
Object.defineProperty(exports, "oidcCallbackStrategy", { enumerable: true, get: function () { return strategies_1.oidcCallbackStrategy; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Saml2BearerProvider.d.ts","sourceRoot":"","sources":["../../src/providers/Saml2BearerProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"Saml2BearerProvider.d.ts","sourceRoot":"","sources":["../../src/providers/Saml2BearerProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAM9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAOtB,MAAM,WAAW,yBACf,SAAQ,iBAAiB,EACvB,yBAAyB;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,OAAO,CAAC,MAAM,CAA4B;gBAE9B,MAAM,EAAE,yBAAyB;IAiB7C,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAsBrD;;;;OAIG;cACa,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAqBxD"}
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
8
8
|
exports.Saml2BearerProvider = void 0;
|
|
9
9
|
const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
|
|
10
10
|
const saml2TokenExchange_1 = require("../auth/saml2TokenExchange");
|
|
11
|
+
const samlBearerAssertion_1 = require("../auth/samlBearerAssertion");
|
|
11
12
|
const BaseTokenProvider_1 = require("./BaseTokenProvider");
|
|
12
13
|
const saml2Utils_1 = require("./saml2Utils");
|
|
13
14
|
class Saml2BearerProvider extends BaseTokenProvider_1.BaseTokenProvider {
|
|
@@ -33,7 +34,9 @@ class Saml2BearerProvider extends BaseTokenProvider_1.BaseTokenProvider {
|
|
|
33
34
|
async performLogin() {
|
|
34
35
|
const samlResponse = await (0, saml2Utils_1.getSamlAssertion)(this.config);
|
|
35
36
|
const tokenUrl = (0, saml2Utils_1.resolveTokenUrl)(this.config);
|
|
36
|
-
|
|
37
|
+
// RFC 7522 takes one base64url Assertion; a login delivers the whole
|
|
38
|
+
// Response in standard base64, which a conforming endpoint refuses.
|
|
39
|
+
const tokens = await (0, saml2TokenExchange_1.exchangeSamlAssertion)((0, samlBearerAssertion_1.toBearerAssertion)(samlResponse), tokenUrl, this.config.clientId, this.config.clientSecret, this.logger);
|
|
37
40
|
return {
|
|
38
41
|
authorizationToken: tokens.accessToken,
|
|
39
42
|
refreshToken: tokens.refreshToken,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UAA / XSUAA one-time passcode provider — the login `cf login --sso` uses.
|
|
3
|
+
*
|
|
4
|
+
* Nothing is opened and nothing listens on this machine: the user fetches a
|
|
5
|
+
* code from `<uaaUrl>/passcode` in any browser, anywhere, logging in however
|
|
6
|
+
* the identity zone asks (SSO through a corporate IdP, MFA), and hands it to
|
|
7
|
+
* the strategy. The provider exchanges it for tokens and refreshes them
|
|
8
|
+
* afterwards, so the user is asked again only when the refresh token is gone.
|
|
9
|
+
*/
|
|
10
|
+
import type { IAuthorizationStrategy, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
|
|
11
|
+
import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
|
|
12
|
+
import { BaseTokenProvider } from './BaseTokenProvider';
|
|
13
|
+
export interface UaaPasscodeProviderConfig {
|
|
14
|
+
/** UAA / XSUAA base URL, e.g. `https://<subdomain>.authentication.<region>.hana.ondemand.com`. */
|
|
15
|
+
uaaUrl: string;
|
|
16
|
+
/** A client allowed the `password` grant; add `refresh_token` to keep the session. */
|
|
17
|
+
clientId: string;
|
|
18
|
+
/** Omitted for a public client, which authenticates with an empty secret. */
|
|
19
|
+
clientSecret?: string;
|
|
20
|
+
/**
|
|
21
|
+
* How the user's code reaches the provider. The strategy is handed
|
|
22
|
+
* `<uaaUrl>/passcode` as the URL to send the user to, and returns the code.
|
|
23
|
+
* Defaults to `manualPasscodeStrategy()`: announce the URL, read the code
|
|
24
|
+
* from the terminal.
|
|
25
|
+
*/
|
|
26
|
+
authorization?: IAuthorizationStrategy<string>;
|
|
27
|
+
accessToken?: string;
|
|
28
|
+
refreshToken?: string;
|
|
29
|
+
logger?: ILogger;
|
|
30
|
+
}
|
|
31
|
+
export declare class UaaPasscodeProvider extends BaseTokenProvider {
|
|
32
|
+
private readonly config;
|
|
33
|
+
constructor(config: UaaPasscodeProviderConfig);
|
|
34
|
+
protected getAuthType(): OAuth2GrantType;
|
|
35
|
+
private get baseUrl();
|
|
36
|
+
protected performLogin(): Promise<ITokenResult>;
|
|
37
|
+
/**
|
|
38
|
+
* A failure is thrown, not handled: BaseTokenProvider drops the refresh
|
|
39
|
+
* token and asks for a new passcode through performLogin().
|
|
40
|
+
*/
|
|
41
|
+
protected performRefresh(): Promise<ITokenResult>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=UaaPasscodeProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UaaPasscodeProvider.d.ts","sourceRoot":"","sources":["../../src/providers/UaaPasscodeProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAI9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,yBAAyB;IACxC,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;gBAEvC,MAAM,EAAE,yBAAyB;IAa7C,SAAS,CAAC,WAAW,IAAI,eAAe;IAIxC,OAAO,KAAK,OAAO,GAElB;cAEe,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAqCrD;;;OAGG;cACa,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAkBxD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* UAA / XSUAA one-time passcode provider — the login `cf login --sso` uses.
|
|
4
|
+
*
|
|
5
|
+
* Nothing is opened and nothing listens on this machine: the user fetches a
|
|
6
|
+
* code from `<uaaUrl>/passcode` in any browser, anywhere, logging in however
|
|
7
|
+
* the identity zone asks (SSO through a corporate IdP, MFA), and hands it to
|
|
8
|
+
* the strategy. The provider exchanges it for tokens and refreshes them
|
|
9
|
+
* afterwards, so the user is asked again only when the refresh token is gone.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.UaaPasscodeProvider = void 0;
|
|
13
|
+
const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
|
|
14
|
+
const passcodeAuth_1 = require("../auth/passcodeAuth");
|
|
15
|
+
const tokenRefresher_1 = require("../auth/tokenRefresher");
|
|
16
|
+
const manualStrategies_1 = require("../strategies/manualStrategies");
|
|
17
|
+
const BaseTokenProvider_1 = require("./BaseTokenProvider");
|
|
18
|
+
class UaaPasscodeProvider extends BaseTokenProvider_1.BaseTokenProvider {
|
|
19
|
+
config;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
super();
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.logger = config.logger;
|
|
24
|
+
if (config.accessToken) {
|
|
25
|
+
this.authorizationToken = config.accessToken;
|
|
26
|
+
this.expiresAt = this.parseExpirationFromJWT(config.accessToken);
|
|
27
|
+
}
|
|
28
|
+
if (config.refreshToken) {
|
|
29
|
+
this.refreshToken = config.refreshToken;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
getAuthType() {
|
|
33
|
+
return interfaces_auth_1.AUTH_TYPE_PASSWORD;
|
|
34
|
+
}
|
|
35
|
+
get baseUrl() {
|
|
36
|
+
return this.config.uaaUrl.replace(/\/+$/, '');
|
|
37
|
+
}
|
|
38
|
+
async performLogin() {
|
|
39
|
+
const supplied = this.config.authorization;
|
|
40
|
+
const strategy = supplied ?? (0, manualStrategies_1.manualPasscodeStrategy)();
|
|
41
|
+
let passcode;
|
|
42
|
+
try {
|
|
43
|
+
// The passcode page takes no redirect: the code travels by hand.
|
|
44
|
+
const outcome = await strategy.authorize({
|
|
45
|
+
logger: this.logger,
|
|
46
|
+
buildAuthorizationUrl: async () => `${this.baseUrl}/passcode`,
|
|
47
|
+
});
|
|
48
|
+
passcode = outcome.payload;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
if (!supplied) {
|
|
52
|
+
await strategy.dispose?.().catch((error) => {
|
|
53
|
+
this.logger?.warn('[UaaPasscodeProvider] dispose failed', {
|
|
54
|
+
error: error instanceof Error ? error.message : String(error),
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const tokens = await (0, passcodeAuth_1.exchangePasscode)(this.baseUrl, this.config.clientId, this.config.clientSecret, passcode, this.logger);
|
|
60
|
+
return {
|
|
61
|
+
authorizationToken: tokens.accessToken,
|
|
62
|
+
refreshToken: tokens.refreshToken,
|
|
63
|
+
authType: interfaces_auth_1.AUTH_TYPE_PASSWORD,
|
|
64
|
+
expiresIn: tokens.expiresIn,
|
|
65
|
+
tokenType: 'jwt',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A failure is thrown, not handled: BaseTokenProvider drops the refresh
|
|
70
|
+
* token and asks for a new passcode through performLogin().
|
|
71
|
+
*/
|
|
72
|
+
async performRefresh() {
|
|
73
|
+
if (!this.refreshToken) {
|
|
74
|
+
throw new Error('Refresh token is required for refresh');
|
|
75
|
+
}
|
|
76
|
+
const result = await (0, tokenRefresher_1.refreshJwtToken)(this.refreshToken, this.baseUrl, this.config.clientId, this.config.clientSecret ?? '');
|
|
77
|
+
return {
|
|
78
|
+
authorizationToken: result.accessToken,
|
|
79
|
+
refreshToken: result.refreshToken || this.refreshToken,
|
|
80
|
+
authType: interfaces_auth_1.AUTH_TYPE_PASSWORD,
|
|
81
|
+
expiresIn: result.expiresIn,
|
|
82
|
+
tokenType: 'jwt',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.UaaPasscodeProvider = UaaPasscodeProvider;
|
|
@@ -9,8 +9,6 @@ export { AuthorizationCodeProvider } from './AuthorizationCodeProvider';
|
|
|
9
9
|
export { BaseTokenProvider } from './BaseTokenProvider';
|
|
10
10
|
export type { ClientCredentialsProviderConfig } from './ClientCredentialsProvider';
|
|
11
11
|
export { ClientCredentialsProvider } from './ClientCredentialsProvider';
|
|
12
|
-
export type { DeviceFlowProviderConfig } from './DeviceFlowProvider';
|
|
13
|
-
export { DeviceFlowProvider } from './DeviceFlowProvider';
|
|
14
12
|
export type { OidcBrowserProviderConfig } from './OidcBrowserProvider';
|
|
15
13
|
export { OidcBrowserProvider } from './OidcBrowserProvider';
|
|
16
14
|
export type { OidcDeviceFlowProviderConfig } from './OidcDeviceFlowProvider';
|
|
@@ -23,4 +21,6 @@ export type { Saml2BearerProviderConfig } from './Saml2BearerProvider';
|
|
|
23
21
|
export { Saml2BearerProvider } from './Saml2BearerProvider';
|
|
24
22
|
export type { Saml2PureProviderConfig } from './Saml2PureProvider';
|
|
25
23
|
export { Saml2PureProvider } from './Saml2PureProvider';
|
|
24
|
+
export type { UaaPasscodeProviderConfig } from './UaaPasscodeProvider';
|
|
25
|
+
export { UaaPasscodeProvider } from './UaaPasscodeProvider';
|
|
26
26
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,YAAY,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,YAAY,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/providers/index.js
CHANGED
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
* All providers extend BaseTokenProvider and implement ITokenProvider.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.Saml2PureProvider = exports.Saml2BearerProvider = exports.OidcTokenExchangeProvider = exports.OidcPasswordProvider = exports.OidcDeviceFlowProvider = exports.OidcBrowserProvider = exports.
|
|
9
|
+
exports.UaaPasscodeProvider = exports.Saml2PureProvider = exports.Saml2BearerProvider = exports.OidcTokenExchangeProvider = exports.OidcPasswordProvider = exports.OidcDeviceFlowProvider = exports.OidcBrowserProvider = exports.ClientCredentialsProvider = exports.BaseTokenProvider = exports.AuthorizationCodeProvider = void 0;
|
|
10
10
|
var AuthorizationCodeProvider_1 = require("./AuthorizationCodeProvider");
|
|
11
11
|
Object.defineProperty(exports, "AuthorizationCodeProvider", { enumerable: true, get: function () { return AuthorizationCodeProvider_1.AuthorizationCodeProvider; } });
|
|
12
12
|
var BaseTokenProvider_1 = require("./BaseTokenProvider");
|
|
13
13
|
Object.defineProperty(exports, "BaseTokenProvider", { enumerable: true, get: function () { return BaseTokenProvider_1.BaseTokenProvider; } });
|
|
14
14
|
var ClientCredentialsProvider_1 = require("./ClientCredentialsProvider");
|
|
15
15
|
Object.defineProperty(exports, "ClientCredentialsProvider", { enumerable: true, get: function () { return ClientCredentialsProvider_1.ClientCredentialsProvider; } });
|
|
16
|
-
var DeviceFlowProvider_1 = require("./DeviceFlowProvider");
|
|
17
|
-
Object.defineProperty(exports, "DeviceFlowProvider", { enumerable: true, get: function () { return DeviceFlowProvider_1.DeviceFlowProvider; } });
|
|
18
16
|
var OidcBrowserProvider_1 = require("./OidcBrowserProvider");
|
|
19
17
|
Object.defineProperty(exports, "OidcBrowserProvider", { enumerable: true, get: function () { return OidcBrowserProvider_1.OidcBrowserProvider; } });
|
|
20
18
|
var OidcDeviceFlowProvider_1 = require("./OidcDeviceFlowProvider");
|
|
@@ -27,3 +25,5 @@ var Saml2BearerProvider_1 = require("./Saml2BearerProvider");
|
|
|
27
25
|
Object.defineProperty(exports, "Saml2BearerProvider", { enumerable: true, get: function () { return Saml2BearerProvider_1.Saml2BearerProvider; } });
|
|
28
26
|
var Saml2PureProvider_1 = require("./Saml2PureProvider");
|
|
29
27
|
Object.defineProperty(exports, "Saml2PureProvider", { enumerable: true, get: function () { return Saml2PureProvider_1.Saml2PureProvider; } });
|
|
28
|
+
var UaaPasscodeProvider_1 = require("./UaaPasscodeProvider");
|
|
29
|
+
Object.defineProperty(exports, "UaaPasscodeProvider", { enumerable: true, get: function () { return UaaPasscodeProvider_1.UaaPasscodeProvider; } });
|
|
@@ -4,5 +4,5 @@ export { BrowserCallbackStrategy, browserCallbackStrategy, DEFAULT_CALLBACK_PORT
|
|
|
4
4
|
export type { ExternalCodeStrategyOptions, StaticCodeStrategyOptions, } from './codeStrategies';
|
|
5
5
|
export { externalCodeStrategy, staticCodeStrategy, } from './codeStrategies';
|
|
6
6
|
export type { ManualStrategyOptions } from './manualStrategies';
|
|
7
|
-
export { manualPasteStrategy, manualSamlResponseStrategy, } from './manualStrategies';
|
|
7
|
+
export { manualPasscodeStrategy, manualPasteStrategy, manualSamlResponseStrategy, } from './manualStrategies';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACV,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACV,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC"}
|
package/dist/strategies/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.manualSamlResponseStrategy = exports.manualPasteStrategy = exports.staticCodeStrategy = exports.externalCodeStrategy = exports.samlCallbackStrategy = exports.oidcCallbackStrategy = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.DEFAULT_CALLBACK_PORT = exports.browserCallbackStrategy = exports.BrowserCallbackStrategy = exports.asOidcResult = void 0;
|
|
3
|
+
exports.manualSamlResponseStrategy = exports.manualPasteStrategy = exports.manualPasscodeStrategy = exports.staticCodeStrategy = exports.externalCodeStrategy = exports.samlCallbackStrategy = exports.oidcCallbackStrategy = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.DEFAULT_CALLBACK_PORT = exports.browserCallbackStrategy = exports.BrowserCallbackStrategy = exports.asOidcResult = void 0;
|
|
4
4
|
var asOidcResult_1 = require("./asOidcResult");
|
|
5
5
|
Object.defineProperty(exports, "asOidcResult", { enumerable: true, get: function () { return asOidcResult_1.asOidcResult; } });
|
|
6
6
|
var BrowserCallbackStrategy_1 = require("./BrowserCallbackStrategy");
|
|
@@ -14,5 +14,6 @@ var codeStrategies_1 = require("./codeStrategies");
|
|
|
14
14
|
Object.defineProperty(exports, "externalCodeStrategy", { enumerable: true, get: function () { return codeStrategies_1.externalCodeStrategy; } });
|
|
15
15
|
Object.defineProperty(exports, "staticCodeStrategy", { enumerable: true, get: function () { return codeStrategies_1.staticCodeStrategy; } });
|
|
16
16
|
var manualStrategies_1 = require("./manualStrategies");
|
|
17
|
+
Object.defineProperty(exports, "manualPasscodeStrategy", { enumerable: true, get: function () { return manualStrategies_1.manualPasscodeStrategy; } });
|
|
17
18
|
Object.defineProperty(exports, "manualPasteStrategy", { enumerable: true, get: function () { return manualStrategies_1.manualPasteStrategy; } });
|
|
18
19
|
Object.defineProperty(exports, "manualSamlResponseStrategy", { enumerable: true, get: function () { return manualStrategies_1.manualSamlResponseStrategy; } });
|
|
@@ -17,4 +17,11 @@ export interface ManualStrategyOptions {
|
|
|
17
17
|
export declare function manualPasteStrategy(options?: ManualStrategyOptions): IAuthorizationStrategy<string>;
|
|
18
18
|
/** The user lifts `SAMLResponse` from the POST body — it never reaches the URL. */
|
|
19
19
|
export declare function manualSamlResponseStrategy(options?: ManualStrategyOptions): IAuthorizationStrategy<string>;
|
|
20
|
+
/**
|
|
21
|
+
* The UAA passcode, typed in by the user: shows where to fetch it —
|
|
22
|
+
* `<uaa>/passcode`, opened in any browser, on any machine — and reads the
|
|
23
|
+
* code they copy from that page. The default for `UaaPasscodeProvider`, so a
|
|
24
|
+
* login works on a machine with no browser at all, as `cf login --sso` does.
|
|
25
|
+
*/
|
|
26
|
+
export declare function manualPasscodeStrategy(options?: ManualStrategyOptions): IAuthorizationStrategy<string>;
|
|
20
27
|
//# sourceMappingURL=manualStrategies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manualStrategies.d.ts","sourceRoot":"","sources":["../../src/strategies/manualStrategies.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAGV,sBAAsB,EACvB,MAAM,+BAA+B,CAAC;AAIvC,MAAM,WAAW,qBAAqB;IACpC,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C;AAiCD,4EAA4E;AAC5E,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,qBAA0B,GAClC,sBAAsB,CAAC,MAAM,CAAC,CAmBhC;AAED,mFAAmF;AACnF,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,qBAA0B,GAClC,sBAAsB,CAAC,MAAM,CAAC,CAiBhC"}
|
|
1
|
+
{"version":3,"file":"manualStrategies.d.ts","sourceRoot":"","sources":["../../src/strategies/manualStrategies.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAGV,sBAAsB,EACvB,MAAM,+BAA+B,CAAC;AAIvC,MAAM,WAAW,qBAAqB;IACpC,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C;AAiCD,4EAA4E;AAC5E,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,qBAA0B,GAClC,sBAAsB,CAAC,MAAM,CAAC,CAmBhC;AAED,mFAAmF;AACnF,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,qBAA0B,GAClC,sBAAsB,CAAC,MAAM,CAAC,CAiBhC;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,qBAA0B,GAClC,sBAAsB,CAAC,MAAM,CAAC,CAgBhC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.manualPasteStrategy = manualPasteStrategy;
|
|
12
12
|
exports.manualSamlResponseStrategy = manualSamlResponseStrategy;
|
|
13
|
+
exports.manualPasscodeStrategy = manualPasscodeStrategy;
|
|
13
14
|
const node_readline_1 = require("node:readline");
|
|
14
15
|
const browserAuth_1 = require("../auth/browserAuth");
|
|
15
16
|
const BrowserCallbackStrategy_1 = require("./BrowserCallbackStrategy");
|
|
@@ -75,3 +76,23 @@ function manualSamlResponseStrategy(options = {}) {
|
|
|
75
76
|
},
|
|
76
77
|
};
|
|
77
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The UAA passcode, typed in by the user: shows where to fetch it —
|
|
81
|
+
* `<uaa>/passcode`, opened in any browser, on any machine — and reads the
|
|
82
|
+
* code they copy from that page. The default for `UaaPasscodeProvider`, so a
|
|
83
|
+
* login works on a machine with no browser at all, as `cf login --sso` does.
|
|
84
|
+
*/
|
|
85
|
+
function manualPasscodeStrategy(options = {}) {
|
|
86
|
+
const redirectUri = options.redirectUri ?? defaultRedirectUri();
|
|
87
|
+
const read = options.read ?? readFromTerminal;
|
|
88
|
+
return {
|
|
89
|
+
async authorize(request) {
|
|
90
|
+
const url = await request.buildAuthorizationUrl(redirectUri);
|
|
91
|
+
announce(request, url);
|
|
92
|
+
const code = (await read('Paste the Temporary Authentication Code (passcode): ')).trim();
|
|
93
|
+
if (!code)
|
|
94
|
+
throw new Error('No passcode was provided');
|
|
95
|
+
return { payload: code, redirectUri };
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|