samlplugin

package module
v0.0.0-...-147d95f Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2018 License: MIT Imports: 28 Imported by: 0

README

caddy-saml

WIP Based heavily on https://github.com/crewjam/saml and https://github.com/RobotsAndPencils/go-saml with a little bit of https://github.com/russellhaering/gosaml2

Usecase

Our usecase is to use caddy as a reverse proxy with shibboleth support (instead of using apache,mod_shib and shibd)

Example with cert from disk and tls enabled

https://:443 {
    tls /path/cert.pem /path/key.pem
    saml {
        root_url https://yourdomain.com
        disk /path/cert.pem /path/key.pem
        idp_metadata https://youridp.com/download/metadata/metadata-yourdomain.xml
        /path1 valid-user
        /path1 mail email2@domain.com
        /path1 require-all
        /path2 mail email@domain.com
        /hello uid testuid
        /hello dump-attributes
 }
proxy /hello https://backendserver.com
proxy /path1 http://backend2.com:8080
}

Example with cert from vault

http://:80 {
    saml {
        root_url https://yourdomain.com
        idp_metadata https://youridp.com/download/metadata/metadata-yourdomain.xml
        vault_server https://vault.yourdomain.com
        vault_path secret/projects/caddy-saml/yourdomain.com
        /path1 valid-user
        /path1 require-nosession
        /path2 mail email@domain.com
        /hello uid testuid
        /hello dump-attributes
 }
proxy /hello https://backendserver.com
proxy /path1 http://backend2.com:8080
}

Example with cert from disk and tls and mysql sessions enabled

https://:443 {
    tls /path/cert.pem /path/key.pem
    saml {
        mysql login:password@tcp(mysql.hostname.com)/caddysaml
        root_url https://yourdomain.com
        disk /path/cert.pem /path/key.pem
        idp_metadata https://youridp.com/download/metadata/metadata-yourdomain.xml
        /path1 valid-user
        /path1 mail email2@domain.com
        /path1 require-all
        /path2 mail email@domain.com
        /hello uid testuid
        /hello dump-attributes
 }
proxy /hello https://backendserver.com
proxy /path1 http://backend2.com:8080
}

Issues

The OpenSSL default format for private keys is PKCS-8. We only support PKCS-1 private keys. A private PKCS-8 formated RSA key can be converted to a private PKCS-1 formated RSA key by:

openssl rsa -in private-pkcs8-key.key -out private.key

Documentation

Overview

based on https://github.com/42wim/crewjam-saml

based on https://github.com/RobotsAndPencils/go-saml/metadata.go

based on https://github.com/42wim/crewjam-saml

based on https://github.com/42wim/crewjam-saml Package samlsp provides helpers that can be used to protect web services using SAML.

based on https://github.com/42wim/crewjam-saml

based on https://github.com/RobotsAndPencils/go-saml/types.go

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewVaultSource

func NewVaultSource() (*api.Client, error)

func RequireAttribute

func RequireAttribute(name, value string) func(http.Handler) http.Handler

RequireAttribute returns a middleware function that requires that the SAML attribute `name` be set to `value`. This can be used to require that a remote user be a member of a group. It relies on the Claims assigned to to the context in RequireAccount.

For example:

goji.Use(m.RequireAccount)
goji.Use(RequireAttributeSAMLPlugin("eduPersonAffiliation", "Staff"))

func WithToken

func WithToken(ctx context.Context, token *AuthorizationToken) context.Context

WithToken returns a new context with token associated

Types

type Assertion

type Assertion struct {
	XMLName            xml.Name
	ID                 string `xml:"ID,attr"`
	Version            string `xml:"Version,attr"`
	XS                 string `xml:"xmlns:xs,attr"`
	XSI                string `xml:"xmlns:xsi,attr"`
	SAML               string `xml:"xmlns:saml,attr"`
	IssueInstant       string `xml:"IssueInstant,attr"`
	Issuer             Issuer `xml:"Issuer"`
	Subject            Subject
	Conditions         Conditions
	AuthnStatements    []AuthnStatement `xml:"AuthnStatement,omitempty"`
	AttributeStatement AttributeStatement
}

type AssertionConsumerService

type AssertionConsumerService struct {
	XMLName  xml.Name
	Binding  string `xml:"Binding,attr"`
	Location string `xml:"Location,attr"`
	Index    string `xml:"index,attr"`
}

