Skip to content

My own little Single Sign On (SSO) solution. It's intentionally kept simple.

License

Notifications You must be signed in to change notification settings

Daniel-Abrecht/dpa-sso

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A simple SSO Portal

This is a Single Sign On (SSO) portal written in PHP.

In the config.php file, you can configure where and how to save sessions, and how to check or save passwords.

If the portal is opened normally, you can log in, check the sessions, log out of the current session, log out all your sessions, and change your password.

Security relevant limitations

For the purpose of being able to retrieve a token transparently, using only HTTP redirects, it has to be passed to /.well-known/dpa-sso/ using a GET parameter. For this reason, be careful with access logs, as they may include the token. The libapache2-mod-auth-dpa-sso module hides the token in the logs, but be careful if you use reverse proxies or the likes, as they may still log the token.

JS currently can't be prevented from obtaining the origins token. Although same origin rules will prevent the token from being obtained directly using fetch, it can install a service worker, which in turn can intercept the token sent to the /.well-known/dpa-sso/ endpoint. Consider restricting the installation of workers using a CSP:

Content-Security-Policy: worker-src 'none'

Getting & renewing tokens

If the page is opened with the renew-token GET or POST parameter set, and the referer GET or POST parameter is also set, a token will be checked, created, or renewed, and the existing or a new token is sent back, to the URL origin derived from the referer, with the location /.well-known/dpa-sso/, and the GET parameters token and location appended. Additionally, the headers X-User and X-Token are set. The HTTP Referer header was used initially, but prooved unreliable.
The token is unique to the origin, and distinct from the session token. If renew-token doesn't contain a valid token and there is no known session, the login page will be shown and the HTTP status will be 401. If the token is known and valid, the session (optional, if present) matches, and the token isn't old, the existing token is returned. Otherwise, a new token is returned, if a session is specified, it is for the specified session, otherwise, it is for the same session as the old token. Referer can be overwritten using a get parameter named "referer".

Constructing and checking a permission token

There is also the /permission/ endpoint. Given a token, a new permission token can be generated, that can be checked using this endpoint. The new permission token starts with a list of permissions followed by the sha256 of the permission list and the token. Everything is seperated by a single space. The token can be checked by passing it to the /permission/ endpoint using the token POST parameter. The user also needs to be passed using the user POST parameter. That is mainly so only the tokens of that user need to be checked if they were used to generate the permission token. The /permission/ returns a JSON containing the origin of the token and some other infos if it is valid. It returns null and status 403 otherwise. This endpoint does not require authentification. A permission token can (currently) not be used in places where a regular token can be used.
Which origins can have which permissions needs to be specified in the config. While generating permission tokens is always possible, it will return a json containing with a permission field, which contains the subset of allowed permissions. If there are none, the token is treated like an invalid token. The fields are also returned as HTTP Headers, prefixed with X-.

Example

The usecase for permission token is to allow a webbapplication to access other applications. Suppose there was a web mail application at origin https://mail.example.com. Suppose a user logged in at the SSO portal, and the application got a token using which the user is logged in, let's suppose it is abc123. Now, the web mail application may need to access the mail server (smtp and/or imap service). So it will generate a permission, for example smtp imap 7609517ee082128699fa209eeaa058203e600371071bcad14594036b491fa51a. The mail server / it's smtp / imap applications, can then be configured to accept the username and that permission token, and use the /permission/ endpoint to validate it. See the libpam-dpa-sso branch for an example to configure postfix and dovecot to do so using pam. The config file of this portal would have to contain an entry like the following:

\sso\config::$permission_map = [
  "https://mail.example.com" => ["smtp","imap"],
];

For completeness sake, here is what a roundcube webmail config should contain:

$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$_SERVER['PHP_AUTH_PW'] = 'smtp imap '.hash('sha256', 'smtp imap '.$_SERVER['PHP_AUTH_PW']);
$config['plugins'] = ['http_authentication'];

Note, that is when using the libapache2-mod-auth-dpa-sso httpd module, with the AuthDPASSOFakeBasicAuth set to user-password. It can also be set up using sso-middleware-php instead, but this currently isn't documented.

Other things

See also the other branches:

  • libapache2-mod-auth-dpa-sso: An apache2 httpd auth module.
  • libpam-dpa-sso: A PAM auth module that checks permission tokens.
  • sso-middleware-php: standalone auth in PHP, mostly as a PoC.

About

My own little Single Sign On (SSO) solution. It's intentionally kept simple.

Topics

Resources

License

Stars

Watchers

Forks