@p0security/cli 0.8.1 → 0.8.2
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/dist/commands/scp.d.ts +1 -1
- package/dist/commands/scp.js +5 -4
- package/dist/commands/shared/index.d.ts +4 -0
- package/dist/commands/shared/index.js +67 -0
- package/dist/commands/{shared.d.ts → shared/ssh.d.ts} +6 -22
- package/dist/commands/{shared.js → shared/ssh.js} +18 -74
- package/dist/commands/ssh.d.ts +1 -1
- package/dist/commands/ssh.js +3 -3
- package/dist/common/retry.d.ts +9 -0
- package/dist/common/retry.js +50 -0
- package/dist/drivers/auth.d.ts +1 -1
- package/dist/drivers/auth.js +7 -3
- package/dist/plugins/aws/config.d.ts +1 -1
- package/dist/plugins/aws/idc/index.d.ts +16 -0
- package/dist/plugins/aws/idc/index.js +150 -0
- package/dist/plugins/aws/ssh.d.ts +3 -3
- package/dist/plugins/aws/ssh.js +21 -11
- package/dist/plugins/aws/types.d.ts +29 -5
- package/dist/plugins/google/ssh.d.ts +5 -3
- package/dist/plugins/google/ssh.js +26 -10
- package/dist/plugins/google/types.d.ts +11 -3
- package/dist/plugins/login.d.ts +3 -0
- package/dist/plugins/login.js +10 -0
- package/dist/plugins/oidc/login.d.ts +33 -2
- package/dist/plugins/oidc/login.js +100 -60
- package/dist/plugins/okta/aws.d.ts +1 -1
- package/dist/plugins/okta/aws.js +2 -2
- package/dist/plugins/okta/login.js +11 -1
- package/dist/plugins/ping/login.d.ts +2 -1
- package/dist/plugins/ping/login.js +11 -1
- package/dist/plugins/ssh/index.d.ts +2 -1
- package/dist/plugins/ssh/index.js +14 -5
- package/dist/types/aws/oidc.d.ts +36 -0
- package/dist/types/aws/oidc.js +12 -0
- package/dist/types/oidc.d.ts +21 -0
- package/dist/types/request.d.ts +2 -7
- package/dist/types/ssh.d.ts +27 -0
- package/dist/types/ssh.js +5 -0
- package/package.json +1 -1
|
@@ -8,7 +8,8 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
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
10
|
**/
|
|
11
|
-
import {
|
|
11
|
+
import { PermissionSpec } from "../../types/request";
|
|
12
|
+
import { CliPermissionSpec } from "../../types/ssh";
|
|
12
13
|
import { CommonSshPermissionSpec } from "../ssh/types";
|
|
13
14
|
export declare type AwsCredentials = {
|
|
14
15
|
AWS_ACCESS_KEY_ID: string;
|
|
@@ -40,7 +41,7 @@ export declare type AwsFederatedLogin = {
|
|
|
40
41
|
};
|
|
41
42
|
};
|
|
42
43
|
};
|
|
43
|
-
declare type AwsLogin = AwsFederatedLogin | AwsIamLogin | AwsIdcLogin;
|
|
44
|
+
export declare type AwsLogin = AwsFederatedLogin | AwsIamLogin | AwsIdcLogin;
|
|
44
45
|
export declare type AwsItemConfig = {
|
|
45
46
|
label?: string;
|
|
46
47
|
state: string;
|
|
@@ -66,7 +67,30 @@ export declare type AwsSshGenerated = {
|
|
|
66
67
|
ssh: {
|
|
67
68
|
linuxUserName: string;
|
|
68
69
|
};
|
|
70
|
+
idc?: {
|
|
71
|
+
region: string;
|
|
72
|
+
id: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export declare type AwsSshPermissionSpec = PermissionSpec<"ssh", AwsSshPermission, AwsSshGenerated>;
|
|
76
|
+
export declare type AwsSsh = CliPermissionSpec<AwsSshPermissionSpec, undefined>;
|
|
77
|
+
export declare type BaseAwsSshRequest = {
|
|
78
|
+
linuxUserName: string;
|
|
79
|
+
accountId: string;
|
|
80
|
+
region: string;
|
|
81
|
+
id: string;
|
|
82
|
+
type: "aws";
|
|
83
|
+
};
|
|
84
|
+
export declare type AwsSshRoleRequest = BaseAwsSshRequest & {
|
|
85
|
+
role: string;
|
|
86
|
+
access: "role";
|
|
87
|
+
};
|
|
88
|
+
export declare type AwsSshIdcRequest = BaseAwsSshRequest & {
|
|
89
|
+
permissionSet: string;
|
|
90
|
+
idc: {
|
|
91
|
+
id: string;
|
|
92
|
+
region: string;
|
|
93
|
+
};
|
|
94
|
+
access: "idc";
|
|
69
95
|
};
|
|
70
|
-
export declare type
|
|
71
|
-
export declare type AwsSsh = CliPermissionSpec<AwsPermissionSpec>;
|
|
72
|
-
export {};
|
|
96
|
+
export declare type AwsSshRequest = AwsSshIdcRequest | AwsSshRoleRequest;
|
|
@@ -8,6 +8,8 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
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
10
|
**/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
export declare const
|
|
11
|
+
import { SshProvider } from "../../types/ssh";
|
|
12
|
+
import { GcpSshPermissionSpec, GcpSshRequest } from "./types";
|
|
13
|
+
export declare const gcpSshProvider: SshProvider<GcpSshPermissionSpec, {
|
|
14
|
+
linuxUserName: string;
|
|
15
|
+
}, GcpSshRequest>;
|
|
@@ -1,13 +1,29 @@
|
|
|
1
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
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
exports.gcpSshProvider = void 0;
|
|
13
|
+
const ssh_key_1 = require("./ssh-key");
|
|
14
|
+
exports.gcpSshProvider = {
|
|
15
|
+
requestToSsh: (request) => {
|
|
16
|
+
return {
|
|
17
|
+
id: request.permission.spec.instanceName,
|
|
18
|
+
projectId: request.permission.spec.projectId,
|
|
19
|
+
zone: request.permission.spec.zone,
|
|
20
|
+
linuxUserName: request.cliLocalData.linuxUserName,
|
|
21
|
+
type: "gcloud",
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
toCliRequest: (request, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
return (Object.assign(Object.assign({}, request), { cliLocalData: {
|
|
26
|
+
linuxUserName: yield (0, ssh_key_1.importSshKey)(request.permission.spec.publicKey, options),
|
|
27
|
+
} }));
|
|
28
|
+
}),
|
|
12
29
|
};
|
|
13
|
-
exports.gcpRequestToSsh = gcpRequestToSsh;
|
|
@@ -8,7 +8,8 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
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
10
|
**/
|
|
11
|
-
import {
|
|
11
|
+
import { PermissionSpec } from "../../types/request";
|
|
12
|
+
import { CliPermissionSpec } from "../../types/ssh";
|
|
12
13
|
import { CommonSshPermissionSpec } from "../ssh/types";
|
|
13
14
|
export declare type GcpSshPermission = {
|
|
14
15
|
spec: CommonSshPermissionSpec & {
|
|
@@ -19,10 +20,17 @@ export declare type GcpSshPermission = {
|
|
|
19
20
|
};
|
|
20
21
|
type: "session";
|
|
21
22
|
};
|
|
22
|
-
export declare type
|
|
23
|
-
export declare type GcpSsh = CliPermissionSpec<
|
|
23
|
+
export declare type GcpSshPermissionSpec = PermissionSpec<"ssh", GcpSshPermission>;
|
|
24
|
+
export declare type GcpSsh = CliPermissionSpec<GcpSshPermissionSpec, {
|
|
24
25
|
linuxUserName: string;
|
|
25
26
|
}>;
|
|
27
|
+
export declare type GcpSshRequest = {
|
|
28
|
+
linuxUserName: string;
|
|
29
|
+
projectId: string;
|
|
30
|
+
zone: string;
|
|
31
|
+
id: string;
|
|
32
|
+
type: "gcloud";
|
|
33
|
+
};
|
|
26
34
|
declare type PosixAccount = {
|
|
27
35
|
username: string;
|
|
28
36
|
uid: string;
|
package/dist/plugins/login.d.ts
CHANGED
|
@@ -10,4 +10,7 @@ You should have received a copy of the GNU General Public License along with @p0
|
|
|
10
10
|
**/
|
|
11
11
|
import { TokenResponse } from "../types/oidc";
|
|
12
12
|
import { OrgData } from "../types/org";
|
|
13
|
+
declare const loginPlugins: readonly ["google", "okta", "ping", "oidc-pkce", "microsoft", "azure-oidc", "google-oidc", "aws-oidc"];
|
|
14
|
+
export declare type LoginPluginType = (typeof loginPlugins)[number];
|
|
13
15
|
export declare const pluginLoginMap: Record<string, (org: OrgData) => Promise<TokenResponse>>;
|
|
16
|
+
export {};
|
package/dist/plugins/login.js
CHANGED
|
@@ -13,6 +13,16 @@ exports.pluginLoginMap = void 0;
|
|
|
13
13
|
const login_1 = require("./google/login");
|
|
14
14
|
const login_2 = require("./okta/login");
|
|
15
15
|
const login_3 = require("./ping/login");
|
|
16
|
+
const loginPlugins = [
|
|
17
|
+
"google",
|
|
18
|
+
"okta",
|
|
19
|
+
"ping",
|
|
20
|
+
"oidc-pkce",
|
|
21
|
+
"microsoft",
|
|
22
|
+
"azure-oidc",
|
|
23
|
+
"google-oidc",
|
|
24
|
+
"aws-oidc",
|
|
25
|
+
];
|
|
16
26
|
exports.pluginLoginMap = {
|
|
17
27
|
google: login_1.googleLogin,
|
|
18
28
|
okta: login_2.oktaLogin,
|
|
@@ -1,5 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AuthorizeResponse, OidcLoginSteps } from "../../types/oidc";
|
|
2
2
|
import { OrgData } from "../../types/org";
|
|
3
|
+
export declare const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
3
4
|
export declare const validateProviderDomain: (org: OrgData) => void;
|
|
5
|
+
/** Executes the first step of a device-authorization grant flow */
|
|
6
|
+
export declare const authorize: <T>(request: {
|
|
7
|
+
url: string;
|
|
8
|
+
init: RequestInit;
|
|
9
|
+
}, validateResponse: (response: Response) => Promise<Response>) => Promise<T>;
|
|
10
|
+
/** Attempts to fetch this device's OIDC token
|
|
11
|
+
*
|
|
12
|
+
* The authorization may or may not be granted at this stage. If it is not, the
|
|
13
|
+
* authorization server will return "authorization_pending", in which case this
|
|
14
|
+
* function will return undefined.
|
|
15
|
+
*/
|
|
16
|
+
export declare const fetchOidcToken: <T>(request: {
|
|
17
|
+
url: string;
|
|
18
|
+
init: RequestInit;
|
|
19
|
+
}) => Promise<T | undefined>;
|
|
20
|
+
/** Waits until user device authorization is complete
|
|
21
|
+
*
|
|
22
|
+
* Returns the OIDC token after completion.
|
|
23
|
+
*/
|
|
24
|
+
export declare const waitForActivation: <A, T>(authorize: A, extractExpiryInterval: (authorize: A) => {
|
|
25
|
+
expires_in: number;
|
|
26
|
+
interval: number;
|
|
27
|
+
}, tokenRequest: {
|
|
28
|
+
url: string;
|
|
29
|
+
init: RequestInit;
|
|
30
|
+
}) => Promise<NonNullable<Awaited<T>>>;
|
|
31
|
+
export declare const oidcLoginSteps: (org: OrgData, scope: string, urls: () => {
|
|
32
|
+
deviceAuthorizationUrl: string;
|
|
33
|
+
tokenUrl: string;
|
|
34
|
+
}) => OidcLoginSteps<AuthorizeResponse>;
|
|
4
35
|
/** Logs in to an Identity Provider via OIDC */
|
|
5
|
-
export declare const oidcLogin:
|
|
36
|
+
export declare const oidcLogin: <A, T>(steps: OidcLoginSteps<A>) => Promise<NonNullable<Awaited<T>>>;
|
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.oidcLogin = exports.validateProviderDomain = void 0;
|
|
15
|
+
exports.oidcLogin = exports.oidcLoginSteps = exports.waitForActivation = exports.fetchOidcToken = exports.authorize = exports.validateProviderDomain = exports.DEVICE_GRANT_TYPE = void 0;
|
|
16
16
|
/** Copyright © 2024-present P0 Security
|
|
17
17
|
|
|
18
18
|
This file is part of @p0security/cli
|
|
@@ -27,107 +27,147 @@ const oidc_1 = require("../../common/auth/oidc");
|
|
|
27
27
|
const fetch_1 = require("../../common/fetch");
|
|
28
28
|
const stdio_1 = require("../../drivers/stdio");
|
|
29
29
|
const util_1 = require("../../util");
|
|
30
|
-
const lodash_1 = require("lodash");
|
|
31
30
|
const open_1 = __importDefault(require("open"));
|
|
32
|
-
|
|
31
|
+
exports.DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
33
32
|
const validateProviderDomain = (org) => {
|
|
34
33
|
if (!org.providerDomain)
|
|
35
34
|
throw "Login requires a configured provider domain.";
|
|
36
35
|
};
|
|
37
36
|
exports.validateProviderDomain = validateProviderDomain;
|
|
37
|
+
const oidcProviderLabels = (providerType) => {
|
|
38
|
+
switch (providerType) {
|
|
39
|
+
case "okta":
|
|
40
|
+
return "Okta";
|
|
41
|
+
case "ping":
|
|
42
|
+
return "PingOne";
|
|
43
|
+
case "google":
|
|
44
|
+
case "google-oidc":
|
|
45
|
+
return "Google";
|
|
46
|
+
case "oidc-pkce":
|
|
47
|
+
return "OIDC";
|
|
48
|
+
case "aws-oidc":
|
|
49
|
+
return "AWS";
|
|
50
|
+
case "azure-oidc":
|
|
51
|
+
case "microsoft":
|
|
52
|
+
return "Entra ID";
|
|
53
|
+
default:
|
|
54
|
+
(0, util_1.throwAssertNever)(providerType);
|
|
55
|
+
}
|
|
56
|
+
throw "Invalid provider type";
|
|
57
|
+
};
|
|
38
58
|
/** Executes the first step of a device-authorization grant flow */
|
|
39
59
|
// cf. https://developer.okta.com/docs/guides/device-authorization-grant/main/
|
|
40
|
-
const authorize = (
|
|
41
|
-
|
|
42
|
-
throw "Login requires a configured provider type.";
|
|
43
|
-
}
|
|
44
|
-
const init = {
|
|
45
|
-
method: "POST",
|
|
46
|
-
headers: oidc_1.OIDC_HEADERS,
|
|
47
|
-
body: (0, fetch_1.urlEncode)({
|
|
48
|
-
client_id: org.clientId,
|
|
49
|
-
scope,
|
|
50
|
-
}),
|
|
51
|
-
};
|
|
52
|
-
(0, exports.validateProviderDomain)(org);
|
|
53
|
-
// This is the "org" authorization server; the okta.apps.* scopes are not
|
|
54
|
-
// available with custom authorization servers
|
|
55
|
-
const url = org.providerType === "okta"
|
|
56
|
-
? `https:${org.providerDomain}/oauth2/v1/device/authorize`
|
|
57
|
-
: org.providerType === "ping"
|
|
58
|
-
? `https://${org.providerDomain}/${org.environmentId}/as/device_authorization`
|
|
59
|
-
: (0, util_1.throwAssertNever)(org.providerType);
|
|
60
|
+
const authorize = (request, validateResponse) => __awaiter(void 0, void 0, void 0, function* () {
|
|
61
|
+
const { url, init } = request;
|
|
60
62
|
const response = yield fetch(url, init);
|
|
61
|
-
yield
|
|
63
|
+
yield validateResponse(response);
|
|
62
64
|
return (yield response.json());
|
|
63
65
|
});
|
|
66
|
+
exports.authorize = authorize;
|
|
64
67
|
/** Attempts to fetch this device's OIDC token
|
|
65
68
|
*
|
|
66
69
|
* The authorization may or may not be granted at this stage. If it is not, the
|
|
67
70
|
* authorization server will return "authorization_pending", in which case this
|
|
68
71
|
* function will return undefined.
|
|
69
72
|
*/
|
|
70
|
-
const fetchOidcToken = (
|
|
71
|
-
|
|
72
|
-
throw "Login requires a configured provider type.";
|
|
73
|
-
}
|
|
74
|
-
const init = {
|
|
75
|
-
method: "POST",
|
|
76
|
-
headers: oidc_1.OIDC_HEADERS,
|
|
77
|
-
body: (0, fetch_1.urlEncode)({
|
|
78
|
-
client_id: org.clientId,
|
|
79
|
-
device_code: authorize.device_code,
|
|
80
|
-
grant_type: DEVICE_GRANT_TYPE,
|
|
81
|
-
}),
|
|
82
|
-
};
|
|
83
|
-
(0, exports.validateProviderDomain)(org);
|
|
84
|
-
const url = org.providerType === "okta"
|
|
85
|
-
? `https:${org.providerDomain}/oauth2/v1/token`
|
|
86
|
-
: org.providerType === "ping"
|
|
87
|
-
? `https://${org.providerDomain}/${org.environmentId}/as/token`
|
|
88
|
-
: (0, util_1.throwAssertNever)(org.providerType);
|
|
73
|
+
const fetchOidcToken = (request) => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
const { url, init } = request;
|
|
89
75
|
const response = yield fetch(url, init);
|
|
90
76
|
if (!response.ok) {
|
|
91
77
|
if (response.status === 400) {
|
|
92
78
|
const data = yield response.json();
|
|
93
79
|
if (data.error === "authorization_pending")
|
|
94
80
|
return undefined;
|
|
81
|
+
if (data.error === "access_denied")
|
|
82
|
+
throw "Access denied, try again";
|
|
95
83
|
}
|
|
96
84
|
yield (0, fetch_1.validateResponse)(response);
|
|
97
85
|
}
|
|
98
86
|
return (yield response.json());
|
|
99
87
|
});
|
|
88
|
+
exports.fetchOidcToken = fetchOidcToken;
|
|
100
89
|
/** Waits until user device authorization is complete
|
|
101
90
|
*
|
|
102
91
|
* Returns the OIDC token after completion.
|
|
103
92
|
*/
|
|
104
|
-
const waitForActivation = (
|
|
93
|
+
const waitForActivation = (authorize, extractExpiryInterval, // Aws implementation differs from standard OIDC response, need function to extract expiry
|
|
94
|
+
tokenRequest) => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
95
|
const start = Date.now();
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
const { expires_in, interval } = extractExpiryInterval(authorize);
|
|
97
|
+
while (Date.now() - start <= expires_in * 1e3) {
|
|
98
|
+
const response = yield (0, exports.fetchOidcToken)(tokenRequest);
|
|
108
99
|
if (!response)
|
|
109
|
-
yield (0, util_1.sleep)(
|
|
100
|
+
yield (0, util_1.sleep)(interval * 1e3);
|
|
110
101
|
else
|
|
111
102
|
return response;
|
|
112
103
|
}
|
|
113
104
|
throw "Expired awaiting in-browser authorization.";
|
|
114
105
|
});
|
|
115
|
-
|
|
116
|
-
const
|
|
106
|
+
exports.waitForActivation = waitForActivation;
|
|
107
|
+
const oidcLoginSteps = (org, scope, urls) => {
|
|
108
|
+
const { deviceAuthorizationUrl, tokenUrl } = urls();
|
|
117
109
|
if (org.providerType === undefined) {
|
|
118
|
-
throw "
|
|
110
|
+
throw "Your organization's login configuration does not support this access. Your P0 admin will need to install a supported OIDC provider in order for you to use this command.";
|
|
119
111
|
}
|
|
120
|
-
const
|
|
112
|
+
const buildOidcAuthorizeRequest = () => {
|
|
113
|
+
(0, exports.validateProviderDomain)(org);
|
|
114
|
+
return {
|
|
115
|
+
init: {
|
|
116
|
+
method: "POST",
|
|
117
|
+
headers: oidc_1.OIDC_HEADERS,
|
|
118
|
+
body: (0, fetch_1.urlEncode)({
|
|
119
|
+
client_id: org.clientId,
|
|
120
|
+
scope,
|
|
121
|
+
}),
|
|
122
|
+
},
|
|
123
|
+
url: deviceAuthorizationUrl,
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
const buildOidcTokenRequest = (authorize) => {
|
|
127
|
+
(0, exports.validateProviderDomain)(org);
|
|
128
|
+
return {
|
|
129
|
+
url: tokenUrl,
|
|
130
|
+
init: {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: oidc_1.OIDC_HEADERS,
|
|
133
|
+
body: (0, fetch_1.urlEncode)({
|
|
134
|
+
client_id: org.clientId,
|
|
135
|
+
device_code: authorize.device_code,
|
|
136
|
+
grant_type: exports.DEVICE_GRANT_TYPE,
|
|
137
|
+
}),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
providerType: org.providerType,
|
|
143
|
+
validateResponse: fetch_1.validateResponse,
|
|
144
|
+
buildAuthorizeRequest: buildOidcAuthorizeRequest,
|
|
145
|
+
buildTokenRequest: buildOidcTokenRequest,
|
|
146
|
+
processAuthzExpiry: (authorize) => ({
|
|
147
|
+
expires_in: authorize.expires_in,
|
|
148
|
+
interval: authorize.interval,
|
|
149
|
+
}),
|
|
150
|
+
processAuthzResponse: (authorize) => ({
|
|
151
|
+
user_code: authorize.user_code,
|
|
152
|
+
verification_uri_complete: authorize.verification_uri_complete,
|
|
153
|
+
}),
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
exports.oidcLoginSteps = oidcLoginSteps;
|
|
157
|
+
/** Logs in to an Identity Provider via OIDC */
|
|
158
|
+
const oidcLogin = (steps) => __awaiter(void 0, void 0, void 0, function* () {
|
|
159
|
+
const { providerType, buildAuthorizeRequest, buildTokenRequest, processAuthzExpiry, processAuthzResponse, validateResponse, } = steps;
|
|
160
|
+
const deviceAuthorizationResponse = yield (0, exports.authorize)(buildAuthorizeRequest(), validateResponse);
|
|
161
|
+
const { user_code, verification_uri_complete } = processAuthzResponse(deviceAuthorizationResponse);
|
|
121
162
|
(0, stdio_1.print2)(`Please use the opened browser window to continue your P0 login.
|
|
122
|
-
|
|
123
|
-
When prompted, confirm that ${(0, lodash_1.capitalize)(org.providerType)} displays this code:
|
|
124
|
-
|
|
125
|
-
${authorizeResponse.user_code}
|
|
126
163
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
164
|
+
When prompted, confirm that ${oidcProviderLabels(providerType)} displays this code:
|
|
165
|
+
|
|
166
|
+
${user_code}
|
|
167
|
+
|
|
168
|
+
Waiting for authorization...
|
|
169
|
+
`);
|
|
170
|
+
void (0, open_1.default)(verification_uri_complete);
|
|
171
|
+
return yield (0, exports.waitForActivation)(deviceAuthorizationResponse, processAuthzExpiry, buildTokenRequest(deviceAuthorizationResponse));
|
|
132
172
|
});
|
|
133
173
|
exports.oidcLogin = oidcLogin;
|
package/dist/plugins/okta/aws.js
CHANGED
|
@@ -24,8 +24,8 @@ const role_1 = require("../../commands/aws/role");
|
|
|
24
24
|
const auth_1 = require("../../drivers/auth");
|
|
25
25
|
const assumeRole_1 = require("../aws/assumeRole");
|
|
26
26
|
const assumeRoleWithOktaSaml = (authn, args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
-
return yield (0, auth_1.cached)(`aws-okta-${args.
|
|
28
|
-
const { account, config, samlResponse } = yield (0, role_1.initOktaSaml)(authn, args.
|
|
27
|
+
return yield (0, auth_1.cached)(`aws-okta-${args.accountId}-${args.role}`, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
|
+
const { account, config, samlResponse } = yield (0, role_1.initOktaSaml)(authn, args.accountId);
|
|
29
29
|
const { roles } = (0, role_1.rolesFromSaml)(account, samlResponse);
|
|
30
30
|
if (!roles.includes(args.role))
|
|
31
31
|
throw `Role not available. Available roles:\n${roles.map((r) => ` ${r}`).join("\n")}`;
|
|
@@ -66,7 +66,17 @@ const fetchSamlResponse = (org, { access_token }) => __awaiter(void 0, void 0, v
|
|
|
66
66
|
return samlInput === null || samlInput === void 0 ? void 0 : samlInput.value;
|
|
67
67
|
});
|
|
68
68
|
/** Logs in to Okta via OIDC */
|
|
69
|
-
const oktaLogin = (org) => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
|
+
const oktaLogin = (org) => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
|
+
return (0, login_1.oidcLogin)((0, login_1.oidcLoginSteps)(org, "openid email profile okta.apps.sso", () => {
|
|
71
|
+
if (org.providerType !== "okta") {
|
|
72
|
+
throw `Invalid provider type ${org.providerType} (expected "okta")`;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
deviceAuthorizationUrl: `https://${org.providerDomain}/oauth2/v1/device/authorize`,
|
|
76
|
+
tokenUrl: `https://${org.providerDomain}/oauth2/v1/token`,
|
|
77
|
+
};
|
|
78
|
+
}));
|
|
79
|
+
});
|
|
70
80
|
exports.oktaLogin = oktaLogin;
|
|
71
81
|
/** Retrieves a SAML response for an okta app */
|
|
72
82
|
// TODO: Inject Okta app
|
|
@@ -8,6 +8,7 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
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
10
|
**/
|
|
11
|
+
import { TokenResponse } from "../../types/oidc";
|
|
11
12
|
import { OrgData } from "../../types/org";
|
|
12
13
|
/** Logs in to PingOne via OIDC */
|
|
13
|
-
export declare const pingLogin: (org: OrgData) => Promise<
|
|
14
|
+
export declare const pingLogin: (org: OrgData) => Promise<TokenResponse>;
|
|
@@ -12,5 +12,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.pingLogin = void 0;
|
|
13
13
|
const login_1 = require("../oidc/login");
|
|
14
14
|
/** Logs in to PingOne via OIDC */
|
|
15
|
-
const pingLogin = (org) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
const pingLogin = (org) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
return (0, login_1.oidcLogin)((0, login_1.oidcLoginSteps)(org, "openid email profile", () => {
|
|
17
|
+
if (org.providerType !== "ping" || org.providerType === undefined) {
|
|
18
|
+
throw `Invalid provider type ${org.providerType} (expected "ping")`;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
deviceAuthorizationUrl: `https://${org.providerDomain}/${org.environmentId}/as/device_authorization`,
|
|
22
|
+
tokenUrl: `https://${org.providerDomain}/${org.environmentId}/as/token`,
|
|
23
|
+
};
|
|
24
|
+
}));
|
|
25
|
+
});
|
|
16
26
|
exports.pingLogin = pingLogin;
|
|
@@ -8,6 +8,7 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
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
10
|
**/
|
|
11
|
-
import { ScpCommandArgs, SshCommandArgs
|
|
11
|
+
import { ScpCommandArgs, SshCommandArgs } from "../../commands/shared/ssh";
|
|
12
12
|
import { Authn } from "../../types/identity";
|
|
13
|
+
import { SshRequest } from "../../types/ssh";
|
|
13
14
|
export declare const sshOrScp: (authn: Authn, data: SshRequest, cmdArgs: ScpCommandArgs | SshCommandArgs, privateKey: string) => Promise<number | null>;
|
|
@@ -13,6 +13,8 @@ exports.sshOrScp = void 0;
|
|
|
13
13
|
const keys_1 = require("../../common/keys");
|
|
14
14
|
const stdio_1 = require("../../drivers/stdio");
|
|
15
15
|
const util_1 = require("../../util");
|
|
16
|
+
const config_1 = require("../aws/config");
|
|
17
|
+
const idc_1 = require("../aws/idc");
|
|
16
18
|
const install_1 = require("../aws/ssm/install");
|
|
17
19
|
const aws_1 = require("../okta/aws");
|
|
18
20
|
const ssh_agent_1 = require("../ssh-agent");
|
|
@@ -256,13 +258,19 @@ const transformForShell = (args) => {
|
|
|
256
258
|
});
|
|
257
259
|
};
|
|
258
260
|
const awsLogin = (authn, data) => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
|
+
var _a, _b, _c, _d;
|
|
259
262
|
if (!(yield (0, install_1.ensureSsmInstall)())) {
|
|
260
263
|
throw "Please try again after installing the required AWS utilities";
|
|
261
264
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
265
|
+
const { config } = yield (0, config_1.getAwsConfig)(authn, data.accountId);
|
|
266
|
+
if (!((_a = config.login) === null || _a === void 0 ? void 0 : _a.type) || ((_b = config.login) === null || _b === void 0 ? void 0 : _b.type) === "iam") {
|
|
267
|
+
throw "This account is not configured for SSH access via the P0 CLI";
|
|
268
|
+
}
|
|
269
|
+
return ((_c = config.login) === null || _c === void 0 ? void 0 : _c.type) === "idc"
|
|
270
|
+
? yield (0, idc_1.assumeRoleWithIdc)(data)
|
|
271
|
+
: ((_d = config.login) === null || _d === void 0 ? void 0 : _d.type) === "federated"
|
|
272
|
+
? yield (0, aws_1.assumeRoleWithOktaSaml)(authn, data)
|
|
273
|
+
: (0, util_1.throwAssertNever)(config.login);
|
|
266
274
|
});
|
|
267
275
|
const sshOrScp = (authn, data, cmdArgs, privateKey) => __awaiter(void 0, void 0, void 0, function* () {
|
|
268
276
|
if (!privateKey) {
|
|
@@ -277,7 +285,8 @@ const sshOrScp = (authn, data, cmdArgs, privateKey) => __awaiter(void 0, void 0,
|
|
|
277
285
|
`eval $(ssh-agent)`,
|
|
278
286
|
`ssh-add "${keys_1.PRIVATE_KEY_PATH}"`,
|
|
279
287
|
// TODO ENG-2284 support login with Google Cloud
|
|
280
|
-
|
|
288
|
+
// TODO: Modify commands to add the ability to get permission set commands
|
|
289
|
+
...(data.type === "aws" && data.access !== "idc"
|
|
281
290
|
? [
|
|
282
291
|
`eval $(p0 aws role assume ${data.role} --account ${data.accountId})`,
|
|
283
292
|
]
|
|
@@ -0,0 +1,36 @@
|
|
|
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 AWSClientInformation = {
|
|
12
|
+
authorizationEndpoint: string;
|
|
13
|
+
clientId: string;
|
|
14
|
+
clientIdIssuedAt: number;
|
|
15
|
+
clientSecret: string;
|
|
16
|
+
clientSecretExpiresAt: number;
|
|
17
|
+
tokenEndpoint: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* AWS OIDC token response uses camelCase instead of snake_case
|
|
21
|
+
*/
|
|
22
|
+
export declare type AWSTokenResponse = {
|
|
23
|
+
accessToken: string;
|
|
24
|
+
expiresIn: number;
|
|
25
|
+
idToken: string;
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
tokenType: string;
|
|
28
|
+
};
|
|
29
|
+
export declare type AWSAuthorizeResponse = {
|
|
30
|
+
deviceCode: string;
|
|
31
|
+
expiresIn: number;
|
|
32
|
+
interval: number;
|
|
33
|
+
userCode: string;
|
|
34
|
+
verificationUri: string;
|
|
35
|
+
verificationUriComplete: string;
|
|
36
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
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 });
|
package/dist/types/oidc.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LoginPluginType } from "../plugins/login";
|
|
1
2
|
/** Copyright © 2024-present P0 Security
|
|
2
3
|
|
|
3
4
|
This file is part of @p0security/cli
|
|
@@ -39,3 +40,23 @@ export declare type TokenResponse = {
|
|
|
39
40
|
export declare type TokenErrorResponse = {
|
|
40
41
|
error: "access_denied" | "authorization_pending" | "bad grant type" | "expired_token" | "missing parameter" | "not found" | "slow_down";
|
|
41
42
|
};
|
|
43
|
+
export declare type OidcLoginSteps<A> = {
|
|
44
|
+
providerType: LoginPluginType;
|
|
45
|
+
validateResponse: (response: Response) => Promise<Response>;
|
|
46
|
+
buildAuthorizeRequest: () => {
|
|
47
|
+
url: string;
|
|
48
|
+
init: RequestInit;
|
|
49
|
+
};
|
|
50
|
+
buildTokenRequest: (authorize: A) => {
|
|
51
|
+
url: string;
|
|
52
|
+
init: RequestInit;
|
|
53
|
+
};
|
|
54
|
+
processAuthzResponse: (authorize: A) => {
|
|
55
|
+
user_code: string;
|
|
56
|
+
verification_uri_complete: string;
|
|
57
|
+
};
|
|
58
|
+
processAuthzExpiry: (authorize: A) => {
|
|
59
|
+
expires_in: number;
|
|
60
|
+
interval: number;
|
|
61
|
+
};
|
|
62
|
+
};
|
package/dist/types/request.d.ts
CHANGED
|
@@ -8,16 +8,10 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
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
10
|
**/
|
|
11
|
-
import {
|
|
12
|
-
import { GcpPermissionSpec, GcpSsh } from "../plugins/google/types";
|
|
11
|
+
import { PluginSshRequest } from "./ssh";
|
|
13
12
|
export declare const DONE_STATUSES: readonly ["DONE", "DONE_NOTIFIED"];
|
|
14
13
|
export declare const DENIED_STATUSES: readonly ["DENIED", "DENIED_NOTIFIED"];
|
|
15
14
|
export declare const ERROR_STATUSES: readonly ["ERRORED", "ERRORED", "ERRORED_NOTIFIED"];
|
|
16
|
-
export declare type CliRequest = AwsSsh | GcpSsh;
|
|
17
|
-
export declare type PluginRequest = AwsPermissionSpec | GcpPermissionSpec;
|
|
18
|
-
export declare type CliPermissionSpec<P extends PluginRequest, C extends object | undefined = undefined> = P & {
|
|
19
|
-
cliLocalData: C;
|
|
20
|
-
};
|
|
21
15
|
export declare type PermissionSpec<K extends string, P extends {
|
|
22
16
|
type: string;
|
|
23
17
|
}, G extends object | undefined = undefined> = {
|
|
@@ -25,6 +19,7 @@ export declare type PermissionSpec<K extends string, P extends {
|
|
|
25
19
|
permission: P;
|
|
26
20
|
generated: G;
|
|
27
21
|
};
|
|
22
|
+
export declare type PluginRequest = PluginSshRequest;
|
|
28
23
|
export declare type Request<P extends PluginRequest> = P & {
|
|
29
24
|
status: string;
|
|
30
25
|
principal: string;
|