saml

package module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 7, 2026 License: BSD-2-Clause Imports: 34 Imported by: 255

README

SAML

Build Status

Package saml contains a partial implementation of the SAML standard in golang. SAML 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.

Introduction

In 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.

The 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.

Getting Started as a Service Provider

Let us assume we have a simple web application to protect. We'll modify this application so it uses SAML to authenticate users.

package main

import (
    "fmt"
    "net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func main() {
    app := http.HandlerFunc(hello)
    http.Handle("/hello", app)
    http.ListenAndServe(":8000", nil)
}

Each service provider must have an self-signed X.509 key pair established. You can generate your own with something like this:

openssl req -x509 -newkey rsa:2048 -keyout myservice.key -out myservice.cert -days 365 -nodes -subj "/CN=myservice.example.com"

We 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.dev, an identity provider designed for testing.

samltest.dev gives each app its own IDP, so first create an app with at least one test user. You can do this on the website or with the API:

curl -X POST https://www.samltest.dev/api/apps \
  -H "Content-Type: application/json" \
  -d '{"users":[{"email":"john@example.com","firstName":"John","lastName":"Doe"}]}'

The response contains the app's ID (for example app_01kg2nmcmp9gey67b0kxpqm643). The IDP metadata URL for the app is https://www.samltest.dev/apps/<APP_ID>/metadata.

package main

import (
	"context"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"net/http"
	"net/url"

	"github.com/crewjam/saml/samlsp"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s!", samlsp.AttributeFromContext(r.Context(), "displayName"))
}

func main() {
	keyPair, err := tls.LoadX509KeyPair("myservice.cert", "myservice.key")
	if err != nil {
		panic(err) // TODO handle error
	}
	keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
	if err != nil {
		panic(err) // TODO handle error
	}

	idpMetadataURL, err := url.Parse("https://www.samltest.dev/apps/<APP_ID>/metadata")
	if err != nil {
		panic(err) // TODO handle error
	}
	idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient,
		*idpMetadataURL)
	if err != nil {
		panic(err) // TODO handle error
	}

	rootURL, err := url.Parse("http://localhost:8000")
	if err != nil {
		panic(err) // TODO handle error
	}

	samlSP, _ := samlsp.New(samlsp.Options{
		URL:            *rootURL,
		Key:            keyPair.PrivateKey.(*rsa.PrivateKey),
		Certificate:    keyPair.Leaf,
		IDPMetadata: idpMetadata,
	})
	app := http.HandlerFunc(hello)
	http.Handle("/hello", samlSP.RequireAccount(app))
	http.Handle("/saml/", samlSP)
	http.ListenAndServe(":8000", nil)
}

Next we'll have to register our service provider with the identity provider to establish trust from the service provider to the IDP. samltest.dev doesn't take an uploaded metadata file. Instead, set the app's SP ACS URL and SP Entity ID, either under "SAML SP Settings" on https://www.samltest.dev/apps/<APP_ID> or with the API:

curl -X PUT https://www.samltest.dev/api/apps/<APP_ID> \
  -H "Content-Type: application/json" \
  -d '{"users":[{"email":"john@example.com","firstName":"John","lastName":"Doe"}],
       "spAcsUrl":"http://localhost:8000/saml/acs",
       "spEntityId":"http://localhost:8000/saml/metadata"}'

By default samlsp uses <root URL>/saml/acs as the ACS URL and <root URL>/saml/metadata as the entity ID (set Options.AcsPath, Options.MetadataPath and Options.SloPath to use different paths). You can view the service provider's metadata at localhost:8000/saml/metadata.

Now you should be able to authenticate. The flow should look like this:

  1. You browse to localhost:8000/hello

  2. The middleware redirects you to https://www.samltest.dev/apps/<APP_ID>/login

  3. samltest.dev asks which of the app's test users you want to log in as. There is no password.

  4. samltest.dev 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.

  5. The local service validates the response, issues a session cookie, and redirects you to the original URL, localhost:8000/hello.

  6. This time when localhost:8000/hello is requested there is a valid session and so the main content is served.

Reading the user's name, email and other attributes

You don't need to parse the SAML response yourself. After the middleware validates it, the handlers wrapped by RequireAccount can read the user's details from the request context:

func hello(w http.ResponseWriter, r *http.Request) {
	// The first value of an attribute, or "" if it is missing.
	email := samlsp.AttributeFromContext(r.Context(), "mail")

	session := samlsp.SessionFromContext(r.Context())

	// Every attribute, with all of its values.
	if s, ok := session.(samlsp.SessionWithAttributes); ok {
		for name, values := range s.GetAttributes() {
			fmt.Fprintf(w, "%s: %v\n", name, values)
		}
	}

	// The NameID from the assertion's Subject, often the user's email or ID.
	if claims, ok := session.(samlsp.JWTSessionClaims); ok {
		fmt.Fprintf(w, "NameID: %s, email: %s\n", claims.Subject, email)
	}
}

Each attribute is stored under its FriendlyName, or its Name when the IDP sends no FriendlyName (for example urn:oid:0.9.2342.19200300.100.1.3 or http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress). The IDP decides which attributes it sends and what they are called, so if one you expect is missing, check the IDP's attribute release settings. Listing every attribute as above shows exactly what you received. The SessionIndex attribute is added by this package, not sent as an attribute by the IDP.

Logging out

The middleware serves the SAML Single Logout endpoint, <root URL>/saml/slo, alongside the metadata and ACS endpoints. To let users log out, route a path of your application to HandleStartLogout:

http.Handle("/saml/", samlSP)
http.HandleFunc("/logout", samlSP.HandleStartLogout)

When a user visits /logout:

  1. HandleStartLogout deletes the session cookie and sends the browser to the IDP's SingleLogoutService with a LogoutRequest for the session's NameID and SessionIndex. It remembers the request's ID in a short-lived samlslo_ cookie, scoped to the SLO URL, just as login remembers the AuthnRequest. It uses the HTTP-Redirect binding if the IDP supports it, and HTTP-POST otherwise. If the IDP has no SingleLogoutService in its metadata, only the local session is ended.

  2. The IDP ends its own session and sends a LogoutResponse back to /saml/slo.

  3. The middleware validates the response's signature, issuer, destination and status, checks that its InResponseTo is the ID of the request it sent from this browser, and redirects the user to /. A response the SP did not ask for, or one that is replayed, is rejected.

The middleware also handles IDP initiated logout: when the IDP sends a signed LogoutRequest to /saml/slo, the middleware deletes the session cookie of that browser and answers the IDP with a LogoutResponse.

For single logout to work, the IDP needs to know the SLO URL. It is in the service provider's metadata, or you can enter <root URL>/saml/slo in the IDP's settings. Many IDPs require logout requests to be signed; set Options.SignRequest to sign them. If you need different behaviour, for example to end server-side sessions, the ServiceProvider methods MakeLogoutRequest, RedirectLogoutRequestURL, ParseLogoutResponse, ValidateLogoutRequest and MakeRedirectLogoutResponse are the building blocks HandleStartLogout and ServeSLO use.

Getting Started as an Identity Provider

Please see example/idp/ for a substantially complete example of how to use the library and helpers to be an identity provider.

Support

The 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.

This 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.

Both directions also support the HTTP POST SimpleSign binding (sstc-saml-binding-simplesign-cs-01), which posts the message like HTTP POST but signs it with a detached signature over the message XML, the RelayState and the signature algorithm, carried in the SigAlg and Signature form fields. The service provider accepts it at the ACS and for logout, and can send authentication requests and logout messages with it (MakeSimpleSignAuthenticationRequest, or samlsp.Options.Binding; samlsp.Options.UseSimpleSignResponse asks for SimpleSign responses). The identity provider accepts SimpleSign authentication requests and answers with SimpleSign when the service provider's ACS endpoint uses that binding.

The package can produce signed SAML assertions, and can validate both signed and encrypted SAML assertions. As an identity provider it also encrypts the assertions it produces, both for SP-initiated and IdP-initiated (ServeIDPInitiated) logins, whenever the service provider's metadata publishes an encryption certificate (a KeyDescriptor with use="encryption", or one with no use). The algorithms default to RSA-OAEP-MGF1P with SHA-1 and AES-128-CBC for compatibility; set IdentityProvider.AssertionEncrypter to choose others, for example xmlenc.OAEP_SHA256() with AES256GCM.

Customizing the session lifetime

Sessions last one hour by default. This used to be set with samlsp.Options.CookieMaxAge, which has been removed. To change it, set the MaxAge of both the session cookie and the JWT it holds, then assign the provider to the middleware:

sessionMaxAge := 12 * time.Hour

codec := samlsp.DefaultSessionCodec(opts)
codec.MaxAge = sessionMaxAge

sessionProvider := samlsp.DefaultSessionProvider(opts)
sessionProvider.MaxAge = sessionMaxAge
sessionProvider.Codec = codec

samlSP, _ := samlsp.New(opts)
samlSP.Session = sessionProvider

Setting only the cookie's MaxAge is not enough: the browser keeps the cookie, but the token in it is rejected once the JWT expires.

RelayState

The 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.

Unfortunately, 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.)

References

The SAML specification is a collection of PDFs (sadly):

SAMLTest is a free SAML identity provider and SCIM directory for testing SAML service providers.

Security Issues

Please do not report security issues in the issue tracker. Rather, please contact me directly at ross@kndr.org (PGP Key 78B6038B3B9DFB88). If your issue is not a security issue, please use the issue tracker so other contributors can help.

Documentation

Overview

Package saml contains a partial implementation of the SAML standard in golang. SAML 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.

Introduction

In 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.

The 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.

Breaking Changes

Version 0.4.0 introduces a few breaking changes to the _samlsp_ package in order to make the package more extensible, and to clean up the interfaces a bit. The default behavior remains the same, but you can now provide interface implementations of _RequestTracker_ (which tracks pending requests), _Session_ (which handles maintaining a session) and _OnError_ which handles reporting errors.

Public fields of _samlsp.Middleware_ have changed, so some usages may require adjustment. See [issue 231](https://github.com/crewjam/saml/issues/231) for details.

The option to provide an IDP metadata URL has been deprecated. Instead, we recommend that you use the `FetchMetadata()` function, or fetch the metadata yourself and use the new `ParseMetadata()` function, and pass the metadata in _samlsp.Options.IDPMetadata_.

Similarly, the _HTTPClient_ field is now deprecated because it was only used for fetching metdata, which is no longer directly implemented.

The fields that manage how cookies are set are deprecated as well. To customize how cookies are managed, provide custom implementation of _RequestTracker_ and/or _Session_, perhaps by extending the default implementations.

The deprecated fields have not been removed from the Options structure, but will be in future.

In particular we have deprecated the following fields in _samlsp.Options_:

- `Logger` - This was used to emit errors while validating, which is an anti-pattern. - `IDPMetadataURL` - Instead use `FetchMetadata()` - `HTTPClient` - Instead pass httpClient to FetchMetadata - `CookieMaxAge` - Instead set MaxAge on both the CookieSessionProvider and its JWTSessionCodec (see "Customizing the session lifetime" below) - `CookieName` - Instead assign a custom CookieRequestTracker or CookieSessionProvider - `CookieDomain` - Instead assign a custom CookieRequestTracker or CookieSessionProvider

Customizing the session lifetime

Sessions last one hour by default. To change that, set the MaxAge of both the session cookie and the JWT it holds, then assign the provider to the middleware:

sessionMaxAge := 12 * time.Hour

codec := samlsp.DefaultSessionCodec(opts)
codec.MaxAge = sessionMaxAge

sessionProvider := samlsp.DefaultSessionProvider(opts)
sessionProvider.MaxAge = sessionMaxAge
sessionProvider.Codec = codec

middleware, _ := samlsp.New(opts)
middleware.Session = sessionProvider

Setting only the cookie's MaxAge is not enough: the browser keeps the cookie, but the token in it is rejected once the JWT expires.

Getting Started as a Service Provider

Let us assume we have a simple web application to protect. We'll modify this application so it uses SAML to authenticate users.

```golang package main

import (

"fmt"
"net/http"

)

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func main() {
    app := http.HandlerFunc(hello)
    http.Handle("/hello", app)
    http.ListenAndServe(":8000", nil)
}

```

Each service provider must have an self-signed X.509 key pair established. You can generate your own with something like this:

openssl req -x509 -newkey rsa:2048 -keyout myservice.key -out myservice.cert -days 365 -nodes -subj "/CN=myservice.example.com"

We 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.dev](https://www.samltest.dev/), an identity provider designed for testing.

samltest.dev gives each app its own IDP, so first create an app with at least one test user. You can do this on the website or with the [API](https://www.samltest.dev/#api):

curl -X POST https://www.samltest.dev/api/apps \
  -H "Content-Type: application/json" \
  -d '{"users":[{"email":"john@example.com","firstName":"John","lastName":"Doe"}]}'

The response contains the app's ID (for example `app_01kg2nmcmp9gey67b0kxpqm643`). The IDP metadata URL for the app is `https://www.samltest.dev/apps/<APP_ID>/metadata`.

```golang package main

import (

"crypto/rsa"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"net/url"

"github.com/crewjam/saml/samlsp"

)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s!", samlsp.Token(r.Context()).Attributes.Get("cn"))
}

func main() {
	keyPair, err := tls.LoadX509KeyPair("myservice.cert", "myservice.key")
	if err != nil {
		panic(err) // TODO handle error
	}
	keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
	if err != nil {
		panic(err) // TODO handle error
	}

	idpMetadataURL, err := url.Parse("https://www.samltest.dev/apps/<APP_ID>/metadata")
	if err != nil {
		panic(err) // TODO handle error
	}

	rootURL, err := url.Parse("http://localhost:8000")
	if err != nil {
		panic(err) // TODO handle error
	}

	samlSP, _ := samlsp.New(samlsp.Options{
		URL:            *rootURL,
		Key:            keyPair.PrivateKey.(*rsa.PrivateKey),
		Certificate:    keyPair.Leaf,
		IDPMetadataURL: idpMetadataURL,
	})
	app := http.HandlerFunc(hello)
	http.Handle("/hello", samlSP.RequireAccount(app))
	http.Handle("/saml/", samlSP)
	http.ListenAndServe(":8000", nil)
}

```

Next we'll have to register our service provider with the identity provider to establish trust from the service provider to the IDP. samltest.dev doesn't take an uploaded metadata file. Instead, set the app's SP ACS URL and SP Entity ID, either under "SAML SP Settings" on `https://www.samltest.dev/apps/<APP_ID>` or with the API:

curl -X PUT https://www.samltest.dev/api/apps/<APP_ID> \
  -H "Content-Type: application/json" \
  -d '{"users":[{"email":"john@example.com","firstName":"John","lastName":"Doe"}],
       "spAcsUrl":"http://localhost:8000/saml/acs",
       "spEntityId":"http://localhost:8000/saml/metadata"}'

By default `samlsp` uses `<root URL>/saml/acs` as the ACS URL and `<root URL>/saml/metadata` as the entity ID. You can view the service provider's metadata at `localhost:8000/saml/metadata`.

Now you should be able to authenticate. The flow should look like this:

1. You browse to `localhost:8000/hello`

1. The middleware redirects you to `https://www.samltest.dev/apps/<APP_ID>/login`

1. samltest.dev asks which of the app's test users you want to log in as. There is no password.

1. samltest.dev 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.

1. The local service validates the response, issues a session cookie, and redirects you to the original URL, `localhost:8000/hello`.

1. This time when `localhost:8000/hello` is requested there is a valid session and so the main content is served.

Getting Started as an Identity Provider

Please see `example/idp/` for a substantially complete example of how to use the library and helpers to be an identity provider.

Support

The 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](http://saml2int.org).

This 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.

Both directions also support the HTTP POST SimpleSign binding (sstc-saml-binding-simplesign-cs-01), which signs the posted message with a detached signature in the SigAlg and Signature form fields. See HTTPPostSimpleSignBinding.

The package can produce signed SAML assertions, and can validate both signed and encrypted SAML assertions.

RelayState

The _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.

Unfortunately, _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.)

