Skip to content
Draft
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 @@ -38,5 +38,7 @@ public class FhirServerConfiguration : IApiConfiguration
public EncryptionConfiguration Encryption { get; } = new EncryptionConfiguration();

public ResourceManagerConfig ResourceManager { get; } = new ResourceManagerConfig();

public SmartIdentityProviderConfiguration SmartIdentityProvider { get; } = new SmartIdentityProviderConfiguration();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

namespace Microsoft.Health.Fhir.Core.Configs
{
public class SmartIdentityProviderConfiguration
{
public string Authority { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,17 @@ namespace Microsoft.Health.Fhir.Core.Features.Conformance
public class GetSmartConfigurationHandler : IRequestHandler<GetSmartConfigurationRequest, GetSmartConfigurationResponse>
{
private readonly SecurityConfiguration _securityConfiguration;
private readonly SmartIdentityProviderConfiguration _smartIdentityProviderConfiguration;

public GetSmartConfigurationHandler(IOptions<SecurityConfiguration> securityConfigurationOptions)
public GetSmartConfigurationHandler(
IOptions<SecurityConfiguration> securityConfigurationOptions,
IOptions<SmartIdentityProviderConfiguration> smartIdentityProviderConfiguration)
{
EnsureArg.IsNotNull(securityConfigurationOptions?.Value, nameof(securityConfigurationOptions));
EnsureArg.IsNotNull(smartIdentityProviderConfiguration?.Value, nameof(smartIdentityProviderConfiguration));

_securityConfiguration = securityConfigurationOptions.Value;
_smartIdentityProviderConfiguration = smartIdentityProviderConfiguration.Value;
}

public Task<GetSmartConfigurationResponse> Handle(GetSmartConfigurationRequest request, CancellationToken cancellationToken)
Expand All @@ -43,7 +48,7 @@ protected GetSmartConfigurationResponse Handle(GetSmartConfigurationRequest requ
{
try
{
string baseEndpoint = _securityConfiguration.Authentication.Authority;
string baseEndpoint = GetAuthority();
Uri authorizationEndpoint = new Uri(baseEndpoint + "/authorize");
Uri tokenEndpoint = new Uri(baseEndpoint + "/token");

Expand Down Expand Up @@ -121,5 +126,12 @@ protected GetSmartConfigurationResponse Handle(GetSmartConfigurationRequest requ
Core.Resources.SecurityConfigurationAuthorizationNotEnabled,
HttpStatusCode.BadRequest);
}

private string GetAuthority()
{
var authority = !string.IsNullOrEmpty(_smartIdentityProviderConfiguration.Authority) ?
_smartIdentityProviderConfiguration.Authority : _securityConfiguration.Authentication.Authority;
return authority?.TrimEnd('/');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public static IFhirServerBuilder AddFhirServer(
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Operations.Terminology));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Audit));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Bundle));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.SmartIdentityProvider));
services.AddSingleton<ISearchParameterStatusManager, SearchParameterStatusManager>();
services.AddSingleton(provider =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task GivenASmartConfigurationHandler_WhenSecurityConfigurationNotEn
var securityConfiguration = new SecurityConfiguration();
securityConfiguration.Authorization.Enabled = false;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration));
var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(new SmartIdentityProviderConfiguration()));

OperationFailedException e = await Assert.ThrowsAsync<OperationFailedException>(() => handler.Handle(request, CancellationToken.None));
Assert.Equal(HttpStatusCode.BadRequest, e.ResponseStatusCode);
Expand All @@ -53,7 +53,7 @@ public async Task GivenASmartConfigurationHandler_WhenSecurityConfigurationEnabl
securityConfiguration.Authorization.Enabled = true;
securityConfiguration.Authentication.Authority = baseEndpoint;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration));
var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(new SmartIdentityProviderConfiguration()));

GetSmartConfigurationResponse response = await handler.Handle(request, CancellationToken.None);

Expand Down Expand Up @@ -86,7 +86,7 @@ public async Task GivenASmartConfigurationHandler_WhenBaseEndpointIsInvalid_Then
securityConfiguration.Authorization.Enabled = true;
securityConfiguration.Authentication.Authority = baseEndpoint;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration));
var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(new SmartIdentityProviderConfiguration()));

