Open LodewijkSioen opened 3 months ago
@LodewijkSioen - Have you assigned the SMART user role ?
As you can see in my JWT, I've put "roles": "smartUser"
in there.
Mind that I'm using my own Identity Provider and EntraID as specified in the documentation. That documentation does not talk about any roles.
You are correct that the token is valid, and that is why you see a 403 instead of a 401. Perhaps you have App Insights configured for your app service? It should have more details about why the 403 was returned.
The 403 comes from the fhir service on Azure. I don't seem to be able to configure App Insights for that.
I tried to configure it locally, but there is no appsetting for the additional Identity Provides. EDIT: what's more, there is no code in here that handles this use case...
(I need both Entra and another provider)
So I've dug deeper and I'm pretty sure it's the _authorizationService.CheckAccess
method that gives me the 403
. So that means that my roles
claim is not correct. @EXPEkesheth can you confirm that I correctly configure the roles
claim to use it on Azure. It works locally, but perhaps the name of the role is different on Azure?
I made a minimal demo project to show you what I've done: https://github.com/LodewijkSioen/fhir-samples/tree/main/identity-provider
@feordin - can you please review the demo project and help ?
I will take a look at the sample and see if I can repro the issue.
I downloaded the sample (thank you for that!) and I was able to get tokens that were validated and functioning.
I did make one update to the Identity Provider to include the "roles" claim:
public Task ValidateAsync(CustomTokenRequestValidationContext context)
{
if (context.Result.ValidatedRequest.RequestedScopes.Contains(Constants.Userscope))
{
context.Result.ValidatedRequest.ClientClaims.Add(new Claim("fhirUser", "https://example.org/Practitioner/123456798"));
}
context.Result.ValidatedRequest.ClientClaims.Add(new Claim("roles", "smartUser"));
With that change I get a token like this for system scope:
{
"alg": "RS256",
"kid": "B699F4C1E63E8F38012738C00B738BE5",
"typ": "JWT"
}.{
"nbf": 1719253724,
"exp": 1719257324,
"iss": "https://localhost:7023",
"aud": "smart-fhir-test-audience",
"client_id": "test",
"azp": "smart-fhir-test-clientid",
"roles": "smartUser",
"scp": "system/*.read",
"jti": "2DD4592B05BB4663EF983374144A31AD",
"iat": 1719253724
}.[Signature]
or for user scope I get this token:
{
"alg": "RS256",
"kid": "B699F4C1E63E8F38012738C00B738BE5",
"typ": "JWT"
}.{
"nbf": 1719254168,
"exp": 1719257768,
"iss": "https://localhost:7023",
"aud": "smart-fhir-test-audience",
"client_id": "test",
"azp": "smart-fhir-test-clientid",
"fhirUser": "https://example.org/Practitioner/123456798",
"roles": "smartUser",
"scp": "user/*.read",
"jti": "2A2A5BD7D8F83023F39AB3E580908C49",
"iat": 1719254168
}.[Signature]
either of those tokens succeed with a 200.
To match the tokens my appsettings.json for the FHIR service has the following security configuration:
"FhirServer": {
"Security": {
"Enabled": true,
"EnableAadSmartOnFhirProxy": true,
"Authentication": {
"Audience": "smart-fhir-test-audience",
"Authority": "https://localhost:7023"
},
You can see that the Audience matches the "aud" claim in the token, and the Authority matches the "iss" claim in the token. The role matches "smartUser" which is defined in roles.jon in the FHIR service code. That will result in the proper data actions being returned by the CheckAccess method that you already mentioned.
I hope this helps!
Thank you for looking into this. I already had it working against the OSS version of the Fhir Server, but it's against the Azure PaaS version that I cannot get it working.
@feordin I dug deeper and I suspect that the Azure FHIR Service is configured to either:
smartUser
role via roles.jsonBut there is no way for me to know of investigate this. Also the fact that a specific role is needed is missing from the documentation.
@LodewijkSioen is the issue resolved or are you looking for any further inputs?
The issue is not resolved. If you us the instructions in my repo, then you'll see that it does not work.
Groeten, Lodewijk Sioen
From: ketki @.> Sent: Monday, July 8, 2024 1:59:23 PM To: microsoft/fhir-server @.> Cc: Lodewijk Sioen @.>; Mention @.> Subject: Re: [microsoft/fhir-server] Configure Custom Identity provider (Issue #3921)
@LodewijkSioenhttps://github.com/LodewijkSioen is the issue resolved or are you looking for any further inputs?
— Reply to this email directly, view it on GitHubhttps://github.com/microsoft/fhir-server/issues/3921#issuecomment-2214839138, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAA56XTDZUDIOUWLSF4BRUTZLLHPXAVCNFSM6AAAAABJKLPP2OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJUHAZTSMJTHA. You are receiving this because you were mentioned.Message ID: @.***>
@LodewijkSioen I have tried the scenario again for the Azure PaaS version. the configuration is a bit different, and it does not use the roles.json file. When using Azure Entra ID as the identity propvider we would read role infomration via Azure RBAC. For 3rd party IDPs we limit the user to only the "smart" role, and role membership is assumed. We validate the token using the appId and issuer to ensure those values match the entries in the portal. Then we check the fhirUserClaim to ensure it matches a resource in the FHIR server and determine the compartment of resources that should be made available to be read.
I published the sample identity provider code in fhir-samples repo you mentioned to an app service. Then I configured my PaaS instance with the following values:
I made a change to the identity provider so that it would populate the fhirUserClaim token with a valid url of a practitioner in the FHIR server:
if (context.Result.ValidatedRequest.RequestedScopes.Contains(Constants.Userscope))
{
context.Result.ValidatedRequest.ClientClaims.Add(new Claim("fhirUser", "https://jaerwin-identitytest.fhir.azurehealthcareapis.com/Practitioner/123456798"));
}
It then generated a token like this: { "alg": "RS256", "kid": "E95C1005887923B229629BDB6D5A0557", "typ": "JWT" }.{ "nbf": 1721770730, "exp": 1721774330, "iss": "https://identityserver20240722190056.azurewebsites.net", "aud": "smart-fhir-test-audience", "client_id": "test", "azp": "smart-fhir-test-clientid", "fhirUser": "https://jaerwin-identitytest.fhir.azurehealthcareapis.com/Practitioner/123456798", "roles": "smartUser", "scp": "user/*.read", "jti": "F2F7D6AA44F05FF070D3FF5A6B2FF818", "iat": 1721770730 }.[Signature]
With that token I was able to successfully read resources within the practitioner compartment.
Ah yes, so for the user scope, you need the full url including the domain in the fhirUser
claim. This is annoying since we don't want to expose the internal azure url, but I can work around that. I'de rather not leak the internal URL to a client, but at least it's hidden in inside an encoded token.
A more pressing issue is that I cannot get the system scopes to work (eg system/*.read
). Are these not supported on external ID providers?
@LodewijkSioen system scopes are not supported on external ID providers.
That's too bad because the system scopes are what we wanted to use in our system :(
I'm pretty sure I had this working at one time, but now I cannot get the custom Identity Provider to work. I have IdentityServer running in an app service. This is the token it generates:
I checked the fields a hundred times:
appid
claim)aud
claim)And I get the following answer from the FHIR service:
Which means that my settings are correct, otherwise I would have gotten a
401
.Why am I getting
Forbidden
? How can I troubleshoot this?