mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 13:29:05 +01:00
Allow making LDAP users admins
This commit is contained in:
parent
6e9a916a18
commit
e0cc17cfa9
21
api/rest.go
21
api/rest.go
@ -55,6 +55,7 @@ func (api *RestApi) MountRoutes(r *mux.Router) {
|
|||||||
r.HandleFunc("/users/", api.createUser).Methods(http.MethodPost, http.MethodPut)
|
r.HandleFunc("/users/", api.createUser).Methods(http.MethodPost, http.MethodPut)
|
||||||
r.HandleFunc("/users/", api.getUsers).Methods(http.MethodGet)
|
r.HandleFunc("/users/", api.getUsers).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/users/", api.deleteUser).Methods(http.MethodDelete)
|
r.HandleFunc("/users/", api.deleteUser).Methods(http.MethodDelete)
|
||||||
|
r.HandleFunc("/user/{id}", api.updateUser).Methods(http.MethodPost)
|
||||||
r.HandleFunc("/configuration/", api.updateConfiguration).Methods(http.MethodPost)
|
r.HandleFunc("/configuration/", api.updateConfiguration).Methods(http.MethodPost)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,7 +556,9 @@ func (api *RestApi) getUsers(rw http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := api.Authentication.FetchUsers(r.URL.Query().Get("via-ldap") == "true")
|
users, err := api.Authentication.FetchUsers(
|
||||||
|
r.URL.Query().Get("via-ldap") == "true",
|
||||||
|
r.URL.Query().Get("not-just-user") == "true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -564,6 +567,22 @@ func (api *RestApi) getUsers(rw http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(rw).Encode(users)
|
json.NewEncoder(rw).Encode(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *RestApi) updateUser(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
if user := auth.GetUser(r.Context()); !user.HasRole(auth.RoleAdmin) {
|
||||||
|
http.Error(rw, "only admins are allowed to update a user", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle anything but roles...
|
||||||
|
newrole := r.FormValue("add-role")
|
||||||
|
if err := api.Authentication.AddRole(r.Context(), mux.Vars(r)["id"], newrole); err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rw.Write([]byte("success"))
|
||||||
|
}
|
||||||
|
|
||||||
func (api *RestApi) updateConfiguration(rw http.ResponseWriter, r *http.Request) {
|
func (api *RestApi) updateConfiguration(rw http.ResponseWriter, r *http.Request) {
|
||||||
rw.Header().Set("Content-Type", "text/plain")
|
rw.Header().Set("Content-Type", "text/plain")
|
||||||
key, value := r.FormValue("key"), r.FormValue("value")
|
key, value := r.FormValue("key"), r.FormValue("value")
|
||||||
|
37
auth/auth.go
37
auth/auth.go
@ -174,17 +174,48 @@ func (auth *Authentication) CreateUser(username, name, password, email string, r
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (auth *Authentication) AddRole(ctx context.Context, username string, role string) error {
|
||||||
|
user, err := auth.FetchUser(username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if role != RoleAdmin && role != RoleApi && role != RoleUser {
|
||||||
|
return fmt.Errorf("invalid user role: %#v", role)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range user.Roles {
|
||||||
|
if r == role {
|
||||||
|
return fmt.Errorf("user %#v already has role %#v", username, role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roles, _ := json.Marshal(append(user.Roles, role))
|
||||||
|
if _, err := sq.Update("user").Set("roles", roles).Where("user.username = ?", username).RunWith(auth.db).Exec(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (auth *Authentication) DelUser(username string) error {
|
func (auth *Authentication) DelUser(username string) error {
|
||||||
_, err := auth.db.Exec(`DELETE FROM user WHERE user.username = ?`, username)
|
_, err := auth.db.Exec(`DELETE FROM user WHERE user.username = ?`, username)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *Authentication) FetchUsers(viaLdap bool) ([]*User, error) {
|
func (auth *Authentication) FetchUsers(viaLdap, notJustUser bool) ([]*User, error) {
|
||||||
q := sq.Select("username", "name", "email", "roles").From("user")
|
q := sq.Select("username", "name", "email", "roles").From("user")
|
||||||
if !viaLdap {
|
if !viaLdap {
|
||||||
q = q.Where("ldap = 0")
|
if notJustUser {
|
||||||
|
q = q.Where("ldap = 0 OR roles != '[\"user\"]'")
|
||||||
|
} else {
|
||||||
|
q = q.Where("ldap = 0")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
q = q.Where("ldap = 1")
|
if notJustUser {
|
||||||
|
q = q.Where("ldap = 1 OR roles != '[\"user\"]'")
|
||||||
|
} else {
|
||||||
|
q = q.Where("ldap = 1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := q.RunWith(auth.db).Query()
|
rows, err := q.RunWith(auth.db).Query()
|
||||||
|
@ -47,7 +47,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col card" style="margin: 10px;">
|
<div class="col card" style="margin: 10px;">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">All Users not Created by an LDAP Sync:</h5>
|
<h5 class="card-title">Special Users</h5>
|
||||||
|
<p>Not created by an LDAP sync and/or having a role other than <code>user</code></p>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -61,7 +62,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody id="users-list"><tr><td colspan="4"><div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div></td></tr></tbody>
|
<tbody id="users-list"><tr><td colspan="4"><div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div></td></tr></tbody>
|
||||||
<script>
|
<script>
|
||||||
fetch('/api/users/?via-ldap=false')
|
fetch('/api/users/?via-ldap=false¬-just-user=true')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(users => {
|
.then(users => {
|
||||||
let listElement = document.querySelector('#users-list')
|
let listElement = document.querySelector('#users-list')
|
||||||
@ -105,6 +106,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col card" style="margin: 10px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Add Role to User</h5>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" placeholder="username" id="add-role-username"/>
|
||||||
|
<select class="form-select" id="add-role-select">
|
||||||
|
<option selected value="">Role...</option>
|
||||||
|
<option value="user">User</option>
|
||||||
|
<option value="admin">Admin</option>
|
||||||
|
<option value="api">API</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn btn-outline-secondary" type="button" id="add-role-button">Button</button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.querySelector('#add-role-button').addEventListener('click', () => {
|
||||||
|
const username = document.querySelector('#add-role-username').value, role = document.querySelector('#add-role-select').value
|
||||||
|
if (username == "" || role == "") {
|
||||||
|
alert('Please fill in a username and select a role.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append('username', username)
|
||||||
|
formData.append('add-role', role)
|
||||||
|
fetch(`/api/user/${username}`, { method: 'POST', body: formData }).then(res => res.text()).then(status => alert(status))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col card" style="margin: 10px;">
|
<div class="col card" style="margin: 10px;">
|
||||||
|
Loading…
Reference in New Issue
Block a user