Skip to content

Commit 559a647

Browse files
authored
Add a script to add support for identity in mgmt libraries (Azure#13953)
* Add a script to add support for identity in mgmt libraries * handle runtime packages v1 * minor edit
1 parent 50ab723 commit 559a647

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
/**
5+
* Management-plane libraries currently do not support authentication using
6+
* the `@azure/identity` package. However, there is an adapter that can be used
7+
* to add support for it without introducing breaking changes. This script
8+
* enables this adapter in an management-plane library.
9+
*/
10+
11+
const fs = require("fs");
12+
const p = require("path");
13+
14+
function rewriteFile(path, f) {
15+
fs.readFile(path, "utf-8", (err, data) => {
16+
if (err) throw err;
17+
fs.writeFile(path, f(data), "utf-8", function(err) {
18+
if (err) throw err;
19+
console.log(`${p.basename(path)} has been updated`);
20+
});
21+
});
22+
}
23+
24+
function getMatch(matches, search, location) {
25+
if (matches.length < 2) {
26+
throw new Error(`Could not find ${search} in ${location}`);
27+
} else {
28+
return matches[1];
29+
}
30+
}
31+
32+
function updateREADME(content) {
33+
const pkgName = getMatch(
34+
content.match(/.+?npm install (@azure\/.+?)$.*/ms),
35+
"package name",
36+
"README file"
37+
);
38+
const clientName = getMatch(
39+
content.match(/## Azure (.+?) SDK for JavaScript$.*/ms),
40+
"client name",
41+
"README file"
42+
);
43+
44+
return `## Azure ${clientName} SDK for JavaScript
45+
46+
This package contains an isomorphic SDK (runs both in node.js and in browsers) for ${clientName}.
47+
48+
### Currently supported environments
49+
50+
- Node.js version 8.x.x or higher
51+
- Browser JavaScript
52+
53+
### How to install
54+
55+
To use this SDK in your project, you will need to install two packages.
56+
- \`${pkgName}\` that contains the client.
57+
- \`@azure/identity\` that contains different credentials for you to authenticate the client using Azure Active Directory.
58+
59+
Install both packages using the below commands.
60+
\`\`\`bash
61+
npm install ${pkgName}
62+
npm install @azure/identity
63+
\`\`\`
64+
Please note that while the credentials from the older [\`@azure/ms-rest-nodeauth\`](https://www.npmjs.com/package/@azure/ms-rest-nodeauth) and [\`@azure/ms-rest-browserauth\`](https://www.npmjs.com/package/@azure/ms-rest-browserauth) packages are still supported, these packages are in maintenance mode receiving critical bug fixes, but no new features.
65+
We strongly encourage you to use the credentials from \`@azure/identity\` where the latest versions of Azure Active Directory and MSAL APIs are used and more authentication options are provided.
66+
67+
### How to use
68+
69+
There are multiple credentials available in the \`@azure/identity\` package to suit your different authentication needs.
70+
Read about them in detail in [readme for @azure/identity package](https://www.npmjs.com/package/@azure/identity).
71+
To get started you can use the [DefaultAzureCredential](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/identity/identity/README.md#defaultazurecredential) which tries different credentials internally until one of them succeeds.
72+
Most of the credentials would require you to [create an Azure App Registration](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals#application-registration) first.
73+
#### nodejs - Authentication, client creation, and get apps as an example written in JavaScript.
74+
75+
##### Sample code
76+
77+
\`\`\`javascript
78+
const { DefaultAzureCredential } = require("@azure/identity");
79+
const { IotCentralClient } = require("@azure/arm-iotcentral");
80+
const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
81+
82+
// Create credentials using the \`@azure/identity\` package.
83+
// Please note that you can also use credentials from the \`@azure/ms-rest-nodeauth\` package instead.
84+
const creds = new DefaultAzureCredential();
85+
const client = new IotCentralClient(creds, subscriptionId);
86+
const resourceGroupName = "testresourceGroupName";
87+
const resourceName = "testresourceName";
88+
client.apps.get(resourceGroupName, resourceName).then((result) => {
89+
console.log("The result is:");
90+
console.log(result);
91+
}).catch((err) => {
92+
console.log("An error occurred:");
93+
console.error(err);
94+
});
95+
\`\`\`
96+
97+
#### browser - Authentication, client creation, and get apps as an example written in JavaScript.
98+
99+
In browser applications, we recommend using the \`InteractiveBrowserCredential\` that interactively authenticates using the default system browser.
100+
It is necessary to [create an Azure App Registration](https://docs.microsoft.com/azure/active-directory/develop/scenario-spa-app-registration) in the portal for your web application first.
101+
102+
##### Sample code
103+
104+
- index.html
105+
106+
\`\`\`html
107+
<!DOCTYPE html>
108+
<html lang="en">
109+
<head>
110+
<title>@azure/arm-iotcentral sample</title>
111+
<script src="node_modules/@azure/ms-rest-azure-js/dist/msRestAzure.js"></script>
112+
<script src="node_modules/@azure/identity/dist/index.js"></script>
113+
<script src="node_modules/@azure/arm-iotcentral/dist/arm-iotcentral.js"></script>
114+
<script type="text/javascript">
115+
const subscriptionId = "<Subscription_Id>";
116+
// Create credentials using the \`@azure/identity\` package.
117+
// Please note that you can also use credentials from the \`@azure/ms-rest-browserauth\` package instead.
118+
const credential = new InteractiveBrowserCredential(
119+
{
120+
clientId: "<client id for your Azure AD app>",
121+
tenant: "<optional tenant for your organization>"
122+
});
123+
const client = new Azure.ArmIotcentral.IotCentralClient(creds, subscriptionId);
124+
const resourceGroupName = "testresourceGroupName";
125+
const resourceName = "testresourceName";
126+
client.apps.get(resourceGroupName, resourceName).then((result) => {
127+
console.log("The result is:");
128+
console.log(result);
129+
}).catch((err) => {
130+
console.log("An error occurred:");
131+
console.error(err);
132+
});
133+
</script>
134+
</head>
135+
<body></body>
136+
</html>
137+
\`\`\`
138+
139+
## Related projects
140+
141+
- [Microsoft Azure SDK for Javascript](https://github.com/Azure/azure-sdk-for-js)
142+
143+
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js/sdk/iotcentral/arm-iotcentral/README.png)
144+
`;
145+
}
146+
147+
function updatePackageJson(newPackageVersion) {
148+
return function(content) {
149+
return content
150+
.replace(/"version": "\d+.\d+.\d+",/ms, `"version": "${newPackageVersion}",`)
151+
.replace(/"@azure\/ms-rest-azure-js": "\^?(\d+).\d+.\d+"/ms, function(match, major) {
152+
return major === "1"
153+
? '"@azure/ms-rest-azure-js": "^1.4.0"'
154+
: '"@azure/ms-rest-azure-js": "^2.1.0"';
155+
})
156+
.replace(/"@azure\/ms-rest-js": "\^?(\d+).\d+.\d+"/ms, function(match, major) {
157+
return (
158+
(major === "1" ? '"@azure/ms-rest-js": "^1.11.0"' : '"@azure/ms-rest-js": "^2.2.0"') +
159+
',\n "@azure/core-auth": "^1.1.4"'
160+
);
161+
})
162+
.replace(/"typescript": ".+?"/ms, '"typescript": "^3.6.0"');
163+
};
164+
}
165+
166+
function getClientFilePath(path) {
167+
const files = fs.readdirSync(p.join(path, "src"));
168+
for (const file of files) {
169+
if (file.match(/.+?Client.ts/)) {
170+
return p.join("src", file);
171+
}
172+
}
173+
throw new Error(`Could not find the src/*Client.ts file`);
174+
}
175+
176+
function getClientContextFilePath(path) {
177+
const files = fs.readdirSync(p.join(path, "src"));
178+
for (const file of files) {
179+
if (file.match(/.+?ClientContext.ts/)) {
180+
return p.join("src", file);
181+
}
182+
}
183+
throw new Error(`Could not find the src/*ClientContext.ts file`);
184+
}
185+
186+
function updateClient(content) {
187+
const newCredComment = `@param credentials Credentials needed for the client to connect to Azure. Credentials
188+
* implementing the TokenCredential interface from the @azure/identity package are recommended. For
189+
* more information about these credentials, see
190+
* {@link https://www.npmjs.com/package/@azure/identity}. Credentials implementing the
191+
* ServiceClientCredentials interface from the older packages @azure/ms-rest-nodeauth and
192+
* @azure/ms-rest-browserauth are also supported.`;
193+
return content
194+
.replace(
195+
/^import \* as msRest from "@azure\/ms-rest-js";/ms,
196+
'import * as msRest from "@azure/ms-rest-js";\nimport { TokenCredential } from "@azure/core-auth";'
197+
)
198+
.replace(/ServiceClientCredentials/gms, "ServiceClientCredentials | TokenCredential")
199+
.replace(
200+
/@param credentials Credentials needed for the client to connect to Azure./ms,
201+
newCredComment
202+
);
203+
}
204+
205+
function updateClientContext(newPackageVersion) {
206+
return function(content) {
207+
return updateClient(content).replace(
208+
/const packageVersion = "\d+\.\d+\.\d+";/,
209+
`const packageVersion = "${newPackageVersion}";`
210+
);
211+
};
212+
}
213+
214+
function getPackageVersion(packageJsonPath) {
215+
const data = fs.readFileSync(packageJsonPath, "utf-8");
216+
const versionMatch = data.match(/"version": "(\d+).(\d+).\d+",/ms);
217+
return `${versionMatch[1]}.${(parseInt(versionMatch[2]) + 1).toString()}.0`;
218+
}
219+
220+
function main(args) {
221+
if (args.length !== 3) {
222+
throw new Error(
223+
"Expected exactly one command-line argument for the path of the package to be updated"
224+
);
225+
}
226+
const path = args[2];
227+
const packageJsonPath = p.join(path, "package.json");
228+
const newPackageVersion = getPackageVersion(packageJsonPath);
229+
rewriteFile(p.join(path, "README.md"), updateREADME);
230+
rewriteFile(packageJsonPath, updatePackageJson(newPackageVersion));
231+
rewriteFile(p.join(path, getClientFilePath(path)), updateClient);
232+
rewriteFile(p.join(path, getClientContextFilePath(path)), updateClientContext(newPackageVersion));
233+
}
234+
235+
main(process.argv);

0 commit comments

Comments
 (0)