From ec1bcfe0b8417d159fd19d8b876f80b03470732b Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Mon, 29 Jan 2018 09:54:57 +0000 Subject: [PATCH] Do not return an error when a user has no encryption keys on Open And make HTTP result codes slightly more meaningful. --- README.md | 7 +++++-- server/keystore.go | 22 ++++++++++++++-------- server/server.go | 12 ++++++++++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 27201a0e..cc2e3907 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,17 @@ similarly JSON-encoded. Retrieve the encrypted key for a user, decrypt it with the provided password, and store it in memory. -OpenRequest is an object with the -following attributes: +OpenRequest is an object with the following attributes: * `username` * `password` to decrypt the user's key with * `ttl` (seconds) time after which the credentials are automatically forgotten +If the user has no encrypted keys in the database, the request will +still return successfully: no action will be performed, and no errors +will be returned. + `/api/get` (*GetRequest*) -> *GetResponse* Retrieve the key for a user. GetRequest must contain the following diff --git a/server/keystore.go b/server/keystore.go index af4f9fe7..19a1d1a3 100644 --- a/server/keystore.go +++ b/server/keystore.go @@ -4,6 +4,7 @@ import ( "context" "errors" "io/ioutil" + "log" "strings" "sync" "time" @@ -15,9 +16,10 @@ import ( ) var ( - ErrNoKeys = errors.New("no keys available") - ErrBadUser = errors.New("username does not match authentication token") - ErrInvalidTTL = errors.New("invalid ttl") + errNoKeys = errors.New("no keys available") + errBadUser = errors.New("username does not match authentication token") + errUnauthorized = errors.New("unauthorized") + errInvalidTTL = errors.New("invalid ttl") ) // Database represents the interface to the underlying backend for @@ -130,7 +132,7 @@ func (s *KeyStore) expire() { // A Context is needed because this method might issue an RPC. func (s *KeyStore) Open(ctx context.Context, username, password string, ttlSeconds int) error { if ttlSeconds == 0 { - return ErrInvalidTTL + return errInvalidTTL } encKeys, err := s.db.GetPrivateKeys(ctx, username) @@ -138,7 +140,8 @@ func (s *KeyStore) Open(ctx context.Context, username, password string, ttlSecon return err } if len(encKeys) == 0 { - return ErrNoKeys + // No keys found. Not an error. + return nil } // Naive and inefficient way of decrypting multiple keys: it @@ -163,17 +166,20 @@ func (s *KeyStore) Get(username, ssoTicket string) ([]byte, error) { // Validate the SSO ticket. tkt, err := s.validator.Validate(ssoTicket, "", s.service, nil) if err != nil { - return nil, err + // Log authentication failures for debugging purposes. + log.Printf("Validate(%s) error: %v", username, err) + return nil, errUnauthorized } if tkt.User != username { - return nil, ErrBadUser + log.Printf("Validate(%s) user mismatch: sso=%s", username, tkt.User) + return nil, errBadUser } s.mx.Lock() defer s.mx.Unlock() u, ok := s.userKeys[username] if !ok { - return nil, ErrNoKeys + return nil, errNoKeys } return u.pkey, nil } diff --git a/server/server.go b/server/server.go index fc97436f..a7de20a9 100644 --- a/server/server.go +++ b/server/server.go @@ -24,7 +24,7 @@ func (s *keyStoreServer) handleOpen(w http.ResponseWriter, r *http.Request) { err := s.KeyStore.Open(r.Context(), req.Username, req.Password, req.TTL) if err != nil { log.Printf("Open(%s) error: %v", req.Username, err) - http.Error(w, err.Error(), http.StatusUnauthorized) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -40,7 +40,15 @@ func (s *keyStoreServer) handleGet(w http.ResponseWriter, r *http.Request) { key, err := s.KeyStore.Get(req.Username, req.SSOTicket) if err != nil { log.Printf("Get(%s) error: %v", req.Username, err) - http.Error(w, err.Error(), http.StatusUnauthorized) + // Return an appropriate error code. + switch err { + case errUnauthorized, errBadUser: + http.Error(w, err.Error(), http.StatusUnauthorized) + case errNoKeys: + http.NotFound(w, r) + default: + http.Error(w, err.Error(), http.StatusInternalServerError) + } return } -- GitLab