References

The SAML specification is a collection of PDFs (sadly):

- [SAMLCore](http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) defines data types.

- [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.

- [SAMLProfiles](http://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf) describes data flows.

- [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.

[SAMLTest](https://www.samltest.dev/) is a free SAML identity provider and SCIM directory for testing SAML service providers.

Security Issues

Please 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)).

Index

Constants

View Source
const (

	// StatusRequester means the request could not be performed due to an error on the part of the requester.
	StatusRequester = "urn:oasis:names:tc:SAML:2.0:status:Requester"

	// StatusResponder means the request could not be performed due to an error on the part of the SAML responder or SAML authority.
	StatusResponder = "urn:oasis:names:tc:SAML:2.0:status:Responder"

	// StatusVersionMismatch means the SAML responder could not process the request because the version of the request message was incorrect.
	StatusVersionMismatch = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"

	// StatusAuthnFailed means the responding provider was unable to successfully authenticate the principal.
	StatusAuthnFailed = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"

	// StatusInvalidAttrNameOrValue means Unexpected or invalid content was encountered within a <saml:Attribute> or <saml:AttributeValue> element.
	StatusInvalidAttrNameOrValue = "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue"

	// StatusInvalidNameIDPolicy means the responding provider cannot or will not support the requested name identifier policy.
	StatusInvalidNameIDPolicy = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"

	// StatusNoAuthnContext means the specified authentication context requirements cannot be met by the responder.
	StatusNoAuthnContext = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"

	// StatusNoAvailableIDP is used by an intermediary to indicate that none of the supported identity provider <Loc> elements in an <IDPList> can be resolved or that none of the supported identity providers are available.
	StatusNoAvailableIDP = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"

	// StatusNoPassive means Indicates the responding provider cannot authenticate the principal passively, as has been requested.
	StatusNoPassive = "urn:oasis:names:tc:SAML:2.0:status:NoPassive" //nolint:gosec

	// StatusNoSupportedIDP is used by an intermediary to indicate that none of the identity providers in an <IDPList> are supported by the intermediary.
	StatusNoSupportedIDP = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"

	// StatusPartialLogout is used by a session authority to indicate to a session participant that it was not able to propagate logout to all other session participants.
	StatusPartialLogout = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout"

	// StatusProxyCountExceeded means Indicates that a responding provider cannot authenticate the principal directly and is not permitted to proxy the request further.
	StatusProxyCountExceeded = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"

	// StatusRequestDenied means the SAML responder or SAML authority is able to process the request but has chosen not to respond. This status code MAY be used when there is concern about the security context of the request message or the sequence of request messages received from a particular requester.
	StatusRequestDenied = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied"

	// StatusRequestUnsupported means the SAML responder or SAML authority does not support the request.
	StatusRequestUnsupported = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"

	// StatusRequestVersionDeprecated means the SAML responder cannot process any requests with the protocol version specified in the request.
	StatusRequestVersionDeprecated = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated" //nolint:gosec

	// StatusRequestVersionTooHigh means the SAML responder cannot process the request because the protocol version specified in the request message is a major upgrade from the highest protocol version supported by the responder.
	StatusRequestVersionTooHigh = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"

	// StatusRequestVersionTooLow means the SAML responder cannot process the request because the protocol version specified in the request message is too low.
	StatusRequestVersionTooLow = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"

	// StatusResourceNotRecognized means the resource value provided in the request message is invalid or unrecognized.
	StatusResourceNotRecognized = "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"

	// StatusTooManyResponses means the response message would contain more elements than the SAML responder is able to return.
	StatusTooManyResponses = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses"

	// StatusUnknownAttrProfile means an entity that has no knowledge of a particular attribute profile has been presented with an attribute means drawn from that profile.
	StatusUnknownAttrProfile = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile"

	// StatusUnknownPrincipal means the responding provider does not recognize the principal specified or implied by the request.
	StatusUnknownPrincipal = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"

	// StatusUnsupportedBinding means the SAML responder cannot properly fulfill the request using the protocol binding specified in the request.
	StatusUnsupportedBinding = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"
)
View Source
const AlgSupportNamespace = "urn:oasis:names:tc:SAML:metadata:algsupport"

AlgSupportNamespace is the namespace of the SAML V2.0 Metadata Profile for Algorithm Support.

See https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-algsupport-v1.0-cs01.html

View Source
const DefaultCacheDuration = time.Hour * 24 * 1

DefaultCacheDuration is how long we ask the IDP to cache the SP metadata.

View Source
const DefaultValidDuration = time.Hour * 24 * 2

DefaultValidDuration is how long we assert that the SP metadata is valid.

View Source
const HTTPArtifactBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"

HTTPArtifactBinding is the official URN for the HTTP-Artifact binding (transport)

View Source
const HTTPPostBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"

HTTPPostBinding is the official URN for the HTTP-POST binding (transport)

View Source
const HTTPPostSimpleSignBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"

HTTPPostSimpleSignBinding is the official URN for the HTTP-POST-SimpleSign binding (transport), defined in sstc-saml-binding-simplesign-cs-01. It carries messages in an HTML form like HTTP-POST, but signs them with a detached signature over the message XML, the RelayState and the SigAlg instead of (or as well as) an XML signature.

The service provider can send authentication requests and logout messages with it (MakeSimpleSignAuthenticationRequest, MakeSimpleSignLogoutRequest, MakeSimpleSignLogoutResponse), and accepts it at the ACS (ParseResponse) and in the logout validation functions. The identity provider accepts authentication requests sent with it and uses it for responses to an AssertionConsumerService endpoint with this binding.

View Source
const HTTPRedirectBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"

HTTPRedirectBinding is the official URN for the HTTP-Redirect binding (transport)

View Source
const SOAPBinding = "urn:oasis:names:tc:SAML:2.0:bindings:SOAP"

SOAPBinding is the official URN for the SOAP binding (transport)

View Source
const SOAPBindingV1 = "urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"

SOAPBindingV1 is the URN for the SOAP binding in SAML 1.0

View Source
const ShibbolethMetadataNamespace = "urn:mace:shibboleth:metadata:1.0"

ShibbolethMetadataNamespace is the namespace of the Shibboleth metadata extensions, such as shibmd:Scope.

Variables

View Source
var (
	// ErrInvalidSignature is attached to every failure to validate the XML
	// signature on a Response, Assertion or ArtifactResponse. The more
	// specific errors below are attached in addition to it.
	ErrInvalidSignature = errors.New("saml: invalid signature")

	// ErrUntrustedCertificate is attached when the element is signed with a
	// certificate that is not one of the trusted IdP certificates (from the
	// IdP metadata, ServiceProvider.IDPCertificate, or the configured
	// fingerprint). This commonly means the IdP rotated its signing
	// certificate and the IdP metadata held by the SP needs to be updated.
	ErrUntrustedCertificate = errors.New("saml: signing certificate is not trusted")

	// ErrCertificateNotValidNow is attached when the element is signed with
	// a trusted certificate that is expired or not yet valid. See
	// ServiceProvider.IgnoreCertificateExpiry.
	ErrCertificateNotValidNow = errors.New("saml: signing certificate is expired or not yet valid")
)

Errors that the ServiceProvider attaches to signature validation failures, so that callers can tell them apart with errors.Is instead of matching error strings. They are reachable through the *InvalidResponseError that ParseResponse and ParseXMLResponse return:

assertion, err := sp.ParseResponse(r, requestIDs)
if errors.Is(err, saml.ErrUntrustedCertificate) {
	// the IdP signed with a certificate that is not in its metadata;
	// the metadata may be out of date
}

The message of the error returned is unchanged by this classification.

View Source
var (
	// ErrMalformedMessage is attached when a message cannot be decoded or
	// parsed: bad base64, deflate or form encoding, invalid XML, a missing root
	// element, an element that cannot be unmarshalled, or more instances of
	// an element than allowed.
	ErrMalformedMessage = errors.New("saml: malformed message")

	// ErrMissingElement is attached when a required element or value is
	// absent: no Assertion, an Assertion with no Subject, Conditions, ID,
	// SubjectConfirmationData or bearer SubjectConfirmation, a LogoutRequest
	// with no NameID, an AuthnRequest with no Issuer, or another required
	// child element.
	ErrMissingElement = errors.New("saml: required element is missing")

	// ErrExpired is attached when a message or assertion is no longer valid:
	// its IssueInstant is older than MaxIssueDelay, or a NotOnOrAfter
	// (allowing MaxClockSkew) has passed. Check the clocks of the IdP and
	// SP if this happens for fresh logins.
	ErrExpired = errors.New("saml: expired")

	// ErrNotYetValid is attached when a message or assertion is not valid
	// yet: a Conditions or SubjectConfirmationData NotBefore (allowing
	// MaxClockSkew) or a LogoutRequest IssueInstant in the future. This usually means the IdP and SP clocks
	// disagree.
	ErrNotYetValid = errors.New("saml: not yet valid")

	// ErrIssuerMismatch is attached when the Issuer of a message or
	// assertion is not the EntityID in the IdP metadata.
	ErrIssuerMismatch = errors.New("saml: issuer does not match the IdP metadata")

	// ErrDestinationMismatch is attached when a message was not addressed to
	// its recipient. At the SP: a Destination that is neither the requested
	// URL nor AcsURL (or SloURL, for logout messages), or a
	// SubjectConfirmationData Recipient that is not AcsURL. At the IdP: an
	// AuthnRequest Destination that is not IdentityProvider.SSOURL.
	ErrDestinationMismatch = errors.New("saml: destination does not match the recipient")

	// ErrRequestIDMismatch is attached when an InResponseTo does not name
	// one of the requests this SP made (possibleRequestIDs), or the artifact
	// request ID for an ArtifactResponse.
	ErrRequestIDMismatch = errors.New("saml: InResponseTo does not match a request ID")

	// ErrAudienceMismatch is attached when the assertion is not restricted
	// to this SP's audience, or ServiceProvider.ValidateAudienceRestriction
	// rejects it.
	ErrAudienceMismatch = errors.New("saml: audience restriction does not match this service provider")

	// ErrAuthnContextMismatch is attached when
	// ServiceProvider.ValidateAuthnContextClassRef is set and none of the
	// assertion's AuthnContextClassRefs is one of those in
	// ServiceProvider.RequestedAuthnContext: the user did not authenticate
	// the way the SP asked.
	ErrAuthnContextMismatch = errors.New("saml: authentication context does not match the requested one")

	// ErrDecryptionFailed is attached when an EncryptedAssertion cannot be
	// decrypted with the SP's keys.
	ErrDecryptionFailed = errors.New("saml: cannot decrypt")

	// ErrArtifactResolution is attached when resolving an artifact with the
	// IdP fails: building the request, the HTTP exchange, or a non-200
	// status.
	ErrArtifactResolution = errors.New("saml: artifact resolution failed")

	// ErrUnknownServiceProvider is attached when an AuthnRequest's Issuer is
	// not a service provider the IdP knows: its ServiceProviderProvider
	// returned os.ErrNotExist, which the error also matches.
	ErrUnknownServiceProvider = errors.New("saml: unknown service provider")

	// ErrUnknownAssertionConsumerService is attached when the
	// AssertionConsumerServiceURL or AssertionConsumerServiceIndex of an
	// AuthnRequest is not in the service provider's metadata, or the
	// metadata has no usable assertion consumer service. The SP metadata the
	// IdP holds may be out of date.
	ErrUnknownAssertionConsumerService = errors.New("saml: unknown assertion consumer service")

	// ErrUnsupported is attached when something is used that is not
	// implemented. At the IdP: an HTTP method other than GET or POST, a SAML
	// version other than 2.0, signed AuthnRequests (WantAuthnRequestsSigned),
	// or an assertion consumer service binding other than HTTP-POST. At the
	// SP: a RequestedAuthnContext Comparison other than "exact" when
	// ValidateAuthnContextClassRef is set.
	ErrUnsupported = errors.New("saml: not supported")

	// ErrInvalidCertificate is attached when a certificate cannot be base64
	// decoded or parsed: an IdP signing certificate in the IdP metadata or
	// ServiceProvider.IDPCertificate, the certificate embedded in a
	// signature when checking ServiceProvider.IDPCertificateFingerprint, or
	// an SP encryption certificate in the SP metadata the IdP holds. At the
	// SP the error also matches ErrInvalidSignature.
	ErrInvalidCertificate = errors.New("saml: invalid certificate")
)

Errors attached to the other reasons a message is rejected: by the ServiceProvider for a Response, Assertion, ArtifactResponse, LogoutResponse or LogoutRequest, and by the IdentityProvider for an AuthnRequest (from NewIdpAuthnRequest and IdpAuthnRequest.Validate). Like the signature errors above, they are matched with errors.Is, through *InvalidResponseError where one is returned, and leave the message of the error unchanged.

A rejected logout response whose status is not success also matches ErrBadStatus with errors.As, as a rejected Response already does.

View Source
var Clock *dsig.Clock

Clock is assigned to dsig validation and signing contexts if it is not nil, otherwise the default clock is used.

View Source
var ErrAssertionReplayed = errors.New("assertion has already been used")

ErrAssertionReplayed is returned by an AssertionReplayCache for an assertion ID it has already recorded.

View Source
var MaxClockSkew = time.Second * 180

MaxClockSkew allows for leeway for clock skew between the IDP and SP when validating assertions. It defaults to 180 seconds (matches shibboleth).

View Source
var MaxIssueDelay = time.Second * 90

MaxIssueDelay is the longest allowed time between when a SAML assertion is issued by the IDP and the time it is received by ParseResponse. This is used to prevent old responses from being replayed (while allowing for some clock drift between the SP and IDP).

View Source
var Metadata = struct{}{}

Metadata as been renamed to EntityDescriptor

This change was made to be consistent with the rest of the API which uses names from the SAML specification for types.

This is a tombstone to help you discover this fact. You should update references to saml.Metadata to be saml.EntityDescriptor.

View Source
var RandReader = rand.Reader

RandReader is the io.Reader that produces cryptographically random bytes when they are need by the library. The default value is rand.Reader, but it can be replaced for testing.

View Source
var StatusSuccess = "urn:oasis:names:tc:SAML:2.0:status:Success"

StatusSuccess means the request succeeded. Additional information MAY be returned in the <StatusMessage> and/or <StatusDetail> elements.

TODO(ross): this value is mostly constant, but is mutated in tests. Fix the hacky test so this can be const.

View Source
var TimeNow = func() time.Time { return time.Now().UTC() }

TimeNow is a function that returns the current time. The default value is time.Now, but it can be replaced for testing.

Functions

func GetSigningContext added in v0.4.6

func GetSigningContext(sp *ServiceProvider) (*dsig.SigningContext, error)

GetSigningContext returns a dsig.SigningContext initialized based on the Service Provider's configuration

Types

type AffiliationDescriptor

type AffiliationDescriptor struct {
	AffiliationOwnerID string        `xml:"affiliationOwnerID,attr"`
	ID                 string        `xml:",attr"`
	ValidUntil         time.Time     `xml:"validUntil,attr,omitempty"`
	CacheDuration      time.Duration `xml:"cacheDuration,attr"`
	Signature          *etree.Element
	Extensions         *Extensions     `xml:"urn:oasis:names:tc:SAML:2.0:metadata Extensions,omitempty"`
	AffiliateMembers   []string        `xml:"AffiliateMember"`
	KeyDescriptors     []KeyDescriptor `xml:"KeyDescriptor"`
}

AffiliationDescriptor represents the SAML AffiliationDescriptor object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.5

func (AffiliationDescriptor) MarshalXML added in v0.6.0

func (m AffiliationDescriptor) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler, writing Signature as XML.

func (*AffiliationDescriptor) UnmarshalXML added in v0.6.0

func (m *AffiliationDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler, reading Signature as XML.

type ArtifactResolve added in v0.4.6

type ArtifactResolve struct {
	XMLName      xml.Name  `xml:"urn:oasis:names:tc:SAML:2.0:protocol ArtifactResolve"`
	ID           string    `xml:",attr"`
	Version      string    `xml:",attr"`
	IssueInstant time.Time `xml:",attr"`
	Issuer       *Issuer   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	Signature    *etree.Element
	Artifact     string `xml:"urn:oasis:names:tc:SAML:2.0:protocol Artifact"`
}

ArtifactResolve represents the SAML object of the same name.

func (*ArtifactResolve) Element added in v0.4.6

func (r *ArtifactResolve) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*ArtifactResolve) MarshalXML added in v0.4.6

func (r *ArtifactResolve) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*ArtifactResolve) SoapRequest added in v0.4.6

func (r *ArtifactResolve) SoapRequest() *etree.Element

SoapRequest returns a SOAP Envelope contining the ArtifactResolve request

func (*ArtifactResolve) UnmarshalXML added in v0.4.6

func (r *ArtifactResolve) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type ArtifactResponse added in v0.4.6

type ArtifactResponse struct {
	XMLName      xml.Name  `xml:"urn:oasis:names:tc:SAML:2.0:protocol ArtifactResponse"`
	ID           string    `xml:",attr"`
	InResponseTo string    `xml:",attr"`
	Version      string    `xml:",attr"`
	IssueInstant time.Time `xml:",attr"`
	Issuer       *Issuer   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	Signature    *etree.Element
	Status       Status   `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`
	Response     Response `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"`
}

ArtifactResponse represents the SAML object of the same name.

func (*ArtifactResponse) Element added in v0.4.6

func (r *ArtifactResponse) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*ArtifactResponse) MarshalXML added in v0.4.6

