mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-25 12:59:06 +01:00
first iteraton of implementing ip-secured enpoint
This commit is contained in:
parent
38f58047f2
commit
6393035e55
@ -20,6 +20,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ClusterCockpit/cc-backend/internal/auth"
|
||||
"github.com/ClusterCockpit/cc-backend/internal/config"
|
||||
"github.com/ClusterCockpit/cc-backend/internal/graph"
|
||||
"github.com/ClusterCockpit/cc-backend/internal/graph/model"
|
||||
"github.com/ClusterCockpit/cc-backend/internal/importer"
|
||||
@ -75,6 +76,8 @@ func (api *RestApi) MountRoutes(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("/secured/addProject/{id}/{project}", api.secureUpdateUser).Methods(http.MethodPost)
|
||||
r.HandleFunc("/secured/addRole/{id}/{role}", api.secureUpdateUser).Methods(http.MethodPost)
|
||||
|
||||
if api.Authentication != nil {
|
||||
r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet)
|
||||
@ -103,6 +106,11 @@ type DeleteJobApiResponse struct {
|
||||
Message string `json:"msg"`
|
||||
}
|
||||
|
||||
// UpdateUserApiResponse model
|
||||
type UpdateUserApiResponse struct {
|
||||
Message string `json:"msg"`
|
||||
}
|
||||
|
||||
// StopJobApiRequest model
|
||||
type StopJobApiRequest struct {
|
||||
// Stop Time of job as epoch
|
||||
@ -1043,6 +1051,77 @@ func (api *RestApi) updateUser(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (api *RestApi) secureUpdateUser(rw http.ResponseWriter, r *http.Request) {
|
||||
if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) {
|
||||
handleError(fmt.Errorf("missing role: %v", auth.GetRoleString(auth.RoleApi)), http.StatusForbidden, rw)
|
||||
return
|
||||
}
|
||||
|
||||
// If nothing declared in config: deny all request to this endpint
|
||||
if config.Keys.ApiAllowedAddrs == nil || len(config.Keys.ApiAllowedAddrs) == 0 {
|
||||
handleError(fmt.Errorf("denied by default policy!"), http.StatusForbidden, rw)
|
||||
return
|
||||
}
|
||||
|
||||
// IP CHECK HERE (WIP)
|
||||
// Probably better as private routine
|
||||
IPAddress := r.Header.Get("X-Real-Ip")
|
||||
if IPAddress == "" {
|
||||
IPAddress = r.Header.Get("X-Forwarded-For")
|
||||
}
|
||||
if IPAddress == "" {
|
||||
IPAddress = r.RemoteAddr
|
||||
}
|
||||
|
||||
// Also This
|
||||
ipOk := false
|
||||
for _, a := range config.Keys.ApiAllowedAddrs {
|
||||
if a == IPAddress {
|
||||
ipOk = true
|
||||
}
|
||||
}
|
||||
|
||||
if IPAddress == "" || ipOk == false {
|
||||
handleError(fmt.Errorf("unknown ip: %v", IPAddress), http.StatusForbidden, rw)
|
||||
return
|
||||
}
|
||||
// IP CHECK END
|
||||
|
||||
// Get Values
|
||||
id := mux.Vars(r)["id"]
|
||||
newproj := mux.Vars(r)["project"]
|
||||
newrole := mux.Vars(r)["role"]
|
||||
|
||||
// TODO: Handle anything but roles...
|
||||
if newrole != "" {
|
||||
if err := api.Authentication.AddRole(r.Context(), id, newrole); err != nil {
|
||||
handleError(errors.New(err.Error()), http.StatusUnprocessableEntity, rw)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(rw).Encode(UpdateUserApiResponse{
|
||||
Message: fmt.Sprintf("Successfully added role %s to %s", newrole, id),
|
||||
})
|
||||
|
||||
} else if newproj != "" {
|
||||
if err := api.Authentication.AddProject(r.Context(), id, newproj); err != nil {
|
||||
handleError(errors.New(err.Error()), http.StatusUnprocessableEntity, rw)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(rw).Encode(UpdateUserApiResponse{
|
||||
Message: fmt.Sprintf("Successfully added project %s to %s", newproj, id),
|
||||
})
|
||||
|
||||
} else {
|
||||
handleError(errors.New("Not Add [role|project]?"), http.StatusBadRequest, rw)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *RestApi) updateConfiguration(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
key, value := r.FormValue("key"), r.FormValue("value")
|
||||
|
@ -69,6 +69,9 @@ type ProgramConfig struct {
|
||||
// Address where the http (or https) server will listen on (for example: 'localhost:80').
|
||||
Addr string `json:"addr"`
|
||||
|
||||
// Addresses from which the /secured/* API endpoints can be reached
|
||||
ApiAllowedAddrs []string `json:"apiAllowedAddrs"`
|
||||
|
||||
// Drop root permissions once .env was read and the port was taken.
|
||||
User string `json:"user"`
|
||||
Group string `json:"group"`
|
||||
|
Loading…
Reference in New Issue
Block a user