Search code examples
oauthocamlmoodlehmacsha1lti

Can't verify OAuth1 signature sent by Moodle


Good morning.

I'm trying to implement OAuth1 authentification in OCaml to get secure LTI request with Moodle. I have some trouble when I want to rebuild the OAuth1 signature : it doesn't match with the signature Moodle sent me in the POST's payload.

I made manually the build of OAuth's signature following the twitter documentation and the OAuth core specification.

Here is my function :

let signature_oauth liste_args http_method basic_uri consumer_key secret =
    let couple_encode = (* 1 : encode keys/values *)
      List.map (
          fun (k,v) -> (Netencoding.Url.encode ~plus:false k, Netencoding.Url.encode ~plus:false v))
      @@ convert_to_gapi liste_args
    in
    let couple_trie =   (* 2 : sort by key [and value] *)
      List.sort   
        (fun (k1, v1) (k2,v2) ->
          let res = compare k1 k2 in
          if res = 0 then compare v1 v2 else res) couple_encode
    in 
    let liste_concat =  (* 3 : key=value&key2=value2 *)
      String.concat "&"
      @@ List.map
           (fun (k,v) -> k ^ "=" ^ v) couple_trie
    in 
    let signature_base_string =     (* 4 :add HTTP_method and uri *)
      sprintf "%s&%s&%s" (String.uppercase_ascii http_method) (Netencoding.Url.encode ~plus:false basic_uri) (Netencoding.Url.encode ~plus:false liste_concat)
    in
    let signing_key = (Netencoding.Url.encode ~plus:false consumer_key) ^ "&" ^ (Netencoding.Url.encode ~plus:false secret) in  (* 5 : Créer la signing_key *)
    let encodage = Netencoding.Base64.encode
                   @@ Cstruct.to_string
                   @@ Nocrypto.Hash.SHA1.hmac (Cstruct.of_string signing_key) (Cstruct.of_string signature_base_string)
    in
   encodage  
  • My function call : signature_oauth liste_args "post" "localhost:8000/launch" !oauth_consumer_key my_secret
  • The liste_args argument is the the payload splitted by "&" (Ex : [oauth_version=1.0;oauth_nonce=5aa374e2728914002261bbb7b4bd8e3e];...).
  • The convert_to_gapi function convert this liste_args in liste of couple (Ex : [(oauth_version,1.0);(oauth_nonce,5aa374e2728914002261bbb7b4bd8e3e);...]. It also remove the oauth_signature.
  • The payload is application/x-www-form-urlencoded encoded.

Here is an example of a payload I can receive :

oauth_version=1.0&oauth_nonce=5aa374e2728914002261bbb7b4bd8e3e&oauth_timestamp=1588583843&oauth_consumer_key=rfrezFZErzfzHJmpmkBFT&user_id=2&lis_person_sourcedid=&roles=Instructor%2Curn%3Alti%3Asysrole%3Aims%2Flis%2FAdministrator%2Curn%3Alti%3Ainstrole%3Aims%2Flis%2FAdministrator&context_id=2&context_label=CT&context_title=Cours+test&resource_link_title=Test&resource_link_description=&resource_link_id=2&context_type=CourseSection&lis_course_section_sourcedid=1&lis_result_sourcedid=%7B%22data%22%3A%7B%22instanceid%22%3A%222%22%2C%22userid%22%3A%222%22%2C%22typeid%22%3A%221%22%2C%22launchid%22%3A2096392689%7D%2C%22hash%22%3A%225dbc6bff5ec32c9eee91ee3dcb476b3a553ae5337f8a21b3876b52e4e6cf862c%22%7D&lis_outcome_service_url=http%3A%2F%2Flocalhost%2Fmod%2Flti%2Fservice.php&lis_person_name_given=Admin&lis_person_name_family=User&lis_person_name_full=Admin+User&ext_user_username=user&lis_person_contact_email_primary=user%40example.com&launch_presentation_locale=en&ext_lms=moodle-2&tool_consumer_info_product_family_code=moodle&tool_consumer_info_version=2019111802&oauth_callback=about%3Ablank&lti_version=LTI-1p0&lti_message_type=basic-lti-launch-request&tool_consumer_instance_guid=localhost&tool_consumer_instance_name=%22New+Site%22&tool_consumer_instance_description=%22New+Site%22&launch_presentation_document_target=iframe&launch_presentation_return_url=http%3A%2F%2Flocalhost%2Fmod%2Flti%2Freturn.php%3Fcourse%3D2%26launch_container%3D3%26instanceid%3D2%26sesskey%3DPPPY9j3N8D&oauth_signature_method=HMAC-SHA1&oauth_signature=fuB7Qm0MXLrHPrvniQsBNcvj7BA%3D

I tried to make the OAuth1 signature with a librairie but I got the same signature as my function.

I guess I am missing something in the creation of signature.

I'm building the signature with the same parameters as Moodle (sent in the payload), using the same secret key and the same algorithm.

  • In the OAuth1's documentation I read they didn't use oauth_callback in the payload but Moodle does. Should I remove it ?
  • They talk of an oauth_token too. But Moodle didn't give me one and I didn't have a clue of how getting it. It is essential to build the signature ?

Thanks in advance for your help.


Solution

  • I found the answer. It had 2 errors :

    First one was the signing_key : I only need to make (Netencoding.Url.encode ~plus:false secret) ^ "&"

    The other was from Moodle : when you configure an "Automatic tool, based on tool URL" and then switch to a Course Tool, Moodle doesn't care about the Course Tool's configuration. You need first to delete all the fields of the Automatic tool and then switch to your Course Tool.

    What helped me to understand: