Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,120 +28,145 @@
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.naming.ServiceUnavailableException;
import javax.net.ssl.SSLSocketFactory;

import com.microsoft.aad.adal4j.AsymmetricKeyCredential;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;

/**
* Azure Active Directory Authentication Client
*/
public class ADALClientWrapper
{
public class ADALClientWrapper {

private String authority = "https://login.microsoftonline.com/";
private ClientCredential credential = null;
private AsymmetricKeyCredential asymmetricCredential = null;
private ExecutorService service = null;
private AuthenticationContext context = null;

/**
* Azure Active Directory Authentication Client
* @param aadTenant - Azure Active Directory tenant
* @param credential - Credential to use for authentication
*
* @param aadTenant
* - Azure Active Directory tenant
* @param credential
* - Credential to use for authentication
* @throws IllegalArgumentException
*/
public ADALClientWrapper(String aadTenant, ClientCredential credential, Properties props) throws IllegalArgumentException
{
if(aadTenant == null || aadTenant.isEmpty())
{
public ADALClientWrapper(String aadTenant, ClientCredential credential, Properties props) throws IllegalArgumentException {
if (aadTenant == null || aadTenant.isEmpty()) {
throw new IllegalArgumentException("The argument 'aadTenant' is missing");
}

if(credential == null)
{
throw new IllegalArgumentException("The argument 'credential' is missing");

if (credential == null) {
throw new IllegalArgumentException("The argument 'credential' is missing");
}

if(props != null)
{
this.authority = props.getProperty("AUTH_AUTHORITY",this.authority);

if (props != null) {
this.authority = props.getProperty("AUTH_AUTHORITY", this.authority);
}

this.credential = credential;
this.service = Executors.newFixedThreadPool(1);

try
{
this.service = new CurrentThreadExecutor();

try {
context = new AuthenticationContext(this.authority + aadTenant, false, service);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("AUTH_AUTHORITY parameter was not formatted correctly which resulted in a MalformedURLException", e);
}
}

/**
* Azure Active Directory Authentication Client
*
* @param aadTenant
* - Azure Active Directory tenant
* @param credential
* - Credential to use for authentication
* @throws IllegalArgumentException
*/
public ADALClientWrapper(String aadTenant, AsymmetricKeyCredential credential, Properties props) throws IllegalArgumentException {
if (aadTenant == null || aadTenant.isEmpty()) {
throw new IllegalArgumentException("The argument 'aadTenant' is missing");
}

if (credential == null) {
throw new IllegalArgumentException("The argument 'credential' is missing");
}

if (props != null) {
this.authority = props.getProperty("AUTH_AUTHORITY", this.authority);
}
catch(MalformedURLException e)
{

this.asymmetricCredential = credential;
this.service = new CurrentThreadExecutor();

try {
context = new AuthenticationContext(this.authority + aadTenant, false, service);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("AUTH_AUTHORITY parameter was not formatted correctly which resulted in a MalformedURLException", e);
}
}

/**
* Sets the SSL factory to be used on the HTTP client for authentication.
*
* @param factory
*/
public void SetSslSocketFactory(SSLSocketFactory factory) throws IllegalArgumentException
{
if(factory == null)
{
public void SetSslSocketFactory(SSLSocketFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("The argument 'factory' is missing.");
}

this.context.setSslSocketFactory(factory);
}

/**
* Sets the proxy to be used by the ADAL library for any HTTP or HTTPS calls
*
* @param proxy
*/
public void SetProxy(Proxy proxy)
{
public void SetProxy(Proxy proxy) {
this.context.setProxy(proxy);
}

/**
* Gets an access token from AAD for the specified resource using the ClientCredential passed in.
* @param resource Resource to get token for.
* @param credential Credential to use to acquire token.
* Gets an access token from AAD for the specified resource using the
* ClientCredential passed in.
*
* @param resource
* Resource to get token for.
* @return
* @throws ExecutionException
* @throws ExecutionException
* @throws IllegalArgumentException
* @throws InterruptedException
* @throws ServiceUnavailableException
* @throws InterruptedException
* @throws ServiceUnavailableException
*/
public AuthenticationResult getAccessTokenFromCredential(String resource)
throws ServiceUnavailableException, InterruptedException, ExecutionException, IllegalArgumentException
{
if(resource == null || resource.isEmpty())
{
public AuthenticationResult getAccessTokenFromCredential(String resource)
throws ServiceUnavailableException, InterruptedException, ExecutionException, IllegalArgumentException {
if (resource == null || resource.isEmpty()) {
throw new IllegalArgumentException("The argument 'resource' is missing");
}

AuthenticationResult result = null;

Future<AuthenticationResult> future = context.acquireToken(resource, credential, null);

Future<AuthenticationResult> future;
if (credential != null) {
future = context.acquireToken(resource, credential, null);
} else {
future = context.acquireToken(resource, asymmetricCredential, null);
}
result = future.get();

if (result == null)
{
if (result == null) {
throw new ServiceUnavailableException("Authentication result was null");
}

return result;
}

@Override
public void finalize()
{
service.shutdown();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.microsoft.intune.scepvalidation;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.TimeUnit;

/**
* This is a non-thread safe ExecutorService implementation that processes all
* submit() calls immediately rather than running on them on a separate thread.
* Since ADALClientWrapper doesn't take advantage of concurrency, this should be
* more efficient, since it doesn't create a new thread with every new
* ADALClientWrapper instance.
*/
class CurrentThreadExecutor extends AbstractExecutorService {

boolean isShutdown = false;

@Override
public void shutdown() {
isShutdown = true;
}

@Override
public List<Runnable> shutdownNow() {
return Collections.emptyList();
}

@Override
public boolean isShutdown() {
return isShutdown;
}

@Override
public boolean isTerminated() {
return isShutdown;
}

@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return false;
}

@Override
public void execute(Runnable command) {
command.run();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.UnknownHostException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
Expand Down Expand Up @@ -69,6 +71,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.microsoft.aad.adal4j.AsymmetricKeyCredential;
import com.microsoft.aad.adal4j.AuthenticationException;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
Expand All @@ -86,6 +89,7 @@ class IntuneClient

protected String intuneTenant;
protected ClientCredential aadCredential;
protected AsymmetricKeyCredential asymmetricAadCredential;
protected ADALClientWrapper authClient;

protected SSLSocketFactory sslSocketFactory = null;
Expand All @@ -110,6 +114,44 @@ public IntuneClient(Properties configProperties) throws IllegalArgumentException
this(configProperties, null, null);
}

/**
* Construct an Intune client which uses asymmetric key authentication.
*
* @param certificate client certificate
* @param privateKey client private key
* @param configProperties configuration that contains the usual fields,
* but without AAD_APP_KEY, since this instance uses the private key instead
* @param authClient previously established wrapper around client credentials.
* May be NULL.
* @param httpClientBuilder alternative http client builder. May be NULL.
*/
public IntuneClient(X509Certificate certificate, PrivateKey privateKey, Properties configProperties, ADALClientWrapper authClient, HttpClientBuilder httpClientBuilder) {

if(configProperties == null)
{
throw new IllegalArgumentException("The argument 'configProperties' is missing");
}

// Read required properties
String azureAppId = configProperties.getProperty("AAD_APP_ID");
if(azureAppId == null || azureAppId.isEmpty())
{
throw new IllegalArgumentException("The argument 'AAD_APP_ID' is missing");
}

this.intuneTenant = configProperties.getProperty("TENANT");
if(this.intuneTenant == null || this.intuneTenant.isEmpty())
{
throw new IllegalArgumentException("The argument 'TENANT' is missing");
}

// Instantiate asymmetric ADAL Client
this.asymmetricAadCredential = AsymmetricKeyCredential.create(azureAppId, privateKey, certificate);
this.authClient = authClient == null ? new ADALClientWrapper(this.intuneTenant, this.asymmetricAadCredential, configProperties) : authClient;

commonConfiguration(configProperties, httpClientBuilder);
}

/**
* Constructs an IntuneClient object. This is meant to be used for unit tests for dependency injection.
* @param configProperties
Expand Down Expand Up @@ -142,17 +184,20 @@ public IntuneClient(Properties configProperties, ADALClientWrapper authClient, H
{
throw new IllegalArgumentException("The argument 'TENANT' is missing");
}
// Instantiate ADAL Client
this.aadCredential = new ClientCredential(azureAppId, azureAppKey);
this.authClient = authClient == null ? new ADALClientWrapper(this.intuneTenant, this.aadCredential, configProperties) : authClient;

commonConfiguration(configProperties, httpClientBuilder);
}

private void commonConfiguration(Properties configProperties, HttpClientBuilder httpClientBuilder) {
// Read optional properties
this.intuneAppId = configProperties.getProperty("INTUNE_APP_ID", this.intuneAppId);
this.intuneResourceUrl = configProperties.getProperty("INTUNE_RESOURCE_URL", this.intuneResourceUrl);
this.graphApiVersion = configProperties.getProperty("GRAPH_API_VERSION", this.graphApiVersion);
this.graphResourceUrl = configProperties.getProperty("GRAPH_RESOURCE_URL", this.graphResourceUrl);

// Instantiate ADAL Client
this.aadCredential = new ClientCredential(azureAppId, azureAppKey);

this.authClient = authClient == null ? new ADALClientWrapper(this.intuneTenant, this.aadCredential, configProperties) : authClient;
this.httpClientBuilder = httpClientBuilder == null ? this.httpClientBuilder : httpClientBuilder;

proxyHost = configProperties.getProperty("PROXY_HOST");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

package com.microsoft.intune.scepvalidation;

import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
Expand Down Expand Up @@ -57,6 +59,16 @@ public class IntuneRevocationClient extends IntuneClient

final Logger log = LoggerFactory.getLogger(IntuneRevocationClient.class);


public IntuneRevocationClient(X509Certificate certificate, PrivateKey privateKey, Properties configProperties) {
this(certificate, privateKey, configProperties, null, null);
}

public IntuneRevocationClient(X509Certificate certificate, PrivateKey privateKey, Properties configProperties, ADALClientWrapper adalClient, HttpClientBuilder httpClientBuilder) throws IllegalArgumentException {
super(certificate, privateKey, configProperties, adalClient, httpClientBuilder);
commonInitialization(configProperties);
}

/**
* IntuneScepService Client constructor
* @param configProperties Properties object containing client configuration information.
Expand All @@ -77,7 +89,10 @@ public IntuneRevocationClient(Properties configProperties) throws IllegalArgumen
public IntuneRevocationClient(Properties configProperties, ADALClientWrapper adalClient, HttpClientBuilder httpClientBuilder) throws IllegalArgumentException
{
super(configProperties, adalClient, httpClientBuilder);

commonInitialization(configProperties);
}

private void commonInitialization(Properties configProperties) {
if(configProperties == null)
{
throw new IllegalArgumentException("The argument 'configProperties' is missing");
Expand Down
Loading