func (r *ArtifactResponse) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*ArtifactResponse) UnmarshalXML added in v0.4.6

func (r *ArtifactResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type Assertion

type Assertion struct {
	XMLName      xml.Name  `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"`
	ID           string    `xml:",attr"`
	IssueInstant time.Time `xml:",attr"`
	Version      string    `xml:",attr"`
	Issuer       Issuer    `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	Signature    *etree.Element
	Subject      *Subject
	Conditions   *Conditions `xml:"urn:oasis:names:tc:SAML:2.0:assertion Conditions"`
	// Advice *Advice
	// Statements []Statement
	AuthnStatements []AuthnStatement `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnStatement"`
	// AuthzDecisionStatements []AuthzDecisionStatement
	AttributeStatements []AttributeStatement `xml:"urn:oasis:names:tc:SAML:2.0:assertion AttributeStatement"`
}

Assertion represents the SAML element Assertion.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.3.3

func (*Assertion) Element

func (a *Assertion) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*Assertion) MarshalXML added in v0.6.0

func (a *Assertion) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*Assertion) UnmarshalXML

func (a *Assertion) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type AssertionAttribute

type AssertionAttribute struct {
	FriendlyName string
	Name         string
	Value        string
}

AssertionAttribute represents an attribute of the user extracted from a SAML Assertion.

type AssertionAttributes

type AssertionAttributes []AssertionAttribute

AssertionAttributes is a list of AssertionAttribute

func (AssertionAttributes) Get

Get returns the assertion attribute whose Name or FriendlyName matches name, or nil if no matching attribute is found.

type AssertionMaker

type AssertionMaker interface {
	// MakeAssertion constructs an assertion from session and the request and
	// assigns it to req.Assertion.
	MakeAssertion(req *IdpAuthnRequest, session *Session) error
}

AssertionMaker is an interface used by IdentityProvider to construct the assertion for a request. The default implementation is DefaultAssertionMaker, which is used if not AssertionMaker is specified.

type AssertionReplayCache added in v0.6.0

type AssertionReplayCache interface {
	// Consume atomically records assertionID as used until expiresAt, the
	// last moment the ServiceProvider would accept the assertion; after
	// that the record may be dropped. It returns ErrAssertionReplayed if
	// assertionID is already recorded, and any other error if it cannot
	// record it. Any error refuses the assertion.
	Consume(assertionID string, expiresAt time.Time) error
}

AssertionReplayCache records the IDs of accepted assertions, so that each is accepted only once. Implementations must be safe for concurrent use, and should be shared by every server that accepts assertions for the same service provider.

type Attribute

type Attribute struct {
	FriendlyName string           `xml:",attr"`
	Name         string           `xml:",attr"`
	NameFormat   string           `xml:",attr"`
	Values       []AttributeValue `xml:"urn:oasis:names:tc:SAML:2.0:assertion AttributeValue"`
}

Attribute represents the SAML element Attribute.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1

func (*Attribute) Element

func (a *Attribute) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type AttributeAuthorityDescriptor

type AttributeAuthorityDescriptor struct {
	RoleDescriptor
	AttributeServices          []Endpoint     `xml:"AttributeService"`
	AssertionIDRequestServices []Endpoint     `xml:"AssertionIDRequestService"`
	NameIDFormats              []NameIDFormat `xml:"NameIDFormat"`
	AttributeProfiles          []string       `xml:"AttributeProfile"`
	Attributes                 []Attribute    `xml:"Attribute"`
}

AttributeAuthorityDescriptor represents the SAML AttributeAuthorityDescriptor object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.7

func (AttributeAuthorityDescriptor) MarshalXML added in v0.6.0

MarshalXML implements xml.Marshaler

func (*AttributeAuthorityDescriptor) UnmarshalXML added in v0.6.0

func (m *AttributeAuthorityDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type AttributeConsumingService

type AttributeConsumingService struct {
	Index               int                  `xml:"index,attr"`
	IsDefault           *bool                `xml:"isDefault,attr"`
	ServiceNames        []LocalizedName      `xml:"ServiceName"`
	ServiceDescriptions []LocalizedName      `xml:"ServiceDescription"`
	RequestedAttributes []RequestedAttribute `xml:"RequestedAttribute"`
}

AttributeConsumingService represents the SAML AttributeConsumingService object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.4.1

type AttributeStatement

type AttributeStatement struct {
	Attributes []Attribute `xml:"urn:oasis:names:tc:SAML:2.0:assertion Attribute"`
}

AttributeStatement represents the SAML element AttributeStatement.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3

func (*AttributeStatement) Element

func (a *AttributeStatement) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type AttributeValue

type AttributeValue struct {
	Type   string  `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"`
	Value  string  `xml:",chardata"`
	NameID *NameID `xml:"urn:oasis:names:tc:SAML:2.0:assertion NameID"`
}

AttributeValue represents the SAML element AttributeValue.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1.1

func (*AttributeValue) Element

func (a *AttributeValue) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type Audience

type Audience struct {
	Value string `xml:",chardata"`
}

Audience represents the SAML element Audience.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4

func (*Audience) Element

func (a *Audience) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type AudienceRestriction

type AudienceRestriction struct {
	Audience            Audience   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Audience"`
	AdditionalAudiences []Audience `xml:"-"`
}

AudienceRestriction represents the SAML element AudienceRestriction.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4

An AudienceRestriction lists one or more audiences, and is satisfied when the relying party is any one of them. Audience holds the first one, and AdditionalAudiences holds the rest, in document order.

func (*AudienceRestriction) AllAudiences added in v0.6.0

func (a *AudienceRestriction) AllAudiences() []Audience

AllAudiences returns every audience in the restriction: Audience followed by AdditionalAudiences.

func (*AudienceRestriction) Element

func (a *AudienceRestriction) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*AudienceRestriction) MarshalXML added in v0.6.0

func (a *AudienceRestriction) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*AudienceRestriction) UnmarshalXML added in v0.6.0

func (a *AudienceRestriction) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type AuthenticatingAuthority added in v0.6.0

type AuthenticatingAuthority struct {
	Value string `xml:",chardata"`
}

AuthenticatingAuthority represents the SAML element AuthenticatingAuthority.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2

func (*AuthenticatingAuthority) Element added in v0.6.0

func (a *AuthenticatingAuthority) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type AuthnAuthorityDescriptor

type AuthnAuthorityDescriptor struct {
	RoleDescriptor
	AuthnQueryServices         []Endpoint     `xml:"AuthnQueryService"`
	AssertionIDRequestServices []Endpoint     `xml:"AssertionIDRequestService"`
	NameIDFormats              []NameIDFormat `xml:"NameIDFormat"`
}

AuthnAuthorityDescriptor represents the SAML AuthnAuthorityDescriptor object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.5

func (AuthnAuthorityDescriptor) MarshalXML added in v0.6.0

func (m AuthnAuthorityDescriptor) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*AuthnAuthorityDescriptor) UnmarshalXML added in v0.6.0

func (m *AuthnAuthorityDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type AuthnContext

type AuthnContext struct {
	AuthnContextClassRef      *AuthnContextClassRef     `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnContextClassRef"`
	AuthenticatingAuthorities []AuthenticatingAuthority `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthenticatingAuthority"`
}

AuthnContext represents the SAML element AuthnContext.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2

func (*AuthnContext) Element

func (a *AuthnContext) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type AuthnContextClassRef

type AuthnContextClassRef struct {
	Value string `xml:",chardata"`
}

AuthnContextClassRef represents the SAML element AuthnContextClassRef.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2

func (*AuthnContextClassRef) Element

func (a *AuthnContextClassRef) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type AuthnRequest

type AuthnRequest struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol AuthnRequest"`

	ID           string    `xml:",attr"`
	Version      string    `xml:",attr"`
	IssueInstant time.Time `xml:",attr"`
	Destination  string    `xml:",attr"`
	Consent      string    `xml:",attr"`
	Issuer       *Issuer   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	Signature    *etree.Element

	Subject               *Subject
	NameIDPolicy          *NameIDPolicy `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"`
	Conditions            *Conditions   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Conditions"`
	RequestedAuthnContext *RequestedAuthnContext
	Scoping               *Scoping `xml:"urn:oasis:names:tc:SAML:2.0:protocol Scoping"`

	ForceAuthn                     *bool  `xml:",attr"`
	IsPassive                      *bool  `xml:",attr"`
	AssertionConsumerServiceIndex  string `xml:",attr"`
	AssertionConsumerServiceURL    string `xml:",attr"`
	ProtocolBinding                string `xml:",attr"`
	AttributeConsumingServiceIndex string `xml:",attr"`
	ProviderName                   string `xml:",attr"`
}

AuthnRequest represents the SAML object of the same name, a request from a service provider to authenticate a user.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*AuthnRequest) Element

func (r *AuthnRequest) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*AuthnRequest) MarshalXML

func (r *AuthnRequest) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*AuthnRequest) Post

func (r *AuthnRequest) Post(relayState string) []byte

Post returns an HTML form suitable for using the HTTP-POST binding with the request

func (*AuthnRequest) PostWithNonce added in v0.6.0

func (r *AuthnRequest) PostWithNonce(relayState, nonce string) []byte

PostWithNonce is like Post, but if nonce is not empty it is set as the nonce attribute of the form's auto-submit <script> element, so that the form can be served under a Content-Security-Policy that allows scripts by nonce.

func (*AuthnRequest) Redirect

func (r *AuthnRequest) Redirect(relayState string, sp *ServiceProvider) (*url.URL, error)

Redirect returns a URL suitable for using the redirect binding with the request. If sp.SignatureMethod is set, the query string is signed as described in saml-bindings-2.0-os section 3.4.4.1.

func (*AuthnRequest) SimpleSign added in v0.6.0

func (r *AuthnRequest) SimpleSign(relayState string, sp *ServiceProvider) ([]byte, error)

SimpleSign returns an auto-submitting HTML form that sends the request to its Destination with the HTTP-POST-SimpleSign binding, signed with sp's Key and SignatureMethod, which must be set. An XML signature the request already carries is kept.

func (*AuthnRequest) SimpleSignWithNonce added in v0.6.0

func (r *AuthnRequest) SimpleSignWithNonce(relayState, nonce string, sp *ServiceProvider) ([]byte, error)

SimpleSignWithNonce is like SimpleSign, but if nonce is not empty it is set as the nonce attribute of the form's auto-submit <script> element, as PostWithNonce does.

func (*AuthnRequest) UnmarshalXML