type Attribute

type Attribute struct {
	XMLName         xml.Name
	Name            string           `xml:",attr"`
	FriendlyName    string           `xml:",attr,omitempty"`
	NameFormat      string           `xml:",attr"`
	AttributeValues []AttributeValue `xml:"AttributeValue"`
}

type AttributeStatement

type AttributeStatement struct {
	XMLName    xml.Name
	Attributes []Attribute `xml:"Attribute"`
}

type AttributeValue

type AttributeValue struct {
	XMLName xml.Name
	Type    string `xml:"xsi:type,attr"`
	Value   string `xml:",innerxml"`
}

type Attributes

type Attributes map[string][]string

Attributes is a map of attributes provided in the SAML assertion

func (Attributes) Get

func (a Attributes) Get(key string) string

Get returns the first attribute named `key` or an empty string if no such attributes is present.

func (Attributes) GetAll

func (a Attributes) GetAll(key string) []string

Get returns the first attribute named `key` or an empty string if no such attributes is present.

type Audience

type Audience struct {
	XMLName xml.Name
	Value   string `xml:",innerxml"`
}

type AudienceRestriction

type AudienceRestriction struct {
	XMLName   xml.Name
	Audiences []Audience `xml:"Audience"`
}

type AuthnContext

type AuthnContext struct {
	XMLName              xml.Name
	AuthnContextClassRef AuthnContextClassRef `xml:"AuthnContextClassRef"`
}

type AuthnContextClassRef

type AuthnContextClassRef struct {
	XMLName   xml.Name
	SAML      string `xml:"xmlns:saml,attr"`
	Transport string `xml:",innerxml"`
}

type AuthnRequest

type AuthnRequest struct {
	XMLName                        xml.Name
	SAMLP                          string                `xml:"xmlns:samlp,attr"`
	SAML                           string                `xml:"xmlns:saml,attr"`
	SAMLSIG                        string                `xml:"xmlns:samlsig,attr,omitempty"`
	ID                             string                `xml:"ID,attr"`
	Version                        string                `xml:"Version,attr"`
	ProtocolBinding                string                `xml:"ProtocolBinding,attr"`
	AssertionConsumerServiceURL    string                `xml:"AssertionConsumerServiceURL,attr"`
	Destination                    string                `xml:"Destination,attr"`
	IssueInstant                   string                `xml:"IssueInstant,attr"`
	AssertionConsumerServiceIndex  int                   `xml:"AssertionConsumerServiceIndex,attr"`
	AttributeConsumingServiceIndex int                   `xml:"AttributeConsumingServiceIndex,attr"`
	Issuer                         Issuer                `xml:"Issuer"`
	NameIDPolicy                   NameIDPolicy          `xml:"NameIDPolicy"`
	RequestedAuthnContext          RequestedAuthnContext `xml:"RequestedAuthnContext"`
	Signature                      *Signature            `xml:"Signature,omitempty"`
	// contains filtered or unexported fields
}

type AuthnStatement

type AuthnStatement struct {
	XMLName             xml.Name
	AuthnInstant        string       `xml:",attr"`
	SessionNotOnOrAfter string       `xml:",attr,omitempty"`
	SessionIndex        string       `xml:",attr,omitempty"`
	AuthnContext        AuthnContext `xml:"AuthnContext"`
}

type AuthorizationToken

type AuthorizationToken struct {
	jwt.StandardClaims
	Attributes Attributes `json:"attr"`
}

AuthorizationToken represents the data stored in the authorization cookie.

func Token

Token returns the token associated with ctx, or nil if no token are associated

type CanonicalizationMethod

type CanonicalizationMethod struct {
	XMLName   xml.Name
	Algorithm string `xml:"Algorithm,attr"`
}

type ClientCookies

type ClientCookies struct {
	ServiceProvider *saml.ServiceProvider
	Name            string
	Domain          string
	Secure          bool
}

ClientCookies implements ClientState and ClientToken using cookies.

func (ClientCookies) DeleteSession

func (c ClientCookies) DeleteSession(w http.ResponseWriter, r *http.Request, id string) error

DeleteSession removes the named stored state by clearing the corresponding cookie.

func (ClientCookies) DeleteState

func (c ClientCookies) DeleteState(w http.ResponseWriter, r *http.Request, id string) error

