Compare commits
3 Commits
ed5253b1a1
...
a8725a7c22
| Author | SHA1 | Date | |
|---|---|---|---|
| a8725a7c22 | |||
| 0806a2b588 | |||
| 0cde901ec2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
# Ignore node modules and config files
|
# Ignore node modules and config files
|
||||||
node_modules
|
node_modules
|
||||||
*config.js
|
*config.js
|
||||||
|
*config.json
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# MacOS system files
|
# MacOS system files
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
import { ClientSecretCredential } from "@azure/identity";
|
|
||||||
import { config } from "../config.js";
|
|
||||||
import { createHash } from "crypto";
|
|
||||||
|
|
||||||
// We need to wrap the async code in an IIFE
|
|
||||||
// Check, authentication using @azure/identity requires a client secret.
|
|
||||||
if (config.clientSecret) {
|
|
||||||
console.log("Client secret is set.");
|
|
||||||
// Create the client
|
|
||||||
const credential = new ClientSecretCredential(
|
|
||||||
config.tenantId,
|
|
||||||
config.clientId,
|
|
||||||
config.clientSecret,
|
|
||||||
);
|
|
||||||
|
|
||||||
const token = await credential.getToken(
|
|
||||||
"https://management.azure.com/.default",
|
|
||||||
);
|
|
||||||
if (token) {
|
|
||||||
console.log("Authentication with client secret successful.");
|
|
||||||
const hash = createHash("sha256").update(token.token).digest("hex");
|
|
||||||
console.log("SHA-256 hash of access token:", hash);
|
|
||||||
console.log("Token expires on:", new Date(token.expiresOnTimestamp).toISOString());
|
|
||||||
} else {
|
|
||||||
console.error("Authentication with client secret failed.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn(
|
|
||||||
"Warning: No client secret generated. Authentication may fail if the application requires a client secret.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
67
bin/login.mjs
Normal file
67
bin/login.mjs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { parseArgs } from "util";
|
||||||
|
import { getCredential } from "../src/azure.js";
|
||||||
|
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Parse command line arguments to determine which credential type to use
|
||||||
|
const args = parseArgs({
|
||||||
|
options: {
|
||||||
|
help: { type: "boolean", short: "h" },
|
||||||
|
"credential-type": { type: "string", short: "t", default: "default" },
|
||||||
|
"config": { type: "string", short: "c", default: "app-config.json" },
|
||||||
|
"tenant-id": { type: "string", default: process.env.AZURE_TENANT_ID || "" },
|
||||||
|
"client-id": { type: "string", default: process.env.AZURE_CLIENT_ID || "" },
|
||||||
|
"client-secret": { type: "string", default: process.env.AZURE_CLIENT_SECRET || "" },
|
||||||
|
"client-secret-file": { type: "string", default: process.env.AZURE_CLIENT_SECRET_FILE || "" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (args.values.help) {
|
||||||
|
console.log("Usage: login.mjs [options]");
|
||||||
|
console.log("Options:");
|
||||||
|
console.log(" -h, --help Show this help message");
|
||||||
|
console.log(" -c, --config Path to the configuration file (default: config.js)");
|
||||||
|
console.log(" --tenant-id Azure Tenant ID");
|
||||||
|
console.log(" --client-id Azure Client ID");
|
||||||
|
console.log(" --client-secret Azure Client Secret");
|
||||||
|
console.log(" --client-secret-file Path to file containing Azure Client Secret");
|
||||||
|
console.log(" -t, --credential-type Specify the credential type to use (default: default)");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, check if configuration file is spefiedd
|
||||||
|
const configPath = args.values.config;
|
||||||
|
if (configPath) {
|
||||||
|
// Load the JSON configuration file using readFileSync
|
||||||
|
const configFile = readFileSync(configPath, "utf-8");
|
||||||
|
config = JSON.parse(configFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process command line overrides
|
||||||
|
if (args.values["tenant-id"]) {
|
||||||
|
config.tenantId = args.values["tenant-id"];
|
||||||
|
}
|
||||||
|
if (args.values["client-id"]) {
|
||||||
|
config.clientId = args.values["client-id"];
|
||||||
|
}
|
||||||
|
if (args.values["client-secret"]) {
|
||||||
|
config.clientSecret = args.values["client-secret"];
|
||||||
|
} else if (args.values["client-secret-file"]) {
|
||||||
|
// Read client secret from file
|
||||||
|
config.clientSecret = readFileSync(args.values["client-secret-file"], "utf-8").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the appropriate credential based on the specified type
|
||||||
|
const credential = await getCredential(args.values["credential-type"], config);
|
||||||
|
|
||||||
|
console.log("Successfully obtained credential:", credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("An error occurred:", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
37
src/azure.js
37
src/azure.js
@@ -1,12 +1,45 @@
|
|||||||
// auth.js
|
// azure.js
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import { URL } from "node:url";
|
import { URL } from "node:url";
|
||||||
import open from "open";
|
import open from "open";
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import { PublicClientApplication } from "@azure/msal-node";
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
|
import { PublicClientApplication, ConfidentialClientApplication } from "@azure/msal-node";
|
||||||
|
import { DefaultAzureCredential, ClientSecretCredential, DeviceCodeCredential } from "@azure/identity";
|
||||||
|
|
||||||
|
export async function getCredential(credentialType, options) {
|
||||||
|
switch (credentialType) {
|
||||||
|
case "d":
|
||||||
|
case "default":
|
||||||
|
return new DefaultAzureCredential();
|
||||||
|
case "cs":
|
||||||
|
case "clientSecret":
|
||||||
|
if (!options.tenantId || !options.clientId || !options.clientSecret) {
|
||||||
|
throw new Error("tenantId, clientId, and clientSecret are required for ClientSecretCredential");
|
||||||
|
}
|
||||||
|
return new ClientSecretCredential(
|
||||||
|
options.tenantId,
|
||||||
|
options.clientId,
|
||||||
|
options.clientSecret
|
||||||
|
);
|
||||||
|
case "dc":
|
||||||
|
case "deviceCode":
|
||||||
|
if (!options.tenantId || !options.clientId) {
|
||||||
|
throw new Error("tenantId and clientId are required for DeviceCodeCredential");
|
||||||
|
}
|
||||||
|
return new DeviceCodeCredential({
|
||||||
|
tenantId: options.tenantId,
|
||||||
|
clientId: options.clientId,
|
||||||
|
userPromptCallback: (info) => {
|
||||||
|
console.log(info.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported credential type: ${credentialType}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fileCachePlugin(cachePath) {
|
function fileCachePlugin(cachePath) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user