-
Notifications
You must be signed in to change notification settings - Fork 367
Adding FMI source to MI app #5299
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
base: main
Are you sure you want to change the base?
Changes from 14 commits
7e29a8b
44e34c5
d1c9a99
615e5d4
951943f
784d438
d60e236
2b3c614
d14ee0c
2caf549
d3318fc
cf3f3bc
8d21f66
62095ff
5c1c4dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,34 +16,79 @@ internal class ServiceFabricManagedIdentitySource : AbstractManagedIdentity | |
private const string ServiceFabricMsiApiVersion = "2019-07-01-preview"; | ||
private readonly Uri _endpoint; | ||
private readonly string _identityHeaderValue; | ||
private readonly bool _isFederated; | ||
private static string _mitsEndpointFmiPath => "/metadata/identity/oauth2/fmi/credential"; | ||
|
||
internal static Lazy<HttpClient> _httpClientLazy; | ||
|
||
public static AbstractManagedIdentity Create(RequestContext requestContext) | ||
public static AbstractManagedIdentity Create(RequestContext requestContext, bool isFmiServiceFabric = false) | ||
{ | ||
Uri endpointUri; | ||
string identityEndpoint = EnvironmentVariables.IdentityEndpoint; | ||
|
||
requestContext.Logger.Info(() => "[Managed Identity] Service fabric managed identity is available."); | ||
|
||
if (!Uri.TryCreate(identityEndpoint, UriKind.Absolute, out Uri endpointUri)) | ||
if (isFmiServiceFabric) | ||
{ | ||
VerifyFederatedEnvVariablesAreAvailable(); | ||
requestContext.Logger.Info(() => "[Managed Identity] Service fabric federated managed identity is available."); | ||
identityEndpoint = EnvironmentVariables.FmiServiceFabricEndpoint; | ||
requestContext.Logger.Info(() => "[Managed Identity] Using FMI Service fabric endpoint."); | ||
|
||
if (!Uri.TryCreate(identityEndpoint + _mitsEndpointFmiPath, UriKind.Absolute, out endpointUri)) | ||
{ | ||
string errorMessage = string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityEndpointInvalidUriError, | ||
"APP_IDENTITY_ENDPOINT", identityEndpoint, "FMI Service Fabric"); | ||
|
||
throw MsalServiceExceptionFactory.CreateManagedIdentityException( | ||
MsalError.InvalidManagedIdentityEndpoint, | ||
errorMessage, | ||
null, | ||
ManagedIdentitySource.ServiceFabric, | ||
null); | ||
} | ||
} | ||
else | ||
{ | ||
string errorMessage = string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityEndpointInvalidUriError, | ||
"IDENTITY_ENDPOINT", identityEndpoint, "Service Fabric"); | ||
|
||
// Use the factory to create and throw the exception | ||
var exception = MsalServiceExceptionFactory.CreateManagedIdentityException( | ||
MsalError.InvalidManagedIdentityEndpoint, | ||
errorMessage, | ||
null, | ||
ManagedIdentitySource.ServiceFabric, | ||
null); | ||
|
||
throw exception; | ||
requestContext.Logger.Info(() => "[Managed Identity] Service fabric managed identity is available."); | ||
|
||
if (!Uri.TryCreate(identityEndpoint, UriKind.Absolute, out endpointUri)) | ||
{ | ||
string errorMessage = string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityEndpointInvalidUriError, | ||
"IDENTITY_ENDPOINT", identityEndpoint, "Service Fabric"); | ||
|
||
throw MsalServiceExceptionFactory.CreateManagedIdentityException( | ||
MsalError.InvalidManagedIdentityEndpoint, | ||
errorMessage, | ||
null, | ||
ManagedIdentitySource.ServiceFabric, | ||
null); | ||
} | ||
} | ||
|
||
requestContext.Logger.Verbose(() => "[Managed Identity] Creating Service Fabric managed identity. Endpoint URI: " + identityEndpoint); | ||
|
||
return new ServiceFabricManagedIdentitySource(requestContext, endpointUri, EnvironmentVariables.IdentityHeader); | ||
requestContext.Logger.Verbose(() => $"[Managed Identity] Creating Service Fabric {(isFmiServiceFabric ? "federated" : "")} managed identity. Endpoint URI: {identityEndpoint}"); | ||
|
||
return new ServiceFabricManagedIdentitySource(requestContext, endpointUri, EnvironmentVariables.IdentityHeader, isFmiServiceFabric); | ||
} | ||
|
||
private static void VerifyFederatedEnvVariablesAreAvailable() | ||
{ | ||
if (string.IsNullOrEmpty(EnvironmentVariables.IdentityServerThumbprint)) | ||
{ | ||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityFmiInvalidEnvVariableError, | ||
"IDENTITY_SERVER_THUMBPRINT")); | ||
} | ||
if (string.IsNullOrEmpty(EnvironmentVariables.FmiServiceFabricEndpoint)) | ||
{ | ||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityFmiInvalidEnvVariableError, | ||
"APP_IDENTITY_ENDPOINT")); | ||
} | ||
if (string.IsNullOrEmpty(EnvironmentVariables.IdentityHeader)) | ||
{ | ||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityFmiInvalidEnvVariableError, | ||
"IDENTITY_HEADER")); | ||
} | ||
if (string.IsNullOrEmpty(EnvironmentVariables.FmiServiceFabricApiVersion)) | ||
{ | ||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.ManagedIdentityFmiInvalidEnvVariableError, | ||
"IDENTITY_API_VERSION", "FMI Service Fabric")); | ||
} | ||
} | ||
|
||
internal override Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> GetValidationCallback() | ||
|
@@ -62,11 +107,12 @@ private bool ValidateServerCertificateCallback(HttpRequestMessage message, X509C | |
return string.Equals(certificate.GetCertHashString(), EnvironmentVariables.IdentityServerThumbprint, StringComparison.OrdinalIgnoreCase); | ||
} | ||
|
||
private ServiceFabricManagedIdentitySource(RequestContext requestContext, Uri endpoint, string identityHeaderValue) : | ||
base(requestContext, ManagedIdentitySource.ServiceFabric) | ||
private ServiceFabricManagedIdentitySource(RequestContext requestContext, Uri endpoint, string identityHeaderValue, bool isFmi) : | ||
base(requestContext, ManagedIdentitySource.ServiceFabric) | ||
{ | ||
_endpoint = endpoint; | ||
_identityHeaderValue = identityHeaderValue; | ||
_isFederated = isFmi; | ||
trwalke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (requestContext.ServiceBundle.Config.ManagedIdentityId.IsUserAssigned) | ||
{ | ||
|
@@ -77,31 +123,43 @@ private ServiceFabricManagedIdentitySource(RequestContext requestContext, Uri en | |
protected override ManagedIdentityRequest CreateRequest(string resource) | ||
{ | ||
ManagedIdentityRequest request = new ManagedIdentityRequest(HttpMethod.Get, _endpoint); | ||
|
||
request.Headers["secret"] = _identityHeaderValue; | ||
|
||
request.QueryParameters["api-version"] = ServiceFabricMsiApiVersion; | ||
request.QueryParameters["resource"] = resource; | ||
|
||
switch (_requestContext.ServiceBundle.Config.ManagedIdentityId.IdType) | ||
if (_isFederated) | ||
{ | ||
case AppConfig.ManagedIdentityIdType.ClientId: | ||
_requestContext.Logger.Info("[Managed Identity] Adding user assigned client id to the request."); | ||
request.QueryParameters[Constants.ManagedIdentityClientId] = _requestContext.ServiceBundle.Config.ManagedIdentityId.UserAssignedId; | ||
break; | ||
|
||
case AppConfig.ManagedIdentityIdType.ResourceId: | ||
_requestContext.Logger.Info("[Managed Identity] Adding user assigned resource id to the request."); | ||
request.QueryParameters[Constants.ManagedIdentityResourceId] = _requestContext.ServiceBundle.Config.ManagedIdentityId.UserAssignedId; | ||
break; | ||
|
||
case AppConfig.ManagedIdentityIdType.ObjectId: | ||
_requestContext.Logger.Info("[Managed Identity] Adding user assigned object id to the request."); | ||
request.QueryParameters[Constants.ManagedIdentityObjectId] = _requestContext.ServiceBundle.Config.ManagedIdentityId.UserAssignedId; | ||
break; | ||
_requestContext.Logger.Info("[Managed Identity] Request is for FMI, no ids or resource will be added to the request."); | ||
request.QueryParameters["api-version"] = EnvironmentVariables.FmiServiceFabricApiVersion; | ||
} | ||
else | ||
{ | ||
request.QueryParameters["api-version"] = ServiceFabricMsiApiVersion; | ||
request.QueryParameters["resource"] = resource; | ||
|
||
switch (_requestContext.ServiceBundle.Config.ManagedIdentityId.IdType) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldnt there be a default case? We could log the unexpected, that could give us additional information when troubleshooting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically yes, but this ID is a required parameter for the managed identity application. So it will always be set to something unless there is a catastrophic failure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's still a good practice to throw an exception @trwalke on default. It will protect against a case where a new enum parameter is added. |
||
{ | ||
case AppConfig.ManagedIdentityIdType.ClientId: | ||
_requestContext.Logger.Info("[Managed Identity] Adding user assigned client id to the request."); | ||
request.QueryParameters[Constants.ManagedIdentityClientId] = _requestContext.ServiceBundle.Config.ManagedIdentityId.UserAssignedId; | ||
break; | ||
|
||
case AppConfig.ManagedIdentityIdType.ResourceId: | ||
_requestContext.Logger.Info("[Managed Identity] Adding user assigned resource id to the request."); | ||
request.QueryParameters[Constants.ManagedIdentityResourceId] = _requestContext.ServiceBundle.Config.ManagedIdentityId.UserAssignedId; | ||
break; | ||
|
||
case AppConfig.ManagedIdentityIdType.ObjectId: | ||
_requestContext.Logger.Info("[Managed Identity] Adding user assigned object id to the request."); | ||
request.QueryParameters[Constants.ManagedIdentityObjectId] = _requestContext.ServiceBundle.Config.ManagedIdentityId.UserAssignedId; | ||
break; | ||
} | ||
} | ||
|
||
return request; | ||
} | ||
|
||
internal string GetEndpointForTesting() | ||
{ | ||
return _endpoint.ToString(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is right. The source detection should not interfere with
isFmi
flag. The MSI source should be expected to be cached (statically, in memory) by MSAL.In other words, each MSI request can either go to the normal endpoint or to the fmi endpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think this is the case. The source detection is effectively turned off if
IsFmi
is enabled and only the FMI source will be used.See ManagedIdentityClient
This parameter specifically is to change this source to only do FMI.
Also, when you say cached (statically, in memory), can more that one of these source objects be cached? meaning, can there be one for regular SF and one for FMI?