Address gosec findings
Mostly handling unhandled errors appropriately. If logging to STDERR fails, we panic. Added #nosec comments to findings we are OK with.
This commit is contained in:
		
							parent
							
								
									7b21f53aad
								
							
						
					
					
						commit
						65c228394f
					
				|  | @ -11,6 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| ## Changes since v6.0.0 | ## Changes since v6.0.0 | ||||||
| 
 | 
 | ||||||
|  | - [#690](https://github.com/oauth2-proxy/oauth2-proxy/pull/690) Address GoSec security findings & remediate (@NickMeves) | ||||||
| - [#689](https://github.com/oauth2-proxy/oauth2-proxy/pull/689) Fix finicky logging_handler_test from time drift (@NickMeves) | - [#689](https://github.com/oauth2-proxy/oauth2-proxy/pull/689) Fix finicky logging_handler_test from time drift (@NickMeves) | ||||||
| - [#699](https://github.com/oauth2-proxy/oauth2-proxy/pull/699) Align persistence ginkgo tests with conventions (@NickMeves) | - [#699](https://github.com/oauth2-proxy/oauth2-proxy/pull/699) Align persistence ginkgo tests with conventions (@NickMeves) | ||||||
| - [#696](https://github.com/oauth2-proxy/oauth2-proxy/pull/696) Preserve query when building redirect | - [#696](https://github.com/oauth2-proxy/oauth2-proxy/pull/696) Preserve query when building redirect | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								http.go
								
								
								
								
							
							
						
						
									
										10
									
								
								http.go
								
								
								
								
							|  | @ -124,7 +124,13 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	tc.SetKeepAlive(true) | 	err = tc.SetKeepAlive(true) | ||||||
| 	tc.SetKeepAlivePeriod(3 * time.Minute) | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	err = tc.SetKeepAlivePeriod(3 * time.Minute) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
| 	return tc, nil | 	return tc, nil | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								main.go
								
								
								
								
							
							
						
						
									
										8
									
								
								main.go
								
								
								
								
							|  | @ -25,7 +25,11 @@ func main() { | ||||||
| 	config := flagSet.String("config", "", "path to config file") | 	config := flagSet.String("config", "", "path to config file") | ||||||
| 	showVersion := flagSet.Bool("version", false, "print version string") | 	showVersion := flagSet.Bool("version", false, "print version string") | ||||||
| 
 | 
 | ||||||
| 	flagSet.Parse(os.Args[1:]) | 	err := flagSet.Parse(os.Args[1:]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("ERROR: Failed to parse flags: %v", err) | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if *showVersion { | 	if *showVersion { | ||||||
| 		fmt.Printf("oauth2-proxy %s (built with %s)\n", VERSION, runtime.Version()) | 		fmt.Printf("oauth2-proxy %s (built with %s)\n", VERSION, runtime.Version()) | ||||||
|  | @ -33,7 +37,7 @@ func main() { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	legacyOpts := options.NewLegacyOptions() | 	legacyOpts := options.NewLegacyOptions() | ||||||
| 	err := options.Load(*config, flagSet, legacyOpts) | 	err = options.Load(*config, flagSet, legacyOpts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		logger.Printf("ERROR: Failed to load config: %v", err) | 		logger.Printf("ERROR: Failed to load config: %v", err) | ||||||
| 		os.Exit(1) | 		os.Exit(1) | ||||||
|  |  | ||||||
|  | @ -364,7 +364,11 @@ func (p *OAuthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *s | ||||||
| // RobotsTxt disallows scraping pages from the OAuthProxy
 | // RobotsTxt disallows scraping pages from the OAuthProxy
 | ||||||
| func (p *OAuthProxy) RobotsTxt(rw http.ResponseWriter) { | func (p *OAuthProxy) RobotsTxt(rw http.ResponseWriter) { | ||||||
| 	rw.WriteHeader(http.StatusOK) | 	rw.WriteHeader(http.StatusOK) | ||||||
| 	fmt.Fprintf(rw, "User-agent: *\nDisallow: /") | 	_, err := fmt.Fprintf(rw, "User-agent: *\nDisallow: /") | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("Error writing robots.txt: %s", err.Error()) | ||||||
|  | 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ErrorPage writes an error response
 | // ErrorPage writes an error response
 | ||||||
|  | @ -379,13 +383,22 @@ func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, m | ||||||
| 		Message:     message, | 		Message:     message, | ||||||
| 		ProxyPrefix: p.ProxyPrefix, | 		ProxyPrefix: p.ProxyPrefix, | ||||||
| 	} | 	} | ||||||
| 	p.templates.ExecuteTemplate(rw, "error.html", t) | 	err := p.templates.ExecuteTemplate(rw, "error.html", t) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("Error rendering error.html template: %s", err.Error()) | ||||||
|  | 		http.Error(rw, "Internal Server Error", http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SignInPage writes the sing in template to the response
 | // SignInPage writes the sing in template to the response
 | ||||||
| func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) { | func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) { | ||||||
| 	prepareNoCache(rw) | 	prepareNoCache(rw) | ||||||
| 	p.ClearSessionCookie(rw, req) | 	err := p.ClearSessionCookie(rw, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("Error clearing session cookie: %s", err.Error()) | ||||||
|  | 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
| 	rw.WriteHeader(code) | 	rw.WriteHeader(code) | ||||||
| 
 | 
 | ||||||
| 	redirectURL, err := p.GetRedirect(req) | 	redirectURL, err := p.GetRedirect(req) | ||||||
|  | @ -419,11 +432,15 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code | ||||||
| 	if p.providerNameOverride != "" { | 	if p.providerNameOverride != "" { | ||||||
| 		t.ProviderName = p.providerNameOverride | 		t.ProviderName = p.providerNameOverride | ||||||
| 	} | 	} | ||||||
| 	p.templates.ExecuteTemplate(rw, "sign_in.html", t) | 	err = p.templates.ExecuteTemplate(rw, "sign_in.html", t) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("Error rendering sign_in.html template: %s", err.Error()) | ||||||
|  | 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ManualSignIn handles basic auth logins to the proxy
 | // ManualSignIn handles basic auth logins to the proxy
 | ||||||
| func (p *OAuthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool) { | func (p *OAuthProxy) ManualSignIn(req *http.Request) (string, bool) { | ||||||
| 	if req.Method != "POST" || p.basicAuthValidator == nil { | 	if req.Method != "POST" || p.basicAuthValidator == nil { | ||||||
| 		return "", false | 		return "", false | ||||||
| 	} | 	} | ||||||
|  | @ -632,10 +649,15 @@ func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	user, ok := p.ManualSignIn(rw, req) | 	user, ok := p.ManualSignIn(req) | ||||||
| 	if ok { | 	if ok { | ||||||
| 		session := &sessionsapi.SessionState{User: user} | 		session := &sessionsapi.SessionState{User: user} | ||||||
| 		p.SaveSession(rw, req, session) | 		err = p.SaveSession(rw, req, session) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("Error saving session: %s", err.Error()) | ||||||
|  | 			p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
| 		http.Redirect(rw, req, redirect, http.StatusFound) | 		http.Redirect(rw, req, redirect, http.StatusFound) | ||||||
| 	} else { | 	} else { | ||||||
| 		if p.SkipProviderButton { | 		if p.SkipProviderButton { | ||||||
|  | @ -663,7 +685,11 @@ func (p *OAuthProxy) UserInfo(rw http.ResponseWriter, req *http.Request) { | ||||||
| 	} | 	} | ||||||
| 	rw.Header().Set("Content-Type", "application/json") | 	rw.Header().Set("Content-Type", "application/json") | ||||||
| 	rw.WriteHeader(http.StatusOK) | 	rw.WriteHeader(http.StatusOK) | ||||||
| 	json.NewEncoder(rw).Encode(userInfo) | 	err = json.NewEncoder(rw).Encode(userInfo) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("Error encoding user info: %s", err.Error()) | ||||||
|  | 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SignOut sends a response to clear the authentication cookie
 | // SignOut sends a response to clear the authentication cookie
 | ||||||
|  | @ -674,7 +700,12 @@ func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request) { | ||||||
| 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	p.ClearSessionCookie(rw, req) | 	err = p.ClearSessionCookie(rw, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("Error clearing session cookie: %s", err.Error()) | ||||||
|  | 		p.ErrorPage(rw, 500, "Internal Error", err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
| 	http.Redirect(rw, req, redirect, http.StatusFound) | 	http.Redirect(rw, req, redirect, http.StatusFound) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -837,7 +868,10 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R | ||||||
| 	if session != nil && session.Email != "" && !p.Validator(session.Email) { | 	if session != nil && session.Email != "" && !p.Validator(session.Email) { | ||||||
| 		logger.Printf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session) | 		logger.Printf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session) | ||||||
| 		// Invalid session, clear it
 | 		// Invalid session, clear it
 | ||||||
| 		p.ClearSessionCookie(rw, req) | 		err := p.ClearSessionCookie(rw, req) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("Error clearing session cookie: %s", err.Error()) | ||||||
|  | 		} | ||||||
| 		return nil, ErrNeedsLogin | 		return nil, ErrNeedsLogin | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| package basic | package basic | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/sha1" | 	"crypto/sha1" // #nosec G505
 | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"encoding/csv" | 	"encoding/csv" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | @ -29,11 +29,16 @@ type sha1Pass string | ||||||
| // NewHTPasswdValidator constructs an httpasswd based validator from the file
 | // NewHTPasswdValidator constructs an httpasswd based validator from the file
 | ||||||
| // at the path given.
 | // at the path given.
 | ||||||
| func NewHTPasswdValidator(path string) (Validator, error) { | func NewHTPasswdValidator(path string) (Validator, error) { | ||||||
| 	r, err := os.Open(path) | 	r, err := os.Open(path) // #nosec G304
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("could not open htpasswd file: %v", err) | 		return nil, fmt.Errorf("could not open htpasswd file: %v", err) | ||||||
| 	} | 	} | ||||||
| 	defer r.Close() | 	defer func(c io.Closer) { | ||||||
|  | 		cerr := c.Close() | ||||||
|  | 		if cerr != nil { | ||||||
|  | 			logger.Fatalf("error closing the htpasswd file: %v", cerr) | ||||||
|  | 		} | ||||||
|  | 	}(r) | ||||||
| 	return newHtpasswd(r) | 	return newHtpasswd(r) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -83,13 +88,16 @@ func (h *htpasswdMap) Validate(user string, password string) bool { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch real := realPassword.(type) { | 	switch rp := realPassword.(type) { | ||||||
| 	case sha1Pass: | 	case sha1Pass: | ||||||
| 		d := sha1.New() | 		d := sha1.New() // #nosec G401
 | ||||||
| 		d.Write([]byte(password)) | 		_, err := d.Write([]byte(password)) | ||||||
| 		return string(real) == base64.StdEncoding.EncodeToString(d.Sum(nil)) | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		return string(rp) == base64.StdEncoding.EncodeToString(d.Sum(nil)) | ||||||
| 	case bcryptPass: | 	case bcryptPass: | ||||||
| 		return bcrypt.CompareHashAndPassword([]byte(real), []byte(password)) == nil | 		return bcrypt.CompareHashAndPassword([]byte(rp), []byte(password)) == nil | ||||||
| 	default: | 	default: | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -2,15 +2,19 @@ package encryption | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/hmac" | 	"crypto/hmac" | ||||||
| 	"crypto/sha1" | 	"crypto/rand" | ||||||
|  | 	"crypto/sha1" // #nosec G505
 | ||||||
| 	"crypto/sha256" | 	"crypto/sha256" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"hash" | 	"hash" | ||||||
|  | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/pkg/logger" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // SecretBytes attempts to base64 decode the secret, if that fails it treats the secret as binary
 | // SecretBytes attempts to base64 decode the secret, if that fails it treats the secret as binary
 | ||||||
|  | @ -76,7 +80,15 @@ func SignedValue(seed string, key string, value []byte, now time.Time) string { | ||||||
| func cookieSignature(signer func() hash.Hash, args ...string) string { | func cookieSignature(signer func() hash.Hash, args ...string) string { | ||||||
| 	h := hmac.New(signer, []byte(args[0])) | 	h := hmac.New(signer, []byte(args[0])) | ||||||
| 	for _, arg := range args[1:] { | 	for _, arg := range args[1:] { | ||||||
| 		h.Write([]byte(arg)) | 		_, err := h.Write([]byte(arg)) | ||||||
|  | 		// If signing fails, fail closed and return something that won't validate
 | ||||||
|  | 		if err != nil { | ||||||
|  | 			garbage := make([]byte, 16) | ||||||
|  | 			if _, err := io.ReadFull(rand.Reader, garbage); err != nil { | ||||||
|  | 				logger.Fatal("HMAC & RNG functions both failing. Shutting down for security") | ||||||
|  | 			} | ||||||
|  | 			return base64.URLEncoding.EncodeToString(garbage) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	var b []byte | 	var b []byte | ||||||
| 	b = h.Sum(b) | 	b = h.Sum(b) | ||||||
|  |  | ||||||
|  | @ -132,13 +132,19 @@ func (l *Logger) Output(calldepth int, message string) { | ||||||
| 	l.mu.Lock() | 	l.mu.Lock() | ||||||
| 	defer l.mu.Unlock() | 	defer l.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	l.stdLogTemplate.Execute(l.writer, stdLogMessageData{ | 	err := l.stdLogTemplate.Execute(l.writer, stdLogMessageData{ | ||||||
| 		Timestamp: FormatTimestamp(now), | 		Timestamp: FormatTimestamp(now), | ||||||
| 		File:      file, | 		File:      file, | ||||||
| 		Message:   message, | 		Message:   message, | ||||||
| 	}) | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	l.writer.Write([]byte("\n")) | 	_, err = l.writer.Write([]byte("\n")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PrintAuthf writes auth info to the logger. Requires an http.Request to
 | // PrintAuthf writes auth info to the logger. Requires an http.Request to
 | ||||||
|  | @ -160,7 +166,7 @@ func (l *Logger) PrintAuthf(username string, req *http.Request, status AuthStatu | ||||||
| 	l.mu.Lock() | 	l.mu.Lock() | ||||||
| 	defer l.mu.Unlock() | 	defer l.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	l.authTemplate.Execute(l.writer, authLogMessageData{ | 	err := l.authTemplate.Execute(l.writer, authLogMessageData{ | ||||||
| 		Client:        client, | 		Client:        client, | ||||||
| 		Host:          req.Host, | 		Host:          req.Host, | ||||||
| 		Protocol:      req.Proto, | 		Protocol:      req.Proto, | ||||||
|  | @ -171,8 +177,14 @@ func (l *Logger) PrintAuthf(username string, req *http.Request, status AuthStatu | ||||||
| 		Status:        string(status), | 		Status:        string(status), | ||||||
| 		Message:       fmt.Sprintf(format, a...), | 		Message:       fmt.Sprintf(format, a...), | ||||||
| 	}) | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	l.writer.Write([]byte("\n")) | 	_, err = l.writer.Write([]byte("\n")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PrintReq writes request details to the Logger using the http.Request,
 | // PrintReq writes request details to the Logger using the http.Request,
 | ||||||
|  | @ -208,7 +220,7 @@ func (l *Logger) PrintReq(username, upstream string, req *http.Request, url url. | ||||||
| 	l.mu.Lock() | 	l.mu.Lock() | ||||||
| 	defer l.mu.Unlock() | 	defer l.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	l.reqTemplate.Execute(l.writer, reqLogMessageData{ | 	err := l.reqTemplate.Execute(l.writer, reqLogMessageData{ | ||||||
| 		Client:          client, | 		Client:          client, | ||||||
| 		Host:            req.Host, | 		Host:            req.Host, | ||||||
| 		Protocol:        req.Proto, | 		Protocol:        req.Proto, | ||||||
|  | @ -222,8 +234,14 @@ func (l *Logger) PrintReq(username, upstream string, req *http.Request, url url. | ||||||
| 		UserAgent:       fmt.Sprintf("%q", req.UserAgent()), | 		UserAgent:       fmt.Sprintf("%q", req.UserAgent()), | ||||||
| 		Username:        username, | 		Username:        username, | ||||||
| 	}) | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	l.writer.Write([]byte("\n")) | 	_, err = l.writer.Write([]byte("\n")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetFileLineString will find the caller file and line number
 | // GetFileLineString will find the caller file and line number
 | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ type storedSessionLoader struct { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // loadSession attempts to load a session as identified by the request cookies.
 | // loadSession attempts to load a session as identified by the request cookies.
 | ||||||
| // If no session is found, the request will be passed to the nex handler.
 | // If no session is found, the request will be passed to the next handler.
 | ||||||
| // If a session was loader by a previous handler, it will not be replaced.
 | // If a session was loader by a previous handler, it will not be replaced.
 | ||||||
| func (s *storedSessionLoader) loadSession(next http.Handler) http.Handler { | func (s *storedSessionLoader) loadSession(next http.Handler) http.Handler { | ||||||
| 	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { | 	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { | ||||||
|  | @ -73,7 +73,10 @@ func (s *storedSessionLoader) loadSession(next http.Handler) http.Handler { | ||||||
| 			// In the case when there was an error loading the session,
 | 			// In the case when there was an error loading the session,
 | ||||||
| 			// we should clear the session
 | 			// we should clear the session
 | ||||||
| 			logger.Printf("Error loading cookied session: %v, removing session", err) | 			logger.Printf("Error loading cookied session: %v, removing session", err) | ||||||
| 			s.store.Clear(rw, req) | 			err = s.store.Clear(rw, req) | ||||||
|  | 			if err != nil { | ||||||
|  | 				logger.Printf("Error removing session: %v", err) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Add the session to the scope if it was found
 | 		// Add the session to the scope if it was found
 | ||||||
|  |  | ||||||
|  | @ -103,6 +103,7 @@ func newReverseProxy(target *url.URL, upstream options.Upstream, errorHandler Pr | ||||||
| 		proxy.FlushInterval = 1 * time.Second | 		proxy.FlushInterval = 1 * time.Second | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/* #nosec G402 */ | ||||||
| 	if upstream.InsecureSkipTLSVerify { | 	if upstream.InsecureSkipTLSVerify { | ||||||
| 		proxy.Transport = &http.Transport{ | 		proxy.Transport = &http.Transport{ | ||||||
| 			TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | 			TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | ||||||
|  | @ -156,6 +157,7 @@ func newWebSocketReverseProxy(u *url.URL, skipTLSVerify bool) http.Handler { | ||||||
| 	wsURL := &url.URL{Scheme: wsScheme, Host: u.Host} | 	wsURL := &url.URL{Scheme: wsScheme, Host: u.Host} | ||||||
| 
 | 
 | ||||||
| 	wsProxy := wsutil.NewSingleHostReverseProxy(wsURL) | 	wsProxy := wsutil.NewSingleHostReverseProxy(wsURL) | ||||||
|  | 	/* #nosec G402 */ | ||||||
| 	if skipTLSVerify { | 	if skipTLSVerify { | ||||||
| 		wsProxy.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} | 		wsProxy.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -85,6 +85,9 @@ func NewProxyErrorHandler(errorTemplate *template.Template, proxyPrefix string) | ||||||
| 			Message:     "Error proxying to upstream server", | 			Message:     "Error proxying to upstream server", | ||||||
| 			ProxyPrefix: proxyPrefix, | 			ProxyPrefix: proxyPrefix, | ||||||
| 		} | 		} | ||||||
| 		errorTemplate.Execute(rw, data) | 		err := errorTemplate.Execute(rw, data) | ||||||
|  | 		if err != nil { | ||||||
|  | 			http.Error(rw, "Internal Server Error", http.StatusInternalServerError) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ func GetCertPool(paths []string) (*x509.CertPool, error) { | ||||||
| 	} | 	} | ||||||
| 	pool := x509.NewCertPool() | 	pool := x509.NewCertPool() | ||||||
| 	for _, path := range paths { | 	for _, path := range paths { | ||||||
| 		data, err := ioutil.ReadFile(path) | 		data, err := ioutil.ReadFile(path) // #nosec G304
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("certificate authority file (%s) could not be read - %s", path, err) | 			return nil, fmt.Errorf("certificate authority file (%s) could not be read - %s", path, err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -13,13 +13,16 @@ func configureLogger(o options.Logging, msgs []string) []string { | ||||||
| 	// Setup the log file
 | 	// Setup the log file
 | ||||||
| 	if len(o.File.Filename) > 0 { | 	if len(o.File.Filename) > 0 { | ||||||
| 		// Validate that the file/dir can be written
 | 		// Validate that the file/dir can be written
 | ||||||
| 		file, err := os.OpenFile(o.File.Filename, os.O_WRONLY|os.O_CREATE, 0666) | 		file, err := os.OpenFile(o.File.Filename, os.O_WRONLY|os.O_CREATE, 0600) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if os.IsPermission(err) { | 			if os.IsPermission(err) { | ||||||
| 				return append(msgs, "unable to write to log file: "+o.File.Filename) | 				return append(msgs, "unable to write to log file: "+o.File.Filename) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file.Close() | 		err = file.Close() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return append(msgs, "error closing the log file: "+o.File.Filename) | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		logger.Printf("Redirecting logging to file: %s", o.File.Filename) | 		logger.Printf("Redirecting logging to file: %s", o.File.Filename) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ func Validate(o *options.Options) error { | ||||||
| 	msgs = append(msgs, validateSessionCookieMinimal(o)...) | 	msgs = append(msgs, validateSessionCookieMinimal(o)...) | ||||||
| 
 | 
 | ||||||
| 	if o.SSLInsecureSkipVerify { | 	if o.SSLInsecureSkipVerify { | ||||||
|  | 		/* #nosec G402 */ | ||||||
| 		insecureTransport := &http.Transport{ | 		insecureTransport := &http.Transport{ | ||||||
| 			TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | 			TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | ||||||
| 		} | 		} | ||||||
|  | @ -217,7 +218,10 @@ func Validate(o *options.Options) error { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(o.TrustedIPs) > 0 && o.ReverseProxy { | 	if len(o.TrustedIPs) > 0 && o.ReverseProxy { | ||||||
| 		fmt.Fprintln(os.Stderr, "WARNING: trusting of IPs with --reverse-proxy poses risks if a header spoofing attack is possible.") | 		_, err := fmt.Fprintln(os.Stderr, "WARNING: trusting of IPs with --reverse-proxy poses risks if a header spoofing attack is possible.") | ||||||
|  | 		if err != nil { | ||||||
|  | 			panic(err) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for i, ipStr := range o.TrustedIPs { | 	for i, ipStr := range o.TrustedIPs { | ||||||
|  |  | ||||||
|  | @ -115,10 +115,12 @@ func checkNonce(idToken string, p *LoginGovProvider) (err error) { | ||||||
| 			return nil, myerr | 			return nil, myerr | ||||||
| 		} | 		} | ||||||
| 		body, myerr := ioutil.ReadAll(resp.Body) | 		body, myerr := ioutil.ReadAll(resp.Body) | ||||||
| 		resp.Body.Close() |  | ||||||
| 		if myerr != nil { | 		if myerr != nil { | ||||||
| 			return nil, myerr | 			return nil, myerr | ||||||
| 		} | 		} | ||||||
|  | 		if myerr = resp.Body.Close(); myerr != nil { | ||||||
|  | 			return nil, myerr | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		var pubkeys jose.JSONWebKeySet | 		var pubkeys jose.JSONWebKeySet | ||||||
| 		myerr = json.Unmarshal(body, &pubkeys) | 		myerr = json.Unmarshal(body, &pubkeys) | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ package main | ||||||
| import ( | import ( | ||||||
| 	"encoding/csv" | 	"encoding/csv" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
|  | @ -47,7 +48,12 @@ func (um *UserMap) LoadAuthenticatedEmailsFile() { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		logger.Fatalf("failed opening authenticated-emails-file=%q, %s", um.usersFile, err) | 		logger.Fatalf("failed opening authenticated-emails-file=%q, %s", um.usersFile, err) | ||||||
| 	} | 	} | ||||||
| 	defer r.Close() | 	defer func(c io.Closer) { | ||||||
|  | 		cerr := c.Close() | ||||||
|  | 		if cerr != nil { | ||||||
|  | 			logger.Fatalf("Error closing authenticated emails file: %s", cerr) | ||||||
|  | 		} | ||||||
|  | 	}(r) | ||||||
| 	csvReader := csv.NewReader(r) | 	csvReader := csv.NewReader(r) | ||||||
| 	csvReader.Comma = ',' | 	csvReader.Comma = ',' | ||||||
| 	csvReader.Comment = '#' | 	csvReader.Comment = '#' | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								watcher.go
								
								
								
								
							
							
						
						
									
										12
									
								
								watcher.go
								
								
								
								
							|  | @ -41,7 +41,12 @@ func WatchForUpdates(filename string, done <-chan bool, action func()) { | ||||||
| 		logger.Fatal("failed to create watcher for ", filename, ": ", err) | 		logger.Fatal("failed to create watcher for ", filename, ": ", err) | ||||||
| 	} | 	} | ||||||
| 	go func() { | 	go func() { | ||||||
| 		defer watcher.Close() | 		defer func(w *fsnotify.Watcher) { | ||||||
|  | 			cerr := w.Close() | ||||||
|  | 			if cerr != nil { | ||||||
|  | 				logger.Fatalf("error closing watcher: %s", err) | ||||||
|  | 			} | ||||||
|  | 		}(watcher) | ||||||
| 		for { | 		for { | ||||||
| 			select { | 			select { | ||||||
| 			case <-done: | 			case <-done: | ||||||
|  | @ -55,7 +60,10 @@ func WatchForUpdates(filename string, done <-chan bool, action func()) { | ||||||
| 				// can't be opened.
 | 				// can't be opened.
 | ||||||
| 				if event.Op&(fsnotify.Remove|fsnotify.Rename|fsnotify.Chmod) != 0 { | 				if event.Op&(fsnotify.Remove|fsnotify.Rename|fsnotify.Chmod) != 0 { | ||||||
| 					logger.Printf("watching interrupted on event: %s", event) | 					logger.Printf("watching interrupted on event: %s", event) | ||||||
| 					watcher.Remove(filename) | 					err = watcher.Remove(filename) | ||||||
|  | 					if err != nil { | ||||||
|  | 						logger.Printf("error removing watcher on %s: %s", filename, err) | ||||||
|  | 					} | ||||||
| 					WaitForReplacement(filename, event.Op, watcher) | 					WaitForReplacement(filename, event.Op, watcher) | ||||||
| 				} | 				} | ||||||
| 				logger.Printf("reloading after event: %s", event) | 				logger.Printf("reloading after event: %s", event) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue