Some work on permissions (lacks tests)

This commit is contained in:
simon987
2019-02-13 21:54:18 -05:00
parent 4edf354f8d
commit c3e5bd77f7
34 changed files with 650 additions and 273 deletions

View File

@@ -145,7 +145,6 @@ func (api *WebAPI) AccountDetails(r *Request) {
logrus.WithFields(logrus.Fields{
"manager": manager,
"session": sess,
}).Trace("Account details request")
if manager == nil {

View File

@@ -90,6 +90,8 @@ func New() *WebAPI {
api.router.GET("/project/monitoring-between/:id", LogRequestMiddleware(api.GetSnapshotsBetween))
api.router.GET("/project/monitoring/:id", LogRequestMiddleware(api.GetNSnapshots))
api.router.GET("/project/assignees/:id", LogRequestMiddleware(api.ProjectGetAssigneeStats))
api.router.GET("/project/requests/:id", LogRequestMiddleware(api.ProjectGetAccessRequests))
api.router.GET("/project/request_access/:id", LogRequestMiddleware(api.WorkerRequestAccess))
api.router.POST("/task/create", LogRequestMiddleware(api.TaskCreate))
api.router.GET("/task/get/:project", LogRequestMiddleware(api.TaskGetFromProject))

View File

@@ -15,6 +15,7 @@ type CreateProjectRequest struct {
Priority int64 `json:"priority"`
Motd string `json:"motd"`
Public bool `json:"public"`
Hidden bool `json:"hidden"`
}
type UpdateProjectRequest struct {
@@ -24,6 +25,7 @@ type UpdateProjectRequest struct {
Priority int64 `json:"priority"`
Motd string `json:"motd"`
Public bool `json:"public"`
Hidden bool `json:"hidden"`
}
type UpdateProjectResponse struct {
@@ -55,8 +57,22 @@ type GetAssigneeStatsResponse struct {
Assignees *[]storage.AssignedTasks `json:"assignees"`
}
type WorkerRequestAccessResponse struct {
Ok bool `json:"ok"`
Message string `json:"message,omitempty"`
}
type ProjectGetAccessRequestsResponse struct {
Ok bool `json:"ok"`
Message string `json:"message,omitempty"`
Requests *[]storage.Worker `json:"requests,omitempty"`
}
func (api *WebAPI) ProjectCreate(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
createReq := &CreateProjectRequest{}
err := json.Unmarshal(r.Ctx.Request.Body(), createReq)
if err != nil {
@@ -74,26 +90,10 @@ func (api *WebAPI) ProjectCreate(r *Request) {
Priority: createReq.Priority,
Motd: createReq.Motd,
Public: createReq.Public,
Hidden: createReq.Hidden,
}
if isValidProject(project) {
id, err := api.Database.SaveProject(project)
if err != nil {
r.Json(CreateProjectResponse{
Ok: false,
Message: err.Error(),
}, 500)
} else {
r.OkJson(CreateProjectResponse{
Ok: true,
Id: id,
})
logrus.WithFields(logrus.Fields{
"project": project,
}).Debug("Created project")
}
} else {
if !isValidProject(project) {
logrus.WithFields(logrus.Fields{
"project": project,
}).Warn("Invalid project")
@@ -102,7 +102,36 @@ func (api *WebAPI) ProjectCreate(r *Request) {
Ok: false,
Message: "Invalid project",
}, 400)
return
}
if !isProjectCreationAuthorized(project, manager) {
logrus.WithFields(logrus.Fields{
"project": project,
}).Warn("Unauthorized project creation")
r.Json(CreateProjectResponse{
Ok: false,
Message: "You are not permitted to create a project with this configuration",
}, 400)
return
}
id, err := api.Database.SaveProject(project)
if err != nil {
r.Json(CreateProjectResponse{
Ok: false,
Message: err.Error(),
}, 500)
return
}
r.OkJson(CreateProjectResponse{
Ok: true,
Id: id,
})
logrus.WithFields(logrus.Fields{
"project": project,
}).Debug("Created project")
}
func (api *WebAPI) ProjectUpdate(r *Request) {
@@ -133,6 +162,7 @@ func (api *WebAPI) ProjectUpdate(r *Request) {
Priority: updateReq.Priority,
Motd: updateReq.Motd,
Public: updateReq.Public,
Hidden: updateReq.Hidden,
}
if isValidProject(project) {
@@ -180,6 +210,38 @@ func isValidProject(project *storage.Project) bool {
return true
}
func isProjectCreationAuthorized(project *storage.Project, manager interface{}) bool {
return true
if manager == nil {
return false
}
if project.Public && manager.(*storage.Manager).WebsiteAdmin {
return false
}
return true
}
func isProjectUpdateAuthorized(project *storage.Project, manager interface{}, db *storage.Database) bool {
var man storage.Manager
if manager != nil {
man = manager.(storage.Manager)
}
if man.WebsiteAdmin {
return true
}
role := db.ManagerHasRoleOn(&man, project.Id)
if role&storage.ROLE_EDIT == 1 {
return true
}
return false
}
func (api *WebAPI) ProjectGet(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
@@ -230,3 +292,64 @@ func (api *WebAPI) ProjectGetAssigneeStats(r *Request) {
Assignees: stats,
})
}
func (api *WebAPI) ProjectGetAccessRequests(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
handleErr(err, r) //todo handle invalid id
if manager == nil {
r.Json(ProjectGetAccessRequestsResponse{
Ok: false,
Message: "Unauthorized",
}, 401)
return
}
if !manager.(*storage.Manager).WebsiteAdmin &&
api.Database.ManagerHasRoleOn(manager.(*storage.Manager), 1)&
storage.ROLE_MANAGE_ACCESS == 0 {
r.Json(ProjectGetAccessRequestsResponse{
Ok: false,
Message: "Unauthorized",
}, 403)
return
}
requests := api.Database.GetAllAccessRequests(id)
r.OkJson(ProjectGetAccessRequestsResponse{
Ok: true,
Requests: requests,
})
}
func (api *WebAPI) WorkerRequestAccess(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
handleErr(err, r) //todo handle invalid id
worker, err := api.validateSignature(r)
if err != nil {
r.Json(WorkerRequestAccessResponse{
Ok: false,
Message: err.Error(),
}, 401)
}
res := api.Database.SaveAccessRequest(worker, id)
if res {
r.OkJson(WorkerRequestAccessResponse{
Ok: true,
})
} else {
r.Json(WorkerRequestAccessResponse{
Ok: false,
Message: "Project is public, you already have " +
"an active request or you already have access to this project",
}, 400)
}
}

View File

@@ -177,6 +177,10 @@ func (api WebAPI) validateSignature(r *Request) (*storage.Worker, error) {
widStr := string(r.Ctx.Request.Header.Peek("X-Worker-Id"))
signature := r.Ctx.Request.Header.Peek("X-Signature")
if widStr == "" {
return nil, errors.New("worker id not specified")
}
wid, err := strconv.ParseInt(widStr, 10, 64)
if err != nil {
logrus.WithError(err).WithFields(logrus.Fields{

View File

@@ -58,11 +58,9 @@ func (api *WebAPI) WorkerCreate(r *Request) {
return
}
identity := getIdentity(r)
if !canCreateWorker(r, workerReq, identity) {
if !canCreateWorker(r, workerReq) {
logrus.WithFields(logrus.Fields{
"identity": identity,
"createWorkerRequest": workerReq,
}).Warn("Failed CreateWorkerRequest")
@@ -73,7 +71,7 @@ func (api *WebAPI) WorkerCreate(r *Request) {
return
}
worker, err := api.workerCreate(workerReq, getIdentity(r))
worker, err := api.workerCreate(workerReq)
if err != nil {
handleErr(err, r)
} else {
@@ -185,7 +183,7 @@ func (api *WebAPI) WorkerUpdate(r *Request) {
r.Json(GetTaskResponse{
Ok: false,
Message: err.Error(),
}, 403)
}, 401)
return
}
@@ -224,24 +222,23 @@ func (api *WebAPI) GetAllWorkerStats(r *Request) {
})
}
func (api *WebAPI) workerCreate(request *CreateWorkerRequest, identity *storage.Identity) (*storage.Worker, error) {
func (api *WebAPI) workerCreate(request *CreateWorkerRequest) (*storage.Worker, error) {
if request.Alias == "" {
request.Alias = "default_alias"
}
worker := storage.Worker{
Created: time.Now().Unix(),
Identity: identity,
Secret: makeSecret(),
Alias: request.Alias,
Created: time.Now().Unix(),
Secret: makeSecret(),
Alias: request.Alias,
}
api.Database.SaveWorker(&worker)
return &worker, nil
}
func canCreateWorker(r *Request, cwr *CreateWorkerRequest, identity *storage.Identity) bool {
func canCreateWorker(r *Request, cwr *CreateWorkerRequest) bool {
if cwr.Alias == "unassigned" {
//Reserved alias
@@ -260,13 +257,3 @@ func makeSecret() []byte {
return secret
}
func getIdentity(r *Request) *storage.Identity {
identity := storage.Identity{
RemoteAddr: r.Ctx.RemoteAddr().String(),
UserAgent: string(r.Ctx.UserAgent()),
}
return &identity
}