Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add object ID option for Managed Identity #854

Merged
merged 1 commit into from
Aug 20, 2024
Merged
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 @@ -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.");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does reduce the visibility in logs as to which user assigned is being used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have a look at the changes in the ManagedIdentityRequest class: the new addUserAssignedIdToQuery method called right after this log has the same sort of "Adding [this type of ID] to the request" log message that these classes used to have.

You'll still get the same information about the MI source type and ID type being used, it's just that they will be in two info logs.

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