Initial work on auth
This commit is contained in:
parent
c072e16cc4
commit
5a151859d7
|
|
@ -8,6 +8,7 @@ message ActionButton {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string title = 2;
|
string title = 2;
|
||||||
string icon = 3;
|
string icon = 3;
|
||||||
|
bool canExec = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetButtonsResponse {
|
message GetButtonsResponse {
|
||||||
|
|
@ -34,6 +35,8 @@ message LogEntry {
|
||||||
string stderr = 4;
|
string stderr = 4;
|
||||||
bool timedOut = 5;
|
bool timedOut = 5;
|
||||||
int32 exitCode = 6;
|
int32 exitCode = 6;
|
||||||
|
string user = 7;
|
||||||
|
string userClass = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetLogsResponse {
|
message GetLogsResponse {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package acl
|
||||||
|
|
||||||
|
import (
|
||||||
|
config "github.com/jamesread/OliveTin/internal/config"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Username string;
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsAllowedExec(cfg *config.Config, user *User, action *config.ActionButton) bool {
|
||||||
|
canExec := cfg.DefaultPermissions.Exec
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"User": user.Username,
|
||||||
|
"Action": action.Title,
|
||||||
|
"CanExec": canExec,
|
||||||
|
}).Debug("isAllowedExec Permission Default")
|
||||||
|
|
||||||
|
for _, permissionEntry := range action.Permissions {
|
||||||
|
if isUserInGroup(user, permissionEntry.Usergroup) {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"User": user.Username,
|
||||||
|
"Action": action.Title,
|
||||||
|
"CanExec": permissionEntry.Exec,
|
||||||
|
}).Debug("isAllowedExec Permission Entry")
|
||||||
|
|
||||||
|
canExec = permissionEntry.Exec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"User": user.Username,
|
||||||
|
"Action": action.Title,
|
||||||
|
"CanExec": canExec,
|
||||||
|
}).Debug("isAllowedExec Final Result")
|
||||||
|
|
||||||
|
return canExec;
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsAllowedView(cfg *config.Config, user *User, action *config.ActionButton) bool {
|
||||||
|
canView := cfg.DefaultPermissions.View
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"User": user.Username,
|
||||||
|
"Action": action.Title,
|
||||||
|
"CanView": canView,
|
||||||
|
}).Debug("isAllowedView Permission Default")
|
||||||
|
|
||||||
|
for idx, permissionEntry := range action.Permissions {
|
||||||
|
if isUserInGroup(user, permissionEntry.Usergroup) {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"User": user.Username,
|
||||||
|
"Action": action.Title,
|
||||||
|
"CanView": permissionEntry.View,
|
||||||
|
"Index": idx,
|
||||||
|
}).Debug("isAllowedView Permission Entry")
|
||||||
|
|
||||||
|
canView = permissionEntry.View
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"User": user.Username,
|
||||||
|
"Action": action.Title,
|
||||||
|
"CanView": canView,
|
||||||
|
}).Debug("isAllowedView Final Result")
|
||||||
|
|
||||||
|
return canView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func isUserInGroup(user *User, usergroup string) bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
func UserFromContext(ctx context.Context) *User {
|
||||||
|
return &User {
|
||||||
|
Username: "Guest",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ type ActionButton struct {
|
||||||
Shell string
|
Shell string
|
||||||
CSS map[string]string `mapstructure:"omitempty"`
|
CSS map[string]string `mapstructure:"omitempty"`
|
||||||
Timeout int
|
Timeout int
|
||||||
|
Permissions []PermissionsEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entity represents a "thing" that can have multiple actions associated with it.
|
// Entity represents a "thing" that can have multiple actions associated with it.
|
||||||
|
|
@ -21,6 +22,22 @@ type Entity struct {
|
||||||
CSS map[string]string
|
CSS map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PermissionsEntry struct {
|
||||||
|
Usergroup string
|
||||||
|
View bool
|
||||||
|
Exec bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultPermissions struct {
|
||||||
|
View bool
|
||||||
|
Exec bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserGroup struct {
|
||||||
|
Name string
|
||||||
|
Members []string
|
||||||
|
}
|
||||||
|
|
||||||
// Config is the global config used through the whole app.
|
// Config is the global config used through the whole app.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
UseSingleHTTPFrontend bool
|
UseSingleHTTPFrontend bool
|
||||||
|
|
@ -34,6 +51,8 @@ type Config struct {
|
||||||
ActionButtons []ActionButton `mapstructure:"actions"`
|
ActionButtons []ActionButton `mapstructure:"actions"`
|
||||||
Entities []Entity `mapstructure:"omitempty"`
|
Entities []Entity `mapstructure:"omitempty"`
|
||||||
CheckForUpdates bool
|
CheckForUpdates bool
|
||||||
|
Usergroups []UserGroup
|
||||||
|
DefaultPermissions DefaultPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig gets a new Config structure with sensible default values.
|
// DefaultConfig gets a new Config structure with sensible default values.
|
||||||
|
|
@ -46,6 +65,8 @@ func DefaultConfig() *Config {
|
||||||
config.ListenAddressWebUI = "localhost:1340"
|
config.ListenAddressWebUI = "localhost:1340"
|
||||||
config.LogLevel = "INFO"
|
config.LogLevel = "INFO"
|
||||||
config.CheckForUpdates = true
|
config.CheckForUpdates = true
|
||||||
|
config.DefaultPermissions.Exec = true
|
||||||
|
config.DefaultPermissions.View = true
|
||||||
|
|
||||||
return &config
|
return &config
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
pb "github.com/jamesread/OliveTin/gen/grpc"
|
pb "github.com/jamesread/OliveTin/gen/grpc"
|
||||||
config "github.com/jamesread/OliveTin/internal/config"
|
config "github.com/jamesread/OliveTin/internal/config"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
acl "github.com/jamesread/OliveTin/internal/acl"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -26,21 +27,11 @@ type Executor struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecAction executes an action.
|
// ExecAction executes an action.
|
||||||
func (e *Executor) ExecAction(cfg *config.Config, action string) *pb.StartActionResponse {
|
func (e *Executor) ExecAction(cfg *config.Config, user *acl.User, actualAction *config.ActionButton) *pb.StartActionResponse {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"actionName": action,
|
"actionName": actualAction.Title,
|
||||||
}).Infof("StartAction")
|
}).Infof("StartAction")
|
||||||
|
|
||||||
actualAction, err := findAction(cfg, action)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error finding action %s, %s", err, action)
|
|
||||||
|
|
||||||
return &pb.StartActionResponse{
|
|
||||||
LogEntry: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := execAction(cfg, actualAction)
|
res := execAction(cfg, actualAction)
|
||||||
|
|
||||||
e.Logs = append(e.Logs, *res);
|
e.Logs = append(e.Logs, *res);
|
||||||
|
|
@ -103,7 +94,7 @@ func sanitizeAction(action *config.ActionButton) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAction(cfg *config.Config, actionTitle string) (*config.ActionButton, error) {
|
func FindAction(cfg *config.Config, actionTitle string) (*config.ActionButton, error) {
|
||||||
for _, action := range cfg.ActionButtons {
|
for _, action := range cfg.ActionButtons {
|
||||||
if action.Title == actionTitle {
|
if action.Title == actionTitle {
|
||||||
sanitizeAction(&action)
|
sanitizeAction(&action)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
config "github.com/jamesread/OliveTin/internal/config"
|
config "github.com/jamesread/OliveTin/internal/config"
|
||||||
executor "github.com/jamesread/OliveTin/internal/executor"
|
executor "github.com/jamesread/OliveTin/internal/executor"
|
||||||
|
acl "github.com/jamesread/OliveTin/internal/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -23,23 +24,52 @@ type oliveTinAPI struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) (*pb.StartActionResponse, error) {
|
func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) (*pb.StartActionResponse, error) {
|
||||||
return ex.ExecAction(cfg, req.ActionName), nil
|
actualAction, err := executor.FindAction(cfg, req.ActionName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error finding action %s, %s", err, req.ActionName)
|
||||||
|
|
||||||
|
return &pb.StartActionResponse{
|
||||||
|
LogEntry: nil,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
user := acl.UserFromContext(ctx)
|
||||||
|
|
||||||
|
if !acl.IsAllowedExec(cfg, user, actualAction) {
|
||||||
|
return &pb.StartActionResponse{
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ex.ExecAction(cfg, acl.UserFromContext(ctx), actualAction), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *oliveTinAPI) GetButtons(ctx ctx.Context, req *pb.GetButtonsRequest) (*pb.GetButtonsResponse, error) {
|
func (api *oliveTinAPI) GetButtons(ctx ctx.Context, req *pb.GetButtonsRequest) (*pb.GetButtonsResponse, error) {
|
||||||
res := &pb.GetButtonsResponse{}
|
res := &pb.GetButtonsResponse{}
|
||||||
|
|
||||||
|
user := acl.UserFromContext(ctx)
|
||||||
|
|
||||||
for _, action := range cfg.ActionButtons {
|
for _, action := range cfg.ActionButtons {
|
||||||
|
if !acl.IsAllowedView(cfg, user, &action) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
btn := pb.ActionButton{
|
btn := pb.ActionButton{
|
||||||
Id: fmt.Sprintf("%x", md5.Sum([]byte(action.Title))),
|
Id: fmt.Sprintf("%x", md5.Sum([]byte(action.Title))),
|
||||||
Title: action.Title,
|
Title: action.Title,
|
||||||
Icon: lookupHTMLIcon(action.Icon),
|
Icon: lookupHTMLIcon(action.Icon),
|
||||||
|
CanExec: acl.IsAllowedExec(cfg, user, &action),
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Actions = append(res.Actions, &btn)
|
res.Actions = append(res.Actions, &btn)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("getButtons: %v", res)
|
if len(res.Actions) == 0 {
|
||||||
|
log.Warn("Zero actions found - check that you have some actions defined, with a view permission")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("getButtons: %v", res)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue