longhornopen / laravel-celtic-lti

Integrates the Celtic LTI library with a Laravel app
GNU Lesser General Public License v2.1
11 stars 12 forks source link

Blackboard LTI 1.3 #9

Closed zoehler closed 1 year ago

zoehler commented 1 year ago

Hey guys, how are you?

Have anyone used this lib to integrate with Blackboard through LTI 1.3? I'm kinda new working with LTI so I don't know if i'm doing something wrong or if it won't work with Blackboard.

To configure the LTI 1.3 with Blackboard I have to insert three URLs in the Blackboard Developers Portal: Login Initiation URL Tool Redirect URL(s) Tool JWKS URL

And I thought that it was like this:

Login Initiation URL: the POST /lti route in the config example Tool Redirect URL(s): my dashboard Tool JWKS URL; the jwks GET route in the config example

I've tried to just make a var_dump in the /lti route to see whats there but received the following error: The GET method is not supported for route lti. Supported methods: POST.

Apparently Blackboard is sending a GET to the Login Initiation URL, so I might have understood something wrong.

Thanks in advance!

chrispittman commented 1 year ago

Hey there! We don't know of any Blackboard users, but also don't know any reasons why Blackboard shouldn't work.

If you've followed along with the docs, all the URLs that you give to the LMS should be the /lti route, except for the JWKS URL, which is /lti/jwks. So I'm guessing it's the Tool Redirect URL which is the problem. If it helps, see https://github.com/longhornopen/chatter/blob/main/web/app/Http/Controllers/LtiController.php for an example of how one of my tools redirects to its dashboard from the LTI launch. (We need to document that flow better here in this repo's docs.)

Try it and let us know if that works or not.

zoehler commented 1 year ago

Hey, Chris!

Thanks for the quick response!

I'm still struggling with the same issue. Here are some prints of my Blackboard configuration and the error i'm getting: image

image

Looks like Blackboard is sending a GET request to my Login Initiation URL.

Here is my code: LTIController: image routes/web: image

As you can see, it's very simple and straight forward, so maybe I'm skipping a step. The only step I didn't undestand in the documentation guide was the following: "Create a Platform database entry for each installation of your app" When should I do this? I should create manually or create a function to create the database entry?

Thanks again, hope it works!

chrispittman commented 1 year ago

Blackboard should be making two POSTs, one to your Login Initiation URL and one to your Tool Redirect URL. The /lti route can be used for both. It's not immediately clear why Blackboard is making a GET, but if you have a log of the requests that are being made (like the one you get from your web server logs or from the browser's DevTools 'network' tab), we may be able to figure it out together.

I don't think it's the cause of the GET problem, but you will need to create that Platform in the database in order for LTI 1.3 to work. (LTI 1.3 is a two-way handshake - the tool and the LMS need to be able to contact each other and so both need to know some URLs that it's expected to use.) So you'll need some Blackboard URLs in order to create that Platform database entry. The info at https://success.tophat.com/s/article/Admin-Blackboard-LTI-1-3-Key-Information looks like about what I'd expect, but if your Blackboard installation is telling you something different, trust it.

Once you have that info, we have some code that'll let you enter that into your database. https://github.com/longhornopen/laravel-celtic-lti/blob/main/src/PlatformCreator.php#L118-L144 is an example of that for the Schoology LMS. We don't have a quick Artisan command for Blackboard like we do for some other LMSes, mostly because I don't have those URLs, but we'd be happy to work on a pull request to add it!

zoehler commented 1 year ago

Once I configure my App in the Blackboard Developer Portal they gave me exactly those informations: image

From what I could see, it's always the same URLs, the only difference is the App ID in the public keyset URL. (the App Id is generated once you create the App in the Developer Portal)

About the GET/POST error, I've tried to use the /lti route to both URL, Login Initiation and Redirect but the error persist.

I'm trying to duplicate what you've done in the Chatter project to achieve a connection but without luck so far.

Maybe if I find some example of open source LTI 1.3 tool working with Blackboard I can get some light, but it's a bit too specific hahaha

I'll continue to work here and if you have some idea on what to do next i'll be happy to try!

Thanks again!

chrispittman commented 1 year ago

One idea, which may be a stupid one:

I'm assuming that you're launching this from a test course of some kind. Are you sure that that course is set up correctly? I've seen LMSes be sloppy about correctly describing the difference between launching a tool (which is two POSTs) and opening a link (which is one GET).

zoehler commented 1 year ago

As far as I know Blackboard (which is some years now) it can be very stupid sometimes.

But Blackboard gives me two options on how to open a LTI Tool:

  1. Creating a placement in the LTI Config, so there is an Content Item exclusively to this tool
  2. Creating an external link and marking it as a Tool Provider

I've tried both and both gave me the same GET Error. But i really don't think it's impossible that they use same sloppy approach on both methods.

chrispittman commented 1 year ago

When you look at your tool's web server logs (or the browser's Dev Tools network tab), what do you see? Is Blackboard making a single GET request to /lti? Or is it making the two POSTs that you'd expect from the LTI 1.3 launch process, and then a GET?

zoehler commented 1 year ago

Just a single GET image

With the following payload: image

Sorry about my browser being in portuguese, but I guess the important part is in english.

