• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H07-Oct-2021-

example/H07-Oct-2021-

logger/H07-Oct-2021-

samlidp/H07-Oct-2021-

samlsp/H07-Oct-2021-

testdata/H03-May-2022-

testsaml/H07-Oct-2021-

xmlenc/H07-Oct-2021-

.gitignoreH A D07-Oct-202173

.golangci.ymlH A D07-Oct-20214.2 KiB

LICENSEH A D07-Oct-20211.3 KiB

README.mdH A D07-Oct-20217 KiB

duration.goH A D07-Oct-20212.9 KiB

duration_test.goH A D07-Oct-20212.7 KiB

go.modH A D07-Oct-2021829

go.sumH A D07-Oct-20215.1 KiB

identity_provider.goH A D07-Oct-202134.5 KiB

identity_provider_test.goH A D07-Oct-202140.3 KiB

metadata.goH A D07-Oct-202112.1 KiB

metadata_test.goH A D07-Oct-20215.4 KiB

saml.goH A D07-Oct-20218.8 KiB

saml_gen.goH A D07-Oct-2021164

schema.goH A D07-Oct-202136.8 KiB

schema_test.goH A D07-Oct-20213 KiB

service_provider.goH A D07-Oct-202142.5 KiB

service_provider_test.goH A D07-Oct-202161.1 KiB

time.goH A D07-Oct-20211.3 KiB

time_test.goH A D07-Oct-20211.7 KiB

util.goH A D07-Oct-2021787

README.md

