git.iko.soy/typeable/oauth2-proxy
on master help sign in
Address gosec findings
65c2283Nick Meves
CHANGELOG.md+1
@@ -11,6 +11,7 @@
11
11
12## Changes since v6.0.0
12## Changes since v6.0.0
13
13
14+- [#690](https://github.com/oauth2-proxy/oauth2-proxy/pull/690) Address GoSec security findings & remediate (@NickMeves)
14- [#689](https://github.com/oauth2-proxy/oauth2-proxy/pull/689) Fix finicky logging_handler_test from time drift (@NickMeves)
15- [#689](https://github.com/oauth2-proxy/oauth2-proxy/pull/689) Fix finicky logging_handler_test from time drift (@NickMeves)
15- [#699](https://github.com/oauth2-proxy/oauth2-proxy/pull/699) Align persistence ginkgo tests with conventions (@NickMeves)
16- [#699](https://github.com/oauth2-proxy/oauth2-proxy/pull/699) Align persistence ginkgo tests with conventions (@NickMeves)
16- [#696](https://github.com/oauth2-proxy/oauth2-proxy/pull/696) Preserve query when building redirect
17- [#696](https://github.com/oauth2-proxy/oauth2-proxy/pull/696) Preserve query when building redirect
http.go+8−2
@@ -124,7 +124,13 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
124 if err != nil {
124 if err != nil {
125 return
125 return
126 }
126 }
127− tc.SetKeepAlive(true)
127+ err = tc.SetKeepAlive(true)
128+ if err != nil {
129+ return nil, err
130+ }
128− tc.SetKeepAlivePeriod(3 * time.Minute)
131+ err = tc.SetKeepAlivePeriod(3 * time.Minute)
132+ if err != nil {
133+ return nil, err
134+ }
129 return tc, nil
135 return tc, nil
130}
136}
main.go+6−2
@@ -25,7 +25,11 @@ func main() {
25 config := flagSet.String("config", "", "path to config file")
25 config := flagSet.String("config", "", "path to config file")
26 showVersion := flagSet.Bool("version", false, "print version string")
26 showVersion := flagSet.Bool("version", false, "print version string")
27
27
28− flagSet.Parse(os.Args[1:])
28+ err := flagSet.Parse(os.Args[1:])
29+ if err != nil {
30+ logger.Printf("ERROR: Failed to parse flags: %v", err)
31+ os.Exit(1)
32+ }
29
33
30 if *showVersion {
34 if *showVersion {
31 fmt.Printf("oauth2-proxy %s (built with %s)\n", VERSION, runtime.Version())
35 fmt.Printf("oauth2-proxy %s (built with %s)\n", VERSION, runtime.Version())
@@ -33,7 +37,7 @@ func main() {
33 }
37 }
34
38
35 legacyOpts := options.NewLegacyOptions()
39 legacyOpts := options.NewLegacyOptions()
36− err := options.Load(*config, flagSet, legacyOpts)
40+ err = options.Load(*config, flagSet, legacyOpts)
37 if err != nil {
41 if err != nil {
38 logger.Printf("ERROR: Failed to load config: %v", err)
42 logger.Printf("ERROR: Failed to load config: %v", err)
39 os.Exit(1)
43 os.Exit(1)
oauthproxy.go+44−10
@@ -364,7 +364,11 @@ func (p *OAuthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *s
364// RobotsTxt disallows scraping pages from the OAuthProxy
364// RobotsTxt disallows scraping pages from the OAuthProxy
365func (p *OAuthProxy) RobotsTxt(rw http.ResponseWriter) {
365func (p *OAuthProxy) RobotsTxt(rw http.ResponseWriter) {
366 rw.WriteHeader(http.StatusOK)
366 rw.WriteHeader(http.StatusOK)
367− fmt.Fprintf(rw, "User-agent: *\nDisallow: /")
367+ _, err := fmt.Fprintf(rw, "User-agent: *\nDisallow: /")
368+ if err != nil {
369+ logger.Printf("Error writing robots.txt: %s", err.Error())
370+ p.ErrorPage(rw, 500, "Internal Error", err.Error())
371+ }
368}
372}
369
373
370// ErrorPage writes an error response
374// ErrorPage writes an error response
@@ -379,13 +383,22 @@ func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, m
379 Message: message,
383 Message: message,
380 ProxyPrefix: p.ProxyPrefix,
384 ProxyPrefix: p.ProxyPrefix,
381 }
385 }
382− p.templates.ExecuteTemplate(rw, "error.html", t)
386+ err := p.templates.ExecuteTemplate(rw, "error.html", t)
387+ if err != nil {
388+ logger.Printf("Error rendering error.html template: %s", err.Error())
389+ http.Error(rw, "Internal Server Error", http.StatusInternalServerError)
390+ }
383}
391}
384
392
385// SignInPage writes the sing in template to the response
393// SignInPage writes the sing in template to the response
386func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) {
394func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) {
387 prepareNoCache(rw)
395 prepareNoCache(rw)
388− p.ClearSessionCookie(rw, req)
396+ err := p.ClearSessionCookie(rw, req)
397+ if err != nil {
398+ logger.Printf("Error clearing session cookie: %s", err.Error())
399+ p.ErrorPage(rw, 500, "Internal Error", err.Error())
400+ return
401+ }
389 rw.WriteHeader(code)
402 rw.WriteHeader(code)
390
403
391 redirectURL, err := p.GetRedirect(req)
404 redirectURL, err := p.GetRedirect(req)
@@ -419,11 +432,15 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
419 if p.providerNameOverride != "" {
432 if p.providerNameOverride != "" {
420 t.ProviderName = p.providerNameOverride
433 t.ProviderName = p.providerNameOverride
421 }
434 }
422− p.templates.ExecuteTemplate(rw, "sign_in.html", t)
435+ err = p.templates.ExecuteTemplate(rw, "sign_in.html", t)
436+ if err != nil {
437+ logger.Printf("Error rendering sign_in.html template: %s", err.Error())
438+ p.ErrorPage(rw, 500, "Internal Error", err.Error())
439+ }
423}
440}
424
441
425// ManualSignIn handles basic auth logins to the proxy
442// ManualSignIn handles basic auth logins to the proxy
426−func (p *OAuthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool) {
443+func (p *OAuthProxy) ManualSignIn(req *http.Request) (string, bool) {
427 if req.Method != "POST" || p.basicAuthValidator == nil {
444 if req.Method != "POST" || p.basicAuthValidator == nil {
428 return "", false
445 return "", false
429 }
446 }
@@ -632,10 +649,15 @@ func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) {
632 return
649 return
633 }
650 }
634
651
635− user, ok := p.ManualSignIn(rw, req)
652+ user, ok := p.ManualSignIn(req)
636 if ok {
653 if ok {
637 session := &sessionsapi.SessionState{User: user}
654 session := &sessionsapi.SessionState{User: user}
638− p.SaveSession(rw, req, session)
655+ err = p.SaveSession(rw, req, session)
656+ if err != nil {
657+ logger.Printf("Error saving session: %s", err.Error())
658+ p.ErrorPage(rw, 500, "Internal Error", err.Error())
659+ return
660+ }
639 http.Redirect(rw, req, redirect, http.StatusFound)
661 http.Redirect(rw, req, redirect, http.StatusFound)
640 } else {
662 } else {
641 if p.SkipProviderButton {
663 if p.SkipProviderButton {
@@ -663,7 +685,11 @@ func (p *OAuthProxy) UserInfo(rw http.ResponseWriter, req *http.Request) {
663 }
685 }
664 rw.Header().Set("Content-Type", "application/json")
686 rw.Header().Set("Content-Type", "application/json")
665 rw.WriteHeader(http.StatusOK)
687 rw.WriteHeader(http.StatusOK)
666− json.NewEncoder(rw).Encode(userInfo)
688+ err = json.NewEncoder(rw).Encode(userInfo)
689+ if err != nil {
690+ logger.Printf("Error encoding user info: %s", err.Error())
691+ p.ErrorPage(rw, 500, "Internal Error", err.Error())
692+ }
667}
693}
668
694
669// SignOut sends a response to clear the authentication cookie
695// SignOut sends a response to clear the authentication cookie
@@ -674,7 +700,12 @@ func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request) {
674 p.ErrorPage(rw, 500, "Internal Error", err.Error())
700 p.ErrorPage(rw, 500, "Internal Error", err.Error())
675 return
701 return
676 }
702 }
677− p.ClearSessionCookie(rw, req)
703+ err = p.ClearSessionCookie(rw, req)
704+ if err != nil {
705+ logger.Printf("Error clearing session cookie: %s", err.Error())
706+ p.ErrorPage(rw, 500, "Internal Error", err.Error())
707+ return
708+ }
678 http.Redirect(rw, req, redirect, http.StatusFound)
709 http.Redirect(rw, req, redirect, http.StatusFound)
679}
710}
680
711
@@ -837,7 +868,10 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R
837 if session != nil && session.Email != "" && !p.Validator(session.Email) {
868 if session != nil && session.Email != "" && !p.Validator(session.Email) {
838 logger.Printf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session)
869 logger.Printf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session)
839 // Invalid session, clear it
870 // Invalid session, clear it
840− p.ClearSessionCookie(rw, req)
871+ err := p.ClearSessionCookie(rw, req)
872+ if err != nil {
873+ logger.Printf("Error clearing session cookie: %s", err.Error())
874+ }
841 return nil, ErrNeedsLogin
875 return nil, ErrNeedsLogin
842 }
876 }
843
877
pkg/authentication/basic/htpasswd.go+16−8
@@ -1,7 +1,7 @@
1package basic
1package basic
2
2
3import (
3import (
4− "crypto/sha1"
4+ "crypto/sha1" // #nosec G505
5 "encoding/base64"
5 "encoding/base64"
6 "encoding/csv"
6 "encoding/csv"
7 "fmt"
7 "fmt"
@@ -29,11 +29,16 @@ type sha1Pass string
29// NewHTPasswdValidator constructs an httpasswd based validator from the file
29// NewHTPasswdValidator constructs an httpasswd based validator from the file
30// at the path given.
30// at the path given.
31func NewHTPasswdValidator(path string) (Validator, error) {
31func NewHTPasswdValidator(path string) (Validator, error) {
32− r, err := os.Open(path)
32+ r, err := os.Open(path) // #nosec G304
33 if err != nil {
33 if err != nil {
34 return nil, fmt.Errorf("could not open htpasswd file: %v", err)
34 return nil, fmt.Errorf("could not open htpasswd file: %v", err)
35 }
35 }
36− defer r.Close()
36+ defer func(c io.Closer) {
37+ cerr := c.Close()
38+ if cerr != nil {
39+ logger.Fatalf("error closing the htpasswd file: %v", cerr)
40+ }
41+ }(r)
37 return newHtpasswd(r)
42 return newHtpasswd(r)
38}
43}
39
44
@@ -83,13 +88,16 @@ func (h *htpasswdMap) Validate(user string, password string) bool {
83 return false
88 return false
84 }
89 }
85
90
86− switch real := realPassword.(type) {
91+ switch rp := realPassword.(type) {
87 case sha1Pass:
92 case sha1Pass:
88− d := sha1.New()
93+ d := sha1.New() // #nosec G401
89− d.Write([]byte(password))
94+ _, err := d.Write([]byte(password))
95+ if err != nil {
96+ return false
97+ }
90− return string(real) == base64.StdEncoding.EncodeToString(d.Sum(nil))
98+ return string(rp) == base64.StdEncoding.EncodeToString(d.Sum(nil))
91 case bcryptPass:
99 case bcryptPass:
92− return bcrypt.CompareHashAndPassword([]byte(real), []byte(password)) == nil
100+ return bcrypt.CompareHashAndPassword([]byte(rp), []byte(password)) == nil
93 default:
101 default:
94 return false
102 return false
95 }
103 }
pkg/encryption/utils.go+14−2
@@ -2,15 +2,19 @@ package encryption
2
2
3import (
3import (
4 "crypto/hmac"
4 "crypto/hmac"
5− "crypto/sha1"
5+ "crypto/rand"
6+ "crypto/sha1" // #nosec G505
6 "crypto/sha256"
7 "crypto/sha256"
7 "encoding/base64"
8 "encoding/base64"
8 "fmt"
9 "fmt"
9 "hash"
10 "hash"
11+ "io"
10 "net/http"
12 "net/http"
11 "strconv"
13 "strconv"
12 "strings"
14 "strings"
13 "time"
15 "time"
16+
17+ "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
14)
18)
15
19
16// SecretBytes attempts to base64 decode the secret, if that fails it treats the secret as binary
20// 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 {
76func cookieSignature(signer func() hash.Hash, args ...string) string {
80func cookieSignature(signer func() hash.Hash, args ...string) string {
77 h := hmac.New(signer, []byte(args[0]))
81 h := hmac.New(signer, []byte(args[0]))
78 for _, arg := range args[1:] {
82 for _, arg := range args[1:] {
79− h.Write([]byte(arg))
83+ _, err := h.Write([]byte(arg))
84+ // If signing fails, fail closed and return something that won't validate
85+ if err != nil {
86+ garbage := make([]byte, 16)
87+ if _, err := io.ReadFull(rand.Reader, garbage); err != nil {
88+ logger.Fatal("HMAC & RNG functions both failing. Shutting down for security")
89+ }
90+ return base64.URLEncoding.EncodeToString(garbage)
91+ }
80 }
92 }
81 var b []byte
93 var b []byte
82 b = h.Sum(b)
94 b = h.Sum(b)
pkg/logger/logger.go+24−6
@@ -132,13 +132,19 @@ func (l *Logger) Output(calldepth int, message string) {
132 l.mu.Lock()
132 l.mu.Lock()
133 defer l.mu.Unlock()
133 defer l.mu.Unlock()
134
134
135− l.stdLogTemplate.Execute(l.writer, stdLogMessageData{
135+ err := l.stdLogTemplate.Execute(l.writer, stdLogMessageData{
136 Timestamp: FormatTimestamp(now),
136 Timestamp: FormatTimestamp(now),
137 File: file,
137 File: file,
138 Message: message,
138 Message: message,
139 })
139 })
140+ if err != nil {
141+ panic(err)
142+ }
140
143
141− l.writer.Write([]byte("\n"))
144+ _, err = l.writer.Write([]byte("\n"))
145+ if err != nil {
146+ panic(err)
147+ }
142}
148}
143
149
144// PrintAuthf writes auth info to the logger. Requires an http.Request to
150// 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
160 l.mu.Lock()
166 l.mu.Lock()
161 defer l.mu.Unlock()
167 defer l.mu.Unlock()
162
168
163− l.authTemplate.Execute(l.writer, authLogMessageData{
169+ err := l.authTemplate.Execute(l.writer, authLogMessageData{
164 Client: client,
170 Client: client,
165 Host: req.Host,
171 Host: req.Host,
166 Protocol: req.Proto,
172 Protocol: req.Proto,
@@ -171,8 +177,14 @@ func (l *Logger) PrintAuthf(username string, req *http.Request, status AuthStatu
171 Status: string(status),
177 Status: string(status),
172 Message: fmt.Sprintf(format, a...),
178 Message: fmt.Sprintf(format, a...),
173 })
179 })
180+ if err != nil {
181+ panic(err)
182+ }
174
183
175− l.writer.Write([]byte("\n"))
184+ _, err = l.writer.Write([]byte("\n"))
185+ if err != nil {
186+ panic(err)
187+ }
176}
188}
177
189
178// PrintReq writes request details to the Logger using the http.Request,
190// 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.
208 l.mu.Lock()
220 l.mu.Lock()
209 defer l.mu.Unlock()
221 defer l.mu.Unlock()
210
222
211− l.reqTemplate.Execute(l.writer, reqLogMessageData{
223+ err := l.reqTemplate.Execute(l.writer, reqLogMessageData{
212 Client: client,
224 Client: client,
213 Host: req.Host,
225 Host: req.Host,
214 Protocol: req.Proto,
226 Protocol: req.Proto,
@@ -222,8 +234,14 @@ func (l *Logger) PrintReq(username, upstream string, req *http.Request, url url.
222 UserAgent: fmt.Sprintf("%q", req.UserAgent()),
234 UserAgent: fmt.Sprintf("%q", req.UserAgent()),
223 Username: username,
235 Username: username,
224 })
236 })
237+ if err != nil {
238+ panic(err)
239+ }
225
240
226− l.writer.Write([]byte("\n"))
241+ _, err = l.writer.Write([]byte("\n"))
242+ if err != nil {
243+ panic(err)
244+ }
227}
245}
228
246
229// GetFileLineString will find the caller file and line number
247// GetFileLineString will find the caller file and line number
pkg/middleware/stored_session.go+5−2
@@ -55,7 +55,7 @@ type storedSessionLoader struct {
55}
55}
56
56
57// loadSession attempts to load a session as identified by the request cookies.
57// loadSession attempts to load a session as identified by the request cookies.
58−// If no session is found, the request will be passed to the nex handler.
58+// If no session is found, the request will be passed to the next handler.
59// If a session was loader by a previous handler, it will not be replaced.
59// If a session was loader by a previous handler, it will not be replaced.
60func (s *storedSessionLoader) loadSession(next http.Handler) http.Handler {
60func (s *storedSessionLoader) loadSession(next http.Handler) http.Handler {
61 return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
61 return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@@ -73,7 +73,10 @@ func (s *storedSessionLoader) loadSession(next http.Handler) http.Handler {
73 // In the case when there was an error loading the session,
73 // In the case when there was an error loading the session,
74 // we should clear the session
74 // we should clear the session
75 logger.Printf("Error loading cookied session: %v, removing session", err)
75 logger.Printf("Error loading cookied session: %v, removing session", err)
76− s.store.Clear(rw, req)
76+ err = s.store.Clear(rw, req)
77+ if err != nil {
78+ logger.Printf("Error removing session: %v", err)
79+ }
77 }
80 }
78
81
79 // Add the session to the scope if it was found
82 // Add the session to the scope if it was found
pkg/upstream/http.go+2
@@ -103,6 +103,7 @@ func newReverseProxy(target *url.URL, upstream options.Upstream, errorHandler Pr
103 proxy.FlushInterval = 1 * time.Second
103 proxy.FlushInterval = 1 * time.Second
104 }
104 }
105
105
106+ /* #nosec G402 */
106 if upstream.InsecureSkipTLSVerify {
107 if upstream.InsecureSkipTLSVerify {
107 proxy.Transport = &http.Transport{
108 proxy.Transport = &http.Transport{
108 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
109 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
@@ -156,6 +157,7 @@ func newWebSocketReverseProxy(u *url.URL, skipTLSVerify bool) http.Handler {
156 wsURL := &url.URL{Scheme: wsScheme, Host: u.Host}
157 wsURL := &url.URL{Scheme: wsScheme, Host: u.Host}
157
158
158 wsProxy := wsutil.NewSingleHostReverseProxy(wsURL)
159 wsProxy := wsutil.NewSingleHostReverseProxy(wsURL)
160+ /* #nosec G402 */
159 if skipTLSVerify {
161 if skipTLSVerify {
160 wsProxy.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
162 wsProxy.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
161 }
163 }
pkg/upstream/proxy.go+4−1
@@ -85,6 +85,9 @@ func NewProxyErrorHandler(errorTemplate *template.Template, proxyPrefix string)
85 Message: "Error proxying to upstream server",
85 Message: "Error proxying to upstream server",
86 ProxyPrefix: proxyPrefix,
86 ProxyPrefix: proxyPrefix,
87 }
87 }
88− errorTemplate.Execute(rw, data)
88+ err := errorTemplate.Execute(rw, data)
89+ if err != nil {
90+ http.Error(rw, "Internal Server Error", http.StatusInternalServerError)
91+ }
89 }
92 }
90}
93}
pkg/util/util.go+1−1
@@ -12,7 +12,7 @@ func GetCertPool(paths []string) (*x509.CertPool, error) {
12 }
12 }
13 pool := x509.NewCertPool()
13 pool := x509.NewCertPool()
14 for _, path := range paths {
14 for _, path := range paths {
15− data, err := ioutil.ReadFile(path)
15+ data, err := ioutil.ReadFile(path) // #nosec G304
16 if err != nil {
16 if err != nil {
17 return nil, fmt.Errorf("certificate authority file (%s) could not be read - %s", path, err)
17 return nil, fmt.Errorf("certificate authority file (%s) could not be read - %s", path, err)
18 }
18 }
pkg/validation/logging.go+5−2
@@ -13,13 +13,16 @@ func configureLogger(o options.Logging, msgs []string) []string {
13 // Setup the log file
13 // Setup the log file
14 if len(o.File.Filename) > 0 {
14 if len(o.File.Filename) > 0 {
15 // Validate that the file/dir can be written
15 // Validate that the file/dir can be written
16− file, err := os.OpenFile(o.File.Filename, os.O_WRONLY|os.O_CREATE, 0666)
16+ file, err := os.OpenFile(o.File.Filename, os.O_WRONLY|os.O_CREATE, 0600)
17 if err != nil {
17 if err != nil {
18 if os.IsPermission(err) {
18 if os.IsPermission(err) {
19 return append(msgs, "unable to write to log file: "+o.File.Filename)
19 return append(msgs, "unable to write to log file: "+o.File.Filename)
20 }
20 }
21 }
21 }
22− file.Close()
22+ err = file.Close()
23+ if err != nil {
24+ return append(msgs, "error closing the log file: "+o.File.Filename)
25+ }
23
26
24 logger.Printf("Redirecting logging to file: %s", o.File.Filename)
27 logger.Printf("Redirecting logging to file: %s", o.File.Filename)
25
28
pkg/validation/options.go+5−1
@@ -30,6 +30,7 @@ func Validate(o *options.Options) error {
30 msgs = append(msgs, validateSessionCookieMinimal(o)...)
30 msgs = append(msgs, validateSessionCookieMinimal(o)...)
31
31
32 if o.SSLInsecureSkipVerify {
32 if o.SSLInsecureSkipVerify {
33+ /* #nosec G402 */
33 insecureTransport := &http.Transport{
34 insecureTransport := &http.Transport{
34 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
35 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
35 }
36 }
@@ -217,7 +218,10 @@ func Validate(o *options.Options) error {
217 }
218 }
218
219
219 if len(o.TrustedIPs) > 0 && o.ReverseProxy {
220 if len(o.TrustedIPs) > 0 && o.ReverseProxy {
220− fmt.Fprintln(os.Stderr, "WARNING: trusting of IPs with --reverse-proxy poses risks if a header spoofing attack is possible.")
221+ _, err := fmt.Fprintln(os.Stderr, "WARNING: trusting of IPs with --reverse-proxy poses risks if a header spoofing attack is possible.")
222+ if err != nil {
223+ panic(err)
224+ }
221 }
225 }
222
226
223 for i, ipStr := range o.TrustedIPs {
227 for i, ipStr := range o.TrustedIPs {
providers/logingov.go+3−1
@@ -115,10 +115,12 @@ func checkNonce(idToken string, p *LoginGovProvider) (err error) {
115 return nil, myerr
115 return nil, myerr
116 }
116 }
117 body, myerr := ioutil.ReadAll(resp.Body)
117 body, myerr := ioutil.ReadAll(resp.Body)
118− resp.Body.Close()
119 if myerr != nil {
118 if myerr != nil {
120 return nil, myerr
119 return nil, myerr
121 }
120 }
121+ if myerr = resp.Body.Close(); myerr != nil {
122+ return nil, myerr
123+ }
122
124
123 var pubkeys jose.JSONWebKeySet
125 var pubkeys jose.JSONWebKeySet
124 myerr = json.Unmarshal(body, &pubkeys)
126 myerr = json.Unmarshal(body, &pubkeys)
validator.go+7−1
@@ -3,6 +3,7 @@ package main
3import (
3import (
4 "encoding/csv"
4 "encoding/csv"
5 "fmt"
5 "fmt"
6+ "io"
6 "os"
7 "os"
7 "strings"
8 "strings"
8 "sync/atomic"
9 "sync/atomic"
@@ -47,7 +48,12 @@ func (um *UserMap) LoadAuthenticatedEmailsFile() {
47 if err != nil {
48 if err != nil {
48 logger.Fatalf("failed opening authenticated-emails-file=%q, %s", um.usersFile, err)
49 logger.Fatalf("failed opening authenticated-emails-file=%q, %s", um.usersFile, err)
49 }
50 }
50− defer r.Close()
51+ defer func(c io.Closer) {
52+ cerr := c.Close()
53+ if cerr != nil {
54+ logger.Fatalf("Error closing authenticated emails file: %s", cerr)
55+ }
56+ }(r)
51 csvReader := csv.NewReader(r)
57 csvReader := csv.NewReader(r)
52 csvReader.Comma = ','
58 csvReader.Comma = ','
53 csvReader.Comment = '#'
59 csvReader.Comment = '#'
watcher.go+10−2
@@ -41,7 +41,12 @@ func WatchForUpdates(filename string, done <-chan bool, action func()) {
41 logger.Fatal("failed to create watcher for ", filename, ": ", err)
41 logger.Fatal("failed to create watcher for ", filename, ": ", err)
42 }
42 }
43 go func() {
43 go func() {
44− defer watcher.Close()
44+ defer func(w *fsnotify.Watcher) {
45+ cerr := w.Close()
46+ if cerr != nil {
47+ logger.Fatalf("error closing watcher: %s", err)
48+ }
49+ }(watcher)
45 for {
50 for {
46 select {
51 select {
47 case <-done:
52 case <-done:
@@ -55,7 +60,10 @@ func WatchForUpdates(filename string, done <-chan bool, action func()) {
55 // can't be opened.
60 // can't be opened.
56 if event.Op&(fsnotify.Remove|fsnotify.Rename|fsnotify.Chmod) != 0 {
61 if event.Op&(fsnotify.Remove|fsnotify.Rename|fsnotify.Chmod) != 0 {
57 logger.Printf("watching interrupted on event: %s", event)
62 logger.Printf("watching interrupted on event: %s", event)
58− watcher.Remove(filename)
63+ err = watcher.Remove(filename)
64+ if err != nil {
65+ logger.Printf("error removing watcher on %s: %s", filename, err)
66+ }
59 WaitForReplacement(filename, event.Op, watcher)
67 WaitForReplacement(filename, event.Op, watcher)
60 }
68 }
61 logger.Printf("reloading after event: %s", event)
69 logger.Printf("reloading after event: %s", event)