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
2 changes: 1 addition & 1 deletion src/CsrValidation/java/example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<dependency>
<groupId>com.microsoft.intune.scep</groupId>
<artifactId>csr-validation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>20210505-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
2 changes: 1 addition & 1 deletion src/CsrValidation/java/lib/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.intune.scep</groupId>
<artifactId>csr-validation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>20210505-SNAPSHOT</version>
<build>
<plugins>
<plugin>
Expand Down
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;
public 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
Loading