1# SAML
2
3[![](https://godoc.org/github.com/crewjam/saml?status.svg)](http://godoc.org/github.com/crewjam/saml)
4
5![Build Status](https://github.com/crewjam/saml/workflows/Presubmit/badge.svg)
6
7Package saml contains a partial implementation of the SAML standard in golang.
8SAML is a standard for identity federation, i.e. either allowing a third party to authenticate your users or allowing third parties to rely on us to authenticate their users.
9
10## Introduction
11
12In SAML parlance an **Identity Provider** (IDP) is a service that knows how to authenticate users. A **Service Provider** (SP) is a service that delegates authentication to an IDP. If you are building a service where users log in with someone else's credentials, then you are a **Service Provider**. This package supports implementing both service providers and identity providers.
13
14The core package contains the implementation of SAML. The package samlsp provides helper middleware suitable for use in Service Provider applications. The package samlidp provides a rudimentary IDP service that is useful for testing or as a starting point for other integrations.
15
16## Getting Started as a Service Provider
17
18Let us assume we have a simple web application to protect. We'll modify this application so it uses SAML to authenticate users.
19
20```golang
21package main
22
23import (
24    "fmt"
25    "net/http"
26)
27
28func hello(w http.ResponseWriter, r *http.Request) {
29    fmt.Fprintf(w, "Hello, World!")
30}
31
32func main() {
33    app := http.HandlerFunc(hello)
34    http.Handle("/hello", app)
35    http.ListenAndServe(":8000", nil)
36}
37```
38
39Each service provider must have an self-signed X.509 key pair established. You can generate your own with something like this:
40
41    openssl req -x509 -newkey rsa:2048 -keyout myservice.key -out myservice.cert -days 365 -nodes -subj "/CN=myservice.example.com"
42
43We will use `samlsp.Middleware` to wrap the endpoint we want to protect. Middleware provides both an `http.Handler` to serve the SAML specific URLs **and** a set of wrappers to require the user to be logged in. We also provide the URL where the service provider can fetch the metadata from the IDP at startup. In our case, we'll use [samltest.id](https://samltest.id/), an identity provider designed for testing.
44
45```golang
46package main
47
48import (
49	"context"
50	"crypto/rsa"
51	"crypto/tls"
52	"crypto/x509"
53	"fmt"
54	"net/http"
55	"net/url"
56
57	"github.com/crewjam/saml/samlsp"
58)
59
60func hello(w http.ResponseWriter, r *http.Request) {
61	fmt.Fprintf(w, "Hello, %s!", samlsp.AttributeFromContext(r.Context(), "cn"))
62}
63
64func main() {
65	keyPair, err := tls.LoadX509KeyPair("myservice.cert", "myservice.key")
66	if err != nil {
67		panic(err) // TODO handle error
68	}
69	keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
70	if err != nil {
71		panic(err) // TODO handle error
72	}
73
74	idpMetadataURL, err := url.Parse("https://samltest.id/saml/idp")
75	if err != nil {
76		panic(err) // TODO handle error
77	}
78	idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient,
79		*idpMetadataURL)
80	if err != nil {
81		panic(err) // TODO handle error
82	}
83
84	rootURL, err := url.Parse("http://localhost:8000")
85	if err != nil {
86		panic(err) // TODO handle error
87	}
88
89	samlSP, _ := samlsp.New(samlsp.Options{
90		URL:            *rootURL,
91		Key:            keyPair.PrivateKey.(*rsa.PrivateKey),
92		Certificate:    keyPair.Leaf,
93		IDPMetadata: idpMetadata,
94	})
95	app := http.HandlerFunc(hello)
96	http.Handle("/hello", samlSP.RequireAccount(app))
97	http.Handle("/saml/", samlSP)
98	http.ListenAndServe(":8000", nil)
99}
100```
101
102Next we'll have to register our service provider with the identity provider to establish trust from the service provider to the IDP. For [samltest.id](https://samltest.id/), you can do something like:
103
104    mdpath=saml-test-$USER-$HOST.xml
105    curl localhost:8000/saml/metadata > $mdpath
106
107Navigate to https://samltest.id/upload.php and upload the file you fetched.
108
109Now you should be able to authenticate. The flow should look like this:
110
1111. You browse to `localhost:8000/hello`
112
1131. The middleware redirects you to `https://samltest.id/idp/profile/SAML2/Redirect/SSO`
114
1151. samltest.id prompts you for a username and password.
116
1171. samltest.id returns you an HTML document which contains an HTML form setup to POST to `localhost:8000/saml/acs`. The form is automatically submitted if you have javascript enabled.
118
1191. The local service validates the response, issues a session cookie, and redirects you to the original URL, `localhost:8000/hello`.
120
1211. This time when `localhost:8000/hello` is requested there is a valid session and so the main content is served.
122
123## Getting Started as an Identity Provider
124
125Please see `example/idp/` for a substantially complete example of how to use the library and helpers to be an identity provider.
126
127## Support
128
129The SAML standard is huge and complex with many dark corners and strange, unused features. This package implements the most commonly used subset of these features required to provide a single sign on experience. The package supports at least the subset of SAML known as [interoperable SAML](https://kantarainitiative.github.io/SAMLprofiles/saml2int.html).
130
131This package supports the **Web SSO** profile. Message flows from the service provider to the IDP are supported using the **HTTP Redirect** binding and the **HTTP POST** binding. Message flows from the IDP to the service provider are supported via the **HTTP POST** binding.
132
133The package can produce signed SAML assertions, and can validate both signed and encrypted SAML assertions. It does not support signed or encrypted requests.
134
135## RelayState
136
137The _RelayState_ parameter allows you to pass user state information across the authentication flow. The most common use for this is to allow a user to request a deep link into your site, be redirected through the SAML login flow, and upon successful completion, be directed to the originally requested link, rather than the root.
138
139Unfortunately, _RelayState_ is less useful than it could be. Firstly, it is **not** authenticated, so anything you supply must be signed to avoid XSS or CSRF. Secondly, it is limited to 80 bytes in length, which precludes signing. (See section 3.6.3.1 of SAMLProfiles.)
140
141## References
142
143The SAML specification is a collection of PDFs (sadly):
144
145- [SAMLCore](http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) defines data types.
146
147- [SAMLBindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) defines the details of the HTTP requests in play.
148
149- [SAMLProfiles](http://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf) describes data flows.
150
151- [SAMLConformance](http://docs.oasis-open.org/security/saml/v2.0/saml-conformance-2.0-os.pdf) includes a support matrix for various parts of the protocol.
152
153[SAMLtest](https://samltest.id/) is a testing ground for SAML service and identity providers.
154
155## Security Issues
156
157Please do not report security issues in the issue tracker. Rather, please contact me directly at ross@kndr.org ([PGP Key `78B6038B3B9DFB88`](https://keybase.io/crewjam)). If your issue is *not* a security issue, please use the issue tracker so other contributors can help.
158