Add create and delete application and service principal scripts
This commit is contained in:
60
bin/create-app-and-sp.mjs
Normal file
60
bin/create-app-and-sp.mjs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { config } from "../public-config.js";
|
||||||
|
import {
|
||||||
|
createApp,
|
||||||
|
createSp,
|
||||||
|
getApp,
|
||||||
|
getGraphClient,
|
||||||
|
getServicePrincipal,
|
||||||
|
} from "../src/graph.js";
|
||||||
|
import { parseArgs } from "node:util";
|
||||||
|
|
||||||
|
async function usage() {
|
||||||
|
console.log("Usage: create-app-and-sp.mjs --app-name <name>");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { client } = await getGraphClient({
|
||||||
|
tenantId: config.tenantId,
|
||||||
|
clientId: config.clientId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const args = parseArgs({
|
||||||
|
options: {
|
||||||
|
"app-name": {
|
||||||
|
type: "string",
|
||||||
|
short: "n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!args.values["app-name"]) {
|
||||||
|
await usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Will create app with name:", args.values["app-name"]);
|
||||||
|
|
||||||
|
let app = await getApp(client, args.values["app-name"]);
|
||||||
|
if (!app) {
|
||||||
|
app = await createApp(client, args.values["app-name"]);
|
||||||
|
console.log("Created app:", app.appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sp = await getServicePrincipal(client, app.appId);
|
||||||
|
if (!sp) {
|
||||||
|
sp = await createSp(client, app.appId);
|
||||||
|
console.log("Created service principal:", sp.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`The application and associated service principal are ready.
|
||||||
|
App ID: ${app.appId}
|
||||||
|
Service Principal ID: ${sp.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await main().catch((e) => {
|
||||||
|
console.error("Error in main:", e);
|
||||||
|
console.error(e.stack);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
65
bin/delete-app-and-sp.mjs
Normal file
65
bin/delete-app-and-sp.mjs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { config } from "../public-config.js";
|
||||||
|
import {
|
||||||
|
deleteApp,
|
||||||
|
deleteSp,
|
||||||
|
getApp,
|
||||||
|
getGraphClient,
|
||||||
|
getServicePrincipal,
|
||||||
|
} from "../src/graph.js";
|
||||||
|
import { parseArgs } from "node:util";
|
||||||
|
|
||||||
|
async function usage() {
|
||||||
|
console.log("Usage: delete-app-and-sp.mjs --app-name <name>");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { client } = await getGraphClient({
|
||||||
|
tenantId: config.tenantId,
|
||||||
|
clientId: config.clientId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const args = parseArgs({
|
||||||
|
options: {
|
||||||
|
"app-name": {
|
||||||
|
type: "string",
|
||||||
|
short: "n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!args.values["app-name"]) {
|
||||||
|
await usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Will delete app with name:", args.values["app-name"]);
|
||||||
|
|
||||||
|
const app = await getApp(client, args.values["app-name"]);
|
||||||
|
if (!app) {
|
||||||
|
console.log("No app found with name:", args.values["app-name"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sp = await getServicePrincipal(client, app.appId);
|
||||||
|
if (sp && sp.id) {
|
||||||
|
await deleteSp(client, sp.id);
|
||||||
|
console.log("Deleted service principal:", sp.id);
|
||||||
|
} else {
|
||||||
|
console.log("No service principal found for appId:", app.appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app && app.id) {
|
||||||
|
await deleteApp(client, app.id);
|
||||||
|
console.log("Deleted app:", app.appId);
|
||||||
|
} else {
|
||||||
|
console.log("App object id missing; cannot delete application");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await main().catch((e) => {
|
||||||
|
console.error("Error in main:", e);
|
||||||
|
console.error(e.stack);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
70
src/graph.js
Normal file
70
src/graph.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { Client } from "@microsoft/microsoft-graph-client";
|
||||||
|
import { loginInteractive } from "./azure.js";
|
||||||
|
|
||||||
|
export async function getGraphClient({ tenantId, clientId }) {
|
||||||
|
const graphApiToken = await loginInteractive({
|
||||||
|
tenantId,
|
||||||
|
clientId,
|
||||||
|
scopes: ["https://graph.microsoft.com/.default"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const client = Client.init({
|
||||||
|
authProvider: (done) => {
|
||||||
|
done(null, graphApiToken.accessToken);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { graphApiToken, client };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApp(client, appName) {
|
||||||
|
const result = await client
|
||||||
|
.api("/applications")
|
||||||
|
.filter(`displayName eq '${appName}'`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// Return the first application found or null if none exists
|
||||||
|
return result.value.length > 0 ? result.value[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getServicePrincipal(client, appId) {
|
||||||
|
const result = await client
|
||||||
|
.api("/servicePrincipals")
|
||||||
|
.filter(`appId eq '${appId}'`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// Return the first service principal found or null if none exists
|
||||||
|
return result.value.length > 0 ? result.value[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createApp(client, appName) {
|
||||||
|
const app = await client.api("/applications").post({
|
||||||
|
displayName: appName,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!app || !app.appId) {
|
||||||
|
throw new Error("Failed to create application");
|
||||||
|
}
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createSp(client, appId) {
|
||||||
|
const sp = await client.api("/servicePrincipals").post({
|
||||||
|
appId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sp || !sp.id) {
|
||||||
|
throw new Error("Failed to create service principal");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteSp(client, spId) {
|
||||||
|
await client.api(`/servicePrincipals/${spId}`).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteApp(client, appObjectId) {
|
||||||
|
await client.api(`/applications/${appObjectId}`).delete();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user