Skip to content
Snippets Groups Projects
Commit 63f7c34b authored by ale's avatar ale
Browse files

Update go-sso

parent 3396b96b
No related branches found
No related tags found
No related merge requests found
sso
===
Login server (or *identity provider*, IDP) using the
[ai/sso](https://git.autistici.org/ai/sso) protocol (version 5) for
single-sign on and [auth-server](https://git.autistici.org/id/auth) 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
attributes:
* `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
expressions.
* `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
[user-meta-server](https://git.autistici.org/id/usermetadb).
It is implemented very simply, with a long-term cookie stored in the
browser.
## Key store
On login, the login server can unlock the user's key store
(see [keystore](https://git.autistici.org/id/keystore)). The
associated key will be cleared either on logout, or when the login
session expires.
# API
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
parameters:
* `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
* `new_groups` (optional): a comma-separated list of groups that the
destination service might check membership for
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.
...@@ -11,17 +11,42 @@ import ( ...@@ -11,17 +11,42 @@ import (
) )
var ( var (
// Errors. // ErrMissingRequiredField is returned when a ticket does not
// contain a required field.
ErrMissingRequiredField = errors.New("missing required field") ErrMissingRequiredField = errors.New("missing required field")
ErrBadNonceLength = errors.New("bad nonce length")
// ErrDeserialization means that the input is not valid base64.
ErrDeserialization = errors.New("deserialization error") ErrDeserialization = errors.New("deserialization error")
// ErrUnsupportedTicketVersion is returned for unsupported
// ticket versions (either too old or too recent).
ErrUnsupportedTicketVersion = errors.New("unsupported ticket version") ErrUnsupportedTicketVersion = errors.New("unsupported ticket version")
// ErrMessageTooShort means that the input is shorter than the
// fixed signature length + minimum ticket size.
ErrMessageTooShort = errors.New("encoded message too short") ErrMessageTooShort = errors.New("encoded message too short")
// ErrBadSignature is returned when the signature does not
// match the given public key.
ErrBadSignature = errors.New("bad signature") ErrBadSignature = errors.New("bad signature")
// ErrBadService is returned when validation fails due to a
// SSO service mismatch.
ErrBadService = errors.New("service mismatch") ErrBadService = errors.New("service mismatch")
// ErrBadDomain is returned when validation fails due to a SSO
// domain mismatch.
ErrBadDomain = errors.New("auth domain mismatch") ErrBadDomain = errors.New("auth domain mismatch")
// ErrBadNonce is returned when validation fails due to a
// nonce mismatch.
ErrBadNonce = errors.New("nonce mismatch") ErrBadNonce = errors.New("nonce mismatch")
// ErrExpired means the ticket has expired.
ErrExpired = errors.New("ticket expired") ErrExpired = errors.New("ticket expired")
// ErrUnauthorized is returned when the user lacks the
// necessary group membership.
ErrUnauthorized = errors.New("unauthorized") ErrUnauthorized = errors.New("unauthorized")
) )
...@@ -234,7 +259,7 @@ func (v *ssoValidator) Validate(encoded, nonce, service string, allowedGroups [] ...@@ -234,7 +259,7 @@ func (v *ssoValidator) Validate(encoded, nonce, service string, allowedGroups []
if t.Expires.Before(time.Now()) { if t.Expires.Before(time.Now()) {
return nil, ErrExpired return nil, ErrExpired
} }
if t.Nonce != nonce { if nonce != "" && t.Nonce != nonce {
return nil, ErrBadNonce return nil, ErrBadNonce
} }
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
"revisionTime": "2018-01-12T09:10:27Z" "revisionTime": "2018-01-12T09:10:27Z"
}, },
{ {
"checksumSHA1": "DFjm2ZJpUwioPApa3htGXLEFWl8=", "checksumSHA1": "zvdsYaPEZrgcsRJy1bOo6YF5rVQ=",
"path": "git.autistici.org/id/go-sso", "path": "git.autistici.org/id/go-sso",
"revision": "2f1d893daf6ea55c4c3a704d14cf3c0996e1fec5", "revision": "10356d2430081e5f6dc60a68d576ef5b476f83ea",
"revisionTime": "2017-12-14T07:43:49Z" "revisionTime": "2018-02-16T18:29:55Z"
}, },
{ {
"checksumSHA1": "spyv5/YFBjYyZLZa1U2LBfDR8PM=", "checksumSHA1": "spyv5/YFBjYyZLZa1U2LBfDR8PM=",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment