feat(graph): add --resolve for list-app-permissions
This commit is contained in:
15
src/cli.js
15
src/cli.js
@@ -7,7 +7,12 @@ import jmespath from "jmespath";
|
|||||||
|
|
||||||
import { loadPublicConfig } from "./index.js";
|
import { loadPublicConfig } from "./index.js";
|
||||||
import { getGraphClient } from "./graph/auth.js";
|
import { getGraphClient } from "./graph/auth.js";
|
||||||
import { listApps, listAppPermissions, listAppGrants } from "./graph/app.js";
|
import {
|
||||||
|
listApps,
|
||||||
|
listAppPermissions,
|
||||||
|
listAppPermissionsResolved,
|
||||||
|
listAppGrants,
|
||||||
|
} from "./graph/app.js";
|
||||||
import { toMarkdownTable } from "./markdown.js";
|
import { toMarkdownTable } from "./markdown.js";
|
||||||
|
|
||||||
function usage() {
|
function usage() {
|
||||||
@@ -15,13 +20,14 @@ function usage() {
|
|||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
list-apps [--display-name <name>]
|
list-apps [--display-name <name>]
|
||||||
list-app-permissions --app-id <appId>
|
list-app-permissions --app-id <appId> [--resolve]
|
||||||
list-app-grants --app-id <appId>
|
list-app-grants --app-id <appId>
|
||||||
table [--pretty]
|
table [--pretty]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--display-name <name> Filter apps by exact display name
|
--display-name <name> Filter apps by exact display name
|
||||||
--app-id <appId> Application (client) ID
|
--app-id <appId> Application (client) ID
|
||||||
|
--resolve Resolve permission GUIDs to human-readable values
|
||||||
--query <jmespath> Filter output JSON using JMESPath
|
--query <jmespath> Filter output JSON using JMESPath
|
||||||
--pretty Use normalized column widths for Markdown table output
|
--pretty Use normalized column widths for Markdown table output
|
||||||
--output <format> Output format: json|table|prettytable (default: json)
|
--output <format> Output format: json|table|prettytable (default: json)
|
||||||
@@ -73,6 +79,7 @@ async function main() {
|
|||||||
help: { type: "boolean", short: "h" },
|
help: { type: "boolean", short: "h" },
|
||||||
"display-name": { type: "string" },
|
"display-name": { type: "string" },
|
||||||
"app-id": { type: "string" },
|
"app-id": { type: "string" },
|
||||||
|
resolve: { type: "boolean" },
|
||||||
query: { type: "string" },
|
query: { type: "string" },
|
||||||
pretty: { type: "boolean" },
|
pretty: { type: "boolean" },
|
||||||
output: { type: "string" },
|
output: { type: "string" },
|
||||||
@@ -117,7 +124,9 @@ async function main() {
|
|||||||
tenantId: config.tenantId,
|
tenantId: config.tenantId,
|
||||||
clientId: config.clientId,
|
clientId: config.clientId,
|
||||||
});
|
});
|
||||||
result = await listAppPermissions(client, values["app-id"]);
|
result = values.resolve
|
||||||
|
? await listAppPermissionsResolved(client, values["app-id"])
|
||||||
|
: await listAppPermissions(client, values["app-id"]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "list-app-grants":
|
case "list-app-grants":
|
||||||
|
|||||||
@@ -84,6 +84,87 @@ export async function listAppPermissions(client, appId) {
|
|||||||
: [];
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List required resource access in a resolved, human-readable form.
|
||||||
|
*
|
||||||
|
* @param { Object } client
|
||||||
|
* @param { string } appId
|
||||||
|
* @returns { Promise<Array> }
|
||||||
|
*/
|
||||||
|
export async function listAppPermissionsResolved(client, appId) {
|
||||||
|
const requiredResourceAccess = await listAppPermissions(client, appId);
|
||||||
|
if (!Array.isArray(requiredResourceAccess) || requiredResourceAccess.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const resourceAppIds = [...new Set(
|
||||||
|
requiredResourceAccess
|
||||||
|
.map((entry) => entry?.resourceAppId)
|
||||||
|
.filter(Boolean),
|
||||||
|
)];
|
||||||
|
|
||||||
|
const resourceDefinitions = await Promise.all(resourceAppIds.map(async (resourceAppId) => {
|
||||||
|
const result = await client
|
||||||
|
.api("/servicePrincipals")
|
||||||
|
.filter(`appId eq '${resourceAppId}'`)
|
||||||
|
.select("appId,displayName,oauth2PermissionScopes,appRoles")
|
||||||
|
.get();
|
||||||
|
|
||||||
|
const sp = Array.isArray(result?.value) && result.value.length > 0
|
||||||
|
? result.value[0]
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const scopesById = new Map(
|
||||||
|
(sp?.oauth2PermissionScopes ?? []).map((scope) => [scope.id, scope]),
|
||||||
|
);
|
||||||
|
const rolesById = new Map(
|
||||||
|
(sp?.appRoles ?? []).map((role) => [role.id, role]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
resourceAppId,
|
||||||
|
resourceDisplayName: sp?.displayName ?? null,
|
||||||
|
scopesById,
|
||||||
|
rolesById,
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
const byResourceAppId = new Map(
|
||||||
|
resourceDefinitions.map((entry) => [entry.resourceAppId, entry]),
|
||||||
|
);
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
for (const resourceEntry of requiredResourceAccess) {
|
||||||
|
const resourceMeta = byResourceAppId.get(resourceEntry.resourceAppId);
|
||||||
|
const resourceAccessItems = Array.isArray(resourceEntry?.resourceAccess)
|
||||||
|
? resourceEntry.resourceAccess
|
||||||
|
: [];
|
||||||
|
|
||||||
|
for (const item of resourceAccessItems) {
|
||||||
|
const permissionType = item?.type ?? null;
|
||||||
|
const permissionId = item?.id ?? null;
|
||||||
|
const resolved = permissionType === "Scope"
|
||||||
|
? resourceMeta?.scopesById.get(permissionId)
|
||||||
|
: resourceMeta?.rolesById.get(permissionId);
|
||||||
|
|
||||||
|
rows.push({
|
||||||
|
resourceAppId: resourceEntry.resourceAppId ?? null,
|
||||||
|
resourceDisplayName: resourceMeta?.resourceDisplayName ?? null,
|
||||||
|
permissionId,
|
||||||
|
permissionType,
|
||||||
|
permissionValue: resolved?.value ?? null,
|
||||||
|
permissionDisplayName:
|
||||||
|
resolved?.adminConsentDisplayName ??
|
||||||
|
resolved?.userConsentDisplayName ??
|
||||||
|
resolved?.displayName ??
|
||||||
|
null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List delegated OAuth2 permission grants for an application by appId.
|
* List delegated OAuth2 permission grants for an application by appId.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user