microsoftarchive / Learn-LTI

Access the Microsoft Learn http://docs.microsoft.com/learn Catalog of Learning Paths and Modules directly from your Learning Management Systems using the Microsoft Learn LTI application
https://microsoft.github.io/Learn-LTI/
MIT License
125 stars 51 forks source link

Using Azure B2C for multiple Domain based users #149

Open LukeDuffy98 opened 3 years ago

LukeDuffy98 commented 3 years ago

Hi

I am having issues trying to progress learner into the lti assignment. I have set up the course and added modules from MS learn without issue.

As a learner when i go to complete the work by clicking in the link

image

I then receive the following error

image

The user is signed in via Azure AD B2C Connect. The user is in a different tenant than our moodle.

If I use oidc OpenID Connect I receive an error AADSTS50020

Sorry, but we’re having trouble signing you in.

AADSTS50020: User account 'bree@XXXonmicrosoft.com' from identity provider 'https://sts.windows.net/00000-8edb-4464-8adc-4611b76ffab1/' does not exist in tenant 'xxx' and cannot access the application 'xxxx-4ed0-4534-b51d-8850917a2dc2'(AAD Moodle) in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.

The App registration is set up as multitenant

image

Short of adding every user as a guest account I dont know how to get past this issue.

Thanks

leestott commented 3 years ago

@LukeDuffy98 So the issue is the Learn LTI application is using the AAD to validate the user.

From what I understand the students are in a different AAD?

If this is the case you will need to assign all the users permissions to the app https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/assign-user-or-group-access-portal

LukeDuffy98 commented 2 years ago

Thanks Lee

I think the issue here is also connected to this one: https://github.com/microsoft/o365-moodle/issues/1738

It appears that all users must exist as a regular or guest in my AAD to use the tool. Is that correct ?

leestott commented 2 years ago

@LukeDuffy98 what extension are you using for moodle? I would recommend the OpenID Connect extension to allow AAD user to auth to Moodle

see https://moodle.org/plugins/auth_oidc#:~:text=The%20OpenID%20Connect%20plugin%20provides%20single-sign-on%20functionality%20using,Moodle%20and%20other%20OpenID%20Connect%20providers%20as%20well.

LukeDuffy98 commented 2 years ago

Hi Lee

That's the plugin I am using. For good measure I just reinstalled it.

For my own sanity s it true that all users must exist as a regular or guest in my AAD to use the tool ??

I'm not sure if I am trying to make something happen that just wont work.

Thanks again

leestott commented 2 years ago

@LukeDuffy98 so typically if you have two AAD which aren't related but want to auth users on a single app you would use Azure B2C on the App https://azure.microsoft.com/services/active-directory/external-identities/b2c/#overview you would then simply point your App Auth to use the B2C connector.. Is this what your doing?

A Diag would help explain what your trying to do.

leestott commented 2 years ago

@LukeDuffy98 see https://moodle.org/mod/forum/discuss.php?d=388317 you will need to install the Learn LTI Application into the Azure B2C so that the app can give access to the users of each AAD.. At present it looks like you have the app installed within only one tenant so users in the other tenant do not have access to the app.

LukeDuffy98 commented 2 years ago

Thanks Lee

I am having a look now, but it seems I am back to the same issue when I try to access the LTI tool. Logging in is ok

image

LukeDuffy98 commented 2 years ago

Hi Lee

I don't know what I am missing to make B2C work with LTI. Does it work with B2C and LTI ? If so do you have any step by steps I can follow ?

Thanks

leestott commented 2 years ago

@LukeDuffy98 So which Dir is the App and App Service principal installed in?

You need to register the Learn LTI in your B2C see https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=app-reg-ga

LukeDuffy98 commented 2 years ago

Hi Lee

I have tried for a few days now to see if I can make it work, but still no joy.

The app and the app service principals are in the same directory.

