Browse Source

etcdhttp: improve user endpoint validation

Giving both roles and grant/revoke is not allowed.
Creating an existing user is not allowed.
Updating a non-existing user is not allowed.
Xiang Li 10 years ago
parent
commit
e291dfd748
2 changed files with 38 additions and 9 deletions
  1. 3 3
      etcdserver/auth/auth.go
  2. 35 6
      etcdserver/etcdhttp/client_auth.go

+ 3 - 3
etcdserver/auth/auth.go

@@ -177,12 +177,12 @@ func (s *Store) GetUser(name string) (User, error) {
 	return u, nil
 }
 
+// CreateOrUpdateUser should be only used for creating the new user or when you are not
+// sure if it is a create or update. (When only password is passed in, we are not sure
+// if it is a update or create)
 func (s *Store) CreateOrUpdateUser(user User) (out User, created bool, err error) {
 	_, err = s.GetUser(user.User)
 	if err == nil {
-		// Remove the update-user roles from updating downstream.
-		// Roles are granted or revoked, not changed directly.
-		user.Roles = nil
 		out, err := s.UpdateUser(user)
 		return out, false, err
 	}

+ 35 - 6
etcdserver/etcdhttp/client_auth.go

@@ -333,19 +333,48 @@ func (sh *authHandler) forUser(w http.ResponseWriter, r *http.Request, user stri
 			writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, "User JSON name does not match the name in the URL"))
 			return
 		}
-		newuser, created, err := sh.sec.CreateOrUpdateUser(u)
-		if err != nil {
-			writeError(w, err)
-			return
+
+		var (
+			out     auth.User
+			created bool
+		)
+
+		if len(u.Grant) == 0 && len(u.Revoke) == 0 {
+			// create or update
+			if len(u.Roles) != 0 {
+				out, err = sh.sec.CreateUser(u)
+			} else {
+				// if user passes in both password and roles, we are unsure about his/her
+				// intention.
+				out, created, err = sh.sec.CreateOrUpdateUser(u)
+			}
+
+			if err != nil {
+				writeError(w, err)
+				return
+			}
+		} else {
+			// update case
+			if len(u.Roles) != 0 {
+				writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, "User JSON contains both roles and grant/revoke"))
+				return
+			}
+			out, err = sh.sec.UpdateUser(u)
+			if err != nil {
+				writeError(w, err)
+				return
+			}
 		}
-		newuser.Password = ""
 
 		if created {
 			w.WriteHeader(http.StatusCreated)
 		} else {
 			w.WriteHeader(http.StatusOK)
 		}
-		err = json.NewEncoder(w).Encode(newuser)
+
+		out.Password = ""
+
+		err = json.NewEncoder(w).Encode(out)
 		if err != nil {
 			plog.Warningf("forUser error encoding on %s", r.URL)
 			return