func (r *AuthnRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type AuthnStatement

type AuthnStatement struct {
	AuthnInstant        time.Time        `xml:",attr"`
	SessionIndex        string           `xml:",attr"`
	SessionNotOnOrAfter *time.Time       `xml:",attr,omitempty"`
	SubjectLocality     *SubjectLocality `xml:"urn:oasis:names:tc:SAML:2.0:assertion SubjectLocality"`
	AuthnContext        AuthnContext     `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnContext"`
}

AuthnStatement represents the SAML element AuthnStatement.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2

func (*AuthnStatement) Element

func (a *AuthnStatement) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*AuthnStatement) MarshalXML

func (a *AuthnStatement) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*AuthnStatement) UnmarshalXML

func (a *AuthnStatement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type Conditions

type Conditions struct {
	NotBefore            time.Time             `xml:",attr"`
	NotOnOrAfter         time.Time             `xml:",attr"`
	AudienceRestrictions []AudienceRestriction `xml:"urn:oasis:names:tc:SAML:2.0:assertion AudienceRestriction"`
	OneTimeUse           *OneTimeUse           `xml:"urn:oasis:names:tc:SAML:2.0:assertion OneTimeUse"`
	ProxyRestriction     *ProxyRestriction     `xml:"urn:oasis:names:tc:SAML:2.0:assertion ProxyRestriction"`
}

Conditions represents the SAML element Conditions.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1

func (*Conditions) Element

func (c *Conditions) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*Conditions) MarshalXML

func (c *Conditions) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*Conditions) UnmarshalXML

func (c *Conditions) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type ContactPerson

type ContactPerson struct {
	ContactType      string `xml:"contactType,attr"`
	Company          string
	GivenName        string
	SurName          string
	EmailAddresses   []string `xml:"EmailAddress"`
	TelephoneNumbers []string `xml:"TelephoneNumber"`
}

ContactPerson represents the SAML element ContactPerson.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2.2

type DefaultAssertionMaker

type DefaultAssertionMaker struct {
}

DefaultAssertionMaker produces a SAML assertion for the given request and assigns it to req.Assertion.

func (DefaultAssertionMaker) MakeAssertion

func (DefaultAssertionMaker) MakeAssertion(req *IdpAuthnRequest, session *Session) error

MakeAssertion implements AssertionMaker. It produces a SAML assertion from the given request and assigns it to req.Assertion.

type DefaultResponseWriter added in v0.6.0

type DefaultResponseWriter struct{}

DefaultResponseWriter is the default ResponseWriter. It calls req.WriteResponse, which writes an auto-submitting HTML form (see IdentityProvider.ResponseFormTemplate) that posts the response to the service provider using the HTTP-POST binding, or, when the ACS endpoint uses the HTTP-POST-SimpleSign binding, using that binding (see IdentityProvider.SimpleSignResponseFormTemplate).

func (DefaultResponseWriter) WriteResponse added in v0.6.0

WriteResponse implements ResponseWriter.

type DigestMethod added in v0.6.0

type DigestMethod struct {
	XMLName   xml.Name `xml:"urn:oasis:names:tc:SAML:metadata:algsupport DigestMethod"`
	Algorithm string   `xml:"Algorithm,attr"`
}

DigestMethod represents the alg:DigestMethod element: an XML Signature digest algorithm the entity supports.

See https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-algsupport-v1.0-cs01.html §2.3

type Duration

type Duration time.Duration

Duration is a time.Duration that uses the xsd:duration format for text marshalling and unmarshalling.

func (Duration) MarshalText

func (d Duration) MarshalText() ([]byte, error)

MarshalText implements the encoding.TextMarshaler interface.

func (*Duration) UnmarshalText

func (d *Duration) UnmarshalText(text []byte) error

UnmarshalText implements the encoding.TextUnmarshaler interface.

type EncryptionMethod

type EncryptionMethod struct {
	Algorithm string `xml:"Algorithm,attr"`
	// KeySize is the optional xenc:KeySize child, which states the key size
	// in bits for algorithms that allow more than one.
	KeySize *int `xml:"http://www.w3.org/2001/04/xmlenc# KeySize,omitempty"`
}

EncryptionMethod represents the XMLSEC object of the same name

type Endpoint

type Endpoint struct {
	Binding          string `xml:"Binding,attr"`
	Location         string `xml:"Location,attr"`
	ResponseLocation string `xml:"ResponseLocation,attr,omitempty"`
}

Endpoint represents the SAML EndpointType object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.2

func (*Endpoint) UnmarshalXML added in v0.4.14

func (m *Endpoint) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type EntitiesDescriptor

type EntitiesDescriptor struct {
	XMLName             xml.Name       `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntitiesDescriptor"`
	ID                  *string        `xml:",attr,omitempty"`
	ValidUntil          *time.Time     `xml:"validUntil,attr,omitempty"`
	CacheDuration       *time.Duration `xml:"cacheDuration,attr,omitempty"`
	Name                *string        `xml:",attr,omitempty"`
	Signature           *etree.Element
	Extensions          *Extensions          `xml:"urn:oasis:names:tc:SAML:2.0:metadata Extensions,omitempty"`
	EntitiesDescriptors []EntitiesDescriptor `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntitiesDescriptor"`
	EntityDescriptors   []EntityDescriptor   `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"`
}

EntitiesDescriptor represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.1

func (EntitiesDescriptor) MarshalXML added in v0.5.0

func (m EntitiesDescriptor) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*EntitiesDescriptor) UnmarshalXML added in v0.5.0

func (m *EntitiesDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type EntityDescriptor

type EntityDescriptor struct {
	XMLName                       xml.Name      `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"`
	EntityID                      string        `xml:"entityID,attr"`
	ID                            string        `xml:",attr,omitempty"`
	ValidUntil                    time.Time     `xml:"validUntil,attr,omitempty"`
	CacheDuration                 time.Duration `xml:"cacheDuration,attr,omitempty"`
	Signature                     *etree.Element
	Extensions                    *Extensions                    `xml:"urn:oasis:names:tc:SAML:2.0:metadata Extensions,omitempty"`
	RoleDescriptors               []RoleDescriptor               `xml:"RoleDescriptor"`
	IDPSSODescriptors             []IDPSSODescriptor             `xml:"IDPSSODescriptor"`
	SPSSODescriptors              []SPSSODescriptor              `xml:"SPSSODescriptor"`
	AuthnAuthorityDescriptors     []AuthnAuthorityDescriptor     `xml:"AuthnAuthorityDescriptor"`
	AttributeAuthorityDescriptors []AttributeAuthorityDescriptor `xml:"AttributeAuthorityDescriptor"`
	PDPDescriptors                []PDPDescriptor                `xml:"PDPDescriptor"`
	AffiliationDescriptor         *AffiliationDescriptor
	Organization                  *Organization
	ContactPerson                 *ContactPerson
	AdditionalMetadataLocations   []string `xml:"AdditionalMetadataLocation"`
}

EntityDescriptor represents the SAML EntityDescriptor object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2

func (EntityDescriptor) MarshalXML

func (m EntityDescriptor) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*EntityDescriptor) UnmarshalXML

func (m *EntityDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type ErrBadStatus added in v0.3.1

type ErrBadStatus struct {
	Status string
}

ErrBadStatus is returned when the assertion provided is valid but the status code is not "urn:oasis:names:tc:SAML:2.0:status:Success".

func (ErrBadStatus) Error added in v0.3.1

func (e ErrBadStatus) Error() string

type ExtensionElement added in v0.6.0

type ExtensionElement struct {
	XMLName  xml.Name
	Attrs    []xml.Attr         `xml:",any,attr"`
	CharData string             `xml:",chardata"`
	Children []ExtensionElement `xml:",any"`
}

ExtensionElement is a generic XML element, used for extension elements that this package does not model. Names are kept with their namespace URIs rather than their prefixes, so the element can be written out again with its namespaces intact. Character data is kept, but its position relative to child elements (mixed content) is not.

func (*ExtensionElement) UnmarshalXML added in v0.6.0

func (m *ExtensionElement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type Extensions added in v0.6.0

type Extensions struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata Extensions"`

	// SigningMethods and DigestMethods are the alg:SigningMethod and
	// alg:DigestMethod elements of the Metadata Profile for Algorithm Support.
	SigningMethods []SigningMethod `xml:"urn:oasis:names:tc:SAML:metadata:algsupport SigningMethod"`
	DigestMethods  []DigestMethod  `xml:"urn:oasis:names:tc:SAML:metadata:algsupport DigestMethod"`

	// ShibbolethScopes are the shibmd:Scope elements an identity provider
	// publishes in its IDPSSODescriptor or AttributeAuthorityDescriptor.
	ShibbolethScopes []ShibbolethScope `xml:"urn:mace:shibboleth:metadata:1.0 Scope"`

	// Other holds the extension elements that have no field of their own.
	Other []ExtensionElement `xml:",any"`
}

Extensions represents the SAML metadata element md:Extensions, which holds extension elements from namespaces other than the SAML metadata namespace.

Elements this package knows are decoded into their own fields. Any other element is kept in Other, so that it is not lost when metadata is parsed and then written out again. Elements are written in field order, so the order of elements in Other relative to the known elements is not preserved.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.1

type IDPEntry added in v0.6.0

type IDPEntry struct {
	XMLName    xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol IDPEntry"`
	ProviderID string   `xml:",attr"`
	Name       string   `xml:",attr,omitempty"`
	Loc        string   `xml:",attr,omitempty"`
}

IDPEntry represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf § 3.4.1.3.1

func (*IDPEntry) Element added in v0.6.0

func (a *IDPEntry) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type IDPList added in v0.6.0

type IDPList struct {
	XMLName     xml.Name   `xml:"urn:oasis:names:tc:SAML:2.0:protocol IDPList"`
	IDPEntries  []IDPEntry `xml:"urn:oasis:names:tc:SAML:2.0:protocol IDPEntry"`
	GetComplete string     `xml:"urn:oasis:names:tc:SAML:2.0:protocol GetComplete,omitempty"`
}

IDPList represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf § 3.4.1.3

func (*IDPList) Element added in v0.6.0

func (a *IDPList) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type IDPSSODescriptor

type IDPSSODescriptor struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata IDPSSODescriptor"`
	SSODescriptor
	WantAuthnRequestsSigned *bool `xml:",attr"`

	SingleSignOnServices       []Endpoint  `xml:"SingleSignOnService"`
	ArtifactResolutionServices []Endpoint  `xml:"ArtifactResolutionService"`
	NameIDMappingServices      []Endpoint  `xml:"NameIDMappingService"`
	AssertionIDRequestServices []Endpoint  `xml:"AssertionIDRequestService"`
	AttributeProfiles          []string    `xml:"AttributeProfile"`
	Attributes                 []Attribute `xml:"Attribute"`
}

IDPSSODescriptor represents the SAML IDPSSODescriptorType object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.3

func (IDPSSODescriptor) MarshalXML added in v0.6.0

func (m IDPSSODescriptor) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*IDPSSODescriptor) UnmarshalXML added in v0.6.0