At a high level the steps are :

  1. Create a new Azure B2C tenant
  2. Create and assign subscription to new tenant
  3. create new global admin user
  4. register web app for auth and add client secret etc
  5. run the run,bat file to deploy the LTI tool, signing in to the new B2C tenant
  6. configure LTI tool as per instructions

At this point any users in the B2C tenant can use the LTI tool no problem. Anyone outside still gets the error "Selected user account does not exist in tenant"

I would really love some help to solve this.

Thanks again

leestott commented 2 years ago

@LukeDuffy98 Have you followed the guidance at https://docs.microsoft.com/en-us/azure/active-directory-b2c/identity-provider-azure-ad-single-tenant?pivots=b2c-user-flow#create-an-azure-ad-app to setup the app? See https://github.com/Azure-Samples/active-directory-b2c-advanced-policies/issues/19 for more details

the Stackoverflow explains the issues with app registrations and domains https://stackoverflow.com/questions/64365648/aadsts50020-user-account-does-not-exist-in-tenant

leestott commented 2 years ago

@LukeDuffy98 The issue is the Learn LTI Application is registered within the AAD Tenant so only users within that Tenant have access to those resources https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals and you need to setup Application multitenant identity https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/

In this guidance, we'll look specifically at using Azure AD for identity management.

If you have on-premises Active Directory you can use Azure AD Connect to sync your on-premises Active Directory with Azure AD. If your on-premises Active Directory cannot use Azure AD Connect (due to corporate IT policy or other reasons), the SaaS provider can federate with the customer's directory through Active Directory Federation Services (AD FS). see https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant

leestott commented 2 years ago

@LukeDuffy98 There are two main options here.

  1. Add the user to the tenant:

In this case you have to add the user to the tenant that the application is hosted in. You can follow this document https://docs.microsoft.com/en-us/azure/active-directory/b2b/b2b-quickstart-add-guest-users-portal#add-a-new-guest-user-in-azure-ad to add the user abc@outlook.com as a Guest User to the tenant. And then you have to grant access to the application https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/methods-for-assigning-users-and-groups#assign-users for the said user.

  1. Make the application as a Multi-Tenant Application:

You can convert the application to accept users from multiple tenants. see https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant In this way you can give access to users who are not in your tenant without having to add them to the tenant where the application is in. This document describes the between Single and Multi-Tenant Applications. Another good read http://www.andrewconnell.com/blog/azure-ad-what%E2%80%99s-the-difference-between-single-vs-multi-tenant on the same.

leestott commented 2 years ago

@LukeDuffy98

OK so you simply need to edit this file https://github.com/microsoft/Learn-LTI/blob/main/client/src/Core/Auth/AppAuthConfig.ts

Line 11 authority: https://login.microsoftonline.com/${process.env.REACT_APP_EDNA_TENANT_ID},

to authority: https://login.microsoftonline.com/common/${process.env.REACT_APP_EDNA_TENANT_ID},

see https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant for other details

leestott commented 2 years ago

@LukeDuffy98 So please look at this best practice for making the application support this scenario https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant

There a few additional changes you will need to make this is a good overview video https://www.youtube.com/watch?v=Jfrp7DI7G0Q

leestott commented 2 years ago

@LukeDuffy98

We have identified a work around which will solve your request on providing access to multiple domains which you own.

But we do not recommend you undertake a security review before implementing this solution

You will need to fork the repo and make the following changes on your fork end after cloning the repository and then deploy the solution from your forked repo..

Note – These steps are not a workaround for proper Multi-Tenant behavior.

It is only a workaround for the above customer issue as the mentioned this in the comments - we use an entirely different azure tenet/account for our servers than from what we use to manage users.

Steps: • In the Install-Client.ps1 file, Replace REACT_APP_EDNA_TENANT_ID="$(Get-TenantId $AppId)"; with REACT_APP_EDNA_TENANT_ID="TID"; where TID is the tenant id with intended users • In the azuredeploy.json file, Remove line no.143 , "issuer": "[concat('https://sts.windows.net/', variables('tenantId'), '/')]" • In the azuredeploy.json file, update line no.234 with the user email address of the admin from the tenant (TID), "AllowedUsers": "user@newTenant", • Run the deployment script. • Make the app multitenant in the azure portal. • While Creating platform registration, login with with upn from tenant TID

warrenbuhler commented 2 years ago

Hi @LukeDuffy98 ,

Would you be interested in testing out a change to the LTI that would support multi-tenant sign-on using Azure Business to Consumer?

I'm part of a UCL team that has been working with Lee at Microsoft to support multi-tenancy. We are finalizing a forked repo and expect to have it ready for testing within 1.5 - 2 weeks (early August). We have done all our testing using Moodle which we have confirmed supports B2C authentication already.

You will need • A B2C tenant -- you will need create one, but we have a script to help configure the remaining settings • An LMS for testing (preferably Moodle) • Two or more AD tenants to whitelist as part of testing

We are scripting as much of the setup and configuration as we can. So we expect the total work on your end to be about than 3 -7 hours, obviously changing based on how much testing you do.

If you are interested, I will reach back out on Github here when our changes are ready. We will have documentation ready and a form for you to fill out feedback on. We can also correspond on this issue thread if you have any issues, questions, or concerns.

Best,

Warren and the UCL Team

LukeDuffy98 commented 2 years ago

Hi Warren

Yes I would love to help out.

warrenbuhler commented 1 year ago

Hi @LukeDuffy98 ,

Our change to the LTI to support Azure Business to Consumer is ready for others to test. It is working for us, so we'd love for you to check it as well and give us any feedback you have! Github Link: https://github.com/UCL-MSc-Learn-LTI/Learn-LTI

If you have time in the next couple weeks to deploy and give us feedback, we should have time to make changes before our program ends.

We have extensive readmes and documentation to support the workflow but at a high level:

You can put any feedback you have for us here, or if you'd prefer a online form we can create one!.

We've also created a forked branch of a Moodle plugin to support B2C authentication with our custom policies that you can use to enable B2C authentication into Moodle. https://github.com/UCL-MSc-Learn-LTI/moodle-auth_azureb2c

If you run into any trouble, please reach out to us and we can troubleshoot asynchronously or hop on a call!

Best,

Warren

Ps our version currently makes the keyvaults without soft deletion or purge protection for easier deletion during testing. If you decided to move forward with this branch, we will be turning those protections back on later.

LukeDuffy98 commented 1 year ago

Hi

I have had a go at setting it up today and have hot a roadblock. When users sign in, they get to the redirect url /auth/azureb2c/ but it has the following error:

I have checked my config multiple times, and am stuck and looking for any direction for troubleshooting.

warrenbuhler commented 1 year ago

Hi @LukeDuffy98 ,

If you'd like, we could jump on a Teams or Zoom call to take a look together. That might be the fastest option for resolving this. We are free the next hour, or could meet Tuesday Morning UK time or anytime Wednesday. Happy to set one up if that works for you!

I can't actually see any error message in your github post. Not sure if pasting the error message failed, or if it just isn't rendering properly

Best,

Warren

warrenbuhler commented 1 year ago

@LukeDuffy98 , if you also could upload the log and transcript file from your deployment we could take a look at that ahead of time.

LukeDuffy98 commented 1 year ago

Thanks for your help @warrenbuhler So I started again with a new b2c tenant .

A couple of errors appear. I have attached the log and transcript:

Issue 1

B2C STEP 1: Create AD application

Please login to your AD tenant for this subscription via the pop-up window that has launched in your browser Creating the client secret for b2c_AD_app Granting permissions to the AD application Creating service principal for b2c_AD_app Granting permissions to the service principal for b2c_AD_app ERROR: The command failed with an unexpected error. Here is the traceback: ERROR: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')) Traceback (most recent call last): File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 699, in urlopen File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 445, in _make_request File "", line 3, in raise_from File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 440, in _make_request File "http\client.py", line 1374, in getresponse File "http\client.py", line 318, in begin File "http\client.py", line 287, in _read_status http.client.RemoteDisconnected: Remote end closed connection without response

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\requests/adapters.py", line 439, in send File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 755, in urlopen File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/util/retry.py", line 532, in increment File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/packages/six.py", line 769, in reraise File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 699, in urlopen File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 445, in _make_request File "", line 3, in raise_from File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\urllib3/connectionpool.py", line 440, in _make_request File "http\client.py", line 1374, in getresponse File "http\client.py", line 318, in begin File "http\client.py", line 287, in _read_status urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\knack/cli.py", line 231, in invoke File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/commands/init.py", line 663, in execute File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/commands/init.py", line 726, in _run_jobs_serially File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/commands/init.py", line 718, in _run_job File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/command_modules/role/commands.py", line 51, in graph_err_handler File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/commands/init.py", line 697, in _run_job File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/commands/init.py", line 333, in call File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/commands/command_operation.py", line 121, in handler File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/command_modules/role/custom.py", line 882, in add_permission File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/command_modules/role/_msgrpah/_graph_client.py", line 105, in application_update File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/command_modules/role/_msgrpah/_graph_client.py", line 52, in _send File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/util.py", line 985, in send_raw_request File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\requests/sessions.py", line 655, in send File "D:\a\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\requests/adapters.py", line 498, in send requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')) To open an issue, please run: 'az feedback'

Issue 2 - Press enter when ready to continue after recording the client secret: A web browser has been opened at https://login.microsoftonline.com/706c4199-f5c7-4b90-b45b-84f5ca1d9811/oauth2/v2.0/authorize. Please continue the login in the web browser. If no web browser is available or if the web browser fails to open, use device code flow with az login --use-device-code. [ { "cloudName": "AzureCloud", "homeTenantId": "706c4199-f5c7-4b90-b45b-84f5ca1d9811", "id": "3883a4dc-062f-4f8f-b4ef-fcebd79afd7f", "isDefault": true, "managedByTenants": [], "name": "Azure Pass - Sponsorship", "state": "Enabled", "tenantId": "706c4199-f5c7-4b90-b45b-84f5ca1d9811", "user": { "name": "ldmoodle08082022@outlook.com", "type": "user" } } ] argument --subscription/-s/--name/-n: expected one argument

Examples from AI knowledge base: az account set --subscription mysubscription Set a subscription to be the current active subscription. (autogenerated)

az account list Get a list of subscriptions for the logged in account. (autogenerated)

az account show Get the details of a subscription. (autogenerated)

https://docs.microsoft.com/en-US/cli/azure/account#az_account_set Read more about the command in reference docs

============================================================= STEP #3 - Choose Location

Issue 3

STEP #12 - Installing the client

npm WARN deprecated lru-cache@7.7.3: Please update to latest patch version to fix memory leak https://github.com/isaacs/node-lru-cache/issues/227 npm WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility npm WARN deprecated source-map-resolve@0.6.0: See https://github.com/lydell/source-map-resolve#deprecated npm WARN deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x. Finished[#############################################################] 100.0000% Client App Published Successfully

Issue 4 When trying to access https://learnclientixxjyxpf6.z8.web.core.windows.net/platform It goes through AAD authentication, giving a blank page, but dev tools displays this error main.565f4574.js:2

   ServerError: invalid_request: AADB2C90238: The provided token does not contain a valid issuer. Please provide another token and try again.

Correlation ID: a2b84abf-03e4-4b80-b81f-1fcd3d36d62c Timestamp: 2022-08-08 23:13:59Z

at t [as constructor] (main.565f4574.js:2:391518)
at new t (main.565f4574.js:2:449244)
at e.validateServerAuthorizationCodeResponse (main.565f4574.js:2:529551)
at t.handleFragmentResponse (main.565f4574.js:2:536155)
at t.<anonymous> (main.565f4574.js:2:631375)
at main.565f4574.js:2:406218
at Object.next (main.565f4574.js:2:406323)
at main.565f4574.js:2:405258
at new Promise (<anonymous>)
at _a (main.565f4574.js:2:405003)

