diff --git a/cmd/admin/auth.go b/cmd/admin/auth.go index f9401d5d..844518c0 100644 --- a/cmd/admin/auth.go +++ b/cmd/admin/auth.go @@ -66,7 +66,7 @@ func handlerAuthCheck(h http.Handler, auth string) http.Handler { http.Redirect(w, r, forbiddenPath, http.StatusFound) return } - u, err = adminUsers.New(samlUser, "", samlUser, "", false) + u, err = adminUsers.New(samlUser, "", samlUser, "", false, false) if err != nil { log.Err(err).Msgf("error creating user %s", samlUser) http.Redirect(w, r, forbiddenPath, http.StatusFound) diff --git a/cmd/admin/handlers/post.go b/cmd/admin/handlers/post.go index e50fe99c..2811524f 100644 --- a/cmd/admin/handlers/post.go +++ b/cmd/admin/handlers/post.go @@ -1083,7 +1083,7 @@ func (h *HandlersAdmin) UsersPOSTHandler(w http.ResponseWriter, r *http.Request) return } // Prepare user to create - newUser, err := h.Users.New(u.Username, u.NewPassword, u.Email, u.Fullname, u.Admin) + newUser, err := h.Users.New(u.Username, u.NewPassword, u.Email, u.Fullname, u.Admin, u.Service) if err != nil { adminErrorResponse(w, "error with new user", http.StatusInternalServerError, err) return @@ -1180,6 +1180,18 @@ func (h *HandlersAdmin) UsersPOSTHandler(w http.ResponseWriter, r *http.Request) } adminOKResponse(w, "admin changed successfully") } + case "service": + if u.Username == ctx[sessions.CtxUser] { + adminErrorResponse(w, "not a good idea", http.StatusInternalServerError, fmt.Errorf("attempt to service current user %s", u.Username)) + return + } + if h.Users.Exists(u.Username) { + if err := h.Users.ChangeService(u.Username, u.Service); err != nil { + adminErrorResponse(w, "error changing service", http.StatusInternalServerError, err) + return + } + adminOKResponse(w, "service changed successfully") + } } // Serialize and send response log.Debug().Msg("Users response sent") diff --git a/cmd/admin/handlers/templates.go b/cmd/admin/handlers/templates.go index cf4a1d00..35212902 100644 --- a/cmd/admin/handlers/templates.go +++ b/cmd/admin/handlers/templates.go @@ -1249,19 +1249,26 @@ func (h *HandlersAdmin) UsersGETHandler(w http.ResponseWriter, r *http.Request) log.Err(err).Msg("error getting platforms") return } - // Get current users - users, err := h.Users.All() + // Get current regular users + systemUsers, err := h.Users.AllNonService() if err != nil { log.Err(err).Msg("error getting users") return } + // Get current service users + serviceUsers, err := h.Users.AllService() + if err != nil { + log.Err(err).Msg("error getting service users") + return + } // Prepare template data templateData := UsersTemplateData{ Title: "Manage users", Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: h.allowedEnvironments(ctx[sessions.CtxUser], envAll), Platforms: platforms, - CurrentUsers: users, + SystemUsers: systemUsers, + ServiceUsers: serviceUsers, } if err := t.Execute(w, templateData); err != nil { log.Err(err).Msg("template error") diff --git a/cmd/admin/handlers/types-requests.go b/cmd/admin/handlers/types-requests.go index 53910049..9da1ed50 100644 --- a/cmd/admin/handlers/types-requests.go +++ b/cmd/admin/handlers/types-requests.go @@ -123,6 +123,7 @@ type UsersRequest struct { NewPassword string `json:"new_password"` Token bool `json:"token"` Admin bool `json:"admin"` + Service bool `json:"service"` Environments []string `json:"environments"` } diff --git a/cmd/admin/handlers/types-templates.go b/cmd/admin/handlers/types-templates.go index 278ad43b..17e9c2ba 100644 --- a/cmd/admin/handlers/types-templates.go +++ b/cmd/admin/handlers/types-templates.go @@ -20,11 +20,11 @@ type LoginTemplateData struct { // TemplateMetadata to pass some metadata to templates type TemplateMetadata struct { - Username string - Level string - Service string - Version string - CSRFToken string + Username string + Level string + Service string + Version string + CSRFToken string } // AsideLeftMetadata to pass metadata to the aside left menu @@ -185,7 +185,8 @@ type UsersTemplateData struct { Title string Environments []environments.TLSEnvironment Platforms []string - CurrentUsers []users.AdminUser + SystemUsers []users.AdminUser + ServiceUsers []users.AdminUser Metadata TemplateMetadata LeftMetadata AsideLeftMetadata } diff --git a/cmd/admin/main.go b/cmd/admin/main.go index 9b5cd555..1ec52034 100644 --- a/cmd/admin/main.go +++ b/cmd/admin/main.go @@ -135,10 +135,10 @@ func loadConfiguration(file, service string) (config.JSONConfigurationService, e } // Check if values are valid if !validAuth[cfg.Auth] { - return cfg, fmt.Errorf("Invalid auth method") + return cfg, fmt.Errorf("invalid auth method") } if !validCarver[cfg.Carver] { - return cfg, fmt.Errorf("Invalid carver method") + return cfg, fmt.Errorf("invalid carver method") } // No errors! return cfg, nil @@ -566,41 +566,41 @@ func cliAction(c *cli.Context) error { if flagParams.ConfigFlag { flagParams.ConfigValues, err = loadConfiguration(flagParams.ServiceConfigFile, config.ServiceAdmin) if err != nil { - return fmt.Errorf("Failed to load service configuration %s - %w", flagParams.ServiceConfigFile, err) + return fmt.Errorf("failed to load service configuration %s - %w", flagParams.ServiceConfigFile, err) } } // Load redis configuration if external JSON config file is used if flagParams.RedisFlag { flagParams.RedisConfigValues, err = cache.LoadConfiguration(flagParams.RedisConfigFile, cache.RedisKey) if err != nil { - return fmt.Errorf("Failed to load redis configuration - %w", err) + return fmt.Errorf("failed to load redis configuration - %w", err) } } // Load DB configuration if external JSON config file is used if flagParams.DBFlag { flagParams.DBConfigValues, err = backend.LoadConfiguration(flagParams.DBConfigFile, backend.DBKey) if err != nil { - return fmt.Errorf("Failed to load DB configuration - %w", err) + return fmt.Errorf("failed to load DB configuration - %w", err) } } // Load SAML configuration if this authentication is used in the service config if flagParams.ConfigValues.Auth == config.AuthSAML { samlConfig, err = loadSAML(flagParams.SAMLConfigFile) if err != nil { - return fmt.Errorf("Failed to load SAML configuration - %w", err) + return fmt.Errorf("failed to load SAML configuration - %w", err) } } // Load JWT configuration if external JWT JSON config file is used if flagParams.JWTFlag { flagParams.JWTConfigValues, err = loadJWTConfiguration(flagParams.JWTConfigFile) if err != nil { - return fmt.Errorf("Failed to load JWT configuration - %w", err) + return fmt.Errorf("failed to load JWT configuration - %w", err) } } // Load osquery tables JSON file osqueryTables, err = loadOsqueryTables(flagParams.OsqueryTablesFile) if err != nil { - return fmt.Errorf("Failed to load osquery tables - %w", err) + return fmt.Errorf("failed to load osquery tables - %w", err) } // Load carver configuration if external JSON config file is used if flagParams.ConfigValues.Carver == config.CarverS3 { @@ -610,7 +610,7 @@ func cliAction(c *cli.Context) error { carvers3, err = carves.CreateCarverS3File(flagParams.CarverConfigFile) } if err != nil { - return fmt.Errorf("Failed to initiate s3 carver - %w", err) + return fmt.Errorf("failed to initiate s3 carver - %w", err) } } return nil diff --git a/cmd/admin/saml.go b/cmd/admin/saml.go index 7fab119e..2ee2adff 100644 --- a/cmd/admin/saml.go +++ b/cmd/admin/saml.go @@ -62,22 +62,22 @@ func loadSAML(file string) (JSONConfigurationSAML, error) { // Function to verify SAML configuration func verifySAML(cfg JSONConfigurationSAML) error { if cfg.CertPath == "" { - return fmt.Errorf("Missing CertPath") + return fmt.Errorf("missing CertPath") } if cfg.KeyPath == "" { - return fmt.Errorf("Missing KeyPath") + return fmt.Errorf("missing KeyPath") } if cfg.MetaDataURL == "" { - return fmt.Errorf("Missing MetaDataURL") + return fmt.Errorf("missing MetaDataURL") } if cfg.RootURL == "" { - return fmt.Errorf("Missing RootURL") + return fmt.Errorf("missing RootURL") } if cfg.LoginURL == "" { - return fmt.Errorf("Missing LoginURL") + return fmt.Errorf("missing LoginURL") } if cfg.LogoutURL == "" { - return fmt.Errorf("Missing LogoutURL") + return fmt.Errorf("missing LogoutURL") } return nil } @@ -88,23 +88,23 @@ func keypairSAML(config JSONConfigurationSAML) (samlThings, error) { var err error data.KeyPair, err = tls.LoadX509KeyPair(config.CertPath, config.KeyPath) if err != nil { - return data, fmt.Errorf("LoadX509KeyPair %w", err) + return data, fmt.Errorf("loadX509KeyPair %w", err) } data.KeyPair.Leaf, err = x509.ParseCertificate(data.KeyPair.Certificate[0]) if err != nil { - return data, fmt.Errorf("ParseCertificate %w", err) + return data, fmt.Errorf("parseCertificate %w", err) } data.IdpMetadataURL, err = url.Parse(config.MetaDataURL) if err != nil { - return data, fmt.Errorf("Parse MetadataURL %w", err) + return data, fmt.Errorf("parse MetadataURL %w", err) } data.IdpMetadata, err = samlsp.FetchMetadata(context.Background(), http.DefaultClient, *data.IdpMetadataURL) if err != nil { - return data, fmt.Errorf("Fetch Metadata %w", err) + return data, fmt.Errorf("fetch Metadata %w", err) } data.RootURL, err = url.Parse(config.RootURL) if err != nil { - return data, fmt.Errorf("Parse RootURL %w", err) + return data, fmt.Errorf("parse RootURL %w", err) } return data, nil } diff --git a/cmd/admin/settings.go b/cmd/admin/settings.go index 3381b3f7..cb3091ae 100644 --- a/cmd/admin/settings.go +++ b/cmd/admin/settings.go @@ -15,30 +15,30 @@ func loadingSettings(mgr *settings.Settings, cfg config.JSONConfigurationService // Check if service settings for sessions cleanup is ready if !mgr.IsValue(config.ServiceAdmin, settings.CleanupSessions, settings.NoEnvironmentID) { if err := mgr.NewIntegerValue(config.ServiceAdmin, settings.CleanupSessions, int64(defaultRefresh), settings.NoEnvironmentID); err != nil { - return fmt.Errorf("Failed to add %s to configuration: %w", settings.CleanupSessions, err) + return fmt.Errorf("failed to add %s to configuration: %w", settings.CleanupSessions, err) } } // Check if service settings for queries/carves cleanup is ready if !mgr.IsValue(config.ServiceAdmin, settings.CleanupExpired, settings.NoEnvironmentID) { if err := mgr.NewIntegerValue(config.ServiceAdmin, settings.CleanupExpired, int64(defaultExpiration), settings.NoEnvironmentID); err != nil { - return fmt.Errorf("Failed to add %s to configuration: %w", settings.CleanupExpired, err) + return fmt.Errorf("failed to add %s to configuration: %w", settings.CleanupExpired, err) } } // Check if service settings for node inactive hours is ready if !mgr.IsValue(config.ServiceAdmin, settings.InactiveHours, settings.NoEnvironmentID) { if err := mgr.NewIntegerValue(config.ServiceAdmin, settings.InactiveHours, int64(defaultInactive), settings.NoEnvironmentID); err != nil { - return fmt.Errorf("Failed to add %s to configuration: %w", settings.InactiveHours, err) + return fmt.Errorf("failed to add %s to configuration: %w", settings.InactiveHours, err) } } // Check if service settings for display dashboard is ready if !mgr.IsValue(config.ServiceAdmin, settings.NodeDashboard, settings.NoEnvironmentID) { if err := mgr.NewBooleanValue(config.ServiceAdmin, settings.NodeDashboard, false, settings.NoEnvironmentID); err != nil { - return fmt.Errorf("Failed to add %s to settings: %w", settings.NodeDashboard, err) + return fmt.Errorf("failed to add %s to settings: %w", settings.NodeDashboard, err) } } // Write JSON config to settings if err := mgr.SetAdminJSON(cfg, settings.NoEnvironmentID); err != nil { - return fmt.Errorf("Failed to add JSON values to configuration: %w", err) + return fmt.Errorf("failed to add JSON values to configuration: %w", err) } return nil } diff --git a/cmd/admin/static/js/users.js b/cmd/admin/static/js/users.js index 9024ea77..2f23613b 100644 --- a/cmd/admin/static/js/users.js +++ b/cmd/admin/static/js/users.js @@ -16,6 +16,7 @@ function confirmAddUser() { var _fullname = $("#user_fullname").val(); var _password = $("#user_password").val(); var _admin = $("#user_admin").is(":checked"); + var _service = $("#user_service").is(":checked"); var _token = $("#user_token").is(":checked"); var data = { @@ -26,6 +27,7 @@ function confirmAddUser() { fullname: _fullname, new_password: _password, admin: _admin, + service: _service, token: _token, }; sendPostRequest(data, _url, _url, false); @@ -43,7 +45,7 @@ function confirmDeleteUser(_user) { function changeAdminUser(_user) { var _csrftoken = $("#csrftoken").val(); - var _value = $("#" + _user).is(":checked"); + var _value = $("#admin_" + _user).is(":checked"); if (_value) { $("#permissions-button-" + _user).hide(); @@ -59,7 +61,22 @@ function changeAdminUser(_user) { username: _user, admin: _value, }; - sendPostRequest(data, _url, "", false); + sendPostRequest(data, _url, _url, false); +} + +function changeServiceUser(_user) { + var _csrftoken = $("#csrftoken").val(); + var _value = $("#service_" + _user).is(":checked"); + + var _url = window.location.pathname; + + var data = { + csrftoken: _csrftoken, + action: "service", + username: _user, + service: _value, + }; + sendPostRequest(data, _url, _url, false); } function deleteUser(_user) { diff --git a/cmd/admin/templates/users.html b/cmd/admin/templates/users.html index 6de218c8..7b2dc37b 100644 --- a/cmd/admin/templates/users.html +++ b/cmd/admin/templates/users.html @@ -46,14 +46,15 @@ Email Fullname Last IP - Last UserAgent + Last UserAgent Admin + Service Last Session - {{range $i, $e := $.CurrentUsers}} + {{range $i, $e := $.SystemUsers}} {{ $e.Username }} @@ -80,7 +81,110 @@ + + + + + {{ pastFutureTimes $e.LastAccess }} + + + + + + + + {{ end }} + + + + + +
+
+ Service Users + +
+
+
+ +
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + {{range $i, $e := $.ServiceUsers}} + + + + + + + + @@ -148,6 +252,13 @@ + +
+ +
UsernameEmailFullnameLast IPLast UserAgentAdminServiceLast Session
{{ $e.Username }} +

{{ $e.Email }}

+
+

{{ $e.Fullname }}

+
+ {{ if eq $e.LastIPAddress "" }} + None + {{ else }} + {{ $e.LastIPAddress }} + {{ end }} + + + {{ if eq $e.LastUserAgent "" }} + None + {{ else }} + {{ $e.LastUserAgent }} + {{ end }} + + + + +