func (m *IDPSSODescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type IdentityProvider

type IdentityProvider struct {
	Key                     crypto.PrivateKey
	Signer                  crypto.Signer
	Logger                  logger.Interface
	Certificate             *x509.Certificate
	Intermediates           []*x509.Certificate
	MetadataURL             url.URL
	SSOURL                  url.URL
	LoginURL                url.URL
	LogoutURL               url.URL
	ServiceProviderProvider ServiceProviderProvider
	SessionProvider         SessionProvider
	AssertionMaker          AssertionMaker
	SignatureMethod         string
	ValidDuration           *time.Duration
	ResponseFormTemplate    *template.Template

	// SimpleSignResponseFormTemplate, if set, replaces the default
	// auto-submitting HTML form used to send responses to ACS endpoints with
	// the HTTP-POST-SimpleSign binding. It is executed with an
	// IdpAuthnRequestSimpleSignForm and must post its SAMLResponse, SigAlg
	// and Signature fields, and RelayState when it is not empty (an empty
	// RelayState field would be included in the signed content).
	SimpleSignResponseFormTemplate *template.Template

	// AdvertiseSimpleSignSSO, if true, adds an HTTP-POST-SimpleSign
	// SingleSignOnService endpoint at SSOURL to the metadata. ServeSSO
	// accepts SimpleSign authentication requests whether or not this is set.
	AdvertiseSimpleSignSSO bool

	// ResponseWriter, if set, writes the HTTP response carrying the SAML
	// response in ServeSSO and ServeIDPInitiated. If nil,
	// DefaultResponseWriter is used, which posts the response with the
	// HTML form from ResponseFormTemplate.
	ResponseWriter ResponseWriter

	// OnError, if non-nil, is called when ServeSSO, ServeIDPInitiated or
	// ServeMetadata cannot complete a request, in place of DefaultOnError,
	// which logs err to Logger and responds with status. status is the HTTP
	// status the IdentityProvider would respond with: StatusBadRequest for a
	// request that cannot be parsed or is invalid, StatusNotFound for an
	// IdP-initiated request for an unknown service provider, and
	// StatusInternalServerError otherwise. err can be matched with errors.Is
	// against the error values of this package, such as
	// ErrUnknownServiceProvider or ErrInvalidCertificate.
	//
	// OnError must write the response. When writing the SAML response or
	// the metadata failed part way, some of it may already have been
	// written to w.
	OnError func(w http.ResponseWriter, r *http.Request, status int, err error)

	// ExtraCertificates are additional certificates published in the IdP
	// metadata as signing keys, after Certificate. They are never used to
	// sign anything. Use them to announce a new signing certificate before
	// switching Certificate (and Key or Signer) to it, so that service
	// providers that refresh their copy of the metadata already trust the
	// new key when the rollover happens, or to keep publishing the old
	// certificate for a while afterwards.
	ExtraCertificates []*x509.Certificate

	// NameIDFormats are the NameID formats advertised in the IdP metadata.
	// When empty it defaults to the transient format for backwards compatibility.
	NameIDFormats []NameIDFormat

	// MetadataScopes are published in the IdP metadata as Shibboleth
	// shibmd:Scope extension elements, which tell service providers the
	// scopes the IdP is authoritative for, i.e. the parts after the "@" in
	// scoped attribute values such as eduPersonScopedAffiliation. When
	// empty, no scopes are published.
	MetadataScopes []ShibbolethScope

	// AssertionEncrypter, if set, encrypts assertions for service providers
	// that publish an encryption certificate. It is passed the SP's
	// *x509.Certificate as the key. Use it to select the key transport,
	// digest and block cipher, for example:
	//
	//	enc := xmlenc.OAEP_SHA256() // XML Encryption 1.1 RSA-OAEP
	//	enc.BlockCipher = xmlenc.AES256GCM
	//	idp.AssertionEncrypter = enc
	//
	// The service provider must support the algorithms chosen; those it
	// supports are usually listed in its metadata.
	//
	// When nil, assertions are encrypted with RSA-OAEP-MGF1P using a SHA-1
	// digest and AES-128-CBC, for compatibility with existing service
	// providers.
	AssertionEncrypter xmlenc.Encrypter

	// SignMetadata, if true, causes ServeMetadata to publish metadata that
	// carries an enveloped XML signature made with the IdP's key. See
	// SignedMetadata.
	SignMetadata bool
}

IdentityProvider implements the SAML Identity Provider role (IDP).

An identity provider receives SAML assertion requests and responds with SAML Assertions.

You must provide a keypair that is used to sign assertions.

You must provide an implementation of ServiceProviderProvider which returns

You must provide an implementation of the SessionProvider which handles the actual authentication (i.e. prompting for a username and password).

func (*IdentityProvider) DefaultOnError added in v0.6.0

func (idp *IdentityProvider) DefaultOnError(w http.ResponseWriter, _ *http.Request, status int, err error)

DefaultOnError is how ServeSSO, ServeIDPInitiated and ServeMetadata report an error when OnError is nil: it logs err to Logger and responds with status. An OnError can call it for the errors it does not handle itself.

func (*IdentityProvider) Handler

func (idp *IdentityProvider) Handler() http.Handler

Handler returns an http.Handler that serves the metadata and SSO URLs

func (*IdentityProvider) Metadata

func (idp *IdentityProvider) Metadata() *EntityDescriptor

Metadata returns the metadata structure for this identity provider.

func (*IdentityProvider) NewIdpInitiatedRequest added in v0.6.0

func (idp *IdentityProvider) NewIdpInitiatedRequest(r *http.Request, serviceProviderID string, relayState string) (*IdpAuthnRequest, error)

NewIdpInitiatedRequest returns the IdpAuthnRequest for an IdP-initiated login to the service provider serviceProviderID, with its metadata and the first HTTP-POST assertion consumer service in it resolved. It is the part of ServeIDPInitiated that runs before the SessionProvider is asked for a session.

It returns an error matching ErrUnknownServiceProvider (and os.ErrNotExist) if the ServiceProviderProvider does not know serviceProviderID, ErrUnknownAssertionConsumerService if the service provider has no HTTP-POST assertion consumer service, and otherwise the ServiceProviderProvider's error, wrapped.

func (*IdentityProvider) ServeIDPInitiated

func (idp *IdentityProvider) ServeIDPInitiated(w http.ResponseWriter, r *http.Request, serviceProviderID string, relayState string)

ServeIDPInitiated handes an IDP-initiated authorization request. Requests of this type require us to know a registered service provider and (optionally) the RelayState that will be passed to the application.

It responds with StatusNotFound if the service provider is unknown, and with StatusInternalServerError if the service provider cannot be looked up or has no usable assertion consumer service, or the assertion cannot be created or returned. Set OnError to handle these failures differently, or build a handler from NewIdpInitiatedRequest.

func (*IdentityProvider) ServeMetadata

func (idp *IdentityProvider) ServeMetadata(w http.ResponseWriter, r *http.Request)

ServeMetadata is an http.HandlerFunc that serves the IDP metadata. If SignMetadata is set, the metadata is signed.

If the metadata cannot be signed, serialized or written, a StatusInternalServerError response is sent. Set OnError to handle these failures differently.

func (*IdentityProvider) ServeSSO

func (idp *IdentityProvider) ServeSSO(w http.ResponseWriter, r *http.Request)

ServeSSO handles SAML auth requests.

When it gets a request for a user that does not have a valid session, then it prompts the user via XXX.

If the session already exists, then it produces a SAML assertion and returns an HTTP response according to the specified binding. The only supported binding right now is the HTTP-POST binding which returns an HTML form in the appropriate format with Javascript to automatically submit that form the to service provider's Assertion Customer Service endpoint.

If the SAML request is invalid or cannot be verified a simple StatusBadRequest response is sent.

If the assertion cannot be created or returned, a StatusInternalServerError response is sent.

Set OnError to handle these failures differently.

func (*IdentityProvider) SignedMetadata added in v0.6.0

func (idp *IdentityProvider) SignedMetadata() (*etree.Element, error)

SignedMetadata returns the IdP metadata as an XML element carrying an enveloped signature made with the IdP's key (saml-metadata-2.0-os §3).

The signature references the EntityDescriptor by its ID attribute; one is generated if the metadata does not have one. The returned element must be serialized as-is: re-indenting it changes the signed content.

type IdpAuthnRequest

type IdpAuthnRequest struct {
	IDP                     *IdentityProvider
	HTTPRequest             *http.Request
	RelayState              string
	RequestBuffer           []byte
	Request                 AuthnRequest
	ServiceProviderMetadata *EntityDescriptor
	SPSSODescriptor         *SPSSODescriptor
	ACSEndpoint             *IndexedEndpoint
	Assertion               *Assertion
	AssertionEl             *etree.Element
	ResponseEl              *etree.Element
	Now                     time.Time
	// contains filtered or unexported fields
}

IdpAuthnRequest is used by IdentityProvider to handle a single authentication request.

func NewIdpAuthnRequest

func NewIdpAuthnRequest(idp *IdentityProvider, r *http.Request) (*IdpAuthnRequest, error)

NewIdpAuthnRequest returns a new IdpAuthnRequest for the given HTTP request to the authorization service.

A GET request carries the request with the HTTP-Redirect binding and a POST request with the HTTP-POST binding, or with the HTTP-POST-SimpleSign binding when the form has a SigAlg or Signature field. The SimpleSign form is checked for duplicated or missing fields here; its signature is checked by Validate, once the service provider is known.

func (*IdpAuthnRequest) MakeAssertionEl

func (req *IdpAuthnRequest) MakeAssertionEl() error

MakeAssertionEl sets `AssertionEl` to a signed, possibly encrypted, version of `Assertion`.

func (*IdpAuthnRequest) MakeResponse

func (req *IdpAuthnRequest) MakeResponse() error

MakeResponse creates and assigns a new SAML response in ResponseEl. `Assertion` must be non-nil. If MakeAssertionEl() has not been called, this function calls it for you.

func (*IdpAuthnRequest) PostBinding added in v0.4.11

func (req *IdpAuthnRequest) PostBinding() (IdpAuthnRequestForm, error)

PostBinding creates the HTTP POST form information for this `IdpAuthnRequest`. If `Response` is not already set, it calls MakeResponse to produce it.

func (*IdpAuthnRequest) SimpleSignBinding added in v0.6.0

func (req *IdpAuthnRequest) SimpleSignBinding() (IdpAuthnRequestSimpleSignForm, error)

SimpleSignBinding creates the HTTP-POST-SimpleSign form information for this IdpAuthnRequest, which must have an ACS endpoint with that binding. If ResponseEl is not already set, it calls MakeResponse to produce it.

The Response and its Assertion keep the enveloped XML signatures MakeResponse gives them (sstc-saml-binding-simplesign-cs-01 §2.4 says such signatures MUST remain intact), so a service provider that ignores the SimpleSign signature can still check them. The SimpleSign signature is made with the IdP's key and SignatureMethod (by default SHA-256 for the key type). The relay state is signed, and sent, only when it is not empty.

func (*IdpAuthnRequest) Validate

func (req *IdpAuthnRequest) Validate() error

Validate checks that the authentication request is valid and assigns the AuthnRequest and Metadata properties. Returns a non-nil error if the request is not valid.

Signatures on requests sent with the HTTP-Redirect or HTTP-POST binding are not checked. A request sent with the HTTP-POST-SimpleSign binding must carry a valid SimpleSign signature made with a signing certificate from the service provider's metadata (its validity period is not checked), and a Destination equal to SSOURL; it is rejected otherwise.

func (*IdpAuthnRequest) WriteResponse

func (req *IdpAuthnRequest) WriteResponse(w http.ResponseWriter) error

WriteResponse writes the `Response` to the http.ResponseWriter. If `Response` is not already set, it calls MakeResponse to produce it.

If the ACS endpoint uses the HTTP-POST-SimpleSign binding, the form is the one SimpleSignBinding describes, rendered with IdentityProvider.SimpleSignResponseFormTemplate. Otherwise it is the HTTP-POST form PostBinding describes, rendered with ResponseFormTemplate.

type IdpAuthnRequestForm added in v0.4.11

type IdpAuthnRequestForm struct {
	URL          string
	SAMLResponse string
	RelayState   string
}

IdpAuthnRequestForm contans HTML form information to be submitted to the SAML HTTP POST binding ACS.

type IdpAuthnRequestSimpleSignForm added in v0.6.0

type IdpAuthnRequestSimpleSignForm struct {
	URL          string
	SAMLResponse string
	RelayState   string

	// SigAlg and Signature are the SimpleSign signature algorithm and the
	// base64 encoded signature over the response XML, RelayState (when not
	// empty) and SigAlg.
	SigAlg    string
	Signature string
}

IdpAuthnRequestSimpleSignForm contains the HTML form information to be submitted to an ACS endpoint with the HTTP-POST-SimpleSign binding.

type IndexedEndpoint

type IndexedEndpoint struct {
	Binding          string  `xml:"Binding,attr"`
	Location         string  `xml:"Location,attr"`
	ResponseLocation *string `xml:"ResponseLocation,attr,omitempty"`
	Index            int     `xml:"index,attr"`
	IsDefault        *bool   `xml:"isDefault,attr"`
}

IndexedEndpoint represents the SAML IndexedEndpointType object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.3

func (*IndexedEndpoint) UnmarshalXML added in v0.4.14

func (m *IndexedEndpoint) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type InvalidResponseError

type InvalidResponseError struct {
	PrivateErr error
	Response   string
	Now        time.Time
}

InvalidResponseError is the error produced by ParseResponse when it fails. The underlying error is in PrivateErr. Response is the response as it was known at the time validation failed. Now is the time that was used to validate time-dependent parts of the assertion.

func (*InvalidResponseError) Error

func (ivr *InvalidResponseError) Error() string

func (*InvalidResponseError) Unwrap added in v0.6.0

func (ivr *InvalidResponseError) Unwrap() error

Unwrap returns PrivateErr, so that errors.Is and errors.As can inspect the reason a response was rejected.

type Issuer

type Issuer struct {
	XMLName         xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	NameQualifier   string   `xml:",attr"`
	SPNameQualifier string   `xml:",attr"`
	Format          string   `xml:",attr"`
	SPProvidedID    string   `xml:",attr"`
	Value           string   `xml:",chardata"`
}

Issuer represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*Issuer) Element

func (a *Issuer) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type KeyDescriptor

type KeyDescriptor struct {
	Use               string             `xml:"use,attr"`
	KeyInfo           KeyInfo            `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
	EncryptionMethods []EncryptionMethod `xml:"EncryptionMethod"`
}

KeyDescriptor represents the XMLSEC object of the same name

type KeyInfo

type KeyInfo struct {
	XMLName  xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
	X509Data X509Data `xml:"X509Data"`
}

KeyInfo represents the XMLSEC object of the same name

type LocalizedName

type LocalizedName struct {
	Lang  string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"`
	Value string `xml:",chardata"`
}

LocalizedName represents the SAML type localizedNameType.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.4

type LocalizedURI

type LocalizedURI struct {
	Lang  string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"`
	Value string `xml:",chardata"`
}

LocalizedURI represents the SAML type localizedURIType.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.5

type LogoutRequest

type LogoutRequest struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutRequest"`

	ID           string     `xml:",attr"`
	Version      string     `xml:",attr"`
	IssueInstant time.Time  `xml:",attr"`
	NotOnOrAfter *time.Time `xml:",attr"`
	Destination  string     `xml:",attr"`
	Issuer       *Issuer    `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	NameID       *NameID    `xml:"urn:oasis:names:tc:SAML:2.0:assertion NameID"`
	Signature    *etree.Element

	SessionIndex *SessionIndex `xml:"SessionIndex"`
}

LogoutRequest represents the SAML object of the same name, a request from an IDP to destroy a user's session.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*LogoutRequest) Bytes added in v0.4.0

func (r *LogoutRequest) Bytes() ([]byte, error)

Bytes returns a byte array representation of the LogoutRequest

func (*LogoutRequest) Deflate added in v0.4.0

func (r *LogoutRequest) Deflate() ([]byte, error)

Deflate returns a compressed byte array of the LogoutRequest

func (*LogoutRequest) Element

func (r *LogoutRequest) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*LogoutRequest) MarshalXML

func (r *LogoutRequest) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*LogoutRequest) Post added in v0.4.1

func (r *LogoutRequest) Post(relayState string) []byte

Post returns an HTML form suitable for using the HTTP-POST binding with the request

func (*LogoutRequest) PostWithNonce added in v0.6.0

func (r *LogoutRequest) PostWithNonce(relayState, nonce string) []byte

PostWithNonce is like Post, but if nonce is not empty it is set as the nonce attribute of the form's auto-submit <script> element, so that the form can be served under a Content-Security-Policy that allows scripts by nonce.

func (*LogoutRequest) Redirect added in v0.4.1

func (r *LogoutRequest) Redirect(relayState string) *url.URL

Redirect returns a URL suitable for using the redirect binding with the request. The URL carries no query string signature; use ServiceProvider.MakeRedirectLogoutRequest to produce a signed one.

func (*LogoutRequest) SimpleSign added in v0.6.0

func (r *LogoutRequest) SimpleSign(relayState string, sp *ServiceProvider) ([]byte, error)

SimpleSign returns an auto-submitting HTML form that sends the request to its Destination with the HTTP-POST-SimpleSign binding, signed with sp's Key and SignatureMethod, which must be set. An XML signature the request already carries is kept.

func (*LogoutRequest) SimpleSignWithNonce added in v0.6.0

func (r *LogoutRequest) SimpleSignWithNonce(relayState, nonce string, sp *ServiceProvider) ([]byte, error)

SimpleSignWithNonce is like SimpleSign, but if nonce is not empty it is set as the nonce attribute of the form's auto-submit <script> element.

func (*LogoutRequest) UnmarshalXML

func (r *LogoutRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type LogoutRequestOption added in v0.6.0

type LogoutRequestOption func(*LogoutRequest)

LogoutRequestOption customizes a LogoutRequest produced by MakeLogoutRequest, MakeRedirectLogoutRequest or MakePostLogoutRequest. The option is applied before the request is signed.

func WithSessionIndex added in v0.6.0

func WithSessionIndex(sessionIndex string) LogoutRequestOption

WithSessionIndex sets the SessionIndex element of a LogoutRequest, which identifies the session at the IDP to terminate (saml-core-2.0-os section 3.7.1). The value is typically the SessionIndex attribute of the AuthnStatement in the assertion the IDP issued at login. Some IDPs require it to perform single logout. An empty value leaves SessionIndex unset.

type LogoutResponse

type LogoutResponse struct {
	XMLName      xml.Name  `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutResponse"`
	ID           string    `xml:",attr"`
	InResponseTo string    `xml:",attr"`
	Version      string    `xml:",attr"`
	IssueInstant time.Time `xml:",attr"`
	Destination  string    `xml:",attr"`
	Consent      string    `xml:",attr"`
	Issuer       *Issuer   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	Signature    *etree.Element
	Status       Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`
}

LogoutResponse represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*LogoutResponse) Element

func (r *LogoutResponse) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*LogoutResponse) MarshalXML

func (r *LogoutResponse) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*LogoutResponse) Post added in v0.4.5

func (r *LogoutResponse) Post(relayState string) []byte

Post returns an HTML form suitable for using the HTTP-POST binding with the LogoutResponse.

func (*LogoutResponse) PostWithNonce added in v0.6.0

func (r *LogoutResponse) PostWithNonce(relayState, nonce string) []byte

PostWithNonce is like Post, but if nonce is not empty it is set as the nonce attribute of the form's auto-submit <script> element, so that the form can be served under a Content-Security-Policy that allows scripts by nonce.

func (*LogoutResponse) Redirect added in v0.4.5

func (r *LogoutResponse) Redirect(relayState string) *url.URL

Redirect returns a URL suitable for using the redirect binding with the LogoutResponse. The URL carries no query string signature; use ServiceProvider.MakeRedirectLogoutResponse to produce a signed one.

func (*LogoutResponse) SimpleSign added in v0.6.0

func (r *LogoutResponse) SimpleSign(relayState string, sp *ServiceProvider) ([]byte, error)

SimpleSign returns an auto-submitting HTML form that sends the response to its Destination with the HTTP-POST-SimpleSign binding, signed with sp's Key and SignatureMethod, which must be set. An XML signature the response already carries is kept.

func (*LogoutResponse) SimpleSignWithNonce added in v0.6.0

func (r *LogoutResponse) SimpleSignWithNonce(relayState, nonce string, sp *ServiceProvider) ([]byte, error)

SimpleSignWithNonce is like SimpleSign, but if nonce is not empty it is set as the nonce attribute of the form's auto-submit <script> element.

func (*LogoutResponse) UnmarshalXML

func (r *LogoutResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type NameID

type NameID struct {
	NameQualifier   string `xml:",attr"`
	SPNameQualifier string `xml:",attr"`
	Format          string `xml:",attr"`
	SPProvidedID    string `xml:",attr"`
	Value           string `xml:",chardata"`
}

NameID represents the SAML element NameID.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.2.3

func (*NameID) Element

func (a *NameID) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type NameIDFormat

type NameIDFormat string

NameIDFormat is the format of the id

const (
	UnspecifiedNameIDFormat  NameIDFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
	TransientNameIDFormat    NameIDFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
	EmailAddressNameIDFormat NameIDFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
	PersistentNameIDFormat   NameIDFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
)

Name ID formats

func (NameIDFormat) Element

func (n NameIDFormat) Element() *etree.Element

Element returns an XML element representation of n.

type NameIDPolicy

type NameIDPolicy struct {
	XMLName         xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"`
	Format          *string  `xml:",attr"`
	SPNameQualifier *string  `xml:",attr"`
	AllowCreate     *bool    `xml:",attr"`
}

