github.com/go-kivik/kivik/v4@v4.3.2/x/kivikd/auth.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 //go:build !js 14 15 package kivikd 16 17 import ( 18 "net/http" 19 20 "github.com/go-kivik/kivik/v4/x/kivikd/auth" 21 "github.com/go-kivik/kivik/v4/x/kivikd/authdb" 22 ) 23 24 type doneWriter struct { 25 http.ResponseWriter 26 done bool 27 } 28 29 func (w *doneWriter) WriteHeader(status int) { 30 w.done = true 31 w.ResponseWriter.WriteHeader(status) 32 } 33 34 func (w *doneWriter) Write(b []byte) (int, error) { 35 w.done = true 36 return w.ResponseWriter.Write(b) 37 } 38 39 func authHandler(next http.Handler) http.Handler { 40 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 41 dw := &doneWriter{ResponseWriter: w} 42 s := GetService(r) 43 session, err := s.validate(dw, r) 44 if err != nil { 45 reportError(w, err) 46 return 47 } 48 sessionPtr := mustGetSessionPtr(r.Context()) 49 *sessionPtr = session 50 if dw.done { 51 // The auth handler already responded to the request 52 return 53 } 54 next.ServeHTTP(w, r) 55 }) 56 } 57 58 // validate must return a 401 error if there is an authentication failure. 59 // No error means the user is permitted. 60 func (s *Service) validate(w http.ResponseWriter, r *http.Request) (*auth.Session, error) { 61 if s.authHandlers == nil { 62 // Perpetual admin party 63 return s.createSession("", &authdb.UserContext{Roles: []string{"_admin"}}), nil 64 } 65 for methodName, handler := range s.authHandlers { 66 uCtx, err := handler.Authenticate(w, r) 67 if err != nil { 68 return nil, err 69 } 70 if uCtx != nil { 71 return s.createSession(methodName, uCtx), nil 72 } 73 } 74 // None of the auth methods succeeded, so return unauthorized 75 return s.createSession("", nil), nil 76 } 77 78 func (s *Service) createSession(method string, user *authdb.UserContext) *auth.Session { 79 return &auth.Session{ 80 AuthMethod: method, 81 AuthDB: s.Conf().GetString("couch_httpd_auth.authentication_db"), 82 Handlers: s.authHandlerNames, 83 User: user, 84 } 85 }