Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-75035

OAuth2 URL in "state" parameter causes issue with ADFS OAuth2

    • MOODLE_311_STABLE, MOODLE_400_STABLE
    • fix/url-in-state
    • Hide

      In my apache configuration, I set an URL-rewriting rule like so:

              RewriteRule ^/admin/oauth2callback.php /oauth2callback.php 

      Then, I created an oauth2callback.php at the root of the moodle folder, used to rewrite the $_GET parameters

      <?php
      // This file is a hack.
      // The OAuth2 flow passes a state to the Identity Provider, that is returned in the url to this page.
      // Moodle uses this state parameter to define the URL to which it should redirect
      // However, the Active Directory Federated Services (ADFS) implementation decodes the url-encoded value for the state
      // and doesn't encode it properly.
      // For example, if the redirect uri is /auth/oauth2/login.php?wantsurl=url&sesskey=a&id=1
      // The state parameter passed and expected to be received is &state=%2Fauth%2Foauth2%2Flogin.php%3Fwantsurl%3Durl%26sesskey%3Da%26id%3D1
      // However, ADFS returns something like &state=/auth/oauth2/login.php?wantsurl=url&sesskey=a&id=1, meaning than the sesskey and id are outside the state variable
      // What's more, the wantsurl parameter is also encoded once (to fit into the state param) instead of twice.
      //
      // This file reencodes that if it detects such case
      if(isset($_GET['state'], $_GET['sesskey'], $_GET['id'])) {
              // This is the hack, integrate sesskey and id into the state param
              preg_match('/\wantsurl=(.*)$/', $_GET['state'], $matches);
              $_GET['state'] = '/auth/oauth2/login.php?wantsurl=' . urlencode($matches[1]) . '&sesskey=' . $_GET['sesskey'] . '&id=' . $_GET['id'];
      }
      include 'admin/oauth2callback.php'; 

      Show
      In my apache configuration, I set an URL-rewriting rule like so:         RewriteRule ^/admin/oauth2callback.php /oauth2callback.php Then, I created an oauth2callback.php at the root of the moodle folder, used to rewrite the $_GET parameters <?php // This file is a hack. // The OAuth2 flow passes a state to the Identity Provider, that is returned in the url to this page. // Moodle uses this state parameter to define the URL to which it should redirect // However, the Active Directory Federated Services (ADFS) implementation decodes the url-encoded value for the state // and doesn't encode it properly. // For example, if the redirect uri is /auth/oauth2/login.php?wantsurl=url&sesskey=a&id=1 // The state parameter passed and expected to be received is &state=%2Fauth%2Foauth2%2Flogin.php%3Fwantsurl%3Durl%26sesskey%3Da%26id%3D1 // However, ADFS returns something like &state=/auth/oauth2/login.php?wantsurl=url&sesskey=a&id=1, meaning than the sesskey and id are outside the state variable // What's more, the wantsurl parameter is also encoded once (to fit into the state param) instead of twice. // // This file reencodes that if it detects such case if (isset($_GET[ 'state' ], $_GET[ 'sesskey' ], $_GET[ 'id' ])) {         // This is the hack, integrate sesskey and id into the state param         preg_match( '/\wantsurl=(.*)$/' , $_GET[ 'state' ], $matches);         $_GET[ 'state' ] = '/auth/oauth2/login.php?wantsurl=' . urlencode($matches[ 1 ]) . '&sesskey=' . $_GET[ 'sesskey' ] . '&id=' . $_GET[ 'id' ]; } include 'admin/oauth2callback.php' ;
    • Hide
      1. Configure an OAuth provider using the procedure here : https://docs.moodle.org/400/en/OAuth_2_services.
      2. Open the developer tools of your browser, in the "network" tab
      3. Try to log in using the OAuth provider you created
      4. Check that the login is successful
      5. Confirm that the "state" parameter passed in your identity provider looks like a sesskey (10 random letters and digits) and not like an URL
      6. Configure other OAuth providers, such as google, nextcloud, dropbox... Ensure that everything still works
      Show
      Configure an OAuth provider using the procedure here :  https://docs.moodle.org/400/en/OAuth_2_services . Open the developer tools of your browser, in the "network" tab Try to log in using the OAuth provider you created Check  that the login is successful Confirm that the "state" parameter passed in your identity provider looks like a sesskey (10 random letters and digits) and not like an URL Configure other OAuth providers, such as google, nextcloud, dropbox... Ensure that everything still works

      When trying to use OAuth2 with Microsoft Active Directory Federated Services (ADFS) 2016, I have got issues when the authentication server redirects to Moodle, something like "invalid sesskey" (It's been a few weeks, I found a workaround, see below, but I figured I'd report the issue here anyway).

      When logging in, moodle redirects to the ADFS server with a `state` parameter set to something like `/auth/oauth2/login.php?wantsurl=url&sesskey=a&id=1`

      However, ADFS 2016 has a bug where it doesn't URL-encode properly the property value, and I have no hope this would ever be fixed.

      So instead of

      &state=%2Fauth%2Foauth2%2Flogin.php%3Fwantsurl%3Durl%26sesskey%3Da%26id%3D1 

      I have this:

      &state=/auth/oauth2/login.php?wantsurl=url&sesskey=a&id=1 

      So now, the state stops with the URL, and the sesskey parameter is outside the state.

       

      My proposal

      I know that ADFS is not officially supported, and I know the bug is outside the scope of moodle, but here's my proposal:

       

      Instead of passing the redirect URL, please pass a token or something in the session, that maps to the redirect URL. That way, even poorly-implemented Identity providers could pass the state untouched. It would also help keeping the URL length a bit shorter.

            Unassigned Unassigned
            jeremyvignelles jeremyVignelles
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:

                Estimated:
                Original Estimate - 0 minutes
                0m
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 1 minute
                1m

                  Error rendering 'clockify-timesheets-time-tracking-reports:timer-sidebar'. Please contact your Jira administrators.