Transcript-09-08-2022-08-49-53.log Log-09-08-2022-08-49-53.log

warrenbuhler commented 1 year ago

Hey @LukeDuffy98 ,

We've taken a look and have some thoughts / suggestions. In short

Issue 1: We haven't seen this issue before. The disconnect appears to have been while it attempts to set the correct permissions status on the "email" and "profile" permissions. It is possible this was a networking issue, and we could look into putting in more defensive programming if this issue is common and actually leads to probleems

Our working deploy looks like this on the AD tenant - app registration "b2c_AD_app" - API permissions blade

image

Can you check whether the status shows "Granted"

Issue 2: We've fixed the code throwing this message. However, we believe the error was functionally benign and didn't cause the later authentication issues.

Issue 3: These npm warnings do not cause any problems in deployment or operation and exist on the current version of the deploy scripts. We'd like to fix them if we have time, but they similarly shouldn't have caused any authentication issues.

Issue 4: This one is obviously a hard stop. We have only seen this error when trying to complete a B2C login from a non-whitelisted tenant. Can you confirm that you are logging in as a user whose home tenant is one of these tenants?

It looks like you used: "user":{"name":"ldmoodle08082022@outlook.com","type":"user"}

And you whitelisted: Important - if no tenants are whitelisted; nobody will be able to access the AD Tenant with ID bdef9bb6-31a1-4d1f-bd33-672f09621c5e added to the whitelist Tenant with ID 6a450216-13ff-486c-8de5-6bbef7b20ae2 added to the whitelist

If the user is from a whitelisted tenant, then we will need to do more digging wih you.

We will look into ways to make the error thrown more obvious.

Best,

Warren

LukeDuffy98 commented 1 year ago

Thanks Warren. I ended up having to reset the AllowedUsers config setting to allow access to the platform settings.

So all good now in accessing that.

Now I'm back to the same place as the other night, when i attempt to login. I end up back at the redirect page https://xxx.com/auth/azureb2c/ with the following information (this is what didnt appear in the original email screenshot):

Error in Azure AD B2C Connect. Please check logs for more information.

More information about this error

Debug info: Error code: errorazureb2ccall×Dismiss this notification Stack trace: line 47 of /auth/azureb2c/classes/utils.php: moodle_exception thrown line 256 of /auth/azureb2c/classes/azureb2cclient.php: call to auth_azureb2c\utils::process_json_response() line 221 of /auth/azureb2c/classes/loginflow/authcode.php: call to auth_azureb2c\azureb2cclient->tokenrequest() line 107 of /auth/azureb2c/classes/loginflow/authcode.php: call to auth_azureb2c\loginflow\authcode->handleauthresponse() line 105 of /auth/azureb2c/auth.php: call to auth_azureb2c\loginflow\authcode->handleredirect() line 29 of /auth/azureb2c/index.php: call to auth_plugin_azureb2c->handleredirect()

danielmusselwhite commented 1 year ago

Hey @LukeDuffy98

Just clarifying:

  1. the platform page now works correctly
  2. the current issue is that when users try to login to Moodle via the Azure AD B2C Connect button it redirects to https://xxx.com/auth/azureb2c/ with the debug errors listed n your above comment

If so, would it be possible if you could send me the values you configured on the platform page/ moodle setup (here and here),

Am currently looking into the issue in the codebase but would also be worth just verifying the values used in the setup of the environment.

LukeDuffy98 commented 1 year ago

If its easier you can email me Screenshot below

image

LukeDuffy98 commented 1 year ago

Hi Daniel

Just sent you an email

leestott commented 1 year ago

Thanks to @LukeDuffy98 for working with @warrenbuhler on the test AAD + B2C connectivity enhancement the team at University College London have this fork for testing https://github.com/UCL-MSc-Learn-LTI/Learn-LTI

leestott commented 1 year ago

Confirmed the AAD + B2C features work by @LukeDuffy98