简体   繁体   English

如何使用PKI证书代替客户端密码?

[英]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. 我想知道是否有人可以建议我在当前设置中如何使用PKI证书而不是客户端机密字符串来访问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. 证书将提供给我,Azure应用程序中的所有设置都将为我完成,我只需要知道如何在Java设置中使用证书即可。

My GraphAuthManager. 我的GraphAuthManager。 I build an OAuth20Service with the information. 我使用该信息构建OAuth20Service。

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. 我快速浏览了scribejava。 It seems that it can only support using client secret now. 看来它现在只能支持使用客户端机密。

To use a PKI certificate instead of client secret, you need to: 要使用PKI证书而不是客户端密钥,您需要:

  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. cer文件将导出到D:\\ test.cer。 You can upload it to your application registered in Azure AD. 您可以将其上传到在Azure AD中注册的应用程序。

A pfx file will be exported too. pfx文件也将被导出。 It is a backup of your certificate. 它是证书的备份。 And it will be used to acquire a token. 它将用于获取令牌。

  1. Add Azure MSAL , and acquire a token 添加Azure MSAL并获取令牌
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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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