Skip to content

Commit e109fb1

Browse files
committed
v1.0.0
1 parent 0322810 commit e109fb1

File tree

3 files changed

+84
-102
lines changed

3 files changed

+84
-102
lines changed

CHANGELOG.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# CHANGELOG
22

3-
### v1.0.0-rc.1
3+
### v1.0.0
44

55
+ `target_url` query parameter for the sign-in/sign-out requests must be
66
`x-www-form-urlencoded`.
@@ -11,8 +11,6 @@
1111

1212
+ `cache-control` header value updated.
1313

14-
### v1.0.0-rc.0
15-
1614
+ Issue: #33 - Content Security Policy
1715
Enabled `Content-Security-Policy` in the HTTP response.
1816

README.md

Lines changed: 81 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
# Samly
22

3-
SAML 2.0 SP SSO made easy. This is a Plug library that can be used to enable SAML 2.0 Single Sign On authentication in a Plug/Phoenix application.
3+
A SAML 2.0 Service Provider Single-Sign-On Authentication library. This Plug library can be used to SAML enable a Plug/Phoenix application.
4+
5+
This has been used in the wild with the following Identity Providers:
6+
7+
+ Okta
8+
+ Ping Identity
9+
+ OneLogin
10+
+ ADFS
11+
+ Nexus GO
12+
+ Shibboleth
13+
+ SimpleSAMLphp
14+
15+
Please send a note by DM if you have successfully used `Samly` with other Identity Providers.
416