NameIDPolicy represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*NameIDPolicy) Element

func (a *NameIDPolicy) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type OneTimeUse

type OneTimeUse struct{}

OneTimeUse represents the SAML element OneTimeUse.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.5

func (*OneTimeUse) Element

func (a *OneTimeUse) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type Organization

type Organization struct {
	OrganizationNames        []LocalizedName `xml:"OrganizationName"`
	OrganizationDisplayNames []LocalizedName `xml:"OrganizationDisplayName"`
	OrganizationURLs         []LocalizedURI  `xml:"OrganizationURL"`
}

Organization represents the SAML Organization object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2.1

type PDPDescriptor

type PDPDescriptor struct {
	RoleDescriptor
	AuthzServices              []Endpoint     `xml:"AuthzService"`
	AssertionIDRequestServices []Endpoint     `xml:"AssertionIDRequestService"`
	NameIDFormats              []NameIDFormat `xml:"NameIDFormat"`
}

PDPDescriptor represents the SAML PDPDescriptor object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.6

func (PDPDescriptor) MarshalXML added in v0.6.0

func (m PDPDescriptor) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*PDPDescriptor) UnmarshalXML added in v0.6.0

func (m *PDPDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type ProxyRestriction

type ProxyRestriction struct {
	Count     *int       `xml:",attr,omitempty"`
	Audiences []Audience `xml:"urn:oasis:names:tc:SAML:2.0:assertion Audience"`
}

ProxyRestriction represents the SAML element ProxyRestriction.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.6

func (*ProxyRestriction) Element

func (a *ProxyRestriction) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type RelaxedTime

type RelaxedTime time.Time

RelaxedTime is a version of time.Time that supports the time format found in SAML documents.

func (RelaxedTime) MarshalText

func (m RelaxedTime) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler

func (RelaxedTime) String

func (m RelaxedTime) String() string

func (*RelaxedTime) UnmarshalText

func (m *RelaxedTime) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler

type RequestedAttribute

type RequestedAttribute struct {
	Attribute
	IsRequired *bool `xml:"isRequired,attr"`
}

RequestedAttribute represents the SAML RequestedAttribute object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.4.2

type RequestedAuthnContext added in v0.4.7

type RequestedAuthnContext struct {
	XMLName    xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol RequestedAuthnContext"`
	Comparison string   `xml:",attr"`

	// AuthnContextClassRefs lists the requested authentication context
	// classes, in order of preference. When parsing, it holds every
	// AuthnContextClassRef element in the request.
	AuthnContextClassRefs []string `xml:"-"`

	// AuthnContextClassRef is a single requested authentication context
	// class. When marshaling it is used only if AuthnContextClassRefs is
	// empty. When parsing it is set to the first AuthnContextClassRef
	// element.
	//
	// Deprecated: use AuthnContextClassRefs, which can carry more than one
	// value.
	AuthnContextClassRef string `xml:"-"`
}

RequestedAuthnContext represents the SAML object of the same name, an indication of the requirements on the authentication process.

The SAML schema allows one or more AuthnContextClassRef elements (saml-core section 3.3.2.2.1).

func (*RequestedAuthnContext) ClassRefs added in v0.6.0

func (r *RequestedAuthnContext) ClassRefs() []string

ClassRefs returns the requested authentication context classes: the values of AuthnContextClassRefs if it is set, otherwise AuthnContextClassRef, if that is set.

func (*RequestedAuthnContext) Element added in v0.4.7

func (r *RequestedAuthnContext) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (RequestedAuthnContext) MarshalXML added in v0.6.0

func (r RequestedAuthnContext) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler.

func (*RequestedAuthnContext) UnmarshalXML added in v0.6.0

func (r *RequestedAuthnContext) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler.

type Response

type Response struct {
	XMLName      xml.Name  `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"`
	ID           string    `xml:",attr"`
	InResponseTo string    `xml:",attr"`
	Version      string    `xml:",attr"`
	IssueInstant time.Time `xml:",attr"`
	Destination  string    `xml:",attr"`
	Consent      string    `xml:",attr"`
	Issuer       *Issuer   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	Signature    *etree.Element
	Status       Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`

	// TODO(ross): more than one EncryptedAssertion is allowed
	EncryptedAssertion *etree.Element `xml:"urn:oasis:names:tc:SAML:2.0:assertion EncryptedAssertion"`

	// TODO(ross): more than one Assertion is allowed
	Assertion *Assertion `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"`
}

Response represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*Response) Element

func (r *Response) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*Response) MarshalXML

func (r *Response) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*Response) UnmarshalXML

func (r *Response) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type ResponseWriter added in v0.6.0

type ResponseWriter interface {
	// WriteResponse writes the HTTP response carrying the SAML response for
	// req. req.ResponseEl is nil until req.MakeResponse (or req.PostBinding,
	// which calls it) has been called. If it returns an error, the caller
	// logs it and replies with an HTTP 500 error, so an implementation
	// should return errors before it starts writing to w.
	WriteResponse(w http.ResponseWriter, req *IdpAuthnRequest) error
}

ResponseWriter is an interface used by IdentityProvider to send the SAML response for a request to the browser, once the assertion has been made. The default implementation is DefaultResponseWriter, which is used if IdentityProvider.ResponseWriter is not set.

Implement it to control the whole HTTP response, for example to set headers, to render the response inside the embedding application's own pages, or to support a binding other than HTTP-POST. To only change the markup of the default auto-submitting HTML form, set IdentityProvider.ResponseFormTemplate instead.

type RoleDescriptor

type RoleDescriptor struct {
	ID                         string        `xml:",attr,omitempty"`
	ValidUntil                 *time.Time    `xml:"validUntil,attr,omitempty"`
	CacheDuration              time.Duration `xml:"cacheDuration,attr,omitempty"`
	ProtocolSupportEnumeration string        `xml:"protocolSupportEnumeration,attr"`
	ErrorURL                   string        `xml:"errorURL,attr,omitempty"`
	Signature                  *etree.Element
	Extensions                 *Extensions     `xml:"urn:oasis:names:tc:SAML:2.0:metadata Extensions,omitempty"`
	KeyDescriptors             []KeyDescriptor `xml:"KeyDescriptor,omitempty"`
	Organization               *Organization   `xml:"Organization,omitempty"`
	ContactPeople              []ContactPerson `xml:"ContactPerson,omitempty"`
}

RoleDescriptor represents the SAML element RoleDescriptor.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.1

type SPSSODescriptor

type SPSSODescriptor struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata SPSSODescriptor"`
	SSODescriptor
	AuthnRequestsSigned        *bool                       `xml:",attr"`
	WantAssertionsSigned       *bool                       `xml:",attr"`
	AssertionConsumerServices  []IndexedEndpoint           `xml:"AssertionConsumerService"`
	AttributeConsumingServices []AttributeConsumingService `xml:"AttributeConsumingService"`
}

SPSSODescriptor represents the SAML SPSSODescriptorType object.

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.2

func (SPSSODescriptor) MarshalXML added in v0.6.0

func (m SPSSODescriptor) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*SPSSODescriptor) UnmarshalXML added in v0.6.0

