• Stars
    star
    945
  • Rank 48,368 (Top 1.0 %)
  • Language
    Go
  • License
    BSD 2-Clause "Sim...
  • Created about 9 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

SAML library for go

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

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://samltest.id/saml/idp")
	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. For samltest.id, you can do something like:

mdpath=saml-test-$USER-$HOST.xml
curl localhost:8000/saml/metadata > $mdpath

Navigate to https://samltest.id/upload.php and upload the file you fetched.

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://samltest.id/idp/profile/SAML2/Redirect/SSO

  3. samltest.id prompts you for a username and password.

  4. samltest.id returns you an HTML document which contains an HTML form setup to POST to localhost:8000/saml/acs. The form is automatically submitted if you have javascript enabled.

  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.

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.

The package can produce signed SAML assertions, and can validate both signed and encrypted SAML assertions. It does not support signed or encrypted requests.

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 testing ground for SAML service and identity providers.

Security Issues

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

More Repositories

1

etcd-aws

tools for building a robust etcd cluster in AWS
Go
123
star
2

go-cloudformation

A golang library for reading and producing CloudFormation templates
Go
103
star
3

go-xmlsec

golang bindings for xmlsec
Go
25
star
4

rfc5424

a Go library that can read and write RFC-5424 syslog messages
Go
18
star
5

awsconsoleauth

Amazon AWS login with Google credentials
Go
13
star
6

dev

Infrastructure for building a development and collaboration environment with CoreOS and Docker.
Python
9
star
7

dynamotree

dynamotree is an implementation of hierarchical data storage for DynamoDB.
Go
8
star
8

redisproxy

Access control for Redis
Go
7
star
9

ec2cluster

Simple EC2 cluster auto-discovery for go
Go
7
star
10

ringfile

A library for writing and reading fixed size circular log files
C++
5
star
11

slackcat

like netcat but for Slack
Go
3
star
12

minichaos

A tiny version of ChaosMonkey for a single autoscaling group
Go
2
star
13

awsregion

tiny golang function to guess the correct aws region for use with aws-sdk-go
Go
2
star
14

standupbot

a super simple slack bot to run standups
Go
2
star
15

certcheck

Tools to check expiration and renew TLS certificates
Shell
2
star
16

cl

cl is a tool to make github pull requests less annoying
Go
2
star
17

s3repo

Tools for manipulating simple Debian repositories in S3
Python
2
star
18

jsupdate

a tool for keeping your `package.json` file updated without breaking everything
Go
2
star
19

csp

go library for generating Content-Security-Policy headers
Go
1
star
20

goupdate

goupdate is a tool for keeping your go.mod file updated without breaking everything.
Go
1
star
21

withebs

Withebs runs a command with the specified EBS volume attached to the currently running EC2 instance.
Go
1
star
22

etcd-amb

Ambassador for etcd
Go
1
star
23

dockerelb

attach docker containers to AWS Elastic Load Balancers
Go
1
star
24

usermgr

Usermgr is a tool to turn access to production systems from a pain in the butt into ponies and rainbows.
Go
1
star
25

reversehttp

reversehttp implements a simple scheme for reversing the request/response flow of HTTP in go
Go
1
star
26

httperr

A golang error object that speaks HTTP
Go
1
star