6.28 KB
Newer Older
ale's avatar
ale committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

Login server (or *identity provider*, IDP) using the
[ai/sso]( protocol (version 5) for
single-sign on and [auth-server]( to
authenticate users.

This repository includes a few separate binaries:

* *sso-server* is the login server / IDP
* *saml-server* is a SSO-to-SAML bridge (for third-party software)
* *sso-proxy* is a reverse HTTP proxy that adds single-sign-on access
  controls to backends

# Configuration

The *sso-server* daemon requires a YAML configuration file,
*/etc/sso/server.yml* by default. It understands the following

* `secret_key_file`: path to the Ed25519 secret key (should be exactly
64 bytes)
* `public_key_file`: path to the Ed25519 public key (should be exactly
32 bytes)
* `domain`: SSO domain
* `allowed_services`: a list of regular expressions. A request will be
  allowed only if the target SSO services matches one of these
* `allowed_exchanges`: a list of regular expression source /
  destination pairs (dictionaries with `src_regexp` and `dst_regexp`
  attributes). Exchange requests will only be allowed if source and
  destination SSO services both match one of these pairs.
* `service_ttls`: a list of dictionaries used to set time-to-live for
  SSO tickets for specific services. Each dictionary should have the
  following attributes:
  * `regexp`: regular expression that should match the SSO service
  * `ttl`: TTL in seconds
* `auth_session_lifetime`: time-to-live (in seconds) for the
  sso-server user authentication session. When it expires, the user
  will have to login again.
* `session_secrets`: a list of two (or more, as long as the number is
  even) secret keys to use for HTTP cookie-based sessions, in
  *authentication-key*, *encryption-key* pairs. Authentication keys
  can be 32 bytes (SHA128) or 64 bytes (SHA512), encryption keys
  should be 16 (AES-128), 24 (AES-192) or 32 (AES-256) bytes long. For
  key rotation, multiple pairs (old, new) can be specified so that
  sessions are not immediately invalidated.
* `csrf_secret`: a secret key used for CSRF protection
* `auth_service`: the service name to use for the authentication
  request sent to *auth-server* (generally "sso")
* `device_manager`: configuration for the device tracking module:
  * `auth_key`: a long-term key to authenticate HTTP-based cookies
  * `geo_ip_data_files`: GeoIP databases to use (in mmdb format), if
    unset the module will use the default GeoLite2-Country db
* `keystore`: configures the connection to the keystore service
  * `url`: URL for the keystore service
  * `sharded`: if true, requests to the keystore service will be
    partitioned according to the user's *shard* attribute
  * `tls_config`: client TLS configuration
    * `cert`: path to the client certificate
    * `key`: path to the private key
    * `ca`: path to the CA used to validate the server
* `http_server`: specifies standard parameters for the HTTP server
  * `tls`: server-side TLS configuration
    * `cert`: path to the server certificate
    * `key`: path to the server's private key
    * `ca`: path to the CA used to validate clients
    * `acl`: TLS-based access controls, a list of entries with the
      following attributes:
      * `path` is a regular expression to match the request URL path
      * `cn` is a regular expression that must match the CommonName
        part of the subject of the client certificate
  * `trusted_forwarders`: list of trusted IP addresses (reverse
    proxies). If a request comes from here, we will trust the
    X-Forwarded-Proto and X-Real-IP headers when determining the
    client IP address
  * `max_inflight_requests`: maximum number of in-flight requests to
    allow before server-side throttling kicks in

## Device tracking

The idea is to track a small amount of non-personally-identifying data
for each device, and use it to notify users of unexpected
accesses. This information is tracked by the

It is implemented very simply, with a long-term cookie stored in the

## Key store

On login, the login server can unlock the user's key store
(see [keystore]( The
associated key will be cleared either on logout, or when the login
session expires.


The *sso-server* binary serves different types of HTTP traffic:

* the login/logout interface (user-facing)
* the SSO login endpoint (user-facing)
* the SSO ticket exchange endpoint (service-facing)

The ticket exchange API allows a service (the *source*) to exchange a
valid SSO ticket for itself with a SSO ticket, for the same user,
meant for a third-party service (*destination*). Its endpoint is
located at the URL `/exchange` and it accepts the following query

* `cur_tkt`: valid source SSO ticket
* `cur_svc`: source SSO service
* `cur_nonce`: nonce for *cur_tkt*
* `new_svc`: destination SSO service
* `new_nonce`: nonce for the new SSO ticket

Note that annoyingly *cur_svc* and *cur_nonce* are redundant, as they
are already contained within *cur_tkt*, but the SSO ticket API won't
allow us to decode the ticket without verifying it at the same time.
ale's avatar
ale committed

123 124 125 126 127 128
The new ticket will not be valid any longer than the original one, or
the configured TTL for the new service, whichever comes first.

Group membership in the original ticket is passed along unchanged to
the new ticket.

ale's avatar
ale committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

# Implementation notes

The single-sign-on functionality works using HTTP cookies and
redirects between the protected service and the SSO server implemented
in this package. This part works without any Javascript, it's just
plain old HTTP (the browser must accept cookies though). SSO cookies
have a builtin (signed) expiration timestamp, and are set to be
automatically deleted on browser exit.

Logout, on the other hand, is more complex: in order to get the
browser to delete the cookies from the signed-in services, we use
XMLHttpRequests from the logout page, and expect the service logout
endpoints to support authenticated CORS. If Javascript is not
available, however, we try to clear the cookies using image requests,
but this may not work depending on the browser (Safari), or the
presence of privacy-protecting extensions meant to block third-party
cookies. In this case a message is displayed asking the user to quit
the browser, but this isn't really a satisfying solution.