@p0security/cli 0.3.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/CONTRIBUTING.md +23 -0
- package/LICENSE.md +675 -0
- package/README.md +201 -0
- package/dist/commands/__tests__/login.test.d.ts +1 -0
- package/dist/commands/__tests__/login.test.js +75 -0
- package/dist/commands/__tests__/ls.test.d.ts +1 -0
- package/dist/commands/__tests__/ls.test.js +84 -0
- package/dist/commands/__tests__/request.test.d.ts +1 -0
- package/dist/commands/__tests__/request.test.js +94 -0
- package/dist/commands/__tests__/ssh.test.d.ts +1 -0
- package/dist/commands/__tests__/ssh.test.js +107 -0
- package/dist/commands/aws/__tests__/__input__/saml-response.d.ts +11 -0
- package/dist/commands/aws/__tests__/__input__/saml-response.js +18 -0
- package/dist/commands/aws/__tests__/__input__/sts-response.d.ts +11 -0
- package/dist/commands/aws/__tests__/__input__/sts-response.js +37 -0
- package/dist/commands/aws/__tests__/role.test.d.ts +1 -0
- package/dist/commands/aws/__tests__/role.test.js +98 -0
- package/dist/commands/aws/index.d.ts +4 -0
- package/dist/commands/aws/index.js +26 -0
- package/dist/commands/aws/role.d.ts +27 -0
- package/dist/commands/aws/role.js +123 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/index.js +49 -0
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.js +93 -0
- package/dist/commands/ls.d.ts +4 -0
- package/dist/commands/ls.js +78 -0
- package/dist/commands/request.d.ts +12 -0
- package/dist/commands/request.js +116 -0
- package/dist/commands/ssh.d.ts +11 -0
- package/dist/commands/ssh.js +154 -0
- package/dist/common/auth/oidc.d.ts +4 -0
- package/dist/common/auth/oidc.js +18 -0
- package/dist/common/auth/server.d.ts +15 -0
- package/dist/common/auth/server.js +73 -0
- package/dist/common/fetch.d.ts +16 -0
- package/dist/common/fetch.js +39 -0
- package/dist/common/mime.d.ts +14 -0
- package/dist/common/mime.js +17 -0
- package/dist/common/xml.d.ts +21 -0
- package/dist/common/xml.js +52 -0
- package/dist/drivers/__mocks__/auth.d.ts +30 -0
- package/dist/drivers/__mocks__/auth.js +46 -0
- package/dist/drivers/api.d.ts +3 -0
- package/dist/drivers/api.js +69 -0
- package/dist/drivers/auth.d.ts +11 -0
- package/dist/drivers/auth.js +122 -0
- package/dist/drivers/env.d.ts +15 -0
- package/dist/drivers/env.js +38 -0
- package/dist/drivers/firestore.d.ts +10 -0
- package/dist/drivers/firestore.js +53 -0
- package/dist/drivers/stdio.d.ts +25 -0
- package/dist/drivers/stdio.js +44 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +23 -0
- package/dist/middlewares/version.d.ts +8 -0
- package/dist/middlewares/version.js +77 -0
- package/dist/plugins/__mocks__/login.d.ts +14 -0
- package/dist/plugins/__mocks__/login.js +24 -0
- package/dist/plugins/aws/__mocks__/assumeRole.d.ts +12 -0
- package/dist/plugins/aws/__mocks__/assumeRole.js +20 -0
- package/dist/plugins/aws/api.d.ts +12 -0
- package/dist/plugins/aws/api.js +16 -0
- package/dist/plugins/aws/assumeRole.d.ts +14 -0
- package/dist/plugins/aws/assumeRole.js +55 -0
- package/dist/plugins/aws/config.d.ts +5 -0
- package/dist/plugins/aws/config.js +38 -0
- package/dist/plugins/aws/ssm/index.d.ts +18 -0
- package/dist/plugins/aws/ssm/index.js +274 -0
- package/dist/plugins/aws/ssm/install.d.ts +7 -0
- package/dist/plugins/aws/ssm/install.js +133 -0
- package/dist/plugins/aws/types.d.ts +54 -0
- package/dist/plugins/aws/types.js +2 -0
- package/dist/plugins/google/login.d.ts +2 -0
- package/dist/plugins/google/login.js +76 -0
- package/dist/plugins/login.d.ts +13 -0
- package/dist/plugins/login.js +19 -0
- package/dist/plugins/okta/aws.d.ts +5 -0
- package/dist/plugins/okta/aws.js +42 -0
- package/dist/plugins/okta/login.d.ts +8 -0
- package/dist/plugins/okta/login.js +165 -0
- package/dist/plugins/ssh/types.d.ts +22 -0
- package/dist/plugins/ssh/types.js +2 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/redirect-landing.html +40 -0
- package/dist/testing/firestore.d.ts +2 -0
- package/dist/testing/firestore.js +16 -0
- package/dist/testing/yargs.d.ts +12 -0
- package/dist/testing/yargs.js +23 -0
- package/dist/types/identity.d.ts +23 -0
- package/dist/types/identity.js +2 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.js +15 -0
- package/dist/types/oidc.d.ts +41 -0
- package/dist/types/oidc.js +2 -0
- package/dist/types/org.d.ts +20 -0
- package/dist/types/org.js +2 -0
- package/dist/types/request.d.ts +35 -0
- package/dist/types/request.js +20 -0
- package/dist/util.d.ts +42 -0
- package/dist/util.js +87 -0
- package/p0 +16 -0
- package/package.json +70 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.googleLogin = void 0;
|
|
16
|
+
/** Copyright © 2024-present P0 Security
|
|
17
|
+
|
|
18
|
+
This file is part of @p0security/cli
|
|
19
|
+
|
|
20
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
21
|
+
|
|
22
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
23
|
+
|
|
24
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
25
|
+
**/
|
|
26
|
+
const oidc_1 = require("../../common/auth/oidc");
|
|
27
|
+
const server_1 = require("../../common/auth/server");
|
|
28
|
+
const fetch_1 = require("../../common/fetch");
|
|
29
|
+
const env_1 = require("../../drivers/env");
|
|
30
|
+
const stdio_1 = require("../../drivers/stdio");
|
|
31
|
+
const open_1 = __importDefault(require("open"));
|
|
32
|
+
const GOOGLE_OIDC_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
33
|
+
const GOOGLE_OIDC_EXCHANGE_URL = "https://oauth2.googleapis.com/token";
|
|
34
|
+
const GOOGLE_OIDC_REDIRECT_PORT = 52700;
|
|
35
|
+
const GOOGLE_OIDC_REDIRECT_URL = `http://127.0.0.1:${GOOGLE_OIDC_REDIRECT_PORT}`;
|
|
36
|
+
const PKCE_LENGTH = 128;
|
|
37
|
+
const requestAuth = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
+
const pkceChallenge = (yield import("pkce-challenge")).default;
|
|
39
|
+
const pkce = yield pkceChallenge(PKCE_LENGTH);
|
|
40
|
+
const authBody = {
|
|
41
|
+
client_id: env_1.config.google.clientId,
|
|
42
|
+
code_challenge: pkce.code_challenge,
|
|
43
|
+
code_challenge_method: "S256",
|
|
44
|
+
redirect_uri: GOOGLE_OIDC_REDIRECT_URL,
|
|
45
|
+
response_type: "code",
|
|
46
|
+
scope: "openid",
|
|
47
|
+
};
|
|
48
|
+
const url = `${GOOGLE_OIDC_URL}?${(0, fetch_1.urlEncode)(authBody)}`;
|
|
49
|
+
(0, open_1.default)(url).catch(() => {
|
|
50
|
+
(0, stdio_1.print2)(`Please visit the following URL to continue login:
|
|
51
|
+
|
|
52
|
+
${url}`);
|
|
53
|
+
});
|
|
54
|
+
return pkce;
|
|
55
|
+
});
|
|
56
|
+
const requestToken = (code, pkce) => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
+
const body = {
|
|
58
|
+
client_id: env_1.config.google.clientId,
|
|
59
|
+
client_secret: env_1.config.google.clientSecret,
|
|
60
|
+
code,
|
|
61
|
+
code_verifier: pkce.code_verifier,
|
|
62
|
+
grant_type: "authorization_code",
|
|
63
|
+
redirect_uri: GOOGLE_OIDC_REDIRECT_URL,
|
|
64
|
+
};
|
|
65
|
+
const response = yield fetch(GOOGLE_OIDC_EXCHANGE_URL, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: oidc_1.OIDC_HEADERS,
|
|
68
|
+
body: (0, fetch_1.urlEncode)(body),
|
|
69
|
+
});
|
|
70
|
+
const valid = yield (0, fetch_1.validateResponse)(response);
|
|
71
|
+
return (yield valid.json());
|
|
72
|
+
});
|
|
73
|
+
const googleLogin = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
return yield (0, server_1.withRedirectServer)(() => __awaiter(void 0, void 0, void 0, function* () { return yield requestAuth(); }), (pkce, token) => __awaiter(void 0, void 0, void 0, function* () { return yield requestToken(token.code, pkce); }), { port: GOOGLE_OIDC_REDIRECT_PORT });
|
|
75
|
+
});
|
|
76
|
+
exports.googleLogin = googleLogin;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
import { TokenResponse } from "../types/oidc";
|
|
12
|
+
import { OrgData } from "../types/org";
|
|
13
|
+
export declare const pluginLoginMap: Record<string, (org: OrgData) => Promise<TokenResponse>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.pluginLoginMap = void 0;
|
|
13
|
+
const login_1 = require("./google/login");
|
|
14
|
+
const login_2 = require("./okta/login");
|
|
15
|
+
exports.pluginLoginMap = {
|
|
16
|
+
google: login_1.googleLogin,
|
|
17
|
+
okta: login_2.oktaLogin,
|
|
18
|
+
"oidc-pkce": (org) => __awaiter(void 0, void 0, void 0, function* () { return yield exports.pluginLoginMap[org.providerType](org); }),
|
|
19
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.assumeRoleWithOktaSaml = void 0;
|
|
13
|
+
/** Copyright © 2024-present P0 Security
|
|
14
|
+
|
|
15
|
+
This file is part of @p0security/cli
|
|
16
|
+
|
|
17
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
18
|
+
|
|
19
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
22
|
+
**/
|
|
23
|
+
const role_1 = require("../../commands/aws/role");
|
|
24
|
+
const auth_1 = require("../../drivers/auth");
|
|
25
|
+
const assumeRole_1 = require("../aws/assumeRole");
|
|
26
|
+
const assumeRoleWithOktaSaml = (authn, args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
return yield (0, auth_1.cached)(`aws-okta-${args.account}-${args.role}`, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
|
+
const { account, config, samlResponse } = yield (0, role_1.initOktaSaml)(authn, args.account);
|
|
29
|
+
const { roles } = (0, role_1.rolesFromSaml)(account, samlResponse);
|
|
30
|
+
if (!roles.includes(args.role))
|
|
31
|
+
throw `Role not available. Available roles:\n${roles.map((r) => ` ${r}`).join("\n")}`;
|
|
32
|
+
return yield (0, assumeRole_1.assumeRoleWithSaml)({
|
|
33
|
+
account,
|
|
34
|
+
role: args.role,
|
|
35
|
+
saml: {
|
|
36
|
+
providerName: config.uidLocation.samlProviderName,
|
|
37
|
+
response: samlResponse,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}), { duration: 3600e3 });
|
|
41
|
+
});
|
|
42
|
+
exports.assumeRoleWithOktaSaml = assumeRoleWithOktaSaml;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Identity } from "../../types/identity";
|
|
2
|
+
import { TokenResponse } from "../../types/oidc";
|
|
3
|
+
import { OrgData } from "../../types/org";
|
|
4
|
+
import { AwsOktaSamlUidLocation } from "../aws/types";
|
|
5
|
+
/** Logs in to Okta via OIDC */
|
|
6
|
+
export declare const oktaLogin: (org: OrgData) => Promise<TokenResponse>;
|
|
7
|
+
/** Retrieves a SAML response for an okta app */
|
|
8
|
+
export declare const getSamlResponse: (identity: Identity, config: AwsOktaSamlUidLocation) => Promise<string>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getSamlResponse = exports.oktaLogin = void 0;
|
|
16
|
+
/** Copyright © 2024-present P0 Security
|
|
17
|
+
|
|
18
|
+
This file is part of @p0security/cli
|
|
19
|
+
|
|
20
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
21
|
+
|
|
22
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
23
|
+
|
|
24
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
25
|
+
**/
|
|
26
|
+
const oidc_1 = require("../../common/auth/oidc");
|
|
27
|
+
const fetch_1 = require("../../common/fetch");
|
|
28
|
+
const stdio_1 = require("../../drivers/stdio");
|
|
29
|
+
const util_1 = require("../../util");
|
|
30
|
+
const jsdom_1 = require("jsdom");
|
|
31
|
+
const lodash_1 = require("lodash");
|
|
32
|
+
const open_1 = __importDefault(require("open"));
|
|
33
|
+
const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
34
|
+
const ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
|
|
35
|
+
const ID_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:id_token";
|
|
36
|
+
const TOKEN_EXCHANGE_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
37
|
+
const WEB_SSO_TOKEN_TYPE = "urn:okta:oauth:token-type:web_sso_token";
|
|
38
|
+
const validateProviderDomain = (org) => {
|
|
39
|
+
if (!org.providerDomain)
|
|
40
|
+
throw "Okta login requires a configured provider domain.";
|
|
41
|
+
};
|
|
42
|
+
/** Executes the first step of Okta's device-authorization grant flow */
|
|
43
|
+
// cf. https://developer.okta.com/docs/guides/device-authorization-grant/main/
|
|
44
|
+
const authorize = (org) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
const init = {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: oidc_1.OIDC_HEADERS,
|
|
48
|
+
body: (0, fetch_1.urlEncode)({
|
|
49
|
+
client_id: org.clientId,
|
|
50
|
+
scope: "openid email profile okta.apps.sso",
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
validateProviderDomain(org);
|
|
54
|
+
// This is the "org" authorization server; the okta.apps.* scopes are not
|
|
55
|
+
// available with custom authorization servers
|
|
56
|
+
const response = yield fetch(`https:${org.providerDomain}/oauth2/v1/device/authorize`, init);
|
|
57
|
+
yield (0, fetch_1.validateResponse)(response);
|
|
58
|
+
return (yield response.json());
|
|
59
|
+
});
|
|
60
|
+
/** Attempts to fetch this device's OIDC token
|
|
61
|
+
*
|
|
62
|
+
* The authorization may or may not be granted at this stage. If it is not, the
|
|
63
|
+
* authorization server will return "authorization_pending", in which case this
|
|
64
|
+
* function will return undefined.
|
|
65
|
+
*/
|
|
66
|
+
const fetchOidcToken = (org, authorize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
+
const init = {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: oidc_1.OIDC_HEADERS,
|
|
70
|
+
body: (0, fetch_1.urlEncode)({
|
|
71
|
+
client_id: org.clientId,
|
|
72
|
+
device_code: authorize.device_code,
|
|
73
|
+
grant_type: DEVICE_GRANT_TYPE,
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
validateProviderDomain(org);
|
|
77
|
+
const response = yield fetch(`https:${org.providerDomain}/oauth2/v1/token`, init);
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
if (response.status === 400) {
|
|
80
|
+
const data = yield response.json();
|
|
81
|
+
if (data.error === "authorization_pending")
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
yield (0, fetch_1.validateResponse)(response);
|
|
85
|
+
}
|
|
86
|
+
return (yield response.json());
|
|
87
|
+
});
|
|
88
|
+
/** Waits until user device authorization is complete
|
|
89
|
+
*
|
|
90
|
+
* Returns the OIDC token after completion.
|
|
91
|
+
*/
|
|
92
|
+
const waitForActivation = (org, authorize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
93
|
+
const start = Date.now();
|
|
94
|
+
while (Date.now() - start <= authorize.expires_in * 1e3) {
|
|
95
|
+
const response = yield fetchOidcToken(org, authorize);
|
|
96
|
+
if (!response)
|
|
97
|
+
yield (0, util_1.sleep)(authorize.interval * 1e3);
|
|
98
|
+
else
|
|
99
|
+
return response;
|
|
100
|
+
}
|
|
101
|
+
throw "Expired awaiting in-browser authorization.";
|
|
102
|
+
});
|
|
103
|
+
/** Exchanges an Okta OIDC SSO token for an Okta app SSO token */
|
|
104
|
+
const fetchSsoWebToken = (appId, { org, credential }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
|
+
const init = {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: oidc_1.OIDC_HEADERS,
|
|
108
|
+
body: (0, fetch_1.urlEncode)({
|
|
109
|
+
audience: `urn:okta:apps:${appId}`,
|
|
110
|
+
client_id: org.clientId,
|
|
111
|
+
actor_token: credential.access_token,
|
|
112
|
+
actor_token_type: ACCESS_TOKEN_TYPE,
|
|
113
|
+
subject_token: credential.id_token,
|
|
114
|
+
subject_token_type: ID_TOKEN_TYPE,
|
|
115
|
+
grant_type: TOKEN_EXCHANGE_TYPE,
|
|
116
|
+
requested_token_type: WEB_SSO_TOKEN_TYPE,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
validateProviderDomain(org);
|
|
120
|
+
const response = yield fetch(`https:${org.providerDomain}/oauth2/v1/token`, init);
|
|
121
|
+
yield (0, fetch_1.validateResponse)(response);
|
|
122
|
+
return (yield response.json());
|
|
123
|
+
});
|
|
124
|
+
/** Retrieves an Okta app's SAML response */
|
|
125
|
+
const fetchSamlResponse = (org, { access_token }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
126
|
+
const init = {
|
|
127
|
+
method: "GET",
|
|
128
|
+
headers: (0, lodash_1.omit)(oidc_1.OIDC_HEADERS, "Content-Type"),
|
|
129
|
+
};
|
|
130
|
+
validateProviderDomain(org);
|
|
131
|
+
const url = `https://${org.providerDomain}/login/token/sso?token=${encodeURIComponent(access_token)}`;
|
|
132
|
+
const response = yield fetch(url, init);
|
|
133
|
+
yield (0, fetch_1.validateResponse)(response);
|
|
134
|
+
const html = yield response.text();
|
|
135
|
+
const dom = new jsdom_1.JSDOM(html);
|
|
136
|
+
const samlInput = dom.window.document.querySelector('input[name="SAMLResponse"]');
|
|
137
|
+
return samlInput === null || samlInput === void 0 ? void 0 : samlInput.value;
|
|
138
|
+
});
|
|
139
|
+
/** Logs in to Okta via OIDC */
|
|
140
|
+
const oktaLogin = (org) => __awaiter(void 0, void 0, void 0, function* () {
|
|
141
|
+
const authorizeResponse = yield authorize(org);
|
|
142
|
+
(0, stdio_1.print2)(`Please use the opened browser window to continue your P0 login.
|
|
143
|
+
|
|
144
|
+
When prompted, confirm that Okta displays this code:
|
|
145
|
+
|
|
146
|
+
${authorizeResponse.user_code}
|
|
147
|
+
|
|
148
|
+
Waiting for authorization...
|
|
149
|
+
`);
|
|
150
|
+
void (0, open_1.default)(authorizeResponse.verification_uri_complete);
|
|
151
|
+
const oidcResponse = yield waitForActivation(org, authorizeResponse);
|
|
152
|
+
return oidcResponse;
|
|
153
|
+
});
|
|
154
|
+
exports.oktaLogin = oktaLogin;
|
|
155
|
+
/** Retrieves a SAML response for an okta app */
|
|
156
|
+
// TODO: Inject Okta app
|
|
157
|
+
const getSamlResponse = (identity, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
158
|
+
const webTokenResponse = yield fetchSsoWebToken(config.appId, identity);
|
|
159
|
+
const samlResponse = yield fetchSamlResponse(identity.org, webTokenResponse);
|
|
160
|
+
if (!samlResponse) {
|
|
161
|
+
throw "No SAML assertion obtained from Okta.";
|
|
162
|
+
}
|
|
163
|
+
return samlResponse;
|
|
164
|
+
});
|
|
165
|
+
exports.getSamlResponse = getSamlResponse;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
declare type SshItemConfig = {
|
|
12
|
+
alias?: string;
|
|
13
|
+
identifier: string;
|
|
14
|
+
state: string;
|
|
15
|
+
type: "aws" | "gcloud";
|
|
16
|
+
};
|
|
17
|
+
export declare type SshConfig = {
|
|
18
|
+
workflows?: {
|
|
19
|
+
items: SshItemConfig[];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<style>
|
|
4
|
+
body {
|
|
5
|
+
font-family:
|
|
6
|
+
-apple-system,
|
|
7
|
+
BlinkMacSystemFont,
|
|
8
|
+
Segoe UI,
|
|
9
|
+
Roboto,
|
|
10
|
+
Oxygen,
|
|
11
|
+
Ubuntu,
|
|
12
|
+
Cantarell,
|
|
13
|
+
Fira Sans,
|
|
14
|
+
Droid Sans,
|
|
15
|
+
Helvetica Neue,
|
|
16
|
+
sans-serif;
|
|
17
|
+
background-color: #f0f2f5;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
body .splash {
|
|
24
|
+
background-color: #fff;
|
|
25
|
+
height: fit-content;
|
|
26
|
+
width: fit-content;
|
|
27
|
+
padding: 0.3em 1em 0.3em 1em;
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
30
|
+
<title>P0 login success</title>
|
|
31
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
<div class="splash">
|
|
35
|
+
<h2>Login success</h2>
|
|
36
|
+
<p>You are now logged in to the P0 CLI.</p>
|
|
37
|
+
<p>You can safely close this browser tab.</p>
|
|
38
|
+
</div>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mockGetDoc = void 0;
|
|
4
|
+
/** Copyright © 2024-present P0 Security
|
|
5
|
+
|
|
6
|
+
This file is part of @p0security/cli
|
|
7
|
+
|
|
8
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
9
|
+
|
|
10
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
11
|
+
|
|
12
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
13
|
+
**/
|
|
14
|
+
const firestore_1 = require("firebase/firestore");
|
|
15
|
+
const mockGetDoc = (data) => firestore_1.getDoc.mockResolvedValue({ data: () => data });
|
|
16
|
+
exports.mockGetDoc = mockGetDoc;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
import yargs from "yargs";
|
|
12
|
+
export declare const failure: (spec: yargs.Argv, command: string) => Promise<any>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.failure = void 0;
|
|
13
|
+
const failure = (spec, command) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
let error;
|
|
15
|
+
try {
|
|
16
|
+
yield spec.fail((_, err) => (error = err)).parse(command);
|
|
17
|
+
}
|
|
18
|
+
catch (thrown) {
|
|
19
|
+
error = thrown;
|
|
20
|
+
}
|
|
21
|
+
return error;
|
|
22
|
+
});
|
|
23
|
+
exports.failure = failure;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
import { TokenResponse } from "./oidc";
|
|
12
|
+
import { OrgData } from "./org";
|
|
13
|
+
import { UserCredential } from "firebase/auth";
|
|
14
|
+
export declare type Identity = {
|
|
15
|
+
credential: TokenResponse & {
|
|
16
|
+
expires_at: number;
|
|
17
|
+
};
|
|
18
|
+
org: OrgData;
|
|
19
|
+
};
|
|
20
|
+
export declare type Authn = {
|
|
21
|
+
identity: Identity;
|
|
22
|
+
userCredential: UserCredential;
|
|
23
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
export declare const isa: <T>(values: readonly T[]) => (item: any) => item is T;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Copyright © 2024-present P0 Security
|
|
3
|
+
|
|
4
|
+
This file is part of @p0security/cli
|
|
5
|
+
|
|
6
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
7
|
+
|
|
8
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
9
|
+
|
|
10
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
11
|
+
**/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.isa = void 0;
|
|
14
|
+
const isa = (values) => (item) => values.includes(item);
|
|
15
|
+
exports.isa = isa;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
export declare type AuthorizeRequest = {
|
|
12
|
+
client_id: string;
|
|
13
|
+
code_challenge: string;
|
|
14
|
+
code_challenge_method: "plain" | "S256";
|
|
15
|
+
redirect_uri: string;
|
|
16
|
+
response_type: "code";
|
|
17
|
+
scope: string;
|
|
18
|
+
state?: string;
|
|
19
|
+
login_hint?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare type AuthorizeResponse = {
|
|
22
|
+
device_code: string;
|
|
23
|
+
user_code: string;
|
|
24
|
+
verification_uri: string;
|
|
25
|
+
verification_uri_complete: string;
|
|
26
|
+
expires_in: number;
|
|
27
|
+
interval: number;
|
|
28
|
+
};
|
|
29
|
+
export declare type TokenResponse = {
|
|
30
|
+
access_token: string;
|
|
31
|
+
id_token: string;
|
|
32
|
+
token_type: string;
|
|
33
|
+
scope: string;
|
|
34
|
+
expires_in: number;
|
|
35
|
+
refresh_token: string;
|
|
36
|
+
device_secret: string;
|
|
37
|
+
expiry: string;
|
|
38
|
+
};
|
|
39
|
+
export declare type TokenErrorResponse = {
|
|
40
|
+
error: "access_denied" | "authorization_pending" | "bad grant type" | "expired_token" | "missing parameter" | "not found" | "slow_down";
|
|
41
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
/** Publicly readable organization data */
|
|
12
|
+
export declare type OrgData = {
|
|
13
|
+
clientId: string;
|
|
14
|
+
providerId: string;
|
|
15
|
+
providerDomain?: string;
|
|
16
|
+
providerType?: "okta";
|
|
17
|
+
ssoProvider: "azure-oidc" | "google-oidc" | "google" | "microsoft" | "oidc-pkce" | "okta";
|
|
18
|
+
slug: string;
|
|
19
|
+
tenantId: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
6
|
+
|
|
7
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
export declare const DONE_STATUSES: readonly ["DONE", "DONE_NOTIFIED"];
|
|
12
|
+
export declare const DENIED_STATUSES: readonly ["DENIED", "DENIED_NOTIFIED"];
|
|
13
|
+
export declare const ERROR_STATUSES: readonly ["ERRORED", "ERRORED", "ERRORED_NOTIFIED"];
|
|
14
|
+
export declare type PluginRequest = {
|
|
15
|
+
permission: object;
|
|
16
|
+
generated?: object;
|
|
17
|
+
};
|
|
18
|
+
export declare type Request<P extends PluginRequest = {
|
|
19
|
+
permission: object;
|
|
20
|
+
}> = {
|
|
21
|
+
status: string;
|
|
22
|
+
generatedRoles: {
|
|
23
|
+
role: string;
|
|
24
|
+
}[];
|
|
25
|
+
generated: P["generated"];
|
|
26
|
+
permission: P["permission"];
|
|
27
|
+
principal: string;
|
|
28
|
+
};
|
|
29
|
+
export declare type RequestResponse = {
|
|
30
|
+
ok: true;
|
|
31
|
+
message: string;
|
|
32
|
+
id: string;
|
|
33
|
+
isPreexisting: boolean;
|
|
34
|
+
isPersistent: boolean;
|
|
35
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ERROR_STATUSES = exports.DENIED_STATUSES = exports.DONE_STATUSES = void 0;
|
|
4
|
+
/** Copyright © 2024-present P0 Security
|
|
5
|
+
|
|
6
|
+
This file is part of @p0security/cli
|
|
7
|
+
|
|
8
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
9
|
+
|
|
10
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
11
|
+
|
|
12
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
13
|
+
**/
|
|
14
|
+
exports.DONE_STATUSES = ["DONE", "DONE_NOTIFIED"];
|
|
15
|
+
exports.DENIED_STATUSES = ["DENIED", "DENIED_NOTIFIED"];
|
|
16
|
+
exports.ERROR_STATUSES = [
|
|
17
|
+
"ERRORED",
|
|
18
|
+
"ERRORED",
|
|
19
|
+
"ERRORED_NOTIFIED",
|
|
20
|
+
];
|