OperationFailedException exception = await Assert.ThrowsAsync<OperationFailedException>(() => handler.Handle(request, CancellationToken.None));
Assert.Equal(HttpStatusCode.BadRequest, exception.ResponseStatusCode);
Expand All @@ -97,7 +97,7 @@ public async Task GivenASmartConfigurationHandler_WhenBaseEndpointIsInvalid_Then
[InlineData(null, "https://ehr.example.com/user/manage", null)]
[InlineData(null, null, "https://ehr.example.com/user/revoke")]
[InlineData("https://ehr.example.com/user/introspect", "https://ehr.example.com/user/manage", "https://ehr.example.com/user/revoke")]
public async Task GivenASmartConfigurationHandler_WhenOtherEndpointsAreSpecifired_ThenSmartConfigurationShouldContainsOtherEndpoints(
public async Task GivenASmartConfigurationHandler_WhenOtherEndpointsAreSpecified_ThenSmartConfigurationShouldContainOtherEndpoints(
string introspectionEndpoint,
string managementEndpoint,
string revocationEndpoint)
Expand All @@ -113,7 +113,7 @@ public async Task GivenASmartConfigurationHandler_WhenOtherEndpointsAreSpecifire
securityConfiguration.ManagementEndpoint = managementEndpoint;
securityConfiguration.RevocationEndpoint = revocationEndpoint;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration));
var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(new SmartIdentityProviderConfiguration()));

GetSmartConfigurationResponse response = await handler.Handle(request, CancellationToken.None);

Expand All @@ -138,7 +138,7 @@ public async Task GivenASmartConfigurationHandler_WhenAadSmartOnFhirProxyEnabled
securityConfiguration.Authentication.Authority = baseEndpoint;
securityConfiguration.EnableAadSmartOnFhirProxy = true;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration));
var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(new SmartIdentityProviderConfiguration()));

GetSmartConfigurationResponse response = await handler.Handle(request, CancellationToken.None);

Expand Down Expand Up @@ -171,7 +171,7 @@ public async Task GivenASmartConfigurationHandler_WhenAadSmartOnFhirProxyDisable
securityConfiguration.Authentication.Authority = "https://logon.onmicrosoft.com/guid";
securityConfiguration.EnableAadSmartOnFhirProxy = false;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration));
var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(new SmartIdentityProviderConfiguration()));

GetSmartConfigurationResponse response = await handler.Handle(request, CancellationToken.None);

Expand All @@ -192,5 +192,30 @@ public async Task GivenASmartConfigurationHandler_WhenAadSmartOnFhirProxyDisable
Assert.NotNull(response.TokenEndpointAuthMethodsSupported);
Assert.NotNull(response.ResponseTypesSupported);
}

[Theory]
[InlineData("https://smart.example.com/")]
[InlineData(null)]
public async Task GivenASmartConfigurationHandler_When3rdPartyIdpSpecified_ThenCorrectAuthorityEndpointShouldBeReturned(string authority)
{
var requestUri = new System.Uri("https://fhir.example.com/");
var request = new GetSmartConfigurationRequest(requestUri);

var baseUri = "https://logon.onmicrosoft.com/guid";
var securityConfiguration = new SecurityConfiguration();
securityConfiguration.Authorization.Enabled = true;
securityConfiguration.Authentication.Authority = baseUri;

var smartIdentityProviderConfiguration = new SmartIdentityProviderConfiguration();
smartIdentityProviderConfiguration.Authority = authority;

var handler = new GetSmartConfigurationHandler(Options.Create(securityConfiguration), Options.Create(smartIdentityProviderConfiguration));

GetSmartConfigurationResponse response = await handler.Handle(request, CancellationToken.None);

var expectedUri = !string.IsNullOrEmpty(authority) ? authority.TrimEnd('/') : baseUri;
Assert.Equal(expectedUri + "/authorize", response.AuthorizationEndpoint.ToString());
Assert.Equal(expectedUri + "/token", response.TokenEndpoint.ToString());
}
}
}
Loading