github.com/crewjam/saml@v0.4.14/samlsp/session_cookie.go (about)

     1  package samlsp
     2  
     3  import (
     4  	"net"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/crewjam/saml"
     9  )
    10  
    11  const defaultSessionCookieName = "token"
    12  
    13  var _ SessionProvider = CookieSessionProvider{}
    14  
    15  // CookieSessionProvider is an implementation of SessionProvider that stores
    16  // session tokens in an HTTP cookie.
    17  type CookieSessionProvider struct {
    18  	Name     string
    19  	Domain   string
    20  	HTTPOnly bool
    21  	Secure   bool
    22  	SameSite http.SameSite
    23  	MaxAge   time.Duration
    24  	Codec    SessionCodec
    25  }
    26  
    27  // CreateSession is called when we have received a valid SAML assertion and
    28  // should create a new session and modify the http response accordingly, e.g. by
    29  // setting a cookie.
    30  func (c CookieSessionProvider) CreateSession(w http.ResponseWriter, r *http.Request, assertion *saml.Assertion) error {
    31  	// Cookies should not have the port attached to them so strip it off
    32  	if domain, _, err := net.SplitHostPort(c.Domain); err == nil {
    33  		c.Domain = domain
    34  	}
    35  
    36  	session, err := c.Codec.New(assertion)
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	value, err := c.Codec.Encode(session)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	http.SetCookie(w, &http.Cookie{
    47  		Name:     c.Name,
    48  		Domain:   c.Domain,
    49  		Value:    value,
    50  		MaxAge:   int(c.MaxAge.Seconds()),
    51  		HttpOnly: c.HTTPOnly,
    52  		Secure:   c.Secure || r.URL.Scheme == "https",
    53  		SameSite: c.SameSite,
    54  		Path:     "/",
    55  	})
    56  	return nil
    57  }
    58  
    59  // DeleteSession is called to modify the response such that it removed the current
    60  // session, e.g. by deleting a cookie.
    61  func (c CookieSessionProvider) DeleteSession(w http.ResponseWriter, r *http.Request) error {
    62  	// Cookies should not have the port attached to them so strip it off
    63  	if domain, _, err := net.SplitHostPort(c.Domain); err == nil {
    64  		c.Domain = domain
    65  	}
    66  
    67  	cookie, err := r.Cookie(c.Name)
    68  
    69  	if err == http.ErrNoCookie {
    70  		return nil
    71  	}
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	cookie.Value = ""
    77  	cookie.Expires = time.Unix(1, 0) // past time as close to epoch as possible, but not zero time.Time{}
    78  	cookie.Path = "/"
    79  	cookie.Domain = c.Domain
    80  	http.SetCookie(w, cookie)
    81  	return nil
    82  }
    83  
    84  // GetSession returns the current Session associated with the request, or
    85  // ErrNoSession if there is no valid session.
    86  func (c CookieSessionProvider) GetSession(r *http.Request) (Session, error) {
    87  	cookie, err := r.Cookie(c.Name)
    88  	if err == http.ErrNoCookie {
    89  		return nil, ErrNoSession
    90  	} else if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	session, err := c.Codec.Decode(cookie.Value)
    95  	if err != nil {
    96  		return nil, ErrNoSession
    97  	}
    98  	return session, nil
    99  }