mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-07-23 04:51:39 +02:00
review and move api endpoints secured check
This commit is contained in:
@@ -69,11 +69,10 @@ func New() *RestApi {
|
||||
|
||||
func (api *RestApi) MountApiRoutes(r *mux.Router) {
|
||||
r.StrictSlash(true)
|
||||
|
||||
// REST API Uses TokenAuth
|
||||
r.HandleFunc("/jobs/start_job/", api.startJob).Methods(http.MethodPost, http.MethodPut)
|
||||
r.HandleFunc("/jobs/stop_job/", api.stopJobByRequest).Methods(http.MethodPost, http.MethodPut)
|
||||
// r.HandleFunc("/jobs/import/", api.importJob).Methods(http.MethodPost, http.MethodPut)
|
||||
|
||||
r.HandleFunc("/jobs/", api.getJobs).Methods(http.MethodGet)
|
||||
r.HandleFunc("/jobs/{id}", api.getJobById).Methods(http.MethodPost)
|
||||
r.HandleFunc("/jobs/{id}", api.getCompleteJobById).Methods(http.MethodGet)
|
||||
@@ -83,7 +82,6 @@ func (api *RestApi) MountApiRoutes(r *mux.Router) {
|
||||
r.HandleFunc("/jobs/delete_job/", api.deleteJobByRequest).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/jobs/delete_job/{id}", api.deleteJobById).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/jobs/delete_job_before/{ts}", api.deleteJobBefore).Methods(http.MethodDelete)
|
||||
|
||||
r.HandleFunc("/clusters/", api.getClusters).Methods(http.MethodGet)
|
||||
|
||||
if api.MachineStateDir != "" {
|
||||
@@ -94,7 +92,7 @@ func (api *RestApi) MountApiRoutes(r *mux.Router) {
|
||||
|
||||
func (api *RestApi) MountUserApiRoutes(r *mux.Router) {
|
||||
r.StrictSlash(true)
|
||||
|
||||
// REST API Uses TokenAuth
|
||||
r.HandleFunc("/jobs/", api.getJobs).Methods(http.MethodGet)
|
||||
r.HandleFunc("/jobs/{id}", api.getJobById).Methods(http.MethodPost)
|
||||
r.HandleFunc("/jobs/{id}", api.getCompleteJobById).Methods(http.MethodGet)
|
||||
@@ -103,7 +101,7 @@ func (api *RestApi) MountUserApiRoutes(r *mux.Router) {
|
||||
|
||||
func (api *RestApi) MountConfigApiRoutes(r *mux.Router) {
|
||||
r.StrictSlash(true)
|
||||
|
||||
// Settings Frontend Uses SessionAuth
|
||||
if api.Authentication != nil {
|
||||
r.HandleFunc("/roles/", api.getRoles).Methods(http.MethodGet)
|
||||
r.HandleFunc("/users/", api.createUser).Methods(http.MethodPost, http.MethodPut)
|
||||
@@ -116,7 +114,7 @@ func (api *RestApi) MountConfigApiRoutes(r *mux.Router) {
|
||||
|
||||
func (api *RestApi) MountFrontendApiRoutes(r *mux.Router) {
|
||||
r.StrictSlash(true)
|
||||
|
||||
// Settings Frontrend Uses SessionAuth
|
||||
if api.Authentication != nil {
|
||||
r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet)
|
||||
r.HandleFunc("/configuration/", api.updateConfiguration).Methods(http.MethodPost)
|
||||
@@ -221,44 +219,6 @@ func decode(r io.Reader, val interface{}) error {
|
||||
return dec.Decode(val)
|
||||
}
|
||||
|
||||
func securedCheck(r *http.Request) error {
|
||||
user := repository.GetUserFromContext(r.Context())
|
||||
if user == nil {
|
||||
return fmt.Errorf("no user in context")
|
||||
}
|
||||
|
||||
if user.AuthType == schema.AuthToken {
|
||||
// If nothing declared in config: deny all request to this endpoint
|
||||
if config.Keys.ApiAllowedIPs == nil || len(config.Keys.ApiAllowedIPs) == 0 {
|
||||
return fmt.Errorf("missing configuration key ApiAllowedIPs")
|
||||
}
|
||||
|
||||
if config.Keys.ApiAllowedIPs[0] == "*" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// extract IP address
|
||||
IPAddress := r.Header.Get("X-Real-Ip")
|
||||
if IPAddress == "" {
|
||||
IPAddress = r.Header.Get("X-Forwarded-For")
|
||||
}
|
||||
if IPAddress == "" {
|
||||
IPAddress = r.RemoteAddr
|
||||
}
|
||||
|
||||
if strings.Contains(IPAddress, ":") {
|
||||
IPAddress = strings.Split(IPAddress, ":")[0]
|
||||
}
|
||||
|
||||
// check if IP is allowed
|
||||
if !util.Contains(config.Keys.ApiAllowedIPs, IPAddress) {
|
||||
return fmt.Errorf("unknown ip: %v", IPAddress)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getClusters godoc
|
||||
// @summary Lists all cluster configs
|
||||
// @tags Cluster query
|
||||
@@ -1093,7 +1053,6 @@ func (api *RestApi) getJobMetrics(rw http.ResponseWriter, r *http.Request) {
|
||||
// @summary Adds a new user
|
||||
// @tags User
|
||||
// @description User specified in form data will be saved to database.
|
||||
// @description Only accessible from IPs registered with apiAllowedIPs configuration option.
|
||||
// @accept mpfd
|
||||
// @produce plain
|
||||
// @param username formData string true "Unique user ID"
|
||||
@@ -1111,11 +1070,7 @@ func (api *RestApi) getJobMetrics(rw http.ResponseWriter, r *http.Request) {
|
||||
// @security ApiKeyAuth
|
||||
// @router /users/ [post]
|
||||
func (api *RestApi) createUser(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// SecuredCheck() only worked with TokenAuth: Removed
|
||||
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
me := repository.GetUserFromContext(r.Context())
|
||||
@@ -1162,7 +1117,6 @@ func (api *RestApi) createUser(rw http.ResponseWriter, r *http.Request) {
|
||||
// @summary Deletes a user
|
||||
// @tags User
|
||||
// @description User defined by username in form data will be deleted from database.
|
||||
// @description Only accessible from IPs registered with apiAllowedIPs configuration option.
|
||||
// @accept mpfd
|
||||
// @produce plain
|
||||
// @param username formData string true "User ID to delete"
|
||||
@@ -1175,11 +1129,7 @@ func (api *RestApi) createUser(rw http.ResponseWriter, r *http.Request) {
|
||||
// @security ApiKeyAuth
|
||||
// @router /users/ [delete]
|
||||
func (api *RestApi) deleteUser(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// SecuredCheck() only worked with TokenAuth: Removed
|
||||
|
||||
if user := repository.GetUserFromContext(r.Context()); !user.HasRole(schema.RoleAdmin) {
|
||||
http.Error(rw, "Only admins are allowed to delete a user", http.StatusForbidden)
|
||||
@@ -1200,7 +1150,6 @@ func (api *RestApi) deleteUser(rw http.ResponseWriter, r *http.Request) {
|
||||
// @tags User
|
||||
// @description Returns a JSON-encoded list of users.
|
||||
// @description Required query-parameter defines if all users or only users with additional special roles are returned.
|
||||
// @description Only accessible from IPs registered with apiAllowedIPs configuration option.
|
||||
// @produce json
|
||||
// @param not-just-user query bool true "If returned list should contain all users or only users with additional special roles"
|
||||
// @success 200 {array} api.ApiReturnedUser "List of users returned successfully"
|
||||
@@ -1211,11 +1160,7 @@ func (api *RestApi) deleteUser(rw http.ResponseWriter, r *http.Request) {
|
||||
// @security ApiKeyAuth
|
||||
// @router /users/ [get]
|
||||
func (api *RestApi) getUsers(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// SecuredCheck() only worked with TokenAuth: Removed
|
||||
|
||||
if user := repository.GetUserFromContext(r.Context()); !user.HasRole(schema.RoleAdmin) {
|
||||
http.Error(rw, "Only admins are allowed to fetch a list of users", http.StatusForbidden)
|
||||
@@ -1236,7 +1181,6 @@ func (api *RestApi) getUsers(rw http.ResponseWriter, r *http.Request) {
|
||||
// @tags User
|
||||
// @description Modifies user defined by username (id) in one of four possible ways.
|
||||
// @description If more than one formValue is set then only the highest priority field is used.
|
||||
// @description Only accessible from IPs registered with apiAllowedIPs configuration option.
|
||||
// @accept mpfd
|
||||
// @produce plain
|
||||
// @param id path string true "Database ID of User"
|
||||
@@ -1253,11 +1197,7 @@ func (api *RestApi) getUsers(rw http.ResponseWriter, r *http.Request) {
|
||||
// @security ApiKeyAuth
|
||||
// @router /user/{id} [post]
|
||||
func (api *RestApi) updateUser(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// SecuredCheck() only worked with TokenAuth: Removed
|
||||
|
||||
if user := repository.GetUserFromContext(r.Context()); !user.HasRole(schema.RoleAdmin) {
|
||||
http.Error(rw, "Only admins are allowed to update a user", http.StatusForbidden)
|
||||
@@ -1305,7 +1245,6 @@ func (api *RestApi) updateUser(rw http.ResponseWriter, r *http.Request) {
|
||||
// @tags User
|
||||
// @description Modifies the content of notice.txt, shown as notice box on the homepage.
|
||||
// @description If more than one formValue is set then only the highest priority field is used.
|
||||
// @description Only accessible from IPs registered with apiAllowedIPs configuration option.
|
||||
// @accept mpfd
|
||||
// @produce plain
|
||||
// @param new-content formData string false "Priority 1: New content to display"
|
||||
@@ -1318,11 +1257,7 @@ func (api *RestApi) updateUser(rw http.ResponseWriter, r *http.Request) {
|
||||
// @security ApiKeyAuth
|
||||
// @router /notice/ [post]
|
||||
func (api *RestApi) editNotice(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// SecuredCheck() only worked with TokenAuth: Removed
|
||||
|
||||
if user := repository.GetUserFromContext(r.Context()); !user.HasRole(schema.RoleAdmin) {
|
||||
http.Error(rw, "Only admins are allowed to update the notice.txt file", http.StatusForbidden)
|
||||
@@ -1364,12 +1299,6 @@ func (api *RestApi) editNotice(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (api *RestApi) getJWT(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
username := r.FormValue("username")
|
||||
me := repository.GetUserFromContext(r.Context())
|
||||
@@ -1398,11 +1327,7 @@ func (api *RestApi) getJWT(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (api *RestApi) getRoles(rw http.ResponseWriter, r *http.Request) {
|
||||
err := securedCheck(r)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// SecuredCheck() only worked with TokenAuth: Removed
|
||||
|
||||
user := repository.GetUserFromContext(r.Context())
|
||||
if !user.HasRole(schema.RoleAdmin) {
|
||||
|
Reference in New Issue
Block a user