diff --git a/persistence/sql_base_repository.go b/persistence/sql_base_repository.go
index fb2a2cfe..e14c7a26 100644
--- a/persistence/sql_base_repository.go
+++ b/persistence/sql_base_repository.go
@@ -31,6 +31,14 @@ func userId(ctx context.Context) string {
return usr.ID
}
+func loggedUser(ctx context.Context) *model.User {
+ user := ctx.Value("user")
+ if user == nil {
+ return &model.User{}
+ }
+ return user.(*model.User)
+}
+
func (r sqlRepository) newSelect(options ...model.QueryOptions) SelectBuilder {
sq := Select().From(r.tableName)
sq = r.applyOptions(sq, options...)
diff --git a/persistence/user_repository.go b/persistence/user_repository.go
index 8f68d763..fbb3a63a 100644
--- a/persistence/user_repository.go
+++ b/persistence/user_repository.go
@@ -85,10 +85,18 @@ func (r *userRepository) UpdateLastAccessAt(id string) error {
}
func (r *userRepository) Count(options ...rest.QueryOptions) (int64, error) {
+ usr := loggedUser(r.ctx)
+ if !usr.IsAdmin {
+ return 0, rest.ErrPermissionDenied
+ }
return r.CountAll(r.parseRestOptions(options...))
}
func (r *userRepository) Read(id string) (interface{}, error) {
+ usr := loggedUser(r.ctx)
+ if !usr.IsAdmin && usr.ID != id {
+ return nil, rest.ErrPermissionDenied
+ }
usr, err := r.Get(id)
if err == model.ErrNotFound {
return nil, rest.ErrNotFound
@@ -97,6 +105,10 @@ func (r *userRepository) Read(id string) (interface{}, error) {
}
func (r *userRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) {
+ usr := loggedUser(r.ctx)
+ if !usr.IsAdmin {
+ return nil, rest.ErrPermissionDenied
+ }
return r.GetAll(r.parseRestOptions(options...))
}
@@ -109,17 +121,25 @@ func (r *userRepository) NewInstance() interface{} {
}
func (r *userRepository) Save(entity interface{}) (string, error) {
- usr := entity.(*model.User)
- err := r.Put(usr)
+ usr := loggedUser(r.ctx)
+ if !usr.IsAdmin {
+ return "", rest.ErrPermissionDenied
+ }
+ u := entity.(*model.User)
+ err := r.Put(u)
if err != nil {
return "", err
}
- return usr.ID, err
+ return u.ID, err
}
func (r *userRepository) Update(entity interface{}, cols ...string) error {
- usr := entity.(*model.User)
- err := r.Put(usr)
+ u := entity.(*model.User)
+ usr := loggedUser(r.ctx)
+ if !usr.IsAdmin && usr.ID != u.ID {
+ return rest.ErrPermissionDenied
+ }
+ err := r.Put(u)
if err == model.ErrNotFound {
return rest.ErrNotFound
}
@@ -127,7 +147,11 @@ func (r *userRepository) Update(entity interface{}, cols ...string) error {
}
func (r *userRepository) Delete(id string) error {
- err := r.Delete(id)
+ usr := loggedUser(r.ctx)
+ if !usr.IsAdmin && usr.ID != id {
+ return rest.ErrPermissionDenied
+ }
+ err := r.delete(Eq{"id": id})
if err == model.ErrNotFound {
return rest.ErrNotFound
}
diff --git a/server/app/auth.go b/server/app/auth.go
index c837502d..49a06948 100644
--- a/server/app/auth.go
+++ b/server/app/auth.go
@@ -63,6 +63,7 @@ func handleLogin(ds model.DataStore, username string, password string, w http.Re
"token": tokenString,
"name": user.Name,
"username": username,
+ "isAdmin": user.IsAdmin,
})
}
@@ -148,10 +149,6 @@ func validateLogin(userRepo model.UserRepository, userName, password string) (*m
if u.Password != password {
return nil, nil
}
- if !u.IsAdmin {
- log.Warn("Non-admin user tried to login", "user", userName)
- return nil, nil
- }
err = userRepo.UpdateLastLoginAt(u.ID)
if err != nil {
log.Error("Could not update LastLoginAt", "user", userName)
@@ -164,6 +161,7 @@ func createToken(u *model.User) (string, error) {
claims := token.Claims.(jwt.MapClaims)
claims["iss"] = consts.JWTIssuer
claims["sub"] = u.UserName
+ claims["adm"] = u.IsAdmin
return touchToken(token)
}
@@ -176,11 +174,10 @@ func touchToken(token *jwt.Token) (string, error) {
return token.SignedString(jwtSecret)
}
-func userFrom(claims jwt.MapClaims) *model.User {
- user := &model.User{
- UserName: claims["sub"].(string),
- }
- return user
+func contextWithUser(ctx context.Context, ds model.DataStore, claims jwt.MapClaims) context.Context {
+ userName := claims["sub"].(string)
+ user, _ := ds.User(ctx).FindByUsername(userName)
+ return context.WithValue(ctx, "user", user)
}
func getToken(ds model.DataStore, ctx context.Context) (*jwt.Token, error) {
@@ -217,7 +214,7 @@ func Authenticator(ds model.DataStore) func(next http.Handler) http.Handler {
claims := token.Claims.(jwt.MapClaims)
- newCtx := context.WithValue(r.Context(), "loggedUser", userFrom(claims))
+ newCtx := contextWithUser(r.Context(), ds, claims)
newTokenString, err := touchToken(token)
if err != nil {
log.Error(r, "signing new token", err)
diff --git a/ui/src/App.js b/ui/src/App.js
index 71116e1e..2448597a 100644
--- a/ui/src/App.js
+++ b/ui/src/App.js
@@ -20,10 +20,12 @@ const App = () => (
layout={Layout}
loginPage={Login}
>
-
-
-
-
+ {(permissions) => [
+ ,
+ ,
+ ,
+ permissions === 'admin' ? : null
+ ]}
)
export default App
diff --git a/ui/src/authProvider.js b/ui/src/authProvider.js
index 5492aa7a..3ee09b35 100644
--- a/ui/src/authProvider.js
+++ b/ui/src/authProvider.js
@@ -25,6 +25,7 @@ const authProvider = {
localStorage.setItem('token', response.token)
localStorage.setItem('name', response.name)
localStorage.setItem('username', response.username)
+ localStorage.setItem('role', response.isAdmin ? 'admin' : 'regular')
return response
})
.catch((error) => {
@@ -59,13 +60,17 @@ const authProvider = {
return Promise.resolve()
},
- getPermissions: (params) => Promise.resolve()
+ getPermissions: () => {
+ const role = localStorage.getItem('role')
+ return role ? Promise.resolve(role) : Promise.reject()
+ }
}
const removeItems = () => {
localStorage.removeItem('token')
localStorage.removeItem('name')
localStorage.removeItem('username')
+ localStorage.removeItem('role')
}
export default authProvider