func (m *SPSSODescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type SSODescriptor

type SSODescriptor struct {
	RoleDescriptor
	ArtifactResolutionServices []IndexedEndpoint `xml:"ArtifactResolutionService"`
	SingleLogoutServices       []Endpoint        `xml:"SingleLogoutService"`
	ManageNameIDServices       []Endpoint        `xml:"ManageNameIDService"`
	NameIDFormats              []NameIDFormat    `xml:"NameIDFormat"`
}

SSODescriptor represents the SAML complex type SSODescriptor

See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.2

type Scoping added in v0.6.0

type Scoping struct {
	XMLName      xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Scoping"`
	ProxyCount   *int     `xml:",attr"`
	IDPList      *IDPList `xml:"urn:oasis:names:tc:SAML:2.0:protocol IDPList"`
	RequesterIDs []string `xml:"urn:oasis:names:tc:SAML:2.0:protocol RequesterID"`
}

Scoping represents the SAML object of the same name. It lets a requester specify the identity providers it trusts to authenticate the presenter, which proxying identity providers (gateways) use to pick a delegate IDP.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf § 3.4.1.2

func (*Scoping) Element added in v0.6.0

func (a *Scoping) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type ServiceProvider

type ServiceProvider struct {
	// Entity ID is optional - if not specified then MetadataURL will be used
	EntityID string

	// Key is the private key we use to sign requests. Its public key must be
	// an *rsa.PublicKey or an *ecdsa.PublicKey. Any crypto.Signer works for
	// signing, including keys held in a KMS or HSM. Unless EncryptionKey is
	// set, Key is also used to decrypt encrypted assertions, which only works
	// when Key is an *rsa.PrivateKey.
	Key crypto.Signer

	// Certificate is the public part of Key.
	Certificate   *x509.Certificate
	Intermediates []*x509.Certificate

	// EncryptionKey, if set, is the private key used to decrypt encrypted
	// assertions, instead of Key. Use it to keep separate signing and
	// encryption keys, for example when Key is an ECDSA key, which cannot be
	// used for XML encryption.
	EncryptionKey *rsa.PrivateKey

	// EncryptionCertificate is the public part of EncryptionKey. It is
	// advertised in the metadata as the encryption key. If it is nil, the
	// metadata advertises Certificate for encryption, but only when its public
	// key is an RSA key.
	EncryptionCertificate *x509.Certificate

	// DecryptionKeys are further private keys that decrypt encrypted
	// assertions, tried in order after EncryptionKey (or Key, if
	// EncryptionKey is unset). Set them while rotating the SP encryption key,
	// so that an assertion the IdP encrypted to either the old or the new key
	// is accepted. They are never used for signing, and are not advertised in
	// the metadata.
	DecryptionKeys []*rsa.PrivateKey

	// HTTPClient to use during SAML artifact resolution
	HTTPClient *http.Client

	// MetadataURL is the full URL to the metadata endpoint on this host,
	// i.e. https://example.com/saml/metadata
	MetadataURL url.URL

	// AcsURL is the full URL to the SAML Assertion Customer Service endpoint
	// on this host, i.e. https://example.com/saml/acs
	AcsURL url.URL

	// AcsIndex, if set, makes authentication requests carry
	// AssertionConsumerServiceIndex with this value, instead of
	// AssertionConsumerServiceURL and ProtocolBinding (SAML core §3.4.1
	// does not allow both). The IdP then sends the response to the
	// AssertionConsumerService endpoint with this index in the SP metadata it
	// has on file, using that endpoint's binding. That endpoint's Location
	// must still be AcsURL, because responses are only accepted there. If nil,
	// requests carry AssertionConsumerServiceURL and ProtocolBinding.
	AcsIndex *int

	// SloURL is the full URL to the SAML Single Logout endpoint on this host.
	// i.e. https://example.com/saml/slo
	SloURL url.URL

	// IDPMetadata is the metadata from the identity provider.
	IDPMetadata *EntityDescriptor

	// IDPCertificateFingerprint is fingerprint of the idp public certificate. If this field is specified,
	// IDPCertificateFingerprintAlgorithm must also be specified, and IDPCertificate must not be specified.
	IDPCertificateFingerprint *string
	// IDPCertificateFingerprintAlgorithm is fingerprint algorithm used to obtain fingerprint of the idp public
	// certificate.
	// If this field is specified, IDPCertificateFingerprint must also be specified, and IDPCertificate must not be specified.
	IDPCertificateFingerprintAlgorithm *string

	// IDPCertificate to use as idp public certificate. If this field is specified, IDPCertificateFingerprint and
	// IDPCertificateFingerprintAlgorithm must not be specified.
	IDPCertificate *string

	// AuthnNameIDFormat is the format used in the NameIDPolicy for
	// authentication requests
	AuthnNameIDFormat NameIDFormat

	// Scoping, when set, is sent in authentication requests. Proxying identity
	// providers (gateways) use its IDPList to choose which identity provider to
	// delegate authentication to.
	Scoping *Scoping

	// MetadataValidDuration is a duration used to calculate validUntil
	// attribute in the metadata endpoint
	MetadataValidDuration time.Duration

	// MetadataOmitValidUntil, when true, omits the optional validUntil
	// attribute from the metadata (saml-metadata-2.0-os §2.3.2). Because the
	// root element must carry validUntil or cacheDuration (§2.3.1), the
	// metadata then carries cacheDuration (DefaultCacheDuration) instead.
	// MetadataValidDuration is ignored when this is set.
	MetadataOmitValidUntil bool

	// ForceAuthn allows you to force re-authentication of users even if the user
	// has a SSO session at the IdP.
	ForceAuthn *bool

	// RequestedAuthnContext allow you to specify the requested authentication
	// context in authentication requests
	RequestedAuthnContext *RequestedAuthnContext

	// ValidateAuthnContextClassRef, if true, requires an assertion to carry
	// an AuthnStatement whose AuthnContextClassRef is one of the classes in
	// RequestedAuthnContext. It has no effect if RequestedAuthnContext is
	// nil or names no class.
	//
	// Only the "exact" Comparison (or an empty one, which means "exact") is
	// supported. The ordering that "minimum", "better" and "maximum" refer
	// to is defined by each deployment, not by the SAML specification
	// (saml-core §3.3.2.2.1), so with any other Comparison every assertion
	// is rejected rather than accepted unchecked.
	ValidateAuthnContextClassRef bool

	// AllowIDPInitiated accepts unsolicited (IdP-initiated) responses, which
	// have no InResponseTo. A response or assertion that does carry an
	// InResponseTo must still match a request this SP made; set
	// ValidateRequestID to accept IdPs that send one on IdP-initiated logins.
	AllowIDPInitiated bool

	// DefaultRedirectURI where untracked requests (as of IDPInitiated) are redirected to
	DefaultRedirectURI string

	// SignatureVerifier, if non-nil, allows you to implement an alternative way
	// to verify signatures.
	SignatureVerifier SignatureVerifier

	// SignatureMethod, if non-empty, authentication requests will be signed.
	//
	// The method specified here must be consistent with the type of Key.
	//
	// If Key is *rsa.PrivateKey, then this must be one of dsig.RSASHA1SignatureMethod,
	// dsig.RSASHA256SignatureMethod, dsig.RSASHA384SignatureMethod, or
	// dsig.RSASHA512SignatureMethod:
	//
	// If Key is *ecdsa.PrivateKey, then this must be one of dsig.ECDSASHA1SignatureMethod,
	// dsig.ECDSASHA256SignatureMethod, dsig.ECDSASHA384SignatureMethod, or
	// dsig.ECDSASHA512SignatureMethod.
	SignatureMethod string

	// SignMetadata, if true, asks that the SP metadata be published with an
	// enveloped XML signature made with Key; samlsp.Middleware.ServeMetadata
	// honors it. See SignedMetadata.
	SignMetadata bool

	// LogoutBindings specify the bindings available for SLO endpoint. If empty,
	// HTTP-POST binding is used. HTTPPostSimpleSignBinding may be listed: the
	// logout validation functions accept HTTP-POST-SimpleSign messages.
	LogoutBindings []string

	// AssertionConsumerServiceBindings specify the bindings advertised for the
	// AssertionConsumerService endpoint in the SP metadata, in order of
	// preference. If empty, both HTTP-POST and HTTP-Artifact bindings are
	// advertised. Set this to []string{HTTPPostBinding} to stop advertising
	// the HTTP-Artifact binding, for example when the IDP does not publish an
	// ArtifactResolutionService or the SP cannot reach it. Include
	// HTTPPostSimpleSignBinding to advertise that the ACS accepts
	// HTTP-POST-SimpleSign responses (ParseResponse always accepts them).
	AssertionConsumerServiceBindings []string

	// ValidateAudienceRestriction allows you to override the default audience validation
	// for an assertion. If nil, the default audience validation is used.
	ValidateAudienceRestriction func(assertion *Assertion) error

	// ValidateRequestID allows you to override the default request ID validation.
	// If nil, the default request ID validation is used. With AllowIDPInitiated
	// set, it also decides a non-empty assertion SubjectConfirmationData
	// InResponseTo, passed as Response.InResponseTo.
	ValidateRequestID func(response Response, possibleRequestIDs []string) error

	// Clock, if non-nil, is the time source for everything this
	// ServiceProvider does that depends on the current time: timestamps on
	// the requests and metadata it issues, assertion and logout message time
	// checks, and certificate validity during XML and redirect binding
	// signature validation.
	//
	// If nil, the package-level TimeNow and Clock are used. Setting this
	// field instead of replacing those globals allows ServiceProviders with
	// different clocks to be used concurrently, for example in parallel
	// tests.
	Clock *dsig.Clock

	// IgnoreCertificateExpiry, if true, disables the check that the IDP's
	// signing certificate is within its validity period (NotBefore and
	// NotAfter) when validating XML and HTTP-Redirect binding signatures.
	// The signature must still be made by a key in one of the trusted IDP
	// certificates.
	//
	// The SAML V2.0 Metadata Interoperability Profile treats certificates in
	// metadata only as a container for a public key, and permits them to be
	// expired or not yet valid. Some IDPs publish expired signing
	// certificates as a result. Enabling this allows interoperating with
	// them.
	IgnoreCertificateExpiry bool

	// ReplayCache, if set, records the ID of the assertion each accepted
	// response is accepted for, and refuses a response whose assertion it
	// has already recorded. Without it, a captured assertion is accepted
	// again until it expires, and an IdP-initiated one has no request ID to
	// tie it to a single use. If nil, assertions are not checked for replay.
	ReplayCache AssertionReplayCache
}

ServiceProvider implements SAML Service provider.

In SAML, service providers delegate responsibility for identifying clients to an identity provider. If you are writing an application that uses passwords (or whatever) stored somewhere else, then you are service provider.

See the example directory for an example of a web application using the service provider interface.

func (*ServiceProvider) GetArtifactBindingLocation added in v0.4.6

func (sp *ServiceProvider) GetArtifactBindingLocation(binding string) string

GetArtifactBindingLocation returns URL for the IDP's Artifact binding of the specified type

func (*ServiceProvider) GetSLOBindingLocation

func (sp *ServiceProvider) GetSLOBindingLocation(binding string) string

GetSLOBindingLocation returns URL for the IDP's Single Log Out Service binding of the specified type (HTTPRedirectBinding or HTTPPostBinding)

func (*ServiceProvider) GetSSOBindingLocation

func (sp *ServiceProvider) GetSSOBindingLocation(binding string) string

GetSSOBindingLocation returns URL for the IDP's Single Sign On Service binding of the specified type (HTTPRedirectBinding, HTTPPostBinding or HTTPPostSimpleSignBinding)

func (*ServiceProvider) MakeArtifactResolveRequest added in v0.4.6

func (sp *ServiceProvider) MakeArtifactResolveRequest(artifactID string) (*ArtifactResolve, error)

MakeArtifactResolveRequest produces a new ArtifactResolve object to send to the idp's Artifact resolver

func (*ServiceProvider) MakeAuthenticationRequest

func (sp *ServiceProvider) MakeAuthenticationRequest(idpURL string, binding string, resultBinding string) (*AuthnRequest, error)

MakeAuthenticationRequest produces a new AuthnRequest object to send to the idpURL that uses the specified binding (HTTPRedirectBinding or HTTPPostBinding)

func (*ServiceProvider) MakeLogoutRequest

func (sp *ServiceProvider) MakeLogoutRequest(idpURL, nameID string, opts ...LogoutRequestOption) (*LogoutRequest, error)

MakeLogoutRequest produces a new LogoutRequest object for idpURL. If sp.SignatureMethod is set, the request carries an enveloped XML signature, which is what the HTTP-POST binding uses.

func (*ServiceProvider) MakeLogoutResponse added in v0.4.5

func (sp *ServiceProvider) MakeLogoutResponse(idpURL, logoutRequestID string) (*LogoutResponse, error)

MakeLogoutResponse produces a new LogoutResponse object for idpURL and logoutRequestID. If sp.SignatureMethod is set, the response carries an enveloped XML signature, which is what the HTTP-POST binding uses.

func (*ServiceProvider) MakePostAuthenticationRequest

func (sp *ServiceProvider) MakePostAuthenticationRequest(relayState string) ([]byte, error)

MakePostAuthenticationRequest creates a SAML authentication request using the HTTP-POST binding. It returns HTML text representing an HTML form that can be sent presented to a browser to initiate the login process.

func (*ServiceProvider) MakePostLogoutRequest added in v0.4.1

func (sp *ServiceProvider) MakePostLogoutRequest(nameID, relayState string, opts ...LogoutRequestOption) ([]byte, error)

MakePostLogoutRequest creates a SAML authentication request using the HTTP-POST binding. It returns HTML text representing an HTML form that can be sent presented to a browser to initiate the logout process.

func (*ServiceProvider) MakePostLogoutResponse added in v0.4.5

func (sp *ServiceProvider) MakePostLogoutResponse(logoutRequestID, relayState string) ([]byte, error)

MakePostLogoutResponse creates a SAML LogoutResponse using the HTTP-POST binding. It returns HTML text representing an HTML form that can be sent presented to a browser for LogoutResponse.

func (*ServiceProvider) MakeRedirectAuthenticationRequest

func (sp *ServiceProvider) MakeRedirectAuthenticationRequest(relayState string) (*url.URL, error)

MakeRedirectAuthenticationRequest creates a SAML authentication request using the HTTP-Redirect binding. It returns a URL that we will redirect the user to in order to start the auth process.

func (*ServiceProvider) MakeRedirectLogoutRequest

func (sp *ServiceProvider) MakeRedirectLogoutRequest(nameID, relayState string, opts ...LogoutRequestOption) (*url.URL, error)

MakeRedirectLogoutRequest creates a SAML LogoutRequest using the HTTP-Redirect binding. It returns a URL that we will redirect the user to in order to start the logout process.

If sp.SignatureMethod is set, the request is signed with a query string signature (SigAlg and Signature parameters) as the binding requires (saml-bindings-2.0-os section 3.4.4.1), rather than with an enveloped XML signature.

func (*ServiceProvider) MakeRedirectLogoutResponse added in v0.4.5

func (sp *ServiceProvider) MakeRedirectLogoutResponse(logoutRequestID, relayState string) (*url.URL, error)

MakeRedirectLogoutResponse creates a SAML LogoutResponse using the HTTP-Redirect binding. It returns a URL that we will redirect the user to for LogoutResponse.

If sp.SignatureMethod is set, the response is signed with a query string signature (SigAlg and Signature parameters) as the binding requires (saml-bindings-2.0-os section 3.4.4.1), rather than with an enveloped XML signature.

func (*ServiceProvider) MakeSimpleSignAuthenticationRequest added in v0.6.0

func (sp *ServiceProvider) MakeSimpleSignAuthenticationRequest(relayState string) ([]byte, error)

MakeSimpleSignAuthenticationRequest creates a SAML authentication request for the IDP's HTTP-POST-SimpleSign single sign-on endpoint. It returns an auto-submitting HTML form that sends the request to the IDP.

The request carries no XML signature; it is signed with a SimpleSign signature (sstc-saml-binding-simplesign-cs-01 section 2.5) made with Key and SignatureMethod, which must be set. The response is requested with the HTTP-POST binding, as for MakePostAuthenticationRequest; use MakeAuthenticationRequest and AuthnRequest.SimpleSign to request another.

func (*ServiceProvider) MakeSimpleSignLogoutRequest added in v0.6.0

func (sp *ServiceProvider) MakeSimpleSignLogoutRequest(nameID, relayState string, opts ...LogoutRequestOption) ([]byte, error)

MakeSimpleSignLogoutRequest creates a SAML LogoutRequest for the IDP's HTTP-POST-SimpleSign single logout endpoint. It returns an auto-submitting HTML form that sends the request to the IDP, signed with a SimpleSign signature made with Key and SignatureMethod, which must be set. The request carries no XML signature.

func (*ServiceProvider) MakeSimpleSignLogoutResponse added in v0.6.0

func (sp *ServiceProvider) MakeSimpleSignLogoutResponse(logoutRequestID, relayState string) ([]byte, error)

MakeSimpleSignLogoutResponse creates a SAML LogoutResponse for the IDP's HTTP-POST-SimpleSign single logout endpoint. It returns an auto-submitting HTML form that sends the response to the IDP, signed with a SimpleSign signature made with Key and SignatureMethod, which must be set. The response carries no XML signature.

func (*ServiceProvider) Metadata

func (sp *ServiceProvider) Metadata() *EntityDescriptor

Metadata returns the service provider metadata

func (*ServiceProvider) ParseLogoutResponse added in v0.6.0

func (sp *ServiceProvider) ParseLogoutResponse(req *http.Request, possibleRequestIDs []string) (*LogoutResponse, error)

ParseLogoutResponse validates the LogoutResponse content from the request, which may use the HTTP-Redirect, HTTP-POST or HTTP-POST-SimpleSign binding, as ValidateLogoutResponseRequest does, and returns it. In addition, the response's InResponseTo must be one of possibleRequestIDs, the IDs of the LogoutRequests this service provider sent and still expects an answer to, so that a LogoutResponse cannot be replayed or delivered unsolicited.

func (*ServiceProvider) ParseResponse

func (sp *ServiceProvider) ParseResponse(req *http.Request, possibleRequestIDs []string) (*Assertion, error)

ParseResponse extracts the SAML IDP response received in req, resolves artifacts when necessary, validates it, and returns the verified assertion. req.ParseForm must have been called.

A posted form that carries a SigAlg or Signature field is an HTTP-POST-SimpleSign message (sstc-saml-binding-simplesign-cs-01 section 2.10). Its SimpleSign signature must then be valid, or the response is rejected; it is never accepted on the strength of XML signatures alone. A valid SimpleSign signature authenticates the whole Response, so the assertions need not be signed, and the Response must carry a Destination. An enveloped XML signature on the Response is still checked when present. Every other check (Destination, InResponseTo, Issuer, Status, assertion conditions, decryption, ReplayCache) applies as for HTTP-POST. A form without SigAlg and Signature is handled as HTTP-POST, as before.

func (*ServiceProvider) ParseXMLArtifactResponse added in v0.4.6

func (sp *ServiceProvider) ParseXMLArtifactResponse(soapResponseXML []byte, possibleRequestIDs []string, artifactRequestID string, currentURL url.URL) (*Assertion, error)

ParseXMLArtifactResponse validates the SAML Artifact resolver response and returns the verified assertion.

This function handles verifying the digital signature, and verifying that the specified conditions and properties are met.

If the function fails it will return an InvalidResponseError whose properties are useful in describing which part of the parsing process failed. However, to discourage inadvertent disclosure the diagnostic information, the Error() method returns a static string.

func (*ServiceProvider) ParseXMLResponse

func (sp *ServiceProvider) ParseXMLResponse(decodedResponseXML []byte, possibleRequestIDs []string, currentURL url.URL) (*Assertion, error)

ParseXMLResponse parses and validates the SAML IDP response and returns the verified assertion.

This function handles decrypting the message, verifying the digital signature on the assertion, and verifying that the specified conditions and properties are met.

If the function fails it will return an InvalidResponseError whose properties are useful in describing which part of the parsing process failed. However, to discourage inadvertent disclosure the diagnostic information, the Error() method returns a static string.

func (*ServiceProvider) RedirectLogoutRequestURL added in v0.6.0

func (sp *ServiceProvider) RedirectLogoutRequestURL(req *LogoutRequest, relayState string) (*url.URL, error)

RedirectLogoutRequestURL returns the URL that sends req to its Destination with the HTTP-Redirect binding. Use it instead of MakeRedirectLogoutRequest when the request's ID is needed, for example to track the request and match it with the IDP's LogoutResponse; req is typically made by MakeLogoutRequest with the IDP's HTTP-Redirect SingleLogoutService location.

Any enveloped XML signature on req is left out of the message. If sp.SignatureMethod is set, the URL carries a query string signature instead, as the binding requires (saml-bindings-2.0-os section 3.4.4.1).

func (*ServiceProvider) SignArtifactResolve added in v0.4.6

func (sp *ServiceProvider) SignArtifactResolve(req *ArtifactResolve) error

SignArtifactResolve adds the `Signature` element to the `ArtifactResolve`.

func (*ServiceProvider) SignAuthnRequest added in v0.4.1

func (sp *ServiceProvider) SignAuthnRequest(req *AuthnRequest) error

SignAuthnRequest adds the `Signature` element to the `AuthnRequest`.

func (*ServiceProvider) SignLogoutRequest added in v0.4.5

func (sp *ServiceProvider) SignLogoutRequest(req *LogoutRequest) error

SignLogoutRequest adds the `Signature` element to the `LogoutRequest`.

func (*ServiceProvider) SignLogoutResponse added in v0.4.5

func (sp *ServiceProvider) SignLogoutResponse(resp *LogoutResponse) error

SignLogoutResponse adds the `Signature` element to the `LogoutResponse`.

func (*ServiceProvider) SignedMetadata added in v0.6.0

func (sp *ServiceProvider) SignedMetadata() (*etree.Element, error)

SignedMetadata returns the SP metadata as an XML element carrying an enveloped signature made with Key and Certificate (saml-metadata-2.0-os §3).

It signs with SignatureMethod, or, when that is empty, with SHA-256 for the key type; signing metadata does not require request signing to be enabled. The signature references the EntityDescriptor by its ID attribute; one is generated if the metadata does not have one. The returned element must be serialized as-is: re-indenting it changes the signed content.

func (*ServiceProvider) ValidateLogoutRequest added in v0.6.0

func (sp *ServiceProvider) ValidateLogoutRequest(req *http.Request) (*LogoutRequest, error)

ValidateLogoutRequest validates a LogoutRequest sent by the IDP (IDP initiated single logout), using the HTTP-Redirect, HTTP-POST or HTTP-POST-SimpleSign binding. It returns the request only if it is valid.

The request must be signed by the IDP. With the HTTP-Redirect binding that is either a query string signature (SigAlg and Signature parameters) or an enveloped XML signature; with the HTTP-POST binding it is an enveloped XML signature. A posted form that carries a SigAlg or Signature field is an HTTP-POST-SimpleSign message and must have a valid SimpleSign signature (an enveloped XML signature it also carries must be valid too).

The caller should end the session identified by the returned request's NameID (and SessionIndex, if present) and then answer the IDP, for example with MakeRedirectLogoutResponse(req.ID, relayState).

func (*ServiceProvider) ValidateLogoutRequestForm added in v0.6.0

func (sp *ServiceProvider) ValidateLogoutRequestForm(postFormData string) (*LogoutRequest, error)

ValidateLogoutRequestForm validates a LogoutRequest received via the HTTP-POST binding. postFormData is the value of the SAMLRequest form field. It returns the request only if it is valid.

func (*ServiceProvider) ValidateLogoutResponseForm added in v0.4.0

func (sp *ServiceProvider) ValidateLogoutResponseForm(postFormData string) error

ValidateLogoutResponseForm returns a nil error if the logout response is valid.

It does not check the response's InResponseTo; see ParseLogoutResponse.

func (*ServiceProvider) ValidateLogoutResponseRedirect added in v0.4.0

func (sp *ServiceProvider) ValidateLogoutResponseRedirect(queryParameterData string) error

ValidateLogoutResponseRedirect returns a nil error if the logout response is valid. queryParameterData is the URL-decoded value of the SAMLResponse query parameter.

Because it only receives the SAMLResponse value, this method cannot check a query string signature and therefore requires the response to carry an enveloped XML signature. Most IDPs sign HTTP-Redirect binding messages with a query string signature instead (as saml-bindings-2.0-os section 3.4.4.1 requires); use ValidateLogoutResponseRequest to accept those.

It does not check the response's InResponseTo; see ParseLogoutResponse.

URL Binding appears to be gzip / flate encoded See https://www.oasis-open.org/committees/download.php/20645/sstc-saml-tech-overview-2%200-draft-10.pdf 6.6

func (*ServiceProvider) ValidateLogoutResponseRequest added in v0.4.0

func (sp *ServiceProvider) ValidateLogoutResponseRequest(req *http.Request) error

ValidateLogoutResponseRequest validates the LogoutResponse content from the request, which may use the HTTP-Redirect, HTTP-POST or HTTP-POST-SimpleSign binding.

With the HTTP-Redirect binding the response must be signed, either with a query string signature (SigAlg and Signature parameters) or with an enveloped XML signature. A posted form that carries a SigAlg or Signature field is an HTTP-POST-SimpleSign message and must have a valid SimpleSign signature; an enveloped XML signature it also carries must be valid too.

It does not check the response's InResponseTo against the LogoutRequest this service provider sent; use ParseLogoutResponse for that.

type ServiceProviderProvider

type ServiceProviderProvider interface {
	// GetServiceProvider returns the Service Provider metadata for the
	// service provider ID, which is typically the service provider's
	// metadata URL. If an appropriate service provider cannot be found then
	// the returned error must be os.ErrNotExist.
	GetServiceProvider(r *http.Request, serviceProviderID string) (*EntityDescriptor, error)
}

ServiceProviderProvider is an interface used by IdentityProvider to look up service provider metadata for a request.

type Session

type Session struct {
	ID         string
	CreateTime time.Time
	ExpireTime time.Time
	Index      string

	NameID       string
	NameIDFormat string
	SubjectID    string

	Groups                 []string
	UserName               string
	UserEmail              string
	UserCommonName         string
	UserSurname            string
	UserGivenName          string
	UserScopedAffiliation  string
	EduPersonPrincipalName string `json:",omitempty"`

	CustomAttributes []Attribute
}

Session represents a user session. It is returned by the SessionProvider implementation's GetSession method. Fields here are used to set fields in the SAML assertion.

type SessionIndex added in v0.4.0

type SessionIndex struct {
	Value string `xml:",chardata"`
}

SessionIndex represents the SAML element SessionIndex.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.7.1

func (*SessionIndex) Element added in v0.4.0

func (s *SessionIndex) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type SessionProvider

type SessionProvider interface {
	// GetSession returns the remote user session associated with the http.Request.
	//
	// If (and only if) the request is not associated with a session then GetSession
	// must complete the HTTP request and return nil.
	GetSession(w http.ResponseWriter, r *http.Request, req *IdpAuthnRequest) *Session
}

SessionProvider is an interface used by IdentityProvider to determine the Session associated with a request. For an example implementation, see GetSession in the samlidp package.

type ShibbolethScope added in v0.6.0

type ShibbolethScope struct {
	XMLName xml.Name `xml:"urn:mace:shibboleth:metadata:1.0 Scope"`
	Regexp  bool     `xml:"regexp,attr"`
	Value   string   `xml:",chardata"`
}

ShibbolethScope represents the shibmd:Scope metadata extension element. An identity provider uses it to list the security domains (scopes) it is authoritative for, such as the "example.com" in a scoped attribute value like "staff@example.com". When Regexp is true, Value is a regular expression rather than a literal scope.

See https://shibboleth.atlassian.net/wiki/spaces/SC/pages/1912406916/ShibMetaExt

type SignatureVerifier added in v0.4.0

type SignatureVerifier interface {
	VerifySignature(validationContext *dsig.ValidationContext, el *etree.Element) error
}

SignatureVerifier verifies a signature

Can be implemented in order to override ServiceProvider's default way of verifying signatures.

type SigningMethod added in v0.6.0

type SigningMethod struct {
	XMLName    xml.Name `xml:"urn:oasis:names:tc:SAML:metadata:algsupport SigningMethod"`
	Algorithm  string   `xml:"Algorithm,attr"`
	MinKeySize int      `xml:"MinKeySize,attr,omitempty"`
	MaxKeySize int      `xml:"MaxKeySize,attr,omitempty"`
}

SigningMethod represents the alg:SigningMethod element: an XML Signature algorithm the entity supports, with optional bounds on the key size, in bits, it supports for that algorithm.

See https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-algsupport-v1.0-cs01.html §2.4

type Status

type Status struct {
	XMLName       xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`
	StatusCode    StatusCode
	StatusMessage *StatusMessage
	StatusDetail  *StatusDetail
}

Status represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*Status) Element

func (s *Status) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type StatusCode

type StatusCode struct {
	XMLName    xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusCode"`
	Value      string   `xml:",attr"`
	StatusCode *StatusCode
}

StatusCode represents the SAML object of the same name.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

func (*StatusCode) Element

func (s *StatusCode) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type StatusDetail

type StatusDetail struct {
	Children []*etree.Element
}

StatusDetail represents the SAML element StatusDetail.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.4

func (StatusDetail) Element

func (sm StatusDetail) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (StatusDetail) MarshalXML added in v0.6.0

func (sm StatusDetail) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler, writing Children as XML.

encoding/xml cannot marshal an *etree.Element itself, so without this method the children were written as their struct fields.

func (*StatusDetail) UnmarshalXML added in v0.6.0

func (sm *StatusDetail) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler, reading every child element into Children. Text between the children is ignored.

Each child keeps its prefixes. Namespaces declared on StatusDetail are declared again on each child, which no longer has StatusDetail as a parent. A prefix declared further out cannot be recovered and is replaced by a generated one bound to the same namespace.

type StatusMessage

type StatusMessage struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusMessage"`
	Value   string   `xml:",chardata"`
}

