cancel
Showing results for 
Search instead for 
Did you mean: 
cesbrandt
Lamplighter

External Site Login


Alright, so let me explain the scenario. I'm looking to make legitimately configured student accounts available to authorized users without needing to provide login credentials for a whole new account or provide masquerade rights.

In and of itself, this isn't a difficult task:

  1. I setup a series of test accounts whose credentials are stored on our system.
  2. Using our own authentication method, validate that a user is authorized access to these accounts.
  3. Find the first set of credentials found to be available (3-hour time limit) and use JavaScript to submit a HTML form with the designated credentials to sign the user into Canvas as that student account.
  4. Log the time the account was signed in to enforce the 3-hour time limit.

There are two primary concerns to this solution:

  1. For browsers that have JavaScript disabled, this won't work due to the form not submitting.
    • Solution: Add a button for the user to submit the form.
  2. For browsers that have JavaScript disabled, the account credentials will be available to the user.
    • Pseudo-Solution: Make all fields hidden.
      • Issue: This only hides the data, visibly, it can still be retrieved by anyone accessing the source or Developer Tools. Though users that would have this opportunity would be authorized access to the accounts, the intent is to avoid supplying credentials to ensure no single user decides to "seize" a particular account and start stepping on toes.

Ideally, JavaScript should be avoided and the credentials of the account they'll be logged into never be passed to the client. This means the solution needs to be through a server-side language. My go-to language is PHP, so that's what I did. My solution works, for non-Canvas.

<?php

  $domain = 'canvas.instructure.com';

  $credentials = array(

    array(

      'user' => 'tstudent1',

      'pass' => 'P@ssw0rd'

    )

  );

  $ch = curl_init('https://' . $domain . '/login/canvas');

  curl_setopt($ch, CURLOPT_POST, 1);

  curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query(array(

    'pseudonym_session' => array(

      'unique_id' => $credentials[0]['user'],

      'password' => $credentials[0]['pass'],

      'remember_me' => 0

    )

  ))));

  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

  curl_setopt($ch, CURLOPT_HEADER, false);

  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $results = curl_exec($ch);

  curl_close($ch);

?>

Note: The actual code is more complex to accommodate authentication, multiple sets of credentials, and determine which sets are available for use. However, this simplified code has the same issue.

If I point this cURL to a login system on one of my servers, it works, no problem. It submits the credentials to the same target as using a HTML form and when I access the actual site, it's logged me in with the designated credentials.

With Canvas, I get nothing but a 400 Bad Request. I've added the source domain to the list of Trusted HTTP Referers and confirmed the JavaScript-based solution works.

Does anyone have ideas on what I am missing?

Tags (3)
2 Replies
dyegopereira
Surveyor

Were you able to evolve in your project? Can you make available ur code for study?

Yes and no. We determined that the closest we could get was a combination of AJAX and PHP, but we dropped the project because we could not determine any way to keep the credentials from being sent to the client.

A server-side language would allow us to sign in and manipulate things from the server, but for a client to be signed in and be able to do things requires the server be setup as either a proxy (the client isn't actually interacting with Canvas) or to send the credentials to the client to be injected to the login process via JavaScript. We thought that setting up a proxy system for this was overkill and the user credentials being injected to the login process via JavaScript makes those credentials available to the client.

We did consider a variation of the inject method that would include changing the passwords for the accounts every time they're used and add to the global JavaScript some logic to remove the reset options for users signed into those accounts, but that still doesn't actually prevent a user that knows what they're doing from being able to hijack the account.

This was ultimately considered too great of a security risk, even if we could control and limit what level of access involved in the system. Do to this, we didn't complete any viably working code relating to this project.