chrispittman commented 1 year ago

I know enough Spanish that I can handle a little Portuguese. :)

So, the single GET is indicating something wrong on the Blackboard side of things. The LMS is supposed to make a POST to the Login Initiation URL, and then a second POST later to the Tool Redirect URL. The fact that it's starting with a GET makes me think that Blackboard is just showing a link, rather than the form with a POST which would start the LTI launch process. But I don't have a lot of Blackboard experience so I couldn't prove that. But nothing in the app you're writing should be able to make Blackboard start with a GET instead of a POST - Blackboard decided that before it even contacted your app.

So, I'd say look into your Blackboard setup a little more and let me know what you find. I'm out of ideas at the moment but if I think of anything, I'll comment here. I'm also going to try to build some better Artisan commands for setting up Blackboard, now that I know what the URLs look like.

zoehler commented 1 year ago

I'm all out of ideas too, so i'm gonna look back to the Blackboard configuration side and if I found something I'll comment here too.

Thanks for the support, Chris!

zoehler commented 1 year ago

Hey Chris!

I've found out some things about how Blackboard handles LTI 1.3 and apparently it is somewhat different from others LMSs.

They do, indeed, send just a GET to the login initiation URL with some information that need to be redirected their authentication URL, and after that they send the POST request.

Here is the documentation: https://docs.anthology.com/docs/LTI/Tutorials/lti-lti_impl_guide#lti-launch

Let me know if I get anything wrong from it.

Here is the function I developed to adapt to this Blackboard auth: image

But then I got a state error when it gets to the /lti endpoint. It's telling me that my state is invalid or expired.

From what I could tell, this handleRequest() function deals exactly what i'm doing in the loginInitiation, so I guess I can't use both.

I'm hoping for some advice on the next step.

Thanks again!

chrispittman commented 1 year ago

Huh, interesting. It appears that the LTI spec allows either GET or POST to be used, but Blackboard is the first LMS I've seen that uses GETs. I think the CeLTIc LTI library we use can handle either. Have you tried just changing Route::post('/lti', [App\Http\Controllers\LtiController::class, 'ltiMessage']); to Route::any('/lti', [App\Http\Controllers\LtiController::class, 'ltiMessage']); and seeing what happens? That may be all you need.

zoehler commented 1 year ago

Actually I had already tested change it to a GET, but received the following: image

I've tried now change it to ANY and received the same error.

I'm afraid that the CeLTIc can't handle a Blackboard LTI 1.3 integration (and I really hate Blackboard for that).

Connecting using the Login Initiation Method that I developedt worked, I received the token_id in my Redirect URL, but I would have to build my LTI methods from scratch.

Any idea if I can use the CeLTIc methods in my Initiation Login function?

chrispittman commented 1 year ago

You should be able to use the CeLTIc methods however you want.... this library is only meant to be a really thin wrapper around CeLTIc. In the CeLTIc project's issues list, the last comment at https://github.com/celtic-project/LTI-PHP/issues/24 sounds like it may be related to this problem, but that issue was closed.

I'd say post a new issue at the CeLTIc repo, since you have an example of an LMS that makes a legitimate GET to this endpoint. If they fix it, let us know and we can pull in their fix pretty quickly. I'll leave this issue open until then.

zoehler commented 1 year ago

Got it. I've opened the issue there and post here as soon as I got an answer.

Here is the issue if you want to follow up: https://github.com/celtic-project/LTI-PHP/issues/59

Thanks again, Chris!

chrispittman commented 1 year ago

This should be the first request to tool->handleRequest(), right? Have you thought about going into the 'vendor' folder, finding the code for Tool->handleRequest(), and dropping in some code like:

dd($parameters, $_SERVER, $_GET, $_POST);

This request should be a GET with 'iss' as one of the GET parameters, and that'd let you confirm what you're actually seeing instead.

zoehler commented 1 year ago

Just tried it and now it return an error telling me that the lti_message_type is missing: image

Maybe it has something to do with the request->input() function being empty here: image

Even thought the parameters are in the URI and in the payload, as you can see here: image

And I need some help to answer Stephen in the CeLTIc issue. I'm currently using the longhornopen/laravel-celtic-lti v0.4.8, but I didn't found the CeLTIc LTI version that it is using.

chrispittman commented 1 year ago

So, you're describing query string parameters going missing before even getting to any of the code in this library. I can't think of a way that this library would cause that, so I'm going to close this issue unless you have more information.

The main thing this library does when a tool launches is to construct a ceLTIc\LTI\Tool object, with four pieces of configuration info pulled from the Laravel config files: https://github.com/longhornopen/laravel-celtic-lti/blob/64b7cfc883402e3f1007db3ebf82ca5f49ee8f7f/src/LtiTool.php#L42-L46 I'd say try using the ceLTIc library directly - you could even hardcode those four values for the moment if you wanted. If that works but then it fails when you try to switch back to this library, please let us know and we can work out the what's causing the problem.

zoehler commented 1 year ago

Hey, Chris! How are you?

I saw that you add an artisan command to create the Blackboard plataform, thanks a lot!

But I have a question: the Application Id is the same that the Client Id? Just explaining why i'm asking this, depending where you look on blackboard they mean the same thing. In the developer portal: image

In the LMS LTI config: image