Search code examples
phplti

LTI Integration issue with Desire2Learn


I am trying to create an external learning tool within Desire2Learn by following the instructions at https://d2l.nl.edu/shared/HelpFiles/10%20Administrator%20Help/learningenvironment/basic_lti_standards_support/org_level_lti_configuration.html and http://devs.valence.desire2learn.com/tag/lti and can't even get the sample quiz project working.

I've tried everything that I can think of and at one point I had it working and could properly load my learning tool in Desire2Learn, but it seems to have just stopped and I can't figure it out anymore as I've spent 5 hours trying to get around this. I've attempted such things as echo'ing out the POST and local variables to debug and throwing different things in the URL fields inside the tool provider and link fields in Desire2Learn.

All that I have noticed in my 5 hours I've spent on this is when the signature is recreated during the authentication process, it never matches the [oauth_signature] field sent in the POST data, despite the key and secret matching those in the LMS.

If this makes sense, I appreciate any and all help I can get on this as I've spent way too much time on this already and can't think straight anymore. Thank you!

EDIT:

Here is a print_r() of the context data Desire2Learn sends back along with the OAUTH parameters I'm validating against, and below it the local variables I set.

[launch_presentation_locale] => EN-US__
    [tool_consumer_instance_guid] => key
    [tool_consumer_instance_name] => secret
    [tool_consumer_instance_description] => Learning Tool.
    [tool_consumer_instance_contact_email] => 
    [tool_consumer_info_version] => 10.3.0 SP5
    [tool_consumer_info_product_family_code] => desire2learn
    [context_id] => 2440554
    [context_title] => context
    [context_label] => context
    [context_type] => 
    [user_id] => userid_88888
    [roles] => None
    [ext_tc_profile_url] => https://sampleprofileurl.com
    [ext_d2l_token_id] => 386867949
    [ext_d2l_link_id] => 9554
    [ext_d2l_token_digest] => 2bv8al0f+NxuBWpBS36nl/RuNWg=
    [resource_link_id] => 
    [resource_link_title] => LinkTitle
    [resource_link_description] => LinkDes.
    [lis_result_sourcedid] => 808080-89989-234232
    [lis_outcome_service_url] => https://outcomeurl.com
    [lti_version] => LTI-1p0
    [lti_message_type] => basic-lti-launch-request
    [oauth_version] => 1.0
    [oauth_nonce] => 784335425
    [oauth_timestamp] => 1403634776
    [oauth_signature_method] => HMAC-SHA1
    [oauth_consumer_key] => key
    [oauth_callback] => about:blank
    [oauth_signature] => PYCJyQe3jSLTXn8vxet1eknSfoc=
    [basiclti_submit] => Launch Endpoint with BasicLTI Data

$OAUTH_KEY    = 'key';
$OAUTH_SECRET = 'secret'; 
$SITE_URL     = 'https://sample.com';

When the POST data is initially sent back from Desire2Learn, $OAUTH_KEY is checked against the $_POST['oauth_consumer_key'] field and if they're equal, the $OAUTH_KEY and $OAUTH_SECRET fields are used to generate a temporary signature/token that is then authenticated against the $_POST['oauth_signature'] field.

public static function CheckSignatureForFormUrlEncoded( $url, $httpMethod, $parameters, $secret) {
        $oauthParameters = array();
        $lmsParameters = array();

        // Separate LMS and OAuth parameters
        foreach( $parameters as $key => $value ) {
            if( strpos( $key, self::OAUTH_PREFIX ) === 0 ) {
                $oauthParameters[urldecode( $key )] = urldecode( $value );
                continue;
            }
            $lmsParameters[urldecode( $key )] = urldecode( $value );
        }

        $signature = self::CalculateSignatureForFormUrlEncoded( $url, $httpMethod, $secret, $lmsParameters, $oauthParameters );

        return $parameters[ self::SIGNATURE ] === $signature;   

    }

This is where I'm being held back. When the return statement returns, or in other words the signature value in the $parameters array doesn't match $signature, I get the error "Invalid OAuth Signature". From what I understand, this shouldn't happen if the 'key' and 'secret' fields I set in my LMS are equal to those that I set in the two variables above.


Solution

  • Okay, I seem to have figured it out. As dumb as it sounds, all that I had to do was append 'index.php' to the end of the URL field in the link to my external learning tool in Desire2Learn, as well as the launch point field in the tool provider configuration. After I did this the signature error went away and it's all better now. Apparently the tool consumer isn't looking specifically for an index.anything file at all as I had assumed.