mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-28 11:16:52 +01:00
139 lines
4.4 KiB
Go
139 lines
4.4 KiB
Go
// Package samlsp provides helpers that can be used to protect web services using SAML.
|
|
package samlsp
|
|
|
|
import (
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
dsig "github.com/russellhaering/goxmldsig"
|
|
|
|
"github.com/crewjam/saml"
|
|
)
|
|
|
|
// Options represents the parameters for creating a new middleware
|
|
type Options struct {
|
|
EntityID string
|
|
URL url.URL
|
|
Key *rsa.PrivateKey
|
|
Certificate *x509.Certificate
|
|
Intermediates []*x509.Certificate
|
|
AllowIDPInitiated bool
|
|
DefaultRedirectURI string
|
|
IDPMetadata *saml.EntityDescriptor
|
|
SignRequest bool
|
|
UseArtifactResponse bool
|
|
ForceAuthn bool // TODO(ross): this should be *bool
|
|
CookieSameSite http.SameSite
|
|
RelayStateFunc func(w http.ResponseWriter, r *http.Request) string
|
|
}
|
|
|
|
// DefaultSessionCodec returns the default SessionCodec for the provided options,
|
|
// a JWTSessionCodec configured to issue signed tokens.
|
|
func DefaultSessionCodec(opts Options) JWTSessionCodec {
|
|
return JWTSessionCodec{
|
|
SigningMethod: defaultJWTSigningMethod,
|
|
Audience: opts.URL.String(),
|
|
Issuer: opts.URL.String(),
|
|
MaxAge: defaultSessionMaxAge,
|
|
Key: opts.Key,
|
|
}
|
|
}
|
|
|
|
// DefaultSessionProvider returns the default SessionProvider for the provided options,
|
|
// a CookieSessionProvider configured to store sessions in a cookie.
|
|
func DefaultSessionProvider(opts Options) CookieSessionProvider {
|
|
return CookieSessionProvider{
|
|
Name: defaultSessionCookieName,
|
|
Domain: opts.URL.Host,
|
|
MaxAge: defaultSessionMaxAge,
|
|
HTTPOnly: true,
|
|
Secure: opts.URL.Scheme == "https",
|
|
SameSite: opts.CookieSameSite,
|
|
Codec: DefaultSessionCodec(opts),
|
|
}
|
|
}
|
|
|
|
// DefaultTrackedRequestCodec returns a new TrackedRequestCodec for the provided
|
|
// options, a JWTTrackedRequestCodec that uses a JWT to encode TrackedRequests.
|
|
func DefaultTrackedRequestCodec(opts Options) JWTTrackedRequestCodec {
|
|
return JWTTrackedRequestCodec{
|
|
SigningMethod: defaultJWTSigningMethod,
|
|
Audience: opts.URL.String(),
|
|
Issuer: opts.URL.String(),
|
|
MaxAge: saml.MaxIssueDelay,
|
|
Key: opts.Key,
|
|
}
|
|
}
|
|
|
|
// DefaultRequestTracker returns a new RequestTracker for the provided options,
|
|
// a CookieRequestTracker which uses cookies to track pending requests.
|
|
func DefaultRequestTracker(opts Options, serviceProvider *saml.ServiceProvider) CookieRequestTracker {
|
|
return CookieRequestTracker{
|
|
ServiceProvider: serviceProvider,
|
|
NamePrefix: "saml_",
|
|
Codec: DefaultTrackedRequestCodec(opts),
|
|
MaxAge: saml.MaxIssueDelay,
|
|
RelayStateFunc: opts.RelayStateFunc,
|
|
SameSite: opts.CookieSameSite,
|
|
}
|
|
}
|
|
|
|
// DefaultServiceProvider returns the default saml.ServiceProvider for the provided
|
|
// options.
|
|
func DefaultServiceProvider(opts Options) saml.ServiceProvider {
|
|
metadataURL := opts.URL.ResolveReference(&url.URL{Path: "saml/metadata"})
|
|
acsURL := opts.URL.ResolveReference(&url.URL{Path: "saml/acs"})
|
|
sloURL := opts.URL.ResolveReference(&url.URL{Path: "saml/slo"})
|
|
|
|
var forceAuthn *bool
|
|
if opts.ForceAuthn {
|
|
forceAuthn = &opts.ForceAuthn
|
|
}
|
|
signatureMethod := dsig.RSASHA1SignatureMethod
|
|
if !opts.SignRequest {
|
|
signatureMethod = ""
|
|
}
|
|
|
|
if opts.DefaultRedirectURI == "" {
|
|
opts.DefaultRedirectURI = "/"
|
|
}
|
|
|
|
return saml.ServiceProvider{
|
|
EntityID: opts.EntityID,
|
|
Key: opts.Key,
|
|
Certificate: opts.Certificate,
|
|
Intermediates: opts.Intermediates,
|
|
MetadataURL: *metadataURL,
|
|
AcsURL: *acsURL,
|
|
SloURL: *sloURL,
|
|
IDPMetadata: opts.IDPMetadata,
|
|
ForceAuthn: forceAuthn,
|
|
SignatureMethod: signatureMethod,
|
|
AllowIDPInitiated: opts.AllowIDPInitiated,
|
|
DefaultRedirectURI: opts.DefaultRedirectURI,
|
|
}
|
|
}
|
|
|
|
// New creates a new Middleware with the default providers for the
|
|
// given options.
|
|
//
|
|
// You can customize the behavior of the middleware in more detail by
|
|
// replacing and/or changing Session, RequestTracker, and ServiceProvider
|
|
// in the returned Middleware.
|
|
func New(opts Options) (*Middleware, error) {
|
|
m := &Middleware{
|
|
ServiceProvider: DefaultServiceProvider(opts),
|
|
Binding: "",
|
|
ResponseBinding: saml.HTTPPostBinding,
|
|
OnError: DefaultOnError,
|
|
Session: DefaultSessionProvider(opts),
|
|
}
|
|
m.RequestTracker = DefaultRequestTracker(opts, &m.ServiceProvider)
|
|
if opts.UseArtifactResponse {
|
|
m.ResponseBinding = saml.HTTPArtifactBinding
|
|
}
|
|
|
|
return m, nil
|
|
}
|