Search code examples
oauthmoodlelti

How to authenticate moodle LTI launch request


I've created a LTI tool that I'm integrating with moodle. I have created a consumer key and secret but I'm unsure how do I validate (authenticate) the launch request.

Here is the raw request that I'm receiving, so I'm guessing I need to validate the oauth_signature to authenticate the request. I've come across some examples but I need the oauth token too, but it's not returned in the launch request.

I would really appreciate any help!

POST http://ltitest.cloudapp.net/launch HTTP/1.1
Host: ltitest.cloudapp.net
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://demo.moodle.net/mod/lti/launch.php?id=7
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 1296

oauth_version=1.0&oauth_nonce=d8e900f0b71e76c4b12e89681c9b5cb9&oauth_timestamp=1412987714&oauth_consumer_key=username&resource_link_id=1&resource_link_title=tool&resource_link_description=&user_id=2&roles=Instructor%2Curn%3Alti%3Asysrole%3Aims%2Flis%2FAdministrator&context_id=2&context_label=My+first+course&context_title=My+first+course&launch_presentation_locale=en&lis_result_sourcedid=%7B%22data%22%3A%7B%22instanceid%22%3A%221%22%2C%22userid%22%3A%222%22%2C%22launchid%22%3A449414780%7D%2C%22hash%22%3A%2226f6510ff6e91e1a7814805190c01a9e9d02575de135d7a1483a70626bae8782%22%7D&lis_outcome_service_url=http%3A%2F%2Fdemo.moodle.net%2Fmod%2Flti%2Fservice.php&lis_person_name_given=Admin&lis_person_name_family=User&lis_person_name_full=Admin+User&lis_person_contact_email_primary=demo%40moodle.a&ext_lms=moodle-2&tool_consumer_info_product_family_code=moodle&tool_consumer_info_version=2014051202&oauth_callback=about%3Ablank&lti_version=LTI-1p0&lti_message_type=basic-lti-launch-request&tool_consumer_instance_guid=demo.moodle.net&launch_presentation_return_url=http%3A%2F%2Fdemo.moodle.net%2Fmod%2Flti%2Freturn.php%3Fcourse%3D2%26launch_container%3D3%26instanceid%3D1&oauth_signature_method=HMAC-SHA1&oauth_signature=JmFLDbhi%2FstYEFTSNA%2F44biCQkM%3D&ext_submit=Press+to+launch+this+activity

Solution

  • I solved this a while back and though it might come in handy for anyone looking for a solution.

    Start by getting the oauth lib: https://www.nuget.org/packages/Microsoft.Owin.Security.OAuth/

    // parse out the signature from the http req.
    ProviderRequest providerRequest = new ProviderRequest();
    providerRequest.ParseRequest(httpRequest, false);
    String httpSig = providerRequest.Signature;
    
    // now generate a new signature from our secret
    String generatedSig = GenerateOAuthSignature(secret, req);
    
    if( generatedSig == httpSig ){
       // valid oauth request
    }
    

    Generate OAuthSignature is part of the owin lib, but there what the code does:

        internal static string GenerateSignatureBase(string httpMethod, Uri url, NameValueCollection parameters)
        {
            var normalizedUrl = string.Format("{0}://{1}", url.Scheme, url.Host);
            if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443)))
            {
                normalizedUrl += ":" + url.Port;
            }
            normalizedUrl += url.AbsolutePath;
    
            StringBuilder signatureBase = new StringBuilder();
            signatureBase.Append(httpMethod.ToRfc3986EncodedString().ToUpper()).Append('&');
            signatureBase.Append(normalizedUrl.ToRfc3986EncodedString()).Append('&');
    
            var excludedNames = new List<string> { OAuthConstants.SignatureParameter };
            signatureBase.Append(parameters.ToNormalizedString(excludedNames).ToRfc3986EncodedString());
    
            return signatureBase.ToString();
        }
    
        /// <summary>
        /// Generates a signature using the specified signatureType 
        /// </summary>
        /// <param name="httpMethod">The http method used</param>
        /// <param name="url">The full url to be signed</param>
        /// <param name="parameters">The collection of parameters to sign</param>
        /// <param name="consumerSecret">The OAuth consumer secret used to generate the signature</param>
        /// <returns>A base64 string of the hash value</returns>
        public static string GenerateSignature(string httpMethod, Uri url, NameValueCollection parameters, string consumerSecret)
        {
            var signatureBase = GenerateSignatureBase(httpMethod, url, parameters);
    
            // Note that in LTI, the TokenSecret (second part of the key) is blank
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&", consumerSecret.ToRfc3986EncodedString()));
    
            var dataBuffer = Encoding.ASCII.GetBytes(signatureBase);
            var hashBytes = hmacsha1.ComputeHash(dataBuffer);
    
            return Convert.ToBase64String(hashBytes);
        }