2019-05-07 00:20:36 +01:00
package cookies
import (
2019-12-16 13:10:04 -05:00
"fmt"
2019-05-07 00:20:36 +01:00
"net"
"net/http"
"strings"
"time"
2020-09-30 01:44:42 +09:00
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
2019-05-07 00:20:36 +01:00
)
// MakeCookie constructs a cookie from the given parameters,
// discovering the domain from the request if not specified.
2019-12-16 13:10:04 -05:00
func MakeCookie ( req * http . Request , name string , value string , path string , domain string , httpOnly bool , secure bool , expiration time . Duration , now time . Time , sameSite http . SameSite ) * http . Cookie {
2019-05-07 00:20:36 +01:00
if domain != "" {
2020-08-21 19:50:32 -07:00
host := util . GetRequestHost ( req )
2019-05-07 00:20:36 +01:00
if h , _ , err := net . SplitHostPort ( host ) ; err == nil {
host = h
}
if ! strings . HasSuffix ( host , domain ) {
2020-08-10 11:44:08 +01:00
logger . Errorf ( "Warning: request host is %q but using configured cookie domain of %q" , host , domain )
2019-05-07 00:20:36 +01:00
}
}
return & http . Cookie {
Name : name ,
Value : value ,
Path : path ,
Domain : domain ,
HttpOnly : httpOnly ,
Secure : secure ,
Expires : now . Add ( expiration ) ,
2019-12-16 13:10:04 -05:00
SameSite : sameSite ,
2019-05-07 00:20:36 +01:00
}
}
2019-05-13 16:01:28 +01:00
2019-12-20 09:44:59 -05:00
// MakeCookieFromOptions constructs a cookie based on the given *options.CookieOptions,
2019-05-13 16:01:28 +01:00
// value and creation time
2020-05-25 12:43:24 +01:00
func MakeCookieFromOptions ( req * http . Request , name string , value string , cookieOpts * options . Cookie , expiration time . Duration , now time . Time ) * http . Cookie {
2020-04-12 14:00:59 +01:00
domain := GetCookieDomain ( req , cookieOpts . Domains )
2020-04-12 04:00:44 -07:00
if domain != "" {
2020-04-12 14:00:59 +01:00
return MakeCookie ( req , name , value , cookieOpts . Path , domain , cookieOpts . HTTPOnly , cookieOpts . Secure , expiration , now , ParseSameSite ( cookieOpts . SameSite ) )
2020-04-12 04:00:44 -07:00
}
// If nothing matches, create the cookie with the shortest domain
defaultDomain := ""
2020-04-12 14:00:59 +01:00
if len ( cookieOpts . Domains ) > 0 {
2020-08-21 19:50:32 -07:00
logger . Errorf ( "Warning: request host %q did not match any of the specific cookie domains of %q" , util . GetRequestHost ( req ) , strings . Join ( cookieOpts . Domains , "," ) )
2020-04-12 14:00:59 +01:00
defaultDomain = cookieOpts . Domains [ len ( cookieOpts . Domains ) - 1 ]
2020-04-12 04:00:44 -07:00
}
2020-04-12 14:00:59 +01:00
return MakeCookie ( req , name , value , cookieOpts . Path , defaultDomain , cookieOpts . HTTPOnly , cookieOpts . Secure , expiration , now , ParseSameSite ( cookieOpts . SameSite ) )
2020-04-12 04:00:44 -07:00
}
// GetCookieDomain returns the correct cookie domain given a list of domains
// by checking the X-Fowarded-Host and host header of an an http request
func GetCookieDomain ( req * http . Request , cookieDomains [ ] string ) string {
2020-08-21 19:50:32 -07:00
host := util . GetRequestHost ( req )
2020-04-12 04:00:44 -07:00
for _ , domain := range cookieDomains {
if strings . HasSuffix ( host , domain ) {
return domain
}
}
return ""
}
2019-12-16 13:10:04 -05:00
// Parse a valid http.SameSite value from a user supplied string for use of making cookies.
func ParseSameSite ( v string ) http . SameSite {
switch v {
case "lax" :
return http . SameSiteLaxMode
case "strict" :
return http . SameSiteStrictMode
case "none" :
return http . SameSiteNoneMode
case "" :
return http . SameSiteDefaultMode
default :
panic ( fmt . Sprintf ( "Invalid value for SameSite: %s" , v ) )
}
2019-05-13 16:01:28 +01:00
}