517
[![Inline docs](http://inch-ci.org/github/handnot2/samly.svg)](http://inch-ci.org/github/handnot2/samly)
618

@@ -12,17 +24,17 @@ plug enabled routes.
1224
```elixir
1325
# mix.exs
1426

27+
# v1.0.0 uses esaml v4.2 which in turn relies on cowboy 2.x
28+
# If you need to work with cowboy 1.x, you need the following override:
29+
# {:esaml, "~> 3.7", override: true}
30+
1531
defp deps() do
1632
[
1733
# ...
18-
{:samly, "~> 1.0.0-rc.1"},
19-
# v1.0.0-rc.1 uses esaml v4.2 which in turn relies on cowboy 2.x
20-
# If you need to work with cowboy 1.x, you need the following override:
21-
# {:esaml, "~> 3.7", override: true}
34+
{:samly, "~> 1.0.0"},
2235
]
2336
end
2437
```
25-
> Starting v0.10.0, Samly uses Cowboy 2.x. This implies that you need to use `phoenix v1.4` and `plug_cowboy v2.0`. Make sure to update your application's `mix.exs` dependencies to reflect this change. If you do not want to use `phoenix v1.4` and want to use Samly with `phoenix v1.3`, make sure to include `:esaml` v3.7 override in your `mix.exs`.
2638

2739
## Supervision Tree
2840

@@ -33,7 +45,7 @@ Add `Samly.Provider` to your application supervision tree.
3345

3446
children = [
3547
# ...
36-
worker(Samly.Provider, []),
48+
{Samly.Provider, []},
3749
]
3850
```
3951

@@ -54,12 +66,15 @@ end
5466

5567
## Certificate and Key for Samly
5668

57-
`Samly` needs a private key and a corresponding certificate. These are used when
58-
communicating with the Identity Provider.
69+
`Samly` needs a private key and a corresponding certificate. These are used to
70+
sign the SAML requests when communicating with the Identity Provider. This certificate
71+
should be made available to `Samly` via config settings. It should also be made
72+
available to the Identity Provider so it can verify the SAML signed requests.
5973

60-
A convenient script, `gencert.sh`, is provided in [`samly_howto`](https://github.com/handnot2/samly_howto) to generate the key and certificate.
61-
Make sure `openssl` is available on your system. The name of the key file and
62-
certificate file generated should be provided as part of the Samly configuration.
74+
You can create a self-signed certificate for this purpose. You can use `phx.gen.cert`
75+
mix task that is available as part of Phoenix 1.4 or use `openssl` directly to generate
76+
the key and corresponding certificate.
77+
(Check out [`samly_howto`](https://github.com/handnot2/samly_howto) `README.md` for this.)
6378

6479
## Identity Provider Metadata
6580

@@ -72,14 +87,14 @@ For example, `SimpleSAMLPhp` IdP provides a URL for the metadata. You can fetch
7287
it using `wget`.
7388

7489
```
75-
wget http://samly.idp:8082/simplesaml/saml2/idp/metadata.php -O idp_metadata.xml
90+
wget --no-check-certificate -O idp1_metadata.xml https://idp1.samly:9091/simplesaml/saml2/idp/metadata.php
7691
```
7792

7893
If you are using the `SimpleSAMLPhp` administrative Web UI, login with you
79-
admin credentials (`http://samly.idp:8082/simplesaml`). Go to the `Federation`
94+
admin credentials (`https://idp1.samly:9091/simplesaml`). Go to the `Federation`
8095
tab. At the top there will be a section titled "SAML 2.0 IdP Metadata". Click
8196
on the `Show metadata` link. Copy the metadata XML from this page and save it
82-
in a local file (`idp_metadata.xml` for example).
97+
in a local file (`idp1_metadata.xml` for example).
8398

8499
Make sure to save this XML file and provide the path to the saved file in
85100
`Samly` configuration.
@@ -98,17 +113,17 @@ Service Provider SAML URLs.
98113
#### URL Path Segment
99114

100115
In this model, the idp_id is present as a URL path segment. Here is an
101-
example URL: `http://do-good.org/sso/auth/signin/affiliates`. The idp_id
116+
example URL: `https://do-good.org/sso/auth/signin/affiliates`. The idp_id
102117
in this URL is "affiliates". If you have more than one IdP, only this last
103118
part changes. The URLs for this model are:
104119

105120
| Description | URL |
106121
|:----|:----|
107122
| Sign-in button/link in Web UI | `/sso/auth/signin/affiliates` |
108123
| Sign-out button/link in Web UI | `/sso/auth/signout/affiliates` |
109-
| SP Metadata URL | `http://do-good.org/sso/sp/metadata/affiliates` |
110-
| SAML Assertion Consumer Service | `http://do-good.org/sso/sp/consume/affiliates` |
111-
| SAML SingleLogout Service | `http://do-good.org/sso/sp/logout/affiliates` |
124+
| SP Metadata URL | `https://do-good.org/sso/sp/metadata/affiliates` |
125+
| SAML Assertion Consumer Service | `https://do-good.org/sso/sp/consume/affiliates` |
126+
| SAML SingleLogout Service | `https://do-good.org/sso/sp/logout/affiliates` |
112127

113128
The path segment model is the default one in `Samly`. If there is only one Identity Provider, use this mode.
114129

@@ -121,22 +136,30 @@ The path segment model is the default one in `Samly`. If there is only one Ident
121136
122137
#### Subdomain in Host Name
123138

124-
In this model, the subdomain name is used as the idp_id. Here is an example URL: `http://ngo.do-good.org/sso/auth/signin`. Here "ngo" is the idp_id. The URLs supported by `Samly`
139+
In this model, the subdomain name is used as the idp_id. Here is an example URL: `https://ngo.do-good.org/sso/auth/signin`. Here `ngo` is the idp_id. The URLs supported by `Samly`
125140
in this model look different.
126141

127142
| Description | URL |
128143
|:----|:----|
129144
| Sign-in button/link in Web UI | `/sso/auth/signin` |
130145
| Sign-out button/link in Web UI | `/sso/auth/signout` |
131-
| SP Metadata URL | `http://ngo.do-good.org/sso/sp/metadata` |
132-
| SAML Assertion Consumer Service | `http://ngo.do-good.org/sso/sp/consume` |
133-
| SAML SingleLogout Service | `http://ngo.do-good.org/sso/sp/logout` |
146+
| SP Metadata URL | `https://ngo.do-good.org/sso/sp/metadata` |
147+
| SAML Assertion Consumer Service | `https://ngo.do-good.org/sso/sp/consume` |
148+
| SAML SingleLogout Service | `https://ngo.do-good.org/sso/sp/logout` |
134149

135150
> Take a look at [`samly_howto`](https://github.com/handnot2/samly_howto) - a reference/demo
136151
> application on how to use this library.
137152
>
138153
> Make sure to use HTTPS URLs in production deployments.
139154
155+
#### Target URL for Sign-In and Sign-Out Actions
156+
157+
The sign-in and sign-out URLs (HTTP GET) mentioned above optionally take a `target_url`
158+
query parameter. `Samly` will redirect the browser to these URLs upon successfuly
159+
completing the sign-in/sign-out operations initiated from your application.
160+
161+
> This `target_url` query parameter value must be `x-www-form-urlencoded`.
162+
140163
## Samly Configuration
141164

142165
```elixir
@@ -148,29 +171,29 @@ config :samly, Samly.Provider,
148171
%{
149172
id: "do-good-affiliates-sp",
150173
entity_id: "urn:do-good.org:affiliates-app",
151-
certfile: "path/to/samly/certfile.crt",
174+
certfile: "path/to/samly/certfile.pem",
152175
keyfile: "path/to/samly/keyfile.pem",
153176
#contact_name: "Affiliates Admin",
154177
#contact_email: "[email protected]",
155178
#org_name: "Do Good",
156179
#org_displayname: "Goodly, No evil!",
157-
#org_url: "http://do-good.org"
180+
#org_url: "https://do-good.org"
158181
}
159182
],
160183
identity_providers: [
161184
%{
162185
id: "affiliates",
163186
sp_id: "do-good-affiliates-sp",
164-
base_url: "http://do-good.org/sso",
165-
metadata_file: "idp_metadata.xml",
187+
base_url: "https://do-good.org/sso",
188+
metadata_file: "idp1_metadata.xml",
166189
#pre_session_create_pipeline: MySamlyPipeline,
167190
#use_redirect_for_req: false,
168191
#sign_requests: true,
169192
#sign_metadata: true,
170193
#signed_assertion_in_resp: true,
171194
#signed_envelopes_in_resp: true,
172195
#allow_idp_initiated_flow: false,
173-
#allowed_target_urls: ["http://do-good.org"],
196+
#allowed_target_urls: ["https://do-good.org"],
174197
#nameid_format: :transient
175198
}
176199
]
@@ -204,8 +227,6 @@ config :samly, Samly.Provider,
204227

205228
#### Authenticated SAML Assertion State Store
206229

207-
> Since v0.10.0
208-
209230
`Samly` internally maintains the authenticated SAML assertions (from `LoginResponse` SAML requests).
210231
There are two built-in state store options available - one based on ETS and the other on Plug Sessions.
211232
The ETS store can be setup using the following configuration:
@@ -222,8 +243,10 @@ This state configuration is optional. If omitted, `Samly` uses `Samly.State.ETS`
222243
|:------------|:-----------|
223244
| `opts` | _(optional)_ The `:table` option is the ETS table name for storing the assertions. This ETS table is created during the store provider initialization if it is not already present. Default is `samly_assertions_table`. |
224245

225-
Use `Samly.State.Session` provider in a clustered deployment. This provider uses the Plug Sessions to keep
226-
the authenticated SAML assertions. This provider can be enabled using the following:
246+
> Use `Samly.State.Session` provider in a clustered deployment. This provider uses
247+
> the Plug Sessions to keep the authenticated SAML assertions.
248+
249+
This session based provider can be enabled using the following:
227250

228251
```elixir
229252
config :samly, Samly.State,
@@ -233,12 +256,12 @@ config :samly, Samly.State,
233256

234257
| Options | Description |
235258
|:------------|:-----------|
236-
| `opts` | _(optional)_ The `:key` is the name of the session key where assertion is stored. Default is `samly_assertion`. |
259+
| `opts` | _(optional)_ The `:key` is the name of the session key where assertion is stored. Default is `:samly_assertion`. |
237260

238261
## SAML Assertion
239262

240263
Once authentication is completed successfully, IdP sends a "consume" SAML
241-
request to `Samly`. `Samly` in turn performs its own checks (including checking
264+
request to `Samly`. `Samly` in-turn performs its own checks (including checking
242265
the integrity of the "consume" request). At this point, the SAML assertion
243266
with the authenticated user subject and attributes is available.
244267

@@ -344,6 +367,8 @@ in `Samly.Subject.in_response_to` field. It is the responsibility of the consumi
344367
expects the SAML reqsponses to be signed (both assertion and envelopes). If your IdP is
345368
not configured to sign, you will have to explicitly turn them off in the configuration.
346369
It is highly recommended to turn signing on in production deployments.
370+
+ Encypted Assertions are supported in `Samly`. There are no explicit config settings for this. Decryption happens automatically when encrypted assertions are detected in the SAML response.
371+
> [Supported Encryption algorithms](https://github.com/handnot2/esaml#assertion-encryption)
347372
+ Make sure to use HTTPS URLs in production deployments.
348373

349374
## FAQ
@@ -352,82 +377,41 @@ in `Samly.Subject.in_response_to` field. It is the responsibility of the consumi
352377

353378
Docker based setup of [`SimpleSAMLPhp`](https://simplesamlphp.org) is made available
354379
at [`samly_simplesaml`](https://github.com/handnot2/samly_simplesaml) Git Repo.
380+
Check out the `README.md` file of this repo.
355381

356-
```sh
357-
git clone https://github.com/handnot2/samly_simplesaml
358-
cd samly_simplesaml
359-
360-
# Ubuntu 16.04 based
361-
./build.sh
362-
363-
# Follow along README.md (skip SAML Service Provider registration part for now)
364-
# Edit setup/params/params.yml with appropriate information
365-
# Add the IDP host name to your /etc/hosts resolving to 127.0.0.1
366-
# 127.0.0.1 samly.idp
367-
# Compose exposes and binds to port 8082 by default.
368-
369-
docker-compose up -d
370-
docker-compose restart
371-
```
372-
373-
You should have a working SAML 2.0 IdP that you can work with.
382+
There is also a Docker based setup of [`Shibboleth`](https://www.shibboleth.net/).
383+
Checkout the corresponding `README.md` file in [`samly_shibboleth`](https://github.com/handnot2/samly_shibboleth) Git Repo.
374384

375385
#### Any sample Phoenix application that shows how to use Samly?
376386

377387
Clone the [`samly_howto`](https://github.com/handnot2/samly_howto) Git Repo.
378-
379-
```sh
380-
git clone https://github.com/handnot2/samly_howto
381-
382-
# Add the SP host name to your /etc/hosts resolving to 127.0.0.1
383-
# 127.0.0.1 samly.howto
384-
385-
cd samly_howto
386-
387-
# Use gencert.sh to create a self-signed certificate for the SAML Service Provider
388-
# embedded in your app (by `Samly`). We will register this and the `Samly` URLs
389-
# with IdP shortly. Take a look at this script and adjust the certificate subject
390-
# if needed.
391-
392-
./gencert.sh
393-
394-
# Get NPM assets
395-
396-
cd assets && npm install && cd ..
397-
398-
# Fetch the IdP metadata XML. `Samly` needs this to make sure that it can
399-
# validate the request/responses to/from IdP.
400-
401-
wget http://samly.idp:8082/simplesaml/saml2/idp/metadata.php -O idp_metadata.xml
402-
403-
mix deps.get
404-
mix compile
405-
406-
HOST=samly.howto PORT=4003 iex -S mix phx.server
407-
```
408-
409-
> Important: Make sure that your have registered this application with
410-
> the IdP before you explore this application using a browser.
411-
412-
Open `http://samly.howto:4003` in your browser and check out the app.
388+
Detailed instructions on how to setup and run this application are available
389+
in the `README.md` file in this repo.
413390

414391
> It is recommended that you use the `SamlyHowto` application to
415-
> sort out any configuration issues by making this demo application work
392+
> sort out any configuration issues by making that demo application work
416393
> successfully with your Identity Provider (IdP) before attempting your
417394
> application.
418395
>
419396
> This demo application supports experimentation with multiple IdPs.
420397
421398
#### How to register the service provider with IdP
422399

423-
Complete the setup by registering `samly_howto` as a Service Provider with the IdP.
400+
If you are using `samly_simplesaml` or `samly_shibboleth`, the instructions
401+
you followed there would take care of registering your Phoenix SAML Service provider
402+
appliccation. For any other IdP, follow the instructions from the respective
403+
IdP vendor.
424404

425-
```sh
426-
mkdir -p samly_simplesaml/setup/sp/samly_howto # use the correct path
427-
cp samly.crt samly_simplesaml/setup/sp/samly_howto/sp.crt
428-
cd samly_simplesaml
429-
docker-compose restart
430-
```
405+
#### Common Errors
406+
407+
`access_denied {:error, :bad_recipient}` - Check the `base_url` in your `Samly`
408+
config setting under `indentity_providers`.
409+
410+
`access_denied {:error, :bad_audience}` - Make sure that the `entity_id` in
411+
the `Samly` config setting is correct.
431412

432-
> The IdP related instructions are very specific to the docker based development
433-
> setup of SimpleSAMLphp IdP. But similar ideas work for your own IdP setup.
413+
`access_denied {:envelope, {:error, :cert_no_accepted}}` - Make sure the
414+
Identity Provider metadata XML file you are using in the `Samly` config setting
415+
is correct and corresponds to the IdP you are attempting to talk to. You get
416+
this error if the certificate used by the IdP to sign the SAML responses
417+
has changed and you don't have the updated IdP metadata XML file on the `Samly` end.

mix.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
defmodule Samly.Mixfile do
22
use Mix.Project
33

4-
@version "1.0.0-rc.1"
5-
@description "SAML SP SSO made easy"
4+
@version "1.0.0"
5+
@description "SAML Single-Sign-On Authentication for Plug/Phoenix Applications"
66
@source_url "https://github.com/handnot2/samly"
77
@blog_url "https://handnot2.github.io/blog/auth/saml-auth-for-phoenix"
88

0 commit comments

Comments
 (0)