DeleteState removes the named stored state by clearing the corresponding cookie.

func (ClientCookies) GetSessions

func (c ClientCookies) GetSessions(r *http.Request) map[string]string

GetSessions returns the currently stored states by reading cookies.

func (ClientCookies) GetState

func (c ClientCookies) GetState(r *http.Request, id string) string

GetState returns a single stored state by reading the cookies

func (ClientCookies) GetStates

func (c ClientCookies) GetStates(r *http.Request) map[string]string

GetStates returns the currently stored states by reading cookies.

func (ClientCookies) GetToken

func (c ClientCookies) GetToken(r *http.Request) string

GetToken returns the token by reading the cookie.

func (ClientCookies) SetSession

func (c ClientCookies) SetSession(w http.ResponseWriter, r *http.Request, id string, value string)

func (ClientCookies) SetState

func (c ClientCookies) SetState(w http.ResponseWriter, r *http.Request, id string, value string)

SetState stores the named state value by setting a cookie.

func (ClientCookies) SetToken

func (c ClientCookies) SetToken(w http.ResponseWriter, r *http.Request, value string, maxAge time.Duration)

SetToken assigns the specified token by setting a cookie.

type ClientState

type ClientState interface {
	SetState(w http.ResponseWriter, r *http.Request, id string, value string)
	GetStates(r *http.Request) map[string]string
	GetState(r *http.Request, id string) string
	DeleteState(w http.ResponseWriter, r *http.Request, id string) error
	SetSession(w http.ResponseWriter, r *http.Request, id string, value string)
	GetSessions(r *http.Request) map[string]string
	DeleteSession(w http.ResponseWriter, r *http.Request, id string) error
}

ClientState implements client side storage for state.

type ClientToken

type ClientToken interface {
	GetToken(r *http.Request) string
	SetToken(w http.ResponseWriter, r *http.Request, value string, maxAge time.Duration)
}

ClientToken implements client side storage for signed authorization tokens.

type Conditions

type Conditions struct {
	XMLName              xml.Name
	NotBefore            string                `xml:",attr"`
	NotOnOrAfter         string                `xml:",attr"`
	AudienceRestrictions []AudienceRestriction `xml:"AudienceRestriction,omitempty"`
}

type DB

type DB struct {
	*gorm.DB
}

func NewDB

func NewDB(uri string) *DB

type DigestMethod

type DigestMethod struct {
	XMLName   xml.Name
	Algorithm string `xml:"Algorithm,attr"`
}

type DigestValue

type DigestValue struct {
	XMLName xml.Name
}

type EntityAttributes

type EntityAttributes struct {
	XMLName xml.Name
	SAML    string `xml:"xmlns:saml,attr"`

	EntityAttributes []Attribute `xml:"Attribute"` // should be array??
}

type EntityDescriptor

type EntityDescriptor struct {
	XMLName  xml.Name
	DS       string `xml:"xmlns:ds,attr"`
	XMLNS    string `xml:"xmlns,attr"`
	MD       string `xml:"xmlns:md,attr"`
	EntityId string `xml:"entityID,attr"`

	Extensions      Extensions      `xml:"Extensions"`
	SPSSODescriptor SPSSODescriptor `xml:"SPSSODescriptor"`
}

type Extensions

type Extensions struct {
	XMLName xml.Name
	Alg     string `xml:"xmlns:alg,attr"`
	MDAttr  string `xml:"xmlns:mdattr,attr"`
	MDRPI   string `xml:"xmlns:mdrpi,attr"`

	EntityAttributes string `xml:"EntityAttributes"`
}

type Issuer

type Issuer struct {
	XMLName xml.Name
	SAML    string `xml:"xmlns:saml,attr"`
	Url     string `xml:",innerxml"`
}

type KeyDescriptor

type KeyDescriptor struct {
	XMLName xml.Name
	Use     string  `xml:"use,attr"`
	KeyInfo KeyInfo `xml:"KeyInfo"`
}

type KeyInfo

type KeyInfo struct {
	XMLName  xml.Name
	X509Data X509Data `xml:",innerxml"`
}

type NameID

type NameID struct {
	XMLName         xml.Name
	Format          string `xml:",attr"`
	SPNameQualifier string `xml:",attr,omitempty"`
	Value           string `xml:",innerxml"`
}

type NameIDPolicy

