Reputation: 533
I've written java program which connect to Azure blob storage that I've created and downloads file content using below program but my real prod scenario is different, client has shared ThumbPrint,ClientId,AzureKeyVaultUrl,SecretId and containerName and certficate. My program works well on account I've created which has trial period. But don't understand how to create account with certificate based authentication n use that while connecting using java program. package com;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Scanner;
public class ConnectToAzureToExistingContainer {
public static final String storageConnectionString =
"DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=yyy;EndpointSuffix=zzzz";
public static void main( String[] args )
{
CloudStorageAccount storageAccount;
CloudBlobClient blobClient = null;
CloudBlobContainer container=null;
try {
storageAccount = CloudStorageAccount.parse(storageConnectionString);
blobClient = storageAccount.createCloudBlobClient();
container = blobClient.getContainerReference("revenuestream");
CloudBlockBlob blob = container.getBlockBlobReference("revenuestreams.csv");
System.out.println(blob.downloadText());
System.out.println("Done...");
}
catch (StorageException ex){
System.out.println(String.format("Error returned from the service. Http code: %d and error code: %s", ex.getHttpStatusCode(), ex.getErrorCode()));
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
Upvotes: 2
Views: 10065
Reputation: 22523
As @Thomas said, you can use Azure AD to get an access token to access your storage files. The main mechanism you can refer to this doc. You need to get an access token to call storage APIs to access your storage service. And you want to use certificate to get this access token to access storage service. You can follow the steps below.
Prepare your .cer certificate and .pfx certificate and upload your .cer to your Azure AD app :
Run this ps to get x5t value of your .pfx file , we will need it while signing jwt token:
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cer.Import("path of your .pfx file","password of your .pfx file",'Exportable')
$x5t = [System.Convert]::ToBase64String($cer.GetCertHash())
$x5t
Convert .pfx file to .der file so that we can use it easily in Java:
1)Convert Pem file from pfx :
openssl pkcs12 -in "your .pfx file path" -out "new .pem file path" -clcerts
2)Convert Pem to der so that java can read it easily :
openssl pkcs8 -topk8 -inform PEM -outform DER -in "pem file path" -out "new der file path" -nocrypt
Pls follow the code below to get access token from Azure AD :
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.naming.ServiceUnavailableException;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientAssertion;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class PublicClient {
private final static String TENANT_ID = "your tanant id";
private final static String AUTHORITY = "https://login.microsoftonline.com/" + TENANT_ID;
private final static String CLIENT_ID = "your Azure AD app ID";
private final static String X5TVALUE_STRING = "x5t value we get from step2 ";
private final static String DERFILE_PATH_STRING = "der file path";
public static void main(String args[]) throws Exception {
// Request access token from AAD
AuthenticationResult result = getAccessToken();
System.out.print(result.getAccessToken());
}
public static PrivateKey getPrivateKey() throws Exception {
byte[] keyBytes = Files.readAllBytes(Paths.get(DERFILE_PATH_STRING));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
private static AuthenticationResult getAccessToken() throws Exception {
AuthenticationContext context;
AuthenticationResult result;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(AUTHORITY, false, service);
PrivateKey key = getPrivateKey();
String jwt = Jwts.builder().setHeaderParam("typ", "JWT").setHeaderParam("alg", "RS256")
.setHeaderParam("x5t",X5TVALUE_STRING).setSubject(CLIENT_ID)
.setExpiration(new Date(System.currentTimeMillis() + 200000)).setIssuer(CLIENT_ID)
.setNotBefore(new Date())
.setAudience("https://login.microsoftonline.com/" + TENANT_ID + "/oauth2/token")
.setId(UUID.randomUUID().toString()).signWith(SignatureAlgorithm.RS256, key).compact();
ClientAssertion clientAssertion = new ClientAssertion(jwt);
Future<AuthenticationResult> future = context.acquireToken("https://storage.azure.com/", clientAssertion,
null);
result = future.get();
} finally {
service.shutdown();
}
if (result == null) {
throw new ServiceUnavailableException("authentication result was null");
}
return result;
}
}
With this token we can call storage REST API , please note that "x-ms-version: 2017-11-09" is required in request header if you use Azure AD auth to access your storage :
Upvotes: 1