lyang/saml-proxy

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# saml-proxy [![Build](https://github.com/lyang/saml-proxy/actions/workflows/build.yml/badge.svg)](https://github.com/lyang/saml-proxy/actions/workflows/build.yml) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![Maintainability](https://api.codeclimate.com/v1/badges/58cdb58ef538f551da7a/maintainability)](https://codeclimate.com/github/lyang/saml-proxy/maintainability) [![codecov](https://codecov.io/gh/lyang/saml-proxy/branch/main/graph/badge.svg?token=2PY9RCMC53)](https://codecov.io/gh/lyang/saml-proxy)
A simple saml proxy for SSO integration

## What is SAML
> Security Assertion Markup Language is an open standard for exchanging authentication and authorization data between parties, in particular, between an identity provider and a service provider. SAML is an XML-based markup language for security assertions (statements that service providers use to make access-control decisions).

## Why use SAML
> An important use case that SAML addresses is web-browser single sign-on (SSO). Single sign-on is relatively easy to accomplish within a security domain (using cookies, for example) but extending SSO across security domains is more difficult and resulted in the proliferation of non-interoperable proprietary technologies. The SAML Web Browser SSO profile was specified and standardized to promote interoperability.

## What is `saml-proxy`?
TLDR: Like [oauth2-proxy](https://github.com/oauth2-proxy/oauth2-proxy), but for SAML. Typical SAML SSO providers include `PingId`, `Okta`, `OneLogin` etc.

## Why use `saml-proxy`?
So you can easily add SSO protection without modifying existing applications.

## How does it work?
TLDR:
```nginx
server{
  ...
  location / {
    auth_request /auth;
    auth_request_set $saml_email $upstream_http_saml_email;
    proxy_set_header Saml-Email $saml_email;
    error_page 401 = /start?redirect=$request_uri;
    proxy_pass http://app:4567;
  }

  location /auth {
    internal;
    proxy_pass http://saml-proxy:9292;
  }

  location /start {
    proxy_pass http://saml-proxy:9292;
  }

  location /consume {
    proxy_pass http://saml-proxy:9292;
  }
}
```
Sequence Diagram:
![sequence-diagram](https://demo.puml.net/github/lyang/saml-proxy-example/blob/main/sequence-diagram.puml)

## I want to see it in action
Take a look at [saml-proxy-example](https://github.com/lyang/saml-proxy-example)

## How do I configure it for my production setup

### Via environment variables

#### Server
| Name | Default | Comment |
|------|---------|---------|
| `RACK_ENV` | `development` | |
| `PORT` | `9292` | |
| `PUMA_MAX_THREADS` | `5` | |

#### SAML
| Name | Required | Comment |
|------|----------|---------|
| `SAML_IDP_METADATA` | `True` | Path to local file or remote url |
| `SAML_SP_ENTITY_ID` | `True` | Your `SP_ENTITY_ID` |
| `SAML_ASSERTION_CONSUMER_SERVICE_URL` | `True` | |
| `SAML_CERTIFICATE` | `False` | Path to your encryption/signing cert |
| `SAML_PRIVATE_KEY` | `False` | Path to your encryption/signing key |
| `SAML_AUTHN_REQUESTS_SIGNED` | `False` | Likely required by your production IdP |
| `SAML_METADATA_SIGNED` | `False` | Likely required by your production IdP |

#### Mappings
| `Name` | Required | Comment |
|------|----------|---------|
| `SAML_MAPPINGS_*` | `False` | HTTP HEADER |

The `*` is the attribute name returned by your SSO. The value is the HTTP header you want returned to `nginx`'s `auth_request`

#### PROXY
| `Name` | Required | Comment |
|------|----------|---------|
| `PROXY_HOST` | `False` | |
| `PROXY_PORT` | `False` | |
| `PROXY_USER` | `False` | |
| `PROXY_PASSWORD` | `False` | |

The only time it makes outbound http call is when it tries to load idp metadata from a remote URL

#### Cookie
| `Name` | Default | Comment |
|------|---------|---------|
| `COOKIE_KEY` | `saml-proxy` | |
| `COOKIE_PATH` | `/` | |
| `COOKIE_SECRET` | `SecureRandom.hex(64)` | **SET IT FOR PRODUCTION** |
| `COOKIE_EXPIRE_AFTER` | `nil` | Integer in seconds. Default to session only |

#### Via config file override
You can also put your override configs in `/app/config/`