Open 0B7002 opened 4 months ago
I tried the following but all failed.
please help.
Is anyone working on this issue? I have to resolve this issue as soon as possible.
@0B7002 I'll try to reproduce this and get back to you later today. Apologies for the delay
When can I get a reply?
Is anyone working on this issue?
Sorry for the delay @0B7002.
From my understanding of certificate-based authentication & these docs what you should be uploading to your app registration is the X509 certificate generated.
From Azure Identity's logic it seems that we expect a certificate file containing a private key. The certs generated by OpenSSL only have the public key in the encoded payload.
Still investigating this.
Thank you for your answer.
As mentioned earlier, I generated and uploaded a public key with the x509 option.
And I read docs but could not find how to generate pem file.
What kind of files should I upload to my app and how to generate it? what value should I specify to pemCertificat()
? I have no idea, please help.
From my understanding, this error has occured causing private key, not public key.
And as mentioned earlier, I created public/private key using openssl, Here is the commands.
$ openssl genrsa -out ms365-private.key 2048
$ openssl req -new -x509 -key ms365-private.key -out ms365-public.crt -days 365000
So I tried to get public key information from private key by a following command, and suceed.
$ openssl rsa -pubout < ms365-private.key
-----BEGIN PUBLIC KEY-----
XXXXX
-----END PUBLIC KEY-----
writing RSA key
Why pemCertificat()
can not read this private key? How should I create a key?
Using the same public/private key, I successed to get access token by the following code.
// private key
byte[] encoded = Base64.getDecoder().decode("[private key]");
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(encoded));
// public key
X509Certificate publicKey = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(Files.newInputStream(Paths.get("[public key file path]")));
// parameter
String authority = "https://login.microsoftonline.com/[tenantid]/";
Set<String> scope = Set.of("https://graph.microsoft.com/.default");
// client
IClientCredential credential = ClientCredentialFactory.createFromCertificate(privateKey, publicKey);
ConfidentialClientApplication cca = ConfidentialClientApplication.builder("[clientid]", credential)
.authority(authority)
.build();
ClientCredentialParameters parameters = ClientCredentialParameters.builder(scope).build();
// get token
CompletableFuture<IAuthenticationResult> result = cca.acquireToken(parameters);
System.out.println(result.get().accessToken());
Because of this, I think that the public/private key is correct.
How to do this in using GraphServiceClient? And, do I need to have and specify the public key on the client side as well?
Using a private key and thumbprint, I successed to authorize by the following code.
import java.security.KeyFactory;
import java.security.interfaces.RSAKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.OffsetDateTime;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.codec.binary.Hex;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.azure.core.credential.TokenCredential;
import com.azure.identity.ClientAssertionCredentialBuilder;
import com.microsoft.graph.serviceclient.GraphServiceClient;
public class MyService {
public GraphServiceClient getGraphClient() throws Exception {
// private key
byte[] encoded = Base64.getDecoder().decode("[private key base64 text]");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
RSAKey privateKey = (RSAKey) KeyFactory.getInstance("RSA").generatePrivate(keySpec);
// generate JWT
byte[] bytes = Hex.decodeHex("thumbprint".toCharArray());
String x5t = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
Map<String, Object> header = new HashMap<>();
header.put("x5t", x5t);
String assertion = JWT.create()
.withHeader(header)
.withAudience("https://login.microsoftonline.com/" + "[tenantId]" + "/oauth2/v2.0/token")
.withExpiresAt(OffsetDateTime.now().plusMinutes(5).toInstant())
.withIssuer("[clientId]")
.withJWTId(UUID.randomUUID().toString())
.withNotBefore(OffsetDateTime.now().toInstant())
.withSubject("[clientId]")
.withIssuedAt(OffsetDateTime.now().toInstant())
.sign(Algorithm.RSA256(privateKey));
// generate GraphServiceClient
TokenCredential credential = new ClientAssertionCredentialBuilder().tenantId("[tenantId]")
.clientId("[clientId]")
.clientAssertion(() -> assertion)
.build();
return new GraphServiceClient(credential);
}
}
Is this a best practice?
I registered the app on the Microsoft Entra admin center by referring to this page:
https://learn.microsoft.com/en-us/graph/auth-v2-service?tabs=http
Then I created public/private key using openssl. Here is the commands.
Uploaded the public key (ms365-private.key) on the Microsoft Entra admin center, and I created this code.
but if i execute some methods on this graphClient , this following error occurs
Q. Should I also specify public key? If so, how to specify public key by using ClientCertificateCredentialBuilder?