From 05a1b3cbd8767871116cb1601dd1e246311dfaea Mon Sep 17 00:00:00 2001 From: Anton Markelov Date: Wed, 26 Jul 2017 15:55:34 +1000 Subject: [PATCH] add admin role, restrict users without it --- api-docs.yml | 2 ++ api/users.go | 45 +++++++++++++++++++++++++++++++++++++- db/User.go | 1 + db/migrations/v2.4.2.sql | 1 + db/versionHistory.go | 1 + public/html/users/add.pug | 9 ++++++++ public/html/users/list.pug | 8 ++++++- public/html/users/user.pug | 4 ++++ 8 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 db/migrations/v2.4.2.sql diff --git a/api-docs.yml b/api-docs.yml index 9cc321d8..ffa63a70 100644 --- a/api-docs.yml +++ b/api-docs.yml @@ -55,6 +55,8 @@ definitions: format: date-time alert: type: boolean + admin: + type: boolean APIToken: type: object properties: diff --git a/api/users.go b/api/users.go index 318eb668..3b65ba91 100644 --- a/api/users.go +++ b/api/users.go @@ -28,6 +28,13 @@ func addUser(w http.ResponseWriter, r *http.Request) { return } + editor := context.Get(r, "user").(*db.User) + if editor.Admin != true { + log.Warn(editor.Username + " doesn't permitted for user creating") + w.WriteHeader(http.StatusUnauthorized) + return + } + user.Created = time.Now() if err := db.Mysql.Insert(&user); err != nil { @@ -53,23 +60,44 @@ func getUserMiddleware(w http.ResponseWriter, r *http.Request) { panic(err) } + editor := context.Get(r, "user").(*db.User) + if editor.Admin != true && editor.ID != user.ID { + log.Warn(editor.Username + " doesn't permitted for user editing") + w.WriteHeader(http.StatusUnauthorized) + return + } + context.Set(r, "_user", user) } func updateUser(w http.ResponseWriter, r *http.Request) { oldUser := context.Get(r, "_user").(db.User) + editor := context.Get(r, "user").(*db.User) var user db.User if err := mulekick.Bind(w, r, &user); err != nil { return } + if editor.Admin != true && editor.ID != oldUser.ID { + log.Warn(editor.Username + " doesn't permitted for user editing") + w.WriteHeader(http.StatusUnauthorized) + return + } + + if editor.ID == oldUser.ID && oldUser.Admin != user.Admin { + log.Warn("User can't edit his own role") + w.WriteHeader(http.StatusUnauthorized) + return + } + if oldUser.External == true && oldUser.Username != user.Username { log.Warn("Username is not editable for external LDAP users") w.WriteHeader(http.StatusBadRequest) + return } - if _, err := db.Mysql.Exec("update user set name=?, username=?, email=?, alert=? where id=?", user.Name, user.Username, user.Email, user.Alert, oldUser.ID); err != nil { + if _, err := db.Mysql.Exec("update user set name=?, username=?, email=?, alert=?, admin=? where id=?", user.Name, user.Username, user.Email, user.Alert, user.Admin, oldUser.ID); err != nil { panic(err) } @@ -78,10 +106,18 @@ func updateUser(w http.ResponseWriter, r *http.Request) { func updateUserPassword(w http.ResponseWriter, r *http.Request) { user := context.Get(r, "_user").(db.User) + editor := context.Get(r, "user").(*db.User) + var pwd struct { Pwd string `json:"password"` } + if editor.Admin != true && editor.ID != user.ID { + log.Warn(editor.Username + " doesn't permitted for user editing") + w.WriteHeader(http.StatusUnauthorized) + return + } + if user.External == true { log.Warn("Password is not editable for external LDAP users") w.WriteHeader(http.StatusBadRequest) @@ -102,6 +138,13 @@ func updateUserPassword(w http.ResponseWriter, r *http.Request) { func deleteUser(w http.ResponseWriter, r *http.Request) { user := context.Get(r, "_user").(db.User) + editor := context.Get(r, "user").(*db.User) + + if editor.Admin != true && editor.ID != user.ID { + log.Warn(editor.Username + " doesn't permitted for user deletion") + w.WriteHeader(http.StatusUnauthorized) + return + } if _, err := db.Mysql.Exec("delete from project__user where user_id=?", user.ID); err != nil { panic(err) diff --git a/db/User.go b/db/User.go index 4e9bf033..7e1326b3 100644 --- a/db/User.go +++ b/db/User.go @@ -11,6 +11,7 @@ type User struct { Name string `db:"name" json:"name" binding:"required"` Email string `db:"email" json:"email" binding:"required"` Password string `db:"password" json:"-"` + Admin bool `db:"admin" json:"admin"` External bool `db:"external" json:"external"` Alert bool `db:"alert" json:"alert"` } diff --git a/db/migrations/v2.4.2.sql b/db/migrations/v2.4.2.sql new file mode 100644 index 00000000..4fd21b53 --- /dev/null +++ b/db/migrations/v2.4.2.sql @@ -0,0 +1 @@ +ALTER TABLE user ADD admin BOOLEAN NOT NULL DEFAULT 1 AFTER password; \ No newline at end of file diff --git a/db/versionHistory.go b/db/versionHistory.go index 370ec4a8..59fa119c 100644 --- a/db/versionHistory.go +++ b/db/versionHistory.go @@ -71,5 +71,6 @@ func init() { {Major: 2, Minor: 3, Patch: 1}, {Major: 2, Minor: 3, Patch: 2}, {Major: 2, Minor: 4}, + {Major: 2, Minor: 4, Patch: 2}, } } diff --git a/public/html/users/add.pug b/public/html/users/add.pug index eac1eecb..00d5e429 100644 --- a/public/html/users/add.pug +++ b/public/html/users/add.pug @@ -20,6 +20,15 @@ .col-sm-6 input#password.form-control(type="password" placeholder="User Password" ng-model="user.password" required) + .form-group + .col-sm-8.col-sm-offset-4: .checkbox: label + input#admin(type="checkbox" title="User have admin privileges" ng-model="user.admin") + | Admin user + .form-group + .col-sm-8.col-sm-offset-4: .checkbox: label + input#alert(type="checkbox" title="Send email alerts about failed tasks" ng-model="user.alert") + | Send alerts + .modal-footer button.btn.btn-default.pull-left(ng-click="$dismiss()") Dismiss button.btn.btn-success(ng-click="$close(user)") Create User diff --git a/public/html/users/list.pug b/public/html/users/list.pug index ceea169f..7c7d7455 100644 --- a/public/html/users/list.pug +++ b/public/html/users/list.pug @@ -1,15 +1,21 @@ .container-fluid: .row: .col-sm-12 h3.no-top-margin Users - button.btn.btn-primary.pull-right(ng-click="addUser()") New User + button.btn.btn-primary.pull-right(ng-click="addUser()" ng-if="user.admin == true") New User table.table.table-hover thead: tr th Name th Username th Email + th Alert + th Admin + th External tr(ng-repeat="u in users" ng-class="{ info: u.id == user.id }" ui-sref="users.user({ user_id: u.id })" style="cursor: pointer;") td {{ u.name }} td {{ u.username }} td {{ u.email }} + td {{ u.alert }} + td {{ u.admin }} + td {{ u.external }} p(ng-show="users.length == 0") No Users diff --git a/public/html/users/user.pug b/public/html/users/user.pug index a776f553..33cdb152 100644 --- a/public/html/users/user.pug +++ b/public/html/users/user.pug @@ -15,6 +15,10 @@ .form-group label.control-label.col-sm-4 Password .col-sm-8: input.form-control(type="password" placeholder="Enter new password" ng-readonly="user.external == true" ng-model="user.password") + .form-group(ng-if="!is_self") + .col-sm-8.col-sm-offset-4: .checkbox: label + input(type="checkbox" title="User have admin privileges" ng-model="user.admin") + | Admin user .form-group .col-sm-8.col-sm-offset-4: .checkbox: label input(type="checkbox" title="Send email alerts about failed tasks" ng-model="user.alert")