type NameIDPolicy struct {
	XMLName     xml.Name
	AllowCreate bool   `xml:"AllowCreate,attr"`
	Format      string `xml:"Format,attr"`
}

type Options

type Options struct {
	URL               url.URL
	Key               *rsa.PrivateKey
	Logger            logger.Interface
	Certificate       *x509.Certificate
	AllowIDPInitiated bool
	IDPMetadata       *saml.EntityDescriptor
	IDPMetadataURL    *url.URL
	HTTPClient        *http.Client
	CookieMaxAge      time.Duration
	CookieSecure      bool
	ForceAuthn        bool
	CookieName        string
	EnableSessions    bool
	DbURI             string
}

Options represents the parameters for creating a new middleware

type RequestedAuthnContext

type RequestedAuthnContext struct {
	XMLName              xml.Name
	SAMLP                string               `xml:"xmlns:samlp,attr"`
	Comparison           string               `xml:"Comparison,attr"`
	AuthnContextClassRef AuthnContextClassRef `xml:"AuthnContextClassRef"`
}

type Response

type Response struct {
	XMLName      xml.Name
	SAMLP        string `xml:"xmlns:samlp,attr"`
	SAML         string `xml:"xmlns:saml,attr"`
	SAMLSIG      string `xml:"xmlns:samlsig,attr"`
	Destination  string `xml:"Destination,attr"`
	ID           string `xml:"ID,attr"`
	Version      string `xml:"Version,attr"`
	IssueInstant string `xml:"IssueInstant,attr"`
	InResponseTo string `xml:"InResponseTo,attr"`

	Issuer    Issuer    `xml:"Issuer"`
	Signature Signature `xml:"Signature"`
	Status    Status    `xml:"Status"`
	Assertion Assertion `xml:"Assertion"`
	// contains filtered or unexported fields
}

type SAMLPlugin

type SAMLPlugin struct {
	ServiceProvider   saml.ServiceProvider
	AllowIDPInitiated bool
	TokenMaxAge       time.Duration
	ClientState       ClientState
	ClientToken       ClientToken
	EnableSessions    bool
	Map               map[string][]string

	Db *DB
	// contains filtered or unexported fields
}

SAMLPlugin implements middleware than allows a web application to support SAML.

It implements http.Handler so that it can provide the metadata and ACS endpoints, typically /saml/metadata and /saml/acs, respectively.

It also provides middleware RequireAccount which redirects users to the auth process if they do not have session credentials.

When redirecting the user through the SAML auth flow, the middlware assigns a temporary cookie with a random name beginning with "saml_". The value of the cookie is a signed JSON Web Token containing the original URL requested and the SAML request ID. The random part of the name corresponds to the RelayState parameter passed through the SAML flow.

When validating the SAML response, the RelayState is used to look up the correct cookie, validate that the SAML request ID, and redirect the user back to their original URL.

Sessions are established by issuing a JSON Web Token (JWT) as a session cookie once the SAML flow has succeeded. The JWT token contains the authenticated attributes from the SAML assertion.

When the middlware receives a request with a valid session JWT it extracts the SAML attributes and modifies the http.Request object adding a Context object to the request context that contains attributes from the initial SAML assertion.

When issuing JSON Web Tokens, a signing key is required. Because the SAML service provider already has a private key, we borrow that key to sign the JWTs as well.

func New

func New(opts Options) (*SAMLPlugin, error)

New creates a new SAMLPlugin

func (*SAMLPlugin) Authorize

func (s *SAMLPlugin) Authorize(w http.ResponseWriter, r *http.Request, assertion *saml.Assertion)

Authorize is invoked by ServeHTTP when we have a new, valid SAML assertion. It sets a cookie that contains a signed JWT containing the assertion attributes. It then redirects the user's browser to the original URL contained in RelayState.

func (*SAMLPlugin) GetAuthorizationToken

func (s *SAMLPlugin) GetAuthorizationToken(r *http.Request) *AuthorizationToken

GetAuthorizationToken is invoked by RequireAccount to determine if the request is already authorized or if the user's browser should be redirected to the SAML login flow. If the request is authorized, then the request context is ammended with a Context object.

func (*SAMLPlugin) GetEntityDescriptor

func (s *SAMLPlugin) GetEntityDescriptor() (string, error)

func (*SAMLPlugin) IsAuthorized

func (s *SAMLPlugin) IsAuthorized(r *http.Request) bool

IsAuthorized returns true if the request has already been authorized.

Note: This function is retained for compatability. Use GetAuthorizationToken in new code instead.

func (*SAMLPlugin) RequireAccount

func (s *SAMLPlugin) RequireAccount(w http.ResponseWriter, r *http.Request)

RequireAccount is HTTP middleware that requires that each request be associated with a valid session. If the request is not associated with a valid session, then rather than serve the request, the middlware redirects the user to start the SAML auth flow.

func (*SAMLPlugin) ServeHTTP

func (s *SAMLPlugin) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)

ServeHTTP implements http.Handler and serves the SAML-specific HTTP endpoints on the URIs specified by m.ServiceProvider.MetadataURL and m.ServiceProvider.AcsURL.

type SPSSODescriptor

type SPSSODescriptor struct {
	XMLName                    xml.Name
	ProtocolSupportEnumeration string `xml:"protocolSupportEnumeration,attr"`
	SigningKeyDescriptor       KeyDescriptor
	EncryptionKeyDescriptor    KeyDescriptor
	SingleLogoutService        SingleLogoutService `xml:"SingleLogoutService"`
	AuthnRequestsSigned        bool                `xml:",attr"`
	WantAssertionsSigned       bool                `xml:",attr"`

	AssertionConsumerServices []AssertionConsumerService
}

type SPSSODescriptors

type SPSSODescriptors struct {
}

type SamlsigReference

type SamlsigReference struct {
	XMLName      xml.Name
	URI          string       `xml:"URI,attr"`
	Transforms   Transforms   `xml:",innerxml"`
	DigestMethod DigestMethod `xml:",innerxml"`
	DigestValue  DigestValue  `xml:",innerxml"`
}

type Session

type Session struct {
	gorm.Model
	Path      string
	Expire    time.Time
	Token     []byte `gorm:"size:20000"`
	NameID    string
	AppID     string
	SessionID string
}

type Signature

type Signature struct {
	XMLName        xml.Name
	Id             string `xml:"Id,attr"`
	SignedInfo     SignedInfo
	SignatureValue SignatureValue
	KeyInfo        KeyInfo
}

type SignatureMethod

type SignatureMethod struct {
	XMLName   xml.Name
	Algorithm string `xml:"Algorithm,attr"`
}

type SignatureValue

type SignatureValue struct {
	XMLName xml.Name
	Value   string `xml:",innerxml"`
}

type SignedInfo

type SignedInfo struct {
	XMLName                xml.Name
	CanonicalizationMethod CanonicalizationMethod
	SignatureMethod        SignatureMethod
	SamlsigReference       SamlsigReference
}

type SingleLogoutService

type SingleLogoutService struct {
	XMLName  xml.Name
	Binding  string `xml:"Binding,attr"`
	Location string `xml:"Location,attr"`
}

type Status

type Status struct {
	XMLName    xml.Name
	StatusCode StatusCode `xml:"StatusCode"`
}

type StatusCode

type StatusCode struct {
	XMLName xml.Name
	Value   string `xml:",attr"`
}

type Subject

type Subject struct {
	XMLName             xml.Name
	NameID              NameID
	SubjectConfirmation SubjectConfirmation
}

type SubjectConfirmation

type SubjectConfirmation struct {
	XMLName                 xml.Name
	Method                  string `xml:",attr"`
	SubjectConfirmationData SubjectConfirmationData
}

type SubjectConfirmationData

type SubjectConfirmationData struct {
	XMLName      xml.Name
	InResponseTo string `xml:",attr"`
	NotOnOrAfter string `xml:",attr"`
	Recipient    string `xml:",attr"`
}

type Transform

type Transform struct {
	XMLName   xml.Name
	Algorithm string `xml:"Algorithm,attr"`
}

type Transforms

type Transforms struct {
	XMLName   xml.Name
	Transform []Transform
}

type VaultSource

type VaultSource struct {
	Addr    string
	Refresh time.Duration
	// contains filtered or unexported fields
}

type X509Certificate

type X509Certificate struct {
	XMLName xml.Name
	Cert    string `xml:",innerxml"`
}

type X509Data

type X509Data struct {
	XMLName         xml.Name
	X509Certificate X509Certificate `xml:",innerxml"`
}

Jump to

Keyboard shortcuts

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