loginsrv

Unnamed repository; edit this file 'description' to name the repository.
git clone git@jamesshield.xyz:repos/loginsrv.git
Log | Files | Refs | README | LICENSE

redirect.go (3189B)


      1 package login
      2 
      3 import (
      4 	"bufio"
      5 	"net/http"
      6 	"net/url"
      7 	"os"
      8 
      9 	"strings"
     10 	"time"
     11 
     12 	"github.com/tarent/loginsrv/logging"
     13 )
     14 
     15 func (h *Handler) setRedirectCookie(w http.ResponseWriter, r *http.Request) {
     16 	redirectTo := r.URL.Query().Get(h.config.RedirectQueryParameter)
     17 	if redirectTo != "" && h.allowRedirect(r) && r.Method != "POST" {
     18 		cookie := http.Cookie{
     19 			Name:  h.config.RedirectQueryParameter,
     20 			Value: redirectTo,
     21 		}
     22 		http.SetCookie(w, &cookie)
     23 	}
     24 }
     25 
     26 func (h *Handler) deleteRedirectCookie(w http.ResponseWriter, r *http.Request) {
     27 	_, err := r.Cookie(h.config.RedirectQueryParameter)
     28 	if err == nil {
     29 		cookie := http.Cookie{
     30 			Name:    h.config.RedirectQueryParameter,
     31 			Value:   "delete",
     32 			Expires: time.Unix(0, 0),
     33 		}
     34 		http.SetCookie(w, &cookie)
     35 	}
     36 }
     37 
     38 func (h *Handler) allowRedirect(r *http.Request) bool {
     39 	if !h.config.Redirect {
     40 		return false
     41 	}
     42 
     43 	if !h.config.RedirectCheckReferer {
     44 		return true
     45 	}
     46 
     47 	referer, err := url.Parse(r.Header.Get("Referer"))
     48 	if err != nil {
     49 		logging.Application(r.Header).Warnf("couldn't parse redirect url %s", err)
     50 		return false
     51 	}
     52 	if referer.Host != r.Host {
     53 		logging.Application(r.Header).Warnf("redirect from referer domain: '%s', not matching current domain '%s'", referer.Host, r.Host)
     54 		return false
     55 	}
     56 	return true
     57 }
     58 
     59 func (h *Handler) redirectURL(r *http.Request, w http.ResponseWriter) string {
     60 	targetURL, foundTarget := h.getRedirectTarget(r)
     61 	if foundTarget && h.config.Redirect {
     62 		sameHost := targetURL.Host == "" || r.Host == targetURL.Host
     63 		if sameHost && targetURL.Path != "" {
     64 			return targetURL.Path
     65 		}
     66 		if !sameHost && h.isRedirectDomainWhitelisted(r, targetURL.Host) {
     67 			return targetURL.String()
     68 		}
     69 	}
     70 	return h.config.SuccessURL
     71 }
     72 
     73 func (h *Handler) getRedirectTarget(r *http.Request) (*url.URL, bool) {
     74 	cookie, err := r.Cookie(h.config.RedirectQueryParameter)
     75 	if err == nil {
     76 		url, err := url.Parse(cookie.Value)
     77 		if err != nil {
     78 			logging.Application(r.Header).Warnf("error parsing redirect URL: %s", err)
     79 			return nil, false
     80 		}
     81 		return url, true
     82 	}
     83 
     84 	// try reading parameter as it might be a POST request and so not have set the cookie yet
     85 	redirectTo := r.URL.Query().Get(h.config.RedirectQueryParameter)
     86 	if redirectTo == "" || r.Method != "POST" {
     87 		return nil, false
     88 	}
     89 	url, err := url.Parse(redirectTo)
     90 	if err != nil {
     91 		logging.Application(r.Header).Warnf("error parsing redirect URL: %s", err)
     92 		return nil, false
     93 	}
     94 	return url, true
     95 }
     96 
     97 func (h *Handler) isRedirectDomainWhitelisted(r *http.Request, host string) bool {
     98 	if h.config.RedirectHostFile == "" {
     99 		logging.Application(r.Header).Warnf("redirect attempt to '%s', but no whitelist domain file given", host)
    100 		return false
    101 	}
    102 
    103 	f, err := os.Open(h.config.RedirectHostFile)
    104 	if err != nil {
    105 		logging.Application(r.Header).Warnf("can't open redirect whitelist domains file '%s'", h.config.RedirectHostFile)
    106 		return false
    107 	}
    108 	defer f.Close()
    109 	scanner := bufio.NewScanner(f)
    110 	scanner.Split(bufio.ScanLines)
    111 	for scanner.Scan() {
    112 		if host == strings.TrimSpace(scanner.Text()) {
    113 			return true
    114 		}
    115 	}
    116 	logging.Application(r.Header).Warnf("redirect attempt to '%s', but not in redirect whitelist", host)
    117 	return false
    118 }