I would like to authenticate with MSAL4J and the certificate stored in Azure Key Vault (AKV). The certificate is a self-signed Azure Key Vault certificate.
I could find an example based on a certificate and key stored locally (file system) but not a certificate created and stored in AKV. How to use the certificate, key, and secret objects obtained from azure-security-keyvault-* with MSAL4J?
The key from azure-security-keyvault-keys is com.azure.security.keyvault.keys.models.KeyVaultKey, but MSAL4J expects java.security.PrivateKey.
How to apply the secret obtained from azure-security-keyvault-secrets to decrypt the private key?
Are you sure it is supported? As far as I know certificated-based authentication is not supported.
MSAL uses either public clients or confidential clients.
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-flows-app-scenarios#daemon-app-that-calls-a-web-api-in-the-daemons-name
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-client-applications
However, I did find this on their wiki: https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki/Client-Credentials
There are two types of client secrets in MSAL4J:
Application Secrets
Certificates
You need to instantiate a confidential client application; if you have a certificate:
String PUBLIC_CLIENT_ID;
String AUTHORITY;
PrivateKey PRIVATE_KEY;
X509Certificate PUBLIC_KEY;
IClientCredential credential = ClientCredentialFactory.createFromCertificate(PRIVATE_KEY, PUBLIC_KEY);
ConfidentialClientApplication app =
ConfidentialClientApplication
.builder(PUBLIC_CLIENT_ID, credential)
.authority(AUTHORITY)
.build();
Then acquire a token: https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki/Acquiring-Tokens#confidential-client-applications
https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/src/client/ConfidentialClientApplication.ts
You would need to use: acquireTokenByClientCredential
https://azuread.github.io/microsoft-authentication-library-for-js/ref/classes/_azure_msal_node.confidentialclientapplication.html#acquiretokenbyclientcredential
Also see:
https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/dev/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/CertificateHelper.java
https://learn.microsoft.com/en-us/azure/active-directory/develop/sample-v2-code
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
Related
I am receiving the following String from a certificate stored in Azure Key Vault. I am using the Secret API in order to retrieve both the certificate and the private key related to this cert.
Initially the certificate was uploaded using a .pfx file to Azure Key vault. Now I need to create a Certificate and a PrivateKey to allow client authentication to a 3rd party system and I am using the given String retrieved from the API, however I am note sure how to get around that in Java.
I took some hints from this link in C# however I am pretty certain that this method doesn't work like that in Java. In particular an X509Certificate or a Certificate in general doesn't hold any information about the PrivateKey in Java, unlike C#, and I am not sure how to extract that information from given String in Java.
This works as expected to retrieve the certificate from the String retrieved from the API
String secret = azureSecret.getValue();
byte[] certkey = Base64.getDecoder().decode(secret);
ByteArrayInputStream inputStream = new ByteArrayInputStream(certkey);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(inputStream);
The azureSecret.getValue() format is like the following however I am not sure how to get PrivateKey out of the given String
MIIKvgIBaaZd6Euf3EYwYdHrIIKYzCC...
YES, Java X509Certificate and Certificate is only the certificate. Instead use KeyStore which can contain multiple entries each of which is either a 'trusted' certificate (for someone else), or a privatekey plus certificate plus other chain cert(s) (if applicable) for yourself, or (not relevant here) a 'secret' (symmetric) key. PKCS12 is supported as one type of KeyStore along with others not relevant here, so after the base64-decoding you already have do something like:
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(inputstreamfromvaultvalue, password);
// then
PrivateKey pkey = (PrivateKey) ks.getKey(alias, password);
// and
Certificate cert = ks.getCertificate(alias); // if you only need the leaf cert
// or
Certificate[] chain = ks.getCertificateChain(alias); // usually
But if you want to do client authentication in TLS/SSL (including HTTPS), you give the JSSE KeyManager the whole keystore object not the individual pieces (privatekey and certificates). Similarly to verify the peer in TLS/SSL, you give TrustManager a keystore containing trusted certificates, usually root CAs and often defaulted to a built-in set of public root CAs.
I am developing a backend application using Spring Boot with Java. I have to fulfill this requirement: when a specific controller of my application is called I have to return a JWT (created by me) to the client.
My application has a certificate that I created using an openssl command.
The command I used generated a .pem certificate which I converted to a .crt certificate (still using openssl).
This is the certificate (.pem version):
-----BEGIN CERTIFICATE-----
MIID3zCCAsegAwIBAgIUaQYkHJTPg5Xl29W18fl1FK3F034NFVDWòEMChvcNAQEL
BQAwfjELMAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JvbG9nbmExEDAOBgNVBAcMB0Jv
bG9nbmExEjAQBgNVBAoMCVVuaXNhbHV0ZTEdMBsGA1UECwwUU3ZpbHVwcG8tTXVs
dGljYW5hbGUxGDAWBgNVBAMMD2JlLXByZW5vdGF6aW9uaTAgFw0yMTEwMTgxNjIx
MDJaGA8yMTIxMDkyNDE2MjEwMlowfjELMAkGA1UEBhMCSVQxEDAOBgNVBAgMB0Jv
bG9nbmExEDAOBgN5KLT56L5KJ6L5JK3L434NREDFEFEL3WECN4CXaqre35EdMBsG
A1UECwwUU3ZpbHVwcG8tTXVsdGljYW5hbGUxGDAWBgNVBAMMD2JlLXByZW5vdGF6
aW9uaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrM4q5Azkjm32Ep
MvtcxnA0Ri+6m2DOOjNvJE5rn392hfiZFZcf4K/NCR8F1uM4thru3RsU5mAuhSrK
Nn58fP5KFKVJFLFJDEHWEB3R4RRIMom7PBusRXPbWM+xr0mGdP3SdXr2c71SvSBQ
KVCEBWfR86qSDSDSDSDXCXs4534rI95R7PYXSOrrH7z89u6p9unSI0OKlEwoVOhM
90JdwhVkc6TSSuFBcsFoXlUjcBDYIkZVIgXpj2+EqhDxUSKIlQr6WKWb3DYaGLyG
/9UUPAbLpMTd+D/T9d+cmM3X0WtoNSSvB30qthMFPs9Pdv5Keba7jbfYyYhpECVu
HVCujSkCAwEAAaNTMFEwHQYDVR0OBBYEFCh3SmbuLXhoCtKEq4wSqlBsPQPOMB8G
A1UdIwQYMBaAFCh3SmbuLXhoCtKEq4wSqlBsPQPOMA8GA1UdEwEB/wQFMAMBAf8w
DQYJKoZIhvcNAQELBQADggEBAA38HsRF4NPEITje0hzQmZG0Zhz2C+2EWH9Z+3ow
JfGc/y40I1WYja23zCwyUndQ5M8QXo4OYt8/yNiuGDPQf/n0QqDQ6ynwfkLkmr6m
3a7ocDT8eUFbisEZGWuYqInAi6oiRNc//NYEQOvapNkasu01p/mLhlrINoRIMwX0
JC5EovSivp05xSB6LHuT454545wddsfcwejh23jkashaksaslasLAF9348D8FlXU
X+cD5wvsGQcwmEu64BxEauDGOSybRDD6ppfSPtTivhR0UyLK9hAQB76Ns6oRbBCc
aLEzzgYhOTKHjkmI27qqUa16Jf6TFJe22Q6wbtOrEOnxDiw=
-----END CERTIFICATE-----
I need to create a JWT token (to be returned to the client) starting from this specific certificate that I have saved within my application. What is the easiest way to do this using Java (possibly with standard Java libraries)?
Unfortunately I am not an expert on tokens, public keys, private keys etc ... I just know that the JWT token I create must allow the client to authenticate to me when it calls new endpoints (managed by other controllers in my application, which will validate the token!)
I will suggest the following way to proceed further:
Follow the blog and resurrect a minimalistic running version that has JWT authentication integrated.
https://medium.com/wolox/securing-applications-with-jwt-spring-boot-da24d3d98f83
Now change AuthenticationFilter class and instead of using the hardcoded key in successfulAuthentication method use the private key of your certificate. You can retrieve the private key using bouncy castle libraries and the method defined in blog section 4.2: https://www.baeldung.com/java-read-pem-file-keys
public RSAPrivateKey readPrivateKey(File file) throws Exception {
KeyFactory factory = KeyFactory.getInstance("RSA");
try (FileReader keyReader = new FileReader(file);
PemReader pemReader = new PemReader(keyReader)) {
PemObject pemObject = pemReader.readPemObject();
byte[] content = pemObject.getContent();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
return (RSAPrivateKey) factory.generatePrivate(privKeySpec);
}
}
Once you retrieve the RSAKey use the get the getEncoded() (https://docs.oracle.com/javase/8/docs/api/java/security/Key.html#getEncoded--)
method of retrieved RSAPRivateKey instead of KEY.getBytes() in line 54 of AuthenticationFilter class
I am using Microsoft Java SDK to connect to Azure cloud.
I have created a certificate (p12 file) from .crt,.key & root.crt.
I have uploaded the .crt under Azure AD>App Registrations >Settings>Upload public key.
After that from my Java code I tried to get Azure client (Authenticate) by passing p12 content and password to below API:
ApplicationTokenCredentials credentials = new ApplicationTokenCredentials();
public ApplicationTokenCredentials(String clientId, String domain, byte[] certificate, String password, AzureEnvironment)
Azure azure = Azure.authenticate(credentials).withSubscription(SUBSCRIPTION_ID);
The above call is successful. But if we try to get azure.networks() or azure.storage() it fails with below error:
AADSTS70002: Error validating credentials. AADSTS50012: Client assertion is not within its valid time range.
Please help me on this.
According to Certificate credentials for application authentication, after upload the Public Key.
We also need to update the manifest
In the Azure app registration for the client application, open the application manifest, and replace the keyCredentials property with your new certificate information using the following schema:
"keyCredentials": [
{
"customKeyIdentifier": "$base64Thumbprint",
"keyId": "$keyid",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": "$base64Value"
}
]
If cert is not manditory, we also could generate the secret with azure portal. After that we could get ApplicationTokenCredentials with follow way
public ApplicationTokenCredentials(String clientId,
String domain,
String secret,
AzureEnvironment environment)
Note: If we want to access the Azure resource,we also need to assgin Azure AD application to role.
Summary
I need to establish a two-way SSL connection (with client certificate) in Android, preferrably using Apache HttpClient. I have access to the client's certificate, but no direct access to the clients private key. I can, however sign data with the client's private key.
Since I can't create a normal keystore without the private key, is there some way to override the SSL handshake and manually sign the challenge sent by the server?
What? You have no key, but you can still use it to sign?
The user's private key is stored on a dedicated hardware device. It will present the user's public certificate, and it allows me to pass in data that it will then sign/encrypt with the private key. But it will not give me the key itself.
I implement a SAML SP in Java.
I send an AuthnRequest to SAML 2.0 IDP and gets an encrypted response.
My question is:
How do I make sure that the response indeed comes from the IDP and not from a hacker?
It is not enough to validate the signature, since this only tells me that the sender has a matching pair of private/public keys, but it could be anyone.
So, I need the IDP to supply me in advance a certificate which I upload to a jks file, and compare it each time to the certificate I extract from the ds:X509Certificate element of the response.
Now, is there a standard way of comparing the sender's certificates with the one stored in my keystore?
I saw the following code:
KeyStore keyStore = getKS();
PKIXParameters params = new PKIXParameters(keyStore);
params.setRevocationEnabled(false);
CertPath certPath = certificateFactory.generateCertPath(Arrays.asList(certFromResponse));
CertPathValidator certPathValidator = CertPathValidator.getInstance(CertPathValidator.getDefaultType());
CertPathValidatorResult result = certPathValidator.validate(certPath, params);
Is it enough? If the validation doesn't throw an exception it verifies the sender's identity?
This is the way i have solved the verification of signatures with OpenSAML
https://blog.samlsecurity.com/2012/11/verifying-signatures-with-opensaml.html
I have also written a book, A Guide to OpenSAML, where I explain in detail encryption and signing and more using OpenSAML.
What is important with the OpenSAML verification methods is that they only verify the cryptographic validity of the signature (That the content has not been changed). It does not however verify that the sender is someone that you trust.
The Signature validator is instantiated with the public key of the sender to validate against, the public key of the sender. This is normally exchanged is the setup of an identity federation using SAML Metadata