| 82 | } |
| 83 | |
| 84 | func (a Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { |
| 85 | repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) |
| 86 | var user User |
| 87 | var candidate User |
| 88 | var hasCandidate bool |
| 89 | var authed bool |
| 90 | var err error |
| 91 | for provName, prov := range a.Providers { |
| 92 | user, authed, err = prov.Authenticate(w, r) |
| 93 | if err != nil { |
| 94 | if c := a.logger.Check(zapcore.ErrorLevel, "auth provider returned error"); c != nil { |
| 95 | c.Write(zap.String("provider", provName), zap.Error(err)) |
| 96 | } |
| 97 | // Set the error from the authentication provider in a placeholder, |
| 98 | // so it can be used in the handle_errors directive. |
| 99 | repl.Set("http.auth."+provName+".error", err.Error()) |
| 100 | continue |
| 101 | } |
| 102 | if authed { |
| 103 | break |
| 104 | } |
| 105 | if userHasInfo(user) { |
| 106 | candidate = user |
| 107 | hasCandidate = true |
| 108 | } |
| 109 | } |
| 110 | if !authed { |
| 111 | if hasCandidate { |
| 112 | setAuthUserPlaceholders(repl, "http.auth.candidate", candidate) |
| 113 | } |
| 114 | return caddyhttp.Error(http.StatusUnauthorized, fmt.Errorf("not authenticated")) |
| 115 | } |
| 116 | |
| 117 | setAuthUserPlaceholders(repl, "http.auth.user", user) |
| 118 | |
| 119 | return next.ServeHTTP(w, r) |
| 120 | } |
| 121 | |
| 122 | func userHasInfo(user User) bool { |
| 123 | return user.ID != "" || len(user.Metadata) > 0 |