Skip to content

Commit ae49802

Browse files
authored
Merge pull request #227591 from msmbaldwin/acl-misc
Add documentation to describe user management in ACL
2 parents 26a9dce + fd02e53 commit ae49802

File tree

4 files changed

+709
-0
lines changed

4 files changed

+709
-0
lines changed
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
---
2+
title: Manage Azure AD token-based users in Azure confidential ledger
3+
description: Learn how to manage Azure AD token-based users in Azure confidential ledger
4+
author: settiy
5+
ms.author: settiy
6+
ms.date: 02/09/2023
7+
ms.service: confidential-ledger
8+
ms.topic: how-to
9+
---
10+
11+
# Manage Azure AD token-based users in Azure confidential ledger
12+
13+
Azure AD-based users are identified by their Azure AD object ID.
14+
15+
Users with Administrator privileges can manage users of the confidential ledger. Available roles are Reader (read-only), Contributor (read and write), and Administrator (read, write, and manage users).
16+
17+
The following client libraries are available to manage users:
18+
19+
- [Python](#python-client-library)
20+
- [.NET](#net-client-library)
21+
- [Java](#java-client-library)
22+
- [TypeScript](#typescript-client-library)
23+
24+
## Sign in to Azure
25+
26+
[!INCLUDE [Sign in to Azure](../../includes/confidential-ledger-sign-in-azure.md)]
27+
28+
Get the confidential ledger's name and the identity service URI from the Azure portal as it is needed to create a client to manage the users. This image shows the appropriate properties in the Azure portal.
29+
30+
:::image type="content" source="./media/ledger-properties.png" alt-text="A screenshot showing ledger properties in the Azure portal.":::
31+
32+
Replace instances of `contoso` and `https://contoso.confidential-ledger.azure.com` in the following code snippets with the respective values from the Azure portal.
33+
34+
## Python Client Library
35+
36+
### Install the packages
37+
38+
```Python
39+
pip install azure-identity azure-confidentialledger
40+
```
41+
42+
### Create a confidential ledger client
43+
44+
```Python
45+
from azure.identity import DefaultAzureCredential
46+
from azure.confidentialledger import ConfidentialLedgerClient
47+
from azure.confidentialledger.identity_service import ConfidentialLedgerIdentityServiceClient
48+
from azure.confidentialledger import LedgerUserRole
49+
50+
identity_client = ConfidentialLedgerCertificateClient()
51+
network_identity = identity_client.get_ledger_identity(
52+
ledger_id="contoso"
53+
)
54+
55+
ledger_tls_cert_file_name = "ledger_certificate.pem"
56+
with open(ledger_tls_cert_file_name, "w") as cert_file:
57+
cert_file.write(network_identity["ledgerTlsCertificate"])
58+
59+
# The DefaultAzureCredential will use the current Azure context to authenticate to Azure
60+
credential = DefaultAzureCredential()
61+
62+
ledger_client = ConfidentialLedgerClient(
63+
endpoint="https://contoso.confidential-ledger.azure.com",
64+
credential=credential,
65+
ledger_certificate_path=ledger_tls_cert_file_name
66+
)
67+
68+
# Add a user with the contributor role
69+
# Other supported roles are Contributor and Administrator
70+
user_id = "Azure AD object id of the user"
71+
user = ledger_client.create_or_update_user(
72+
user_id, {"assignedRole": "Contributor"}
73+
)
74+
75+
# Get the user and check their properties
76+
user = ledger_client.get_user(user_id)
77+
assert user["userId"] == user_id
78+
assert user["assignedRole"] == "Contributor"
79+
80+
# Delete the user
81+
ledger_client.delete_user(user_id)
82+
```
83+
84+
## .NET Client Library
85+
86+
### Install the packages
87+
88+
89+
```
90+
dotnet add package Azure.Security.ConfidentialLedger
91+
dotnet add package Azure.Identity
92+
dotnet add Azure.Security
93+
```
94+
95+
### Create a client and manage the users
96+
97+
```Dotnet
98+
using Azure.Core;
99+
using Azure.Identity;
100+
using Azure.Security.ConfidentialLedger;
101+
102+
internal class ACLUserManagement
103+
{
104+
static void Main(string[] args)
105+
{
106+
// Create a ConfidentialLedgerClient instance
107+
// The DefaultAzureCredential will use the current Azure context to authenticate to Azure
108+
var ledgerClient = new ConfidentialLedgerClient(new Uri("https://contoso.confidential-ledger.azure.com"), new DefaultAzureCredential());
109+
110+
string userId = "Azure AD object id of the user";
111+
112+
// Add the user with the Reader role
113+
// Other supported roles are Contributor and Administrator
114+
ledgerClient.CreateOrUpdateUser(
115+
userId,
116+
RequestContent.Create(new { assignedRole = "Reader" }));
117+
118+
// Get the user and print their properties
119+
Azure.Response response = ledgerClient.GetUser(userId);
120+
var aclUser = System.Text.Json.JsonDocument.Parse(response.Content.ToString());
121+
122+
Console.WriteLine($"Assigned Role is = {aclUser.RootElement.GetProperty("assignedRole").ToString()}");
123+
Console.WriteLine($"User id is = {aclUser.RootElement.GetProperty("userId").ToString()}");
124+
125+
// Delete the user
126+
ledgerClient.DeleteUser(userId);
127+
}
128+
}
129+
```
130+
131+
## Java Client Library
132+
133+
### Install the packages
134+
135+
```Java
136+
<!-- https://mvnrepository.com/artifact/com.azure/azure-security-confidentialledger -->
137+
<dependency>
138+
<groupId>com.azure</groupId>
139+
<artifactId>azure-security-confidentialledger</artifactId>
140+
<version>1.0.6</version>
141+
</dependency>
142+
<!-- https://mvnrepository.com/artifact/com.azure/azure-identity -->
143+
<dependency>
144+
<groupId>com.azure</groupId>
145+
<artifactId>azure-identity</artifactId>
146+
<version>1.8.0</version>
147+
</dependency>
148+
<!-- https://mvnrepository.com/artifact/com.azure/azure-core -->
149+
<dependency>
150+
<groupId>com.azure</groupId>
151+
<artifactId>azure-core</artifactId>
152+
<version>1.36.0</version>
153+
</dependency>
154+
```
155+
156+
### Create a client and manage the users
157+
158+
```Java
159+
import java.io.IOException;
160+
import com.azure.core.http.HttpClient;
161+
import java.io.ByteArrayInputStream;
162+
import java.nio.charset.StandardCharsets;
163+
164+
import com.azure.security.confidentialledger.*;
165+
import com.azure.core.http.rest.RequestOptions;
166+
import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
167+
import com.azure.core.http.rest.Response;
168+
import com.azure.core.util.BinaryData;
169+
import com.azure.identity.DefaultAzureCredentialBuilder;
170+
import com.fasterxml.jackson.databind.JsonNode;
171+
import com.fasterxml.jackson.databind.ObjectMapper;
172+
import com.azure.security.confidentialledger.certificate.ConfidentialLedgerCertificateClient;
173+
import com.azure.security.confidentialledger.certificate.ConfidentialLedgerCertificateClientBuilder;
174+
175+
import io.netty.handler.ssl.SslContext;
176+
import io.netty.handler.ssl.SslContextBuilder;
177+
178+
public class CreateOrUpdateUserSample {
179+
public static void main(String[] args) {
180+
try {
181+
// Download the service identity certificate of the ledger from the well-known identity service endpoint.
182+
// Do not change the identity endpoint.
183+
ConfidentialLedgerCertificateClientBuilder confidentialLedgerCertificateClientbuilder = new ConfidentialLedgerCertificateClientBuilder()
184+
.certificateEndpoint("https://identity.confidential-ledger.core.azure.com")
185+
.credential(new DefaultAzureCredentialBuilder().build()).httpClient(HttpClient.createDefault());
186+
187+
ConfidentialLedgerCertificateClient confidentialLedgerCertificateClient = confidentialLedgerCertificateClientbuilder
188+
.buildClient();
189+
190+
String ledgerId = "contoso";
191+
Response<BinaryData> ledgerCertificateWithResponse = confidentialLedgerCertificateClient
192+
.getLedgerIdentityWithResponse(ledgerId, null);
193+
BinaryData certificateResponse = ledgerCertificateWithResponse.getValue();
194+
ObjectMapper mapper = new ObjectMapper();
195+
JsonNode jsonNode = mapper.readTree(certificateResponse.toBytes());
196+
String ledgerTlsCertificate = jsonNode.get("ledgerTlsCertificate").asText();
197+
198+
SslContext sslContext = SslContextBuilder.forClient()
199+
.trustManager(new ByteArrayInputStream(ledgerTlsCertificate.getBytes(StandardCharsets.UTF_8)))
200+
.build();
201+
reactor.netty.http.client.HttpClient reactorClient = reactor.netty.http.client.HttpClient.create()
202+
.secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
203+
HttpClient httpClient = new NettyAsyncHttpClientBuilder(reactorClient).wiretap(true).build();
204+
205+
// The DefaultAzureCredentialBuilder will use the current Azure context to authenticate to Azure
206+
ConfidentialLedgerClient confidentialLedgerClient = new ConfidentialLedgerClientBuilder()
207+
.credential(new DefaultAzureCredentialBuilder().build()).httpClient(httpClient)
208+
.ledgerEndpoint("https://contoso.confidential-ledger.azure.com").buildClient();
209+
210+
// Add a user
211+
// Other supported roles are Contributor and Administrator
212+
BinaryData userDetails = BinaryData.fromString("{\"assignedRole\":\"Reader\"}");
213+
RequestOptions requestOptions = new RequestOptions();
214+
String userId = "Azure AD object id of the user";
215+
Response<BinaryData> response = confidentialLedgerClient.createOrUpdateUserWithResponse(userId,
216+
userDetails, requestOptions);
217+
218+
BinaryData parsedResponse = response.getValue();
219+
220+
ObjectMapper objectMapper = new ObjectMapper();
221+
JsonNode responseBodyJson = null;
222+
223+
try {
224+
responseBodyJson = objectMapper.readTree(parsedResponse.toBytes());
225+
} catch (IOException e) {
226+
e.printStackTrace();
227+
}
228+
229+
System.out.println("Assigned role for user is " + responseBodyJson.get("assignedRole"));
230+
231+
// Get the user and print the details
232+
response = confidentialLedgerClient.getUserWithResponse(userId, requestOptions);
233+
234+
parsedResponse = response.getValue();
235+
236+
try {
237+
responseBodyJson = objectMapper.readTree(parsedResponse.toBytes());
238+
} catch (IOException e) {
239+
e.printStackTrace();
240+
}
241+
242+
System.out.println("Assigned role for user is " + responseBodyJson.get("assignedRole"));
243+
244+
// Delete the user
245+
confidentialLedgerClient.deleteUserWithResponse(userId, requestOptions);
246+
} catch (Exception ex) {
247+
System.out.println("Caught exception" + ex);
248+
}
249+
}
250+
}
251+
```
252+
253+
## TypeScript Client Library
254+
255+
### Install the packages
256+
257+
```
258+
"dependencies": {
259+
"@azure-rest/confidential-ledger": "^1.0.0",
260+
"@azure/identity": "^3.1.3",
261+
"typescript": "^4.9.5"
262+
}
263+
```
264+
### Create a client and manage the users
265+
266+
```TypeScript
267+
import ConfidentialLedger, { getLedgerIdentity } from "@azure-rest/confidential-ledger";
268+
import { DefaultAzureCredential } from "@azure/identity";
269+
270+
export async function main() {
271+
// Get the signing certificate from the confidential ledger Identity Service
272+
const ledgerIdentity = await getLedgerIdentity("contoso");
273+
274+
// Create the confidential ledger Client
275+
const confidentialLedger = ConfidentialLedger(
276+
"https://contoso.confidential-ledger.azure.com",
277+
ledgerIdentity.ledgerIdentityCertificate,
278+
new DefaultAzureCredential()
279+
);
280+
281+
// Azure AD object id of the user
282+
const userId = "Azure AD Object id"
283+
284+
// Other supported roles are Reader and Contributor
285+
const createUserParams: CreateOrUpdateUserParameters = {
286+
contentType: "application/merge-patch+json",
287+
body: {
288+
assignedRole: "Contributor",
289+
userId: `${userId}`
290+
}
291+
}
292+
293+
// Add the user
294+
var response = await confidentialLedger.path("/app/users/{userId}", userId).patch(createUserParams)
295+
296+
// Check for a non-success response
297+
if (response.status !== "200") {
298+
throw response.body.error;
299+
}
300+
301+
// Print the response
302+
console.log(response.body);
303+
304+
// Get the user
305+
response = await confidentialLedger.path("/app/users/{userId}", userId).get()
306+
307+
// Check for a non-success response
308+
if (response.status !== "200") {
309+
throw response.body.error;
310+
}
311+
312+
// Print the response
313+
console.log(response.body);
314+
315+
// Set the user role to Reader
316+
const updateUserParams: CreateOrUpdateUserParameters = {
317+
contentType: "application/merge-patch+json",
318+
body: {
319+
assignedRole: "Reader",
320+
userId: `${userId}`
321+
}
322+
}
323+
324+
// Update the user
325+
response = await confidentialLedger.path("/app/users/{userId}", userId).patch(updateUserParams)
326+
327+
// Check for a non-success response
328+
if (response.status !== "200") {
329+
throw response.body.error;
330+
}
331+
332+
// Print the response
333+
console.log(response.body);
334+
335+
// Delete the user
336+
await confidentialLedger.path("/app/users/{userId}", userId).delete()
337+
338+
// Get the user to make sure it is deleted
339+
response = await confidentialLedger.path("/app/users/{userId}", userId).get()
340+
341+
// Check for a non-success response
342+
if (response.status !== "200") {
343+
throw response.body.error;
344+
}
345+
}
346+
347+
main().catch((err) => {
348+
console.error(err);
349+
});
350+
```
351+
352+
## Next steps
353+
354+
- [Register an ACL app with Azure AD](register-application.md)
355+
- [Manage certificate-based users](manage-certificate-based-users.md)

0 commit comments

Comments
 (0)