简体   繁体   中英

How to use a PKI certificate instead of client secret?

I am wondering if anyone could advise me on how to use a PKI certificate instead of a client secret string in my current setup for accessing graph in Java. The certificate will be provided to me and all set up in the Azure app will be done for me, I just need to know how to use the Cert in my java setup.

My GraphAuthManager. I build an OAuth20Service with the information.

package com.mycompany.graph.connect;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;

import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse;
import com.github.scribejava.core.oauth.OAuth20Service;
import com.microsoft.graph.core.ClientException;
import com.microsoft.graph.logger.LoggerLevel;

//this modifying the example authentication manager to my purposes
public class GraphAuthManager {

    //extrnalised info like scopes,client secret,etc
    private OAuth2AccessToken mAccessToken;
    // this is set if we already have a refresh token

    /**
        * Initialization block. Runs before constructor to get a logger and start up
        * the ScribeJava OAuth2 authentication service
        */
    {
        if (Debug.DebugLevel == LoggerLevel.DEBUG) {
            DebugLogger.getInstance().writeLog(Level.INFO, "AuthenticationManager initialization block called");

            try (OAuth20Service service = new ServiceBuilder(Constants.CLIENT_ID).callback(Constants.REDIRECT_URL)
                    .scope(Constants.SCOPES).apiKey(Constants.CLIENT_ID).apiSecret(API_SECRET).debugStream(System.out)
                    .debug().build(MicrosoftAzureAD20Api.instance())) {
                mOAuthService = service;
            } catch (java.io.IOException | IllegalArgumentException ex) {
                try {
                    throw ex;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            try (OAuth20Service service = new ServiceBuilder(Constants.CLIENT_ID).callback(Constants.REDIRECT_URL)
                    .scope(Constants.SCOPES).apiKey(Constants.CLIENT_ID).apiKey(Constants.CLIENT_ID)
                    .apiSecret(API_SECRET).build(MicrosoftAzureAD20Api.instance())) {
                mOAuthService = service;
            } catch (java.io.IOException | IllegalArgumentException ex) {
                try {
                    throw ex;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private GraphAuthManager() throws IOException {
        DebugLogger.getInstance().writeLog(Level.INFO, "AuthenticationManager constructor called");
    }

    public static synchronized GraphAuthManager getInstance() throws java.io.IOException, java.net.ConnectException {
        return new GraphAuthManager();
    }

    public OAuth2AccessToken getRefreshTokenWithAuthToken(String authToken)
            throws OAuth2AccessTokenErrorResponse, IOException, InterruptedException, ExecutionException {


        try {
            System.out.println("trying for the first time");
            mAccessToken = mOAuthService.getAccessToken(authToken);
            return mAccessToken;
        }
        catch (IOException | InterruptedException | ExecutionException e) {
            // if a catch other than a response code error occurs, try it agaiin
            System.out.println("trying a second time");
            try {
                mAccessToken = mOAuthService.getAccessToken(authToken);
                return mAccessToken;
            } catch (IOException | InterruptedException | ExecutionException e2) {

                // TODO Auto-generated catch block
                // an error occured
                e2.printStackTrace();
                throw e2; // this is for bubbling up the exception to the class using graphauth to do
                            // validations
            }
        }

    }

    public OAuth2AccessToken getAccessTokenWithRefreshToken(String refreshToken)
            throws OAuth2AccessTokenErrorResponse, IOException, InterruptedException, ExecutionException {
        try {
            System.out.println("trying for the first time");
            OAuth2AccessToken mAccessToken = mOAuthService.refreshAccessToken(refreshToken);
            return mAccessToken;
        } catch (IOException | InterruptedException | ExecutionException e) {
            try {
                System.out.println("trying for the second time");
                OAuth2AccessToken mAccessToken = mOAuthService.refreshAccessToken(refreshToken);
                return mAccessToken;
            } catch (IOException | InterruptedException | ExecutionException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
                throw e2;
            }
        }


    }

    public OAuth20Service getOAuthService() {
        return mOAuthService;
    }

    public String getRefreshToken() {
        if (mAccessToken == null) {
            return "";
        }
        return mAccessToken.getRefreshToken();
    }

    public String getAccessToken() {
        if (mAccessToken == null) {
            return "";
        }
        return mAccessToken.getAccessToken();
    }
}

I took a fast look on scribejava. It seems that it can only support using client secret now.

To use a PKI certificate instead of client secret, you need to:

  1. Create and upload a self-signed certificate
$cert=New-SelfSignedCertificate -Subject "CN=AADCert" -CertStoreLocation "Cert:\CurrentUser\My"  -KeyExportPolicy Exportable -KeySpec Signature
$bin = $cert.RawData
$base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cert.GetCertHash()
$base64Thumbprint = [System.Convert]::ToBase64String($bin)
$cert | Export-Certificate -FilePath D:\test.cer
$CertPassword = ConvertTo-SecureString -String “YourPassword” -Force –AsPlainText
$cert | Export-PfxCertificate -FilePath D:\test.pfx -Password $CertPassword

A cer file will be exported to D:\\test.cer. You can upload it to your application registered in Azure AD.

A pfx file will be exported too. It is a backup of your certificate. And it will be used to acquire a token.

  1. Add Azure MSAL , and acquire a token
import com.microsoft.aad.msal4j.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class MsalTest {
    public static void main(String[] args) throws Exception {

        Set<String> scopes = new HashSet<>();
        scopes.add("openid");
        scopes.add("User.Read");

        String code = "The authorization code, AQABAAI......UQ_CIAA";

        IClientCredential clientCredential = ClientCredentialFactory.create(ClassLoader.getSystemResourceAsStream("./others/test.pfx"), "YourPassword");

        String clientId = "Your client id, dc17****-****-****-****-****e56da5e7";

        String authority = "https://login.microsoftonline.com/+tenantid, for example: https://login.microsoftonline.com/e4c9ab4e-bd27-40d5-8459-230ba2a757fb";

        URI redirectUri = new URI("redirect uri of your applicaiton in azure ad, https://localhost/");

        IAuthenticationResult result = GetTokenWithCertficate(scopes, code, clientCredential, clientId, authority, redirectUri);

        System.out.println(result.accessToken());
    }

    static IAuthenticationResult GetTokenWithCertficate(Set<String> scopes, String code, IClientCredential clientCredential, String clientId, String authority, URI redirectUri){
        IAuthenticationResult result = null;
        ExecutorService service = null;
        try{
            service = Executors.newFixedThreadPool(1);
            ConfidentialClientApplication app = ConfidentialClientApplication.builder(clientId, clientCredential).authority(authority).executorService(service).build();
            AuthorizationCodeParameters authorizationCodeParameters = AuthorizationCodeParameters.builder(code, redirectUri).scopes(scopes).build();
            result = app.acquireToken(authorizationCodeParameters).get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            service.shutdown();
        }

        return result;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM