I'm new to Azure and I'm struggling to get a simple demo working.
I'm trying to write a daemon client that accesses a blob. The access must be via a registered app, and I want to explicitly acquire an access token.
As a warm-up I wrote a demo that accesses the blob using the blob api, and this works OK:
ClientCertificateCredential credentials = new ClientCertificateCredentialBuilder()
.clientId("11518eab-7b5a-493c-8d12-27731fe51341")
.tenantId("4b106bc5-7518-4f86-a259-f5726d124732")
.pemCertificate("/home/william/cert/new/azure.pem")
.build();
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.credential(credentials)
.endpoint("https://wemsa.blob.core.windows.net/")
.buildClient();
BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("wemco");
blobContainerClient.getBlobClient("spiral.jpeg")
.downloadToFile("/home/william/blob.jpeg");
The above code uses my registered app to create a BlobClient
that downloads my blob file. The fact that this works shows me that my app does have the role required to access my storage container.
I want to create a second demo that does the same thing, but I want to get an access token explicitly and use it to authorise a plain http request to the blob api. So far this is what I've produced:
private static final String TENANT_ID = "4b106bc5-7518-4f86-a259-f5726d124732";
private static final String CLIENT_ID = "11518eab-7b5a-493c-8d12-27731fe51341";
private static final String AUTHORITY = "https://login.microsoftonline.com/" + TENANT_ID;
private static final Set<String> SCOPE = Collections.singleton("api://" + CLIENT_ID + "/.default");
InputStream pkcs12Cert = new FileInputStream("/home/william/cert/new/azure.p12");
String certPwd = "password123";
IClientCredential credential = ClientCredentialFactory.createFromCertificate(pkcs12Cert, certPwd);
ConfidentialClientApplication cca = ConfidentialClientApplication
.builder(CLIENT_ID, credential).authority(AUTHORITY).build();
ClientCredentialParameters parameters = ClientCredentialParameters.builder(SCOPE).build();
IAuthenticationResult result = cca.acquireToken(parameters).join();
String token = result.accessToken();
URI uri = new URI("https://wemsa.blob.core.windows.net/wemco/spiral.jpeg");
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.header("Authorization", "Bearer " + token)
.header("Date", formatNow())
.header("x-ms-version", "2020-06-12")
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode()); // 401 !!!
This uses the same registered app as the first demo. Debugging tells me that it is successfully getting access tokens. But, when I try to use them I always get a 401 response. I had hoped that since the first demo works OK, the second demo would automatically work as well - but it doesn't.
Any suggestions ?
Additional info: This is what I did in Azure (accepting defaults for everything):
Then I returned to the container wemco and:
This was enough to get demo 1 working.
Fixed by changing the scope (i.e. the requested resource) to azure storage:
private static final Set<String> SCOPE =
Collections.singleton("https://storage.azure.com//.default");
After making this change I was able to download my blob file using the demo 2 code in the original posting.