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 }