Federated Command Line Client Authentication with SimpleSAMLphp and OAuth

I've added OAuth support in a module in SimpleSAMLphp and made a proof of concept demo on how to perform authentication initiated from a command line client.

Here is how it looks:

You can update simplesamlphp, enable the oauth module, and run the demo.php command line script your self. The server side is also embedded in the module. Make sure that you do not enable the oauth module on your production server, this is for demo purposes only.

The CLI runs as an OAuth Consumer, the OAuth Service Provider is co-located with a SAML 2.0 Service Provider and perform the federated authentication via an SAML 2.0 IdP.

Here is more or less all the neccessary code that needs to be included in your CLI script:

echo 'Welcome to the OAuth CLI client' . "\n";
$consumer = new sspmod_oauth_Consumer($key, $secret);

// Get the request token
$requestToken = $consumer->getRequestToken($baseurl . 
    '/module.php/oauth/requestToken.php');
echo "Got a request token from the OAuth service provider [" . 
    $requestToken->key . "] with the secret [" . $requestToken->secret . "]\n";

// Authorize the request token
$consumer->getAuthorizeRequest($baseurl . '/module.php/oauth/authorize.php', $requestToken);

// Replace the request token with an access token
$accessToken = $consumer->getAccessToken( $baseurl . '/module.php/oauth/accessToken.php', 
    $requestToken);
echo "Got an access token from the OAuth service provider [" . 
    $accessToken->key . "] with the secret [" . $accessToken->secret . "]\n";

$userdata = $consumer->getUserInfo($baseurl . '/module.php/oauth/getUserInfo.php', 
    $accessToken);


echo 'You are successfully authenticated to this Command Line CLI. ' . "\n";
echo 'Got data [' . join(', ', array_keys($userdata)) . ']' . "\n";
echo 'Your user ID is :  ' . $userdata['eduPersonPrincipalName'][0] . "\n";

The Background

The Identity Federations that we work with is more or less entirely based upon WebSSO. From time to time we get requests from people wanting to re-use the widely deployed WebSSO framework for applications that are not Web-based. it could be stand-alone GUI applications or command line clients.

Recently, I got a question (from the GRID world) about standarizing the name of the Input elements in the HTML of the login pages across Identity Providers, to make it simpler to webscrape the login pages to provide federated login to a command line client.

In the following section, I'll try to expain my approach to 'a better way of doing it'.

My approach

You have a client-server architecture with a non-web based client, and you want to re-use WebSSO infrastructure. Usually the client wants to get some personalized data form the server, and the client must prove towards the server that it represents a specific user.

The client implements OAuth Consumer capabilities. The server implements both an OAuth Provider and a SAML 2.0 WebSSO Service Provider.

  1. Client gets a request token from the server. (back-channel) OAUth
  2. Clients will open a web browser or tell the user to manually go to an endpoint on the server containing the request key.
  3. At this web-based endpoint, the user follows normal WebSSO SAML 2.0 until the user ends up authenticated.
  4. User is told to click continue in the client.
  5. Client exchanges the request token with an access token with a call to the server (back-channel) OAuth

Now, we are sure that both the client and the server represent the same user, and the access token can be used to communicate, referring to the user behind the client. If the server is the only entity that needs to know the identity of the user, the client can now request the data it needs.

If the client itself also need to know who the user is, some extra steps is neccessary. I implemented a very simple WS getUserInfo endpoint at the server, that uses OAuth, and returns user attributes as a JSON array.

  1. Client do a back-channel request to the userInfo endpoint using the OAuth access token, and gets user attributes back in an JSON array.

I can imagine that this kind

I can imagine that this kind of solution may be very elegant when using a standalone GUI application, possibly with an embedded web-browser. However, with a command-line client it fails from the usability perspective, because it feels very strange if users have to change from their command-line client to a browser window and have to enter their credentials there. Command-line users tend to use the command-line exactly for the reason of avoiding stuff like that. If the user has to use the browser window to authenticate with her identity provider, she might as well do the whole process using the browser and then download a certificate/proxy from a web portal. Plus, it won't work on systems without graphical interfaces on which command-line tools may be used.

So OAuth is nice if you have a GUI and probably essential, if you don't want to trust the CLI-client to securely administer the user credentials. But, sadly, from the usability perspective it does not convince me.

But then, I have been convinced...

... that this depends on the actual AuthN method deployed at the IdP and hence is more a problem of the login forms used for AuthN there than of OAuth.

By the way, if you want to use OAuth with your own simplesamlphp Service Provider, the following field has to be present in config/authsources.php, section saml2:

'idp' => '<idp-to-use>.example.com',
'entityId' => 'your-sp.example.com'

Add an entry for "<your-sp.example.com/path-to-simplesaml>/module.php/saml2/sp/metadata.php?source=saml2" in metadata/saml2-sp-hosted.php.

It took some time to figure that out, so maybe I can save somebody time by mentioning that :)