Skip to content

Commit

Permalink
Add object ID option for Managed Identity
Browse files Browse the repository at this point in the history
  • Loading branch information
Avery-Dunn committed Aug 19, 2024
1 parent 424eea6 commit 51a0101
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
//base class for all sources that support managed identity
abstract class AbstractManagedIdentitySource {

protected static final String TIMEOUT_ERROR = "[Managed Identity] Authentication unavailable. The request to the managed identity endpoint timed out.";
private static final Logger LOG = LoggerFactory.getLogger(AbstractManagedIdentitySource.class);
private static final String MANAGED_IDENTITY_NO_RESPONSE_RECEIVED = "[Managed Identity] Authentication unavailable. No response received from the managed identity endpoint.";

protected final ManagedIdentityRequest managedIdentityRequest;
protected final ServiceBundle serviceBundle;
ManagedIdentitySourceType managedIdentitySourceType;
ManagedIdentityIdType idType;
String userAssignedId;

@Getter
@Setter
Expand All @@ -40,6 +41,8 @@ public AbstractManagedIdentitySource(MsalRequest msalRequest, ServiceBundle serv
this.managedIdentityRequest = (ManagedIdentityRequest) msalRequest;
this.managedIdentitySourceType = sourceType;
this.serviceBundle = serviceBundle;
this.idType = ((ManagedIdentityApplication) msalRequest.application()).getManagedIdentityId().getIdType();
this.userAssignedId = ((ManagedIdentityApplication) msalRequest.application()).getManagedIdentityId().getUserAssignedId();
}

public ManagedIdentityResponse getManagedIdentityResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,9 @@ public void createManagedIdentityRequest(String resource) {
managedIdentityRequest.queryParameters.put("api-version", Collections.singletonList(APP_SERVICE_MSI_API_VERSION));
managedIdentityRequest.queryParameters.put("resource", Collections.singletonList(resource));

if (!StringHelper.isNullOrBlank(getManagedIdentityUserAssignedClientId()))
{
LOG.info("[Managed Identity] Adding user assigned client id to the request.");
managedIdentityRequest.queryParameters.put(Constants.MANAGED_IDENTITY_CLIENT_ID, Collections.singletonList(getManagedIdentityUserAssignedClientId()));
}

if (!StringHelper.isNullOrBlank(getManagedIdentityUserAssignedResourceId()))
{
LOG.info("[Managed Identity] Adding user assigned resource id to the request.");
managedIdentityRequest.queryParameters.put(Constants.MANAGED_IDENTITY_RESOURCE_ID, Collections.singletonList(getManagedIdentityUserAssignedResourceId()));
if (this.idType != null && !StringHelper.isNullOrBlank(this.userAssignedId)) {
LOG.info("[Managed Identity] Adding user assigned ID to the request for App Service Managed Identity.");
managedIdentityRequest.addUserAssignedIdToQuery(this.idType, this.userAssignedId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class Constants {

public static final String MANAGED_IDENTITY_CLIENT_ID = "client_id";
public static final String MANAGED_IDENTITY_RESOURCE_ID = "mi_res_id";
public static final String MANAGED_IDENTITY_OBJECT_ID = "object_id";
public static final String MANAGED_IDENTITY_DEFAULT_TENTANT = "managed_identity";

public static final String IDENTITY_ENDPOINT = "IDENTITY_ENDPOINT";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class IMDSManagedIdentitySource extends AbstractManagedIdentitySource{
public IMDSManagedIdentitySource(MsalRequest msalRequest,
ServiceBundle serviceBundle) {
super(msalRequest, serviceBundle, ManagedIdentitySourceType.IMDS);
ManagedIdentityParameters parameters = (ManagedIdentityParameters) msalRequest.requestContext().apiParameters();
IEnvironmentVariables environmentVariables = getEnvironmentVariables();

if (!StringHelper.isNullOrBlank(environmentVariables.getEnvironmentVariable(Constants.AZURE_POD_IDENTITY_AUTHORITY_HOST))){
LOG.info(String.format("[Managed Identity] Environment variable AZURE_POD_IDENTITY_AUTHORITY_HOST for IMDS returned endpoint: %s", environmentVariables.getEnvironmentVariable(Constants.AZURE_POD_IDENTITY_AUTHORITY_HOST)));
try {
Expand Down Expand Up @@ -77,18 +77,9 @@ public void createManagedIdentityRequest(String resource) {
managedIdentityRequest.queryParameters.put("api-version", Collections.singletonList(IMDS_API_VERSION));
managedIdentityRequest.queryParameters.put("resource", Collections.singletonList(resource));

String clientId = getManagedIdentityUserAssignedClientId();
String resourceId = getManagedIdentityUserAssignedResourceId();
if (!StringHelper.isNullOrBlank(clientId))
{
LOG.info("[Managed Identity] Adding user assigned client id to the request.");
managedIdentityRequest.queryParameters.put(Constants.MANAGED_IDENTITY_CLIENT_ID, Collections.singletonList(clientId));
}

if (!StringHelper.isNullOrBlank(resourceId))
{
LOG.info("[Managed Identity] Adding user assigned resource id to the request.");
managedIdentityRequest.queryParameters.put(Constants.MANAGED_IDENTITY_RESOURCE_ID, Collections.singletonList(resourceId));
if (this.idType != null && !StringHelper.isNullOrBlank(this.userAssignedId)) {
LOG.info("[Managed Identity] Adding user assigned ID to the request for IMDS Managed Identity.");
managedIdentityRequest.addUserAssignedIdToQuery(this.idType, this.userAssignedId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

package com.microsoft.aad.msal4j;

import lombok.AccessLevel;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -31,8 +29,9 @@ static ManagedIdentitySourceType getManagedIdentitySource() {
!StringHelper.isNullOrBlank(environmentVariables.getEnvironmentVariable(Constants.IDENTITY_HEADER))) {
if (!StringHelper.isNullOrBlank(environmentVariables.getEnvironmentVariable(Constants.IDENTITY_SERVER_THUMBPRINT))) {
managedIdentitySourceType = ManagedIdentitySourceType.SERVICE_FABRIC;
} else
managedIdentitySourceType = ManagedIdentitySourceType.APP_SERVICE;
} else {
managedIdentitySourceType = ManagedIdentitySourceType.APP_SERVICE;
}
} else if (!StringHelper.isNullOrBlank(environmentVariables.getEnvironmentVariable(Constants.MSI_ENDPOINT))) {
managedIdentitySourceType = ManagedIdentitySourceType.CLOUD_SHELL;
} else if (!StringHelper.isNullOrBlank(environmentVariables.getEnvironmentVariable(Constants.IDENTITY_ENDPOINT)) &&
Expand All @@ -54,12 +53,6 @@ static ManagedIdentitySourceType getManagedIdentitySource() {
ManagedIdentityIdType identityIdType = managedIdentityApplication.getManagedIdentityId().getIdType();
if (!identityIdType.equals(ManagedIdentityIdType.SYSTEM_ASSIGNED)) {
managedIdentitySource.setUserAssignedManagedIdentity(true);
String userAssignedId = managedIdentityApplication.getManagedIdentityId().getUserAssignedId();
if (identityIdType.equals(ManagedIdentityIdType.CLIENT_ID)) {
managedIdentitySource.setManagedIdentityUserAssignedClientId(userAssignedId);
} else if (identityIdType.equals(ManagedIdentityIdType.RESOURCE_ID)) {
managedIdentitySource.setManagedIdentityUserAssignedResourceId(userAssignedId);
}
}
}

Expand All @@ -70,7 +63,6 @@ ManagedIdentityResponse getManagedIdentityResponse(ManagedIdentityParameters par
// This method tries to create managed identity source for different sources, if none is created then defaults to IMDS.
private static AbstractManagedIdentitySource createManagedIdentitySource(MsalRequest msalRequest,
ServiceBundle serviceBundle) {
AbstractManagedIdentitySource managedIdentitySource;

if (managedIdentitySourceType == null || managedIdentitySourceType == ManagedIdentitySourceType.NONE) {
managedIdentitySourceType = getManagedIdentitySource();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,21 @@ public static ManagedIdentityId userAssignedResourceId(String resourceId)

return new ManagedIdentityId(ManagedIdentityIdType.RESOURCE_ID, resourceId);
}

/**
* Create an instance of ManagedIdentityId for a user assigned managed identity from an object id.
*
* @param objectId Object ID of the user assigned managed identity assigned to azure resource.
* @return Instance of ManagedIdentityId
* @exception NullPointerException Indicates the resourceId param is null or blank
*/
public static ManagedIdentityId userAssignedObjectId(String objectId)
{
if (StringHelper.isNullOrBlank(objectId))
{
throw new NullPointerException(objectId);
}

return new ManagedIdentityId(ManagedIdentityIdType.OBJECT_ID, objectId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ enum ManagedIdentityIdType {

SYSTEM_ASSIGNED,
CLIENT_ID,
RESOURCE_ID
RESOURCE_ID,
OBJECT_ID
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
package com.microsoft.aad.msal4j;

import com.nimbusds.oauth2.sdk.util.URLUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;

class ManagedIdentityRequest extends MsalRequest {

private static final Logger LOG = LoggerFactory.getLogger(ManagedIdentityRequest.class);

URI baseEndpoint;

HttpMethod method;
Expand Down Expand Up @@ -53,4 +58,21 @@ private String appendQueryParametersToBaseEndpoint() {

return baseEndpoint.toString() + "?" + queryString;
}

void addUserAssignedIdToQuery(ManagedIdentityIdType idType, String userAssignedId) {
switch (idType) {
case CLIENT_ID:
LOG.info("[Managed Identity] Adding user assigned client id to the request.");
queryParameters.put(Constants.MANAGED_IDENTITY_CLIENT_ID, Collections.singletonList(userAssignedId));
break;
case RESOURCE_ID:
LOG.info("[Managed Identity] Adding user assigned resource id to the request.");
queryParameters.put(Constants.MANAGED_IDENTITY_RESOURCE_ID, Collections.singletonList(userAssignedId));
break;
case OBJECT_ID:
LOG.info("[Managed Identity] Adding user assigned object id to the request.");
queryParameters.put(Constants.MANAGED_IDENTITY_OBJECT_ID, Collections.singletonList(userAssignedId));
break;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ class ServiceFabricManagedIdentitySource extends AbstractManagedIdentitySource {

private final URI msiEndpoint;
private final String identityHeader;
private final ManagedIdentityIdType idType;
private final String userAssignedId;

//Service Fabric requires a special check for an environment variable containing a certificate thumbprint used for validating requests.
//No other flow need this and an app developer may not be aware of it, so it was decided that for the Service Fabric flow we will simply override
Expand All @@ -41,12 +39,9 @@ public void createManagedIdentityRequest(String resource) {
managedIdentityRequest.queryParameters.put("resource", Collections.singletonList(resource));
managedIdentityRequest.queryParameters.put("api-version", Collections.singletonList(SERVICE_FABRIC_MSI_API_VERSION));

if (idType == ManagedIdentityIdType.CLIENT_ID) {
LOG.info("[Managed Identity] Adding user assigned client id to the request for Service Fabric Managed Identity.");
managedIdentityRequest.queryParameters.put(Constants.MANAGED_IDENTITY_CLIENT_ID, Collections.singletonList(userAssignedId));
} else if (idType == ManagedIdentityIdType.RESOURCE_ID) {
LOG.info("[Managed Identity] Adding user assigned resource id to the request for Service Fabric Managed Identity.");
managedIdentityRequest.queryParameters.put(Constants.MANAGED_IDENTITY_RESOURCE_ID, Collections.singletonList(userAssignedId));
if (this.idType != null && !StringHelper.isNullOrBlank(this.userAssignedId)) {
LOG.info("[Managed Identity] Adding user assigned ID to the request for Service Fabric Managed Identity.");
managedIdentityRequest.addUserAssignedIdToQuery(this.idType, this.userAssignedId);
}
}

Expand All @@ -55,9 +50,6 @@ private ServiceFabricManagedIdentitySource(MsalRequest msalRequest, ServiceBundl
super(msalRequest, serviceBundle, ManagedIdentitySourceType.SERVICE_FABRIC);
this.msiEndpoint = msiEndpoint;
this.identityHeader = identityHeader;

this.idType = ((ManagedIdentityApplication) msalRequest.application()).getManagedIdentityId().getIdType();
this.userAssignedId = ((ManagedIdentityApplication) msalRequest.application()).getManagedIdentityId().getUserAssignedId();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
class ManagedIdentityTestDataProvider {
private static final String CLIENT_ID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa";
private static final String RESOURCE_ID = "/subscriptions/ffa4aaa2-4444-4444-5555-e3ccedd3d046/resourcegroups/UAMI_group/providers/Microsoft.ManagedIdentityClient/userAssignedIdentities/UAMI";
private static final String OBJECT_ID = "593b2662-5af7-4a90-a9cb-5a9de615b82f";

public static Stream<Arguments> createData() {
return Stream.of(
Expand Down Expand Up @@ -43,14 +44,20 @@ public static Stream<Arguments> createDataUserAssigned() {
ManagedIdentityId.userAssignedClientId(CLIENT_ID)),
Arguments.of(ManagedIdentitySourceType.APP_SERVICE, ManagedIdentityTests.appServiceEndpoint,
ManagedIdentityId.userAssignedResourceId(RESOURCE_ID)),
Arguments.of(ManagedIdentitySourceType.APP_SERVICE, ManagedIdentityTests.appServiceEndpoint,
ManagedIdentityId.userAssignedObjectId(OBJECT_ID)),
Arguments.of(ManagedIdentitySourceType.IMDS, null,
ManagedIdentityId.userAssignedClientId(CLIENT_ID)),
Arguments.of(ManagedIdentitySourceType.IMDS, null,
ManagedIdentityId.userAssignedResourceId(RESOURCE_ID)),
Arguments.of(ManagedIdentitySourceType.IMDS, null,
ManagedIdentityId.userAssignedObjectId(OBJECT_ID)),
Arguments.of(ManagedIdentitySourceType.SERVICE_FABRIC, ManagedIdentityTests.serviceFabricEndpoint,
ManagedIdentityId.userAssignedResourceId(CLIENT_ID)),
Arguments.of(ManagedIdentitySourceType.SERVICE_FABRIC, ManagedIdentityTests.serviceFabricEndpoint,
ManagedIdentityId.userAssignedResourceId(RESOURCE_ID)));
ManagedIdentityId.userAssignedResourceId(RESOURCE_ID)),
Arguments.of(ManagedIdentitySourceType.SERVICE_FABRIC, ManagedIdentityTests.serviceFabricEndpoint,
ManagedIdentityId.userAssignedObjectId(OBJECT_ID)));
}

public static Stream<Arguments> createDataUserAssignedNotSupported() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ private HttpRequest expectedRequest(ManagedIdentitySourceType source, String res
case RESOURCE_ID:
queryParameters.put("mi_res_id", Collections.singletonList(id.getUserAssignedId()));
break;
case OBJECT_ID:
queryParameters.put("object_id", Collections.singletonList(id.getUserAssignedId()));
break;
}

return new HttpRequest(HttpMethod.GET, computeUri(endpoint, queryParameters), headers);
Expand Down

0 comments on commit 51a0101

Please sign in to comment.