StatusMessage represents the SAML element StatusMessage.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.3

func (StatusMessage) Element

func (sm StatusMessage) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type Subject

type Subject struct {
	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Subject"`
	// BaseID               *BaseID  ... TODO
	NameID *NameID `xml:"urn:oasis:names:tc:SAML:2.0:assertion NameID"`
	// EncryptedID          *EncryptedID  ... TODO
	SubjectConfirmations []SubjectConfirmation `xml:"urn:oasis:names:tc:SAML:2.0:assertion SubjectConfirmation"`
}

Subject represents the SAML element Subject.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1

func (*Subject) Element

func (a *Subject) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type SubjectConfirmation

type SubjectConfirmation struct {
	Method string `xml:",attr"`
	// BaseID               *BaseID  ... TODO
	NameID *NameID `xml:"urn:oasis:names:tc:SAML:2.0:assertion NameID"`
	// EncryptedID          *EncryptedID  ... TODO
	SubjectConfirmationData *SubjectConfirmationData `xml:"urn:oasis:names:tc:SAML:2.0:assertion SubjectConfirmationData"`
}

SubjectConfirmation represents the SAML element SubjectConfirmation.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.1

func (*SubjectConfirmation) Element

func (a *SubjectConfirmation) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type SubjectConfirmationData

type SubjectConfirmationData struct {
	NotBefore    time.Time `xml:",attr"`
	NotOnOrAfter time.Time `xml:",attr"`
	Recipient    string    `xml:",attr"`
	InResponseTo string    `xml:",attr"`
	Address      string    `xml:",attr"`
}

SubjectConfirmationData represents the SAML element SubjectConfirmationData.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.2

func (*SubjectConfirmationData) Element

func (s *SubjectConfirmationData) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

func (*SubjectConfirmationData) MarshalXML

func (s *SubjectConfirmationData) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML implements xml.Marshaler

func (*SubjectConfirmationData) UnmarshalXML

func (s *SubjectConfirmationData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler

type SubjectLocality

type SubjectLocality struct {
	Address string `xml:",attr"`
	DNSName string `xml:",attr"`
}

SubjectLocality represents the SAML element SubjectLocality.

See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.1

func (*SubjectLocality) Element

func (a *SubjectLocality) Element() *etree.Element

Element returns an etree.Element representing the object in XML form.

type X509Certificate added in v0.4.6

type X509Certificate struct {
	XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"`
	Data    string   `xml:",chardata"`
}

X509Certificate represents the XMLSEC object of the same name

type X509Data added in v0.4.6

type X509Data struct {
	XMLName          xml.Name          `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
	X509Certificates []X509Certificate `xml:"X509Certificate"`
}

X509Data represents the XMLSEC object of the same name

Directories

Path Synopsis
This is an example that implements a bitly-esque short link service.
This is an example that implements a bitly-esque short link service.
idp command
Package main contains an example identity provider implementation.
Package main contains an example identity provider implementation.
trivial command
Package main contains an example service provider implementation.
Package main contains an example service provider implementation.
internal
signerutil
Package signerutil contains helpers for working with crypto.Signer values.
Package signerutil contains helpers for working with crypto.Signer values.
Package logger provides a logging interface.
Package logger provides a logging interface.
Package samlidp a rudimentary SAML identity provider suitable for testing or as a starting point for a more complex service.
Package samlidp a rudimentary SAML identity provider suitable for testing or as a starting point for a more complex service.
Package samlsp provides helpers that can be used to protect web services using SAML.
Package samlsp provides helpers that can be used to protect web services using SAML.
Package testsaml contains functions for use in testing SAML requests and responses.
Package testsaml contains functions for use in testing SAML requests and responses.
Package xmlenc is a partial implementation of the xmlenc standard as described in https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html.
Package xmlenc is a partial implementation of the xmlenc standard as described in https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL