diff --git a/.gitignore b/.gitignore index 9f608082..c21d480d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ glide.lock bin build vendor +dist # Plugins *.so diff --git a/admin/auth.go b/admin/auth.go index 4df7fb9e..d58d30f4 100644 --- a/admin/auth.go +++ b/admin/auth.go @@ -6,6 +6,7 @@ import ( "net/http" "strings" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" ) @@ -25,15 +26,10 @@ const ( ) // Helper to convert permissions for a user to a level for context -func levelPermissions(user users.AdminUser) string { +func levelPermissions(user users.AdminUser, perms users.UserPermissions) string { if user.Admin { return adminLevel } - perms, err := adminUsers.ConvertPermissions(user.Permissions.RawMessage) - if err != nil { - log.Printf("error converting permissions %v", err) - return userLevel - } // Check for query access if perms.Query { return queryLevel @@ -58,14 +54,13 @@ func handlerAuthCheck(h http.Handler) http.Handler { return } // Set middleware values - s := make(contextValue) + s := make(sessions.ContextValue) s[ctxUser] = session.Username s[ctxCSRF] = session.Values[ctxCSRF].(string) s[ctxLevel] = session.Values[ctxLevel].(string) - ctx := context.WithValue(r.Context(), contextKey("session"), s) + ctx := context.WithValue(r.Context(), sessions.ContextKey("session"), s) // Update metadata for the user - err := adminUsers.UpdateMetadata(session.IPAddress, session.UserAgent, session.Username, s["csrftoken"]) - if err != nil { + if err := adminUsers.UpdateMetadata(session.IPAddress, session.UserAgent, session.Username, s["csrftoken"]); err != nil { log.Printf("error updating metadata for user %s: %v", session.Username, err) } // Access granted @@ -99,8 +94,14 @@ func handlerAuthCheck(h http.Handler) http.Handler { http.Redirect(w, r, forbiddenPath, http.StatusFound) return } + permissions, err := adminUsers.ConvertPermissions(u.Permissions.RawMessage) + if err != nil { + log.Printf("error getting permissions for %s: %v", jwtdata.Username, err) + http.Redirect(w, r, forbiddenPath, http.StatusFound) + return + } // Create new session - session, err = sessionsmgr.Save(r, w, u) + session, err = sessionsmgr.Save(r, w, u, permissions) if err != nil { log.Printf("session error: %v", err) http.Redirect(w, r, samlConfig.LoginURL, http.StatusFound) @@ -108,11 +109,11 @@ func handlerAuthCheck(h http.Handler) http.Handler { } } // Set middleware values - s := make(contextValue) + s := make(sessions.ContextValue) s[ctxUser] = session.Username s[ctxCSRF] = session.Values[ctxCSRF].(string) s[ctxLevel] = session.Values[ctxLevel].(string) - ctx := context.WithValue(r.Context(), contextKey("session"), s) + ctx := context.WithValue(r.Context(), sessions.ContextKey("session"), s) // Update metadata for the user err = adminUsers.UpdateMetadata(session.IPAddress, session.UserAgent, session.Username, s["csrftoken"]) if err != nil { @@ -134,7 +135,7 @@ func handlerAuthCheck(h http.Handler) http.Handler { return } // Set middleware values - s := make(contextValue) + s := make(sessions.ContextValue) s[ctxUser] = username s[ctxCSRF] = generateCSRF() for _, group := range groups { @@ -165,19 +166,9 @@ func handlerAuthCheck(h http.Handler) http.Handler { } // _, session := sessionsmgr.CheckAuth(r) // s["csrftoken"] = session.Values["csrftoken"].(string) - ctx := context.WithValue(r.Context(), contextKey("session"), s) + ctx := context.WithValue(r.Context(), sessions.ContextKey("session"), s) // Access granted h.ServeHTTP(w, r.WithContext(ctx)) } }) } - -// Helper to prepare context based on the user -func prepareContext(user users.AdminUser) contextValue { - s := make(contextValue) - s[ctxUser] = user.Username - s[ctxEmail] = user.Email - s[ctxCSRF] = user.CSRFToken - s[ctxLevel] = levelPermissions(user) - return s -} diff --git a/admin/auth/auth.go b/admin/auth/auth.go new file mode 100644 index 00000000..89a3e387 --- /dev/null +++ b/admin/auth/auth.go @@ -0,0 +1,220 @@ +package auth + +import ( + "context" + "log" + "net/http" + "strings" + + "github.com/jmpsec/osctrl/admin/sessions" + "github.com/jmpsec/osctrl/settings" + "github.com/jmpsec/osctrl/users" +) + +// AdminAuth to handle authentication for admin +type AdminAuth struct { + Users *users.UserManager + Sessions *sessions.SessionManager +} + +type AuthOption func(*AdminAuth) + +func WithSessions(sessions *sessions.SessionManager) AuthOption { + return func(a *AdminAuth) { + a.Sessions = sessions + } +} + +func WithUsers(users *users.UserManager) AuthOption { + return func(a *AdminAuth) { + a.Users = users + } +} + +// CreateAdminAuth to initialize the Admin handlers struct +func CreateAdminAuth(opts ...AuthOption) *AdminAuth { + a := &AdminAuth{} + for _, opt := range opts { + opt(a) + } + return a +} + +// LevelPermissions to convert permissions for a user to a level for context +func (a *AdminAuth) LevelPermissions(user users.AdminUser) string { + if user.Admin { + return sessions.AdminLevel + } + perms, err := a.Users.ConvertPermissions(user.Permissions.RawMessage) + if err != nil { + log.Printf("error converting permissions %v", err) + return sessions.UserLevel + } + // Check for query access + if perms.Query { + return sessions.QueryLevel + } + // Check for carve access + if perms.Carve { + return sessions.CarveLevel + } + // At this point, no access granted + return sessions.UserLevel +} + +// Handler to check access to a resource based on the authentication enabled +func (a *AdminAuth) HandlerAuthCheck(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch adminConfig.Auth { + case settings.AuthDB: + // Check if user is already authenticated + authenticated, session := a.Sessions.CheckAuth(r) + if !authenticated { + http.Redirect(w, r, "/login", http.StatusFound) + return + } + // Set middleware values + s := make(sessions.ContextValue) + s[sessions.CtxUser] = session.Username + s[sessions.CtxCSRF] = session.Values[sessions.CtxCSRF].(string) + s[sessions.CtxLevel] = session.Values[sessions.CtxLevel].(string) + ctx := context.WithValue(r.Context(), sessions.ContextKey("session"), s) + // Update metadata for the user + if err := a.Users.UpdateMetadata(session.IPAddress, session.UserAgent, session.Username, s["csrftoken"]); err != nil { + log.Printf("error updating metadata for user %s: %v", session.Username, err) + } + // Access granted + h.ServeHTTP(w, r.WithContext(ctx)) + case settings.AuthSAML: + if samlMiddleware.IsAuthorized(r) { + cookiev, err := r.Cookie(samlConfig.TokenName) + if err != nil { + log.Printf("error extracting JWT data: %v", err) + http.Redirect(w, r, samlConfig.LoginURL, http.StatusFound) + return + } + jwtdata, err := parseJWTFromCookie(samlData.KeyPair, cookiev.Value) + if err != nil { + log.Printf("error parsing JWT: %v", err) + http.Redirect(w, r, samlConfig.LoginURL, http.StatusFound) + return + } + // Check if user is already authenticated + authenticated, session := a.Sessions.CheckAuth(r) + if !authenticated { + // Create user if it does not exist + if !a.Users.Exists(jwtdata.Username) { + log.Printf("user not found: %s", jwtdata.Username) + http.Redirect(w, r, forbiddenPath, http.StatusFound) + return + } + u, err := a.Users.Get(jwtdata.Username) + if err != nil { + log.Printf("error getting user %s: %v", jwtdata.Username, err) + http.Redirect(w, r, forbiddenPath, http.StatusFound) + return + } + // Create new session + session, err = a.Sessions.Save(r, w, u) + if err != nil { + log.Printf("session error: %v", err) + http.Redirect(w, r, samlConfig.LoginURL, http.StatusFound) + return + } + } + // Set middleware values + s := make(sessions.ContextValue) + s[sessions.CtxUser] = session.Username + s[sessions.CtxCSRF] = session.Values[sessions.CtxCSRF].(string) + s[sessions.CtxLevel] = session.Values[sessions.CtxLevel].(string) + ctx := context.WithValue(r.Context(), sessions.ContextKey("session"), s) + // Update metadata for the user + err = a.Users.UpdateMetadata(session.IPAddress, session.UserAgent, session.Username, s["csrftoken"]) + if err != nil { + log.Printf("error updating metadata for user %s: %v", session.Username, err) + } + // Access granted + samlMiddleware.RequireAccount(h).ServeHTTP(w, r.WithContext(ctx)) + } else { + samlMiddleware.RequireAccount(h).ServeHTTP(w, r) + } + case settings.AuthHeaders: + username := r.Header.Get(headersConfig.TrustedPrefix + headersConfig.UserName) + email := r.Header.Get(headersConfig.TrustedPrefix + headersConfig.Email) + groups := strings.Split(r.Header.Get(headersConfig.TrustedPrefix+headersConfig.Groups), ",") + fullname := r.Header.Get(headersConfig.TrustedPrefix + headersConfig.DisplayName) + // A username is required to use this system + if username == "" { + http.Redirect(w, r, forbiddenPath, http.StatusBadRequest) + return + } + // Set middleware values + s := make(sessions.ContextValue) + s[sessions.CtxUser] = username + s[sessions.CtxCSRF] = generateCSRF() + for _, group := range groups { + if group == headersConfig.AdminGroup { + s[sessions.CtxLevel] = sessions.AdminLevel + // We can break because there is no greater permission level + break + } else if group == headersConfig.UserGroup { + s[sessions.CtxLevel] = sessions.UserLevel + // We can't break because we might still find a higher permission level + } + } + // This user didn't present a group that has permission to use the service + if _, ok := s[sessions.CtxLevel]; !ok { + http.Redirect(w, r, forbiddenPath, http.StatusForbidden) + return + } + newUser, err := a.Users.New(username, "", email, fullname, (s[sessions.CtxLevel] == sessions.AdminLevel)) + if err != nil { + log.Printf("Error with new user %s: %v", username, err) + http.Redirect(w, r, forbiddenPath, http.StatusFound) + return + } + if err := a.Users.Create(newUser); err != nil { + log.Printf("Error creating user %s: %v", username, err) + http.Redirect(w, r, forbiddenPath, http.StatusFound) + return + } + // _, session := sessionsmgr.CheckAuth(r) + // s["csrftoken"] = session.Values["csrftoken"].(string) + ctx := context.WithValue(r.Context(), sessions.ContextKey("session"), s) + // Access granted + h.ServeHTTP(w, r.WithContext(ctx)) + } + }) +} + +// Helper to prepare context based on the user +func prepareContext(user users.AdminUser) sessions.ContextValue { + s := make(sessions.ContextValue) + s[sessions.CtxUser] = user.Username + s[sessions.CtxEmail] = user.Email + s[sessions.CtxCSRF] = user.CSRFToken + s[sessions.CtxLevel] = levelPermissions(user) + return s +} + +// Helper to parse JWT tokens because the SAML library is total garbage +func parseJWTFromCookie(keypair tls.Certificate, cookie string) (JWTData, error) { + type TokenClaims struct { + jwt.StandardClaims + Attributes map[string][]string `json:"attr"` + } + tokenClaims := TokenClaims{} + token, err := jwt.ParseWithClaims(cookie, &tokenClaims, func(t *jwt.Token) (interface{}, error) { + secretBlock := x509.MarshalPKCS1PrivateKey(keypair.PrivateKey.(*rsa.PrivateKey)) + return secretBlock, nil + }) + if err != nil || !token.Valid { + return JWTData{}, err + } + return JWTData{ + Subject: tokenClaims.Subject, + Email: tokenClaims.Attributes["mail"][0], + Display: tokenClaims.Attributes["displayName"][0], + Username: tokenClaims.Attributes["sAMAccountName"][0], + }, nil +} diff --git a/admin/auth/go.mod b/admin/auth/go.mod new file mode 100644 index 00000000..c47a2e02 --- /dev/null +++ b/admin/auth/go.mod @@ -0,0 +1,3 @@ +module github.com/jmpsec/osctrl/admin/auth + +go 1.12 diff --git a/admin/db.go b/admin/db.go deleted file mode 100644 index fba8f897..00000000 --- a/admin/db.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "log" - - _ "github.com/jinzhu/gorm/dialects/postgres" -) - -// Automigrate of tables -func automigrateDB() error { - var err error - // table osquery_status_data - err = db.AutoMigrate(OsqueryStatusData{}).Error - if err != nil { - log.Fatalf("Failed to AutoMigrate table (osquery_status_data): %v", err) - } - // table osquery_result_data - err = db.AutoMigrate(OsqueryResultData{}).Error - if err != nil { - log.Fatalf("Failed to AutoMigrate table (osquery_result_data): %v", err) - } - // table osquery_query_data - err = db.AutoMigrate(OsqueryQueryData{}).Error - if err != nil { - log.Fatalf("Failed to AutoMigrate table (osquery_query_data): %v", err) - } - return nil -} diff --git a/admin/handlers.go b/admin/handlers.go deleted file mode 100644 index caa751e4..00000000 --- a/admin/handlers.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/jmpsec/osctrl/settings" - "github.com/jmpsec/osctrl/utils" -) - -const ( - metricJSONReq = "admin-json-req" - metricJSONErr = "admin-json-err" - metricJSONOK = "admin-json-ok" - metricHealthReq = "health-req" - metricHealthOK = "health-ok" -) - -// Empty default osquery configuration -const emptyConfiguration string = "data/osquery-empty.json" - -const errorContent = "❌" -const okContent = "✅" - -// Handle health requests -func healthHTTPHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricHealthReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) - // Send response - utils.HTTPResponse(w, "", http.StatusOK, okContent) - incMetric(metricHealthOK) -} - -// Handle error requests -func errorHTTPHandler(w http.ResponseWriter, r *http.Request) { - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) - // Send response - utils.HTTPResponse(w, "", http.StatusInternalServerError, []byte("oh no...")) -} - -// Handle forbidden error requests -func forbiddenHTTPHandler(w http.ResponseWriter, r *http.Request) { - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) - // Send response - utils.HTTPResponse(w, "", http.StatusForbidden, errorContent) -} - -// Handler for the favicon -func faviconHandler(w http.ResponseWriter, r *http.Request) { - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) - w.Header().Set("Content-Type", "image/png") - http.ServeFile(w, r, "./static/favicon.png") -} diff --git a/admin/handlers/get.go b/admin/handlers/get.go new file mode 100644 index 00000000..983c51e8 --- /dev/null +++ b/admin/handlers/get.go @@ -0,0 +1,145 @@ +package handlers + +import ( + "io" + "log" + "net/http" + "os" + "strconv" + + "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" + "github.com/jmpsec/osctrl/settings" + "github.com/jmpsec/osctrl/users" + "github.com/jmpsec/osctrl/utils" +) + +// osquery +const ( + // osquery version to display tables + osqueryTablesVersion string = "4.2.0" + // JSON file with osquery tables data + osqueryTablesFile string = "data/" + osqueryTablesVersion + ".json" + // Carved files folder + carvedFilesFolder string = "carved_files/" +) + +// FaviconHandler for the favicon +func (h *HandlersAdmin) FaviconHandler(w http.ResponseWriter, r *http.Request) { + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) + w.Header().Set(utils.ContentType, "image/png") + http.ServeFile(w, r, "./static/favicon.png") +} + +// HealthHandler for health requests +func (h *HandlersAdmin) HealthHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricHealthReq) + // Send response + utils.HTTPResponse(w, "", http.StatusOK, []byte(okContent)) + h.Inc(metricHealthOK) +} + +// ErrorHandler for error requests +func (h *HandlersAdmin) ErrorHandler(w http.ResponseWriter, r *http.Request) { + // Send response + utils.HTTPResponse(w, "", http.StatusInternalServerError, []byte(errorContent)) +} + +// ForbiddenHandler for forbidden error requests +func (h *HandlersAdmin) ForbiddenHandler(w http.ResponseWriter, r *http.Request) { + // Debug HTTP for environment + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) + // Send response + utils.HTTPResponse(w, "", http.StatusForbidden, errorContent) +} + +// Handler for the root path +func (h *HandlersAdmin) RootHandler(w http.ResponseWriter, r *http.Request) { + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) + // Redirect to table for active nodes in default environment + defaultEnvironment := h.Settings.DefaultEnv(settings.ServiceAdmin) + if h.Envs.Exists(defaultEnvironment) { + http.Redirect(w, r, "/environment/"+defaultEnvironment+"/active", http.StatusFound) + } else { + http.Redirect(w, r, "/environments", http.StatusFound) + } +} + +// PermissionsGETHandler for platform/environment stats in JSON +func (h *HandlersAdmin) PermissionsGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) + vars := mux.Vars(r) + // Extract username and verify + usernameVar, ok := vars["username"] + if !ok || !h.Users.Exists(usernameVar) { + if h.Settings.DebugService(settings.ServiceAdmin) { + log.Printf("DebugService: error getting username") + } + return + } + // Get context data + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) + // Check permissions + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) + return + } + // Get permissions + permissions, err := h.Users.GetPermissions(usernameVar) + if err != nil { + h.Inc(metricAdminErr) + log.Printf("error getting permissions %v", err) + } + // Serve JSON + utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, permissions) + h.Inc(metricJSONOK) +} + +// CarvesDownloadHandler for GET requests to download carves +func (h *HandlersAdmin) CarvesDownloadHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) + vars := mux.Vars(r) + // Get context data + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) + // Check permissions + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) + return + } + // Extract id to download + carveSession, ok := vars["sessionid"] + if !ok { + h.Inc(metricAdminErr) + log.Println("error getting carve") + return + } + // Prepare file to download + result, err := h.Carves.Archive(carveSession, carvedFilesFolder) + if err != nil { + h.Inc(metricAdminErr) + log.Printf("error downloading carve - %v", err) + return + } + if h.Settings.DebugService(settings.ServiceAdmin) { + log.Println("DebugService: Carve download") + } + h.Inc(metricAdminOK) + // Send response + w.Header().Set("Content-Description", "File Carve Download") + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", "attachment; filename="+result.File) + w.Header().Set("Content-Transfer-Encoding", "binary") + w.Header().Set("Connection", "Keep-Alive") + w.Header().Set("Expires", "0") + w.Header().Set("Cache-Control", "must-revalidate, post-check=0, pre-check=0") + w.Header().Set("Pragma", "public") + w.Header().Set("Content-Length", strconv.FormatInt(result.Size, 10)) + w.WriteHeader(http.StatusOK) + var fileReader io.Reader + fileReader, _ = os.Open(result.File) + _, _ = io.Copy(w, fileReader) +} diff --git a/admin/handlers/handlers.go b/admin/handlers/handlers.go index 85a1e20f..46daa8d3 100644 --- a/admin/handlers/handlers.go +++ b/admin/handlers/handlers.go @@ -1,10 +1,140 @@ package handlers +import ( + "github.com/jinzhu/gorm" + "github.com/jmpsec/osctrl/admin/sessions" + "github.com/jmpsec/osctrl/carves" + "github.com/jmpsec/osctrl/environments" + "github.com/jmpsec/osctrl/metrics" + "github.com/jmpsec/osctrl/nodes" + "github.com/jmpsec/osctrl/queries" + "github.com/jmpsec/osctrl/settings" + "github.com/jmpsec/osctrl/types" + "github.com/jmpsec/osctrl/users" +) + const ( metricJSONReq = "admin-json-req" metricJSONErr = "admin-json-err" metricJSONOK = "admin-json-ok" metricHealthReq = "health-req" metricHealthOK = "health-ok" + metricAdminReq = "admin-req" + metricAdminErr = "admin-err" + metricAdminOK = "admin-ok" + metricTokenReq = "admin-token-req" + metricTokenErr = "admin-token-err" + metricTokenOK = "admin-token-ok" ) +// Empty default osquery configuration +const emptyConfiguration string = "data/osquery-empty.json" + +const errorContent = "❌" +const okContent = "✅" + +// HandlersAdmin to keep all handlers for TLS +type HandlersAdmin struct { + DB *gorm.DB + Users *users.UserManager + Envs *environments.Environment + Nodes *nodes.NodeManager + Queries *queries.Queries + Carves *carves.Carves + Settings *settings.Settings + Metrics *metrics.Metrics + Sessions *sessions.SessionManager + ServiceVersion string + OsqueryTables []types.OsqueryTable + AdminConfig *types.JSONConfigurationService +} + +type HandlersOption func(*HandlersAdmin) + +func WithDB(db *gorm.DB) HandlersOption { + return func(h *HandlersAdmin) { + h.DB = db + } +} + +func WithEnvs(envs *environments.Environment) HandlersOption { + return func(h *HandlersAdmin) { + h.Envs = envs + } +} + +func WithUsers(users *users.UserManager) HandlersOption { + return func(h *HandlersAdmin) { + h.Users = users + } +} + +func WithSettings(settings *settings.Settings) HandlersOption { + return func(h *HandlersAdmin) { + h.Settings = settings + } +} + +func WithNodes(nodes *nodes.NodeManager) HandlersOption { + return func(h *HandlersAdmin) { + h.Nodes = nodes + } +} + +func WithQueries(queries *queries.Queries) HandlersOption { + return func(h *HandlersAdmin) { + h.Queries = queries + } +} + +func WithCarves(carves *carves.Carves) HandlersOption { + return func(h *HandlersAdmin) { + h.Carves = carves + } +} + +func WithMetrics(metrics *metrics.Metrics) HandlersOption { + return func(h *HandlersAdmin) { + h.Metrics = metrics + } +} + +func WithSessions(sessions *sessions.SessionManager) HandlersOption { + return func(h *HandlersAdmin) { + h.Sessions = sessions + } +} + +func WithVersion(version string) HandlersOption { + return func(h *HandlersAdmin) { + h.ServiceVersion = version + } +} + +func WithOsqueryTables(tables []types.OsqueryTable) HandlersOption { + return func(h *HandlersAdmin) { + h.OsqueryTables = tables + } +} + +func WithAdminConfig(config *types.JSONConfigurationService) HandlersOption { + return func(h *HandlersAdmin) { + h.AdminConfig = config + } +} + +// CreateHandlersAdmin to initialize the Admin handlers struct +func CreateHandlersAdmin(opts ...HandlersOption) *HandlersAdmin { + h := &HandlersAdmin{} + for _, opt := range opts { + opt(h) + } + return h +} + +// Inc - Helper to send metrics if it is enabled +func (h *HandlersAdmin) Inc(name string) { + if h.Metrics != nil && h.Settings.ServiceMetrics(settings.ServiceAdmin) { + h.Metrics.Inc(name) + } +} diff --git a/admin/json-carves.go b/admin/handlers/json-carves.go similarity index 77% rename from admin/json-carves.go rename to admin/handlers/json-carves.go index 811e0355..bcea9387 100644 --- a/admin/json-carves.go +++ b/admin/handlers/json-carves.go @@ -1,10 +1,11 @@ -package main +package handlers import ( "log" "net/http" "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/carves" "github.com/jmpsec/osctrl/queries" "github.com/jmpsec/osctrl/settings" @@ -50,46 +51,46 @@ type CarveTarget struct { Value string `json:"value"` } -// Handler for JSON carves by target -func jsonCarvesHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricJSONReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// JSONCarvesHandler for JSON carves by target +func (h *HandlersAdmin) JSONCarvesHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricJSONReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } vars := mux.Vars(r) // Extract target target, ok := vars["target"] if !ok { - incMetric(metricJSONErr) + h.Inc(metricJSONErr) log.Println("error getting target") return } // Verify target if !CarvesTargets[target] { - incMetric(metricJSONErr) + h.Inc(metricJSONErr) log.Printf("invalid target %s", target) return } // Retrieve carves for that target - qs, err := queriesmgr.GetCarves(target) + qs, err := h.Queries.GetCarves(target) if err != nil { - incMetric(metricJSONErr) + h.Inc(metricJSONErr) log.Printf("error getting query carves %v", err) return } // Prepare data to be returned cJSON := []CarveJSON{} for _, q := range qs { - c, err := carvesmgr.GetByQuery(q.Name) + c, err := h.Carves.GetByQuery(q.Name) if err != nil { log.Printf("error getting carves %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) continue } status := queries.StatusActive @@ -107,7 +108,7 @@ func jsonCarvesHandler(w http.ResponseWriter, r *http.Request) { data["path"] = q.Path data["name"] = q.Name // Preparing query targets - ts, _ := queriesmgr.GetTargets(q.Name) + ts, _ := h.Queries.GetTargets(q.Name) _ts := []CarveTarget{} for _, t := range ts { _t := CarveTarget{ @@ -136,5 +137,5 @@ func jsonCarvesHandler(w http.ResponseWriter, r *http.Request) { } // Serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } diff --git a/admin/json-logs.go b/admin/handlers/json-logs.go similarity index 71% rename from admin/json-logs.go rename to admin/handlers/json-logs.go index bd1f056b..3549e98a 100644 --- a/admin/json-logs.go +++ b/admin/handlers/json-logs.go @@ -1,4 +1,4 @@ -package main +package handlers import ( "log" @@ -6,6 +6,7 @@ import ( "strconv" "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/utils" @@ -48,43 +49,43 @@ type QueryLogJSON struct { Data string `json:"data"` } -// Handler GET requests for JSON status/result logs by node and environment -func jsonLogsHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricJSONReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// JSONLogsHandler GET requests for JSON status/result logs by node and environment +func (h *HandlersAdmin) JSONLogsHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricJSONReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract type logType, ok := vars["type"] if !ok { log.Println("error getting log type") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Verify log type if !LogTypes[logType] { log.Printf("invalid log type %s", logType) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Extract environment env, ok := vars["environment"] if !ok { log.Println("environment is missing") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Check if environment is valid - if !envs.Exists(env) { + if !h.Envs.Exists(env) { log.Printf("error unknown environment (%s)", env) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, env) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, env) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } // Extract UUID @@ -92,7 +93,7 @@ func jsonLogsHandler(w http.ResponseWriter, r *http.Request) { UUID, ok := vars["uuid"] if !ok { log.Println("error getting UUID") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Extract parameter for seconds @@ -108,10 +109,10 @@ func jsonLogsHandler(w http.ResponseWriter, r *http.Request) { // Get logs logJSON := []LogJSON{} if logType == "status" { - statusLogs, err := postgresStatusLogs(UUID, env, secondsBack) + statusLogs, err := h.postgresStatusLogs(UUID, env, secondsBack) if err != nil { log.Printf("error getting logs %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Prepare data to be returned @@ -128,10 +129,10 @@ func jsonLogsHandler(w http.ResponseWriter, r *http.Request) { logJSON = append(logJSON, _l) } } else if logType == "result" { - resultLogs, err := postgresResultLogs(UUID, env, secondsBack) + resultLogs, err := h.postgresResultLogs(UUID, env, secondsBack) if err != nil { log.Printf("error getting logs %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Prepare data to be returned @@ -152,19 +153,19 @@ func jsonLogsHandler(w http.ResponseWriter, r *http.Request) { } // Serialize and serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } -// Handler for JSON query logs by query name -func jsonQueryLogsHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricJSONReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// JSONQueryLogsHandler for JSON query logs by query name +func (h *HandlersAdmin) JSONQueryLogsHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricJSONReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } vars := mux.Vars(r) @@ -173,14 +174,14 @@ func jsonQueryLogsHandler(w http.ResponseWriter, r *http.Request) { name, ok := vars["name"] if !ok { log.Println("error getting name") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Get logs - queryLogs, err := postgresQueryLogs(name) + queryLogs, err := h.postgresQueryLogs(name) if err != nil { log.Printf("error getting logs %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Prepare data to be returned @@ -201,5 +202,5 @@ func jsonQueryLogsHandler(w http.ResponseWriter, r *http.Request) { } // Serialize and serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } diff --git a/admin/json-nodes.go b/admin/handlers/json-nodes.go similarity index 69% rename from admin/json-nodes.go rename to admin/handlers/json-nodes.go index e001c4f4..d8cc321a 100644 --- a/admin/json-nodes.go +++ b/admin/handlers/json-nodes.go @@ -1,10 +1,11 @@ -package main +package handlers import ( "log" "net/http" "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/utils" @@ -38,48 +39,48 @@ type NodeJSON struct { } // Handler for JSON endpoints by environment -func jsonEnvironmentHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricJSONReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +func (h *HandlersAdmin) JSONEnvironmentHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricJSONReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract environment env, ok := vars["environment"] if !ok { log.Println("error getting environment") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Check if environment is valid - if !envs.Exists(env) { + if !h.Envs.Exists(env) { log.Printf("error unknown environment (%s)", env) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, env) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, env) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } // Extract target target, ok := vars["target"] if !ok { log.Println("error getting target") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Verify target if !NodeTargets[target] { log.Printf("invalid target %s", target) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } - nodes, err := nodesmgr.GetByEnv(env, target, settingsmgr.InactiveHours()) + nodes, err := h.Nodes.GetByEnv(env, target, h.Settings.InactiveHours()) if err != nil { log.Printf("error getting nodes %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Prepare data to be returned @@ -105,19 +106,19 @@ func jsonEnvironmentHandler(w http.ResponseWriter, r *http.Request) { } // Serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } // Handler for JSON endpoints by platform -func jsonPlatformHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricJSONReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +func (h *HandlersAdmin) JSONPlatformHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricJSONReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } vars := mux.Vars(r) @@ -125,26 +126,26 @@ func jsonPlatformHandler(w http.ResponseWriter, r *http.Request) { platform, ok := vars["platform"] if !ok { log.Println("error getting platform") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Extract target target, ok := vars["target"] if !ok { log.Println("error getting target") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Verify target if !NodeTargets[target] { log.Printf("invalid target %s", target) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } - nodes, err := nodesmgr.GetByPlatform(platform, target, settingsmgr.InactiveHours()) + nodes, err := h.Nodes.GetByPlatform(platform, target, h.Settings.InactiveHours()) if err != nil { log.Printf("error getting nodes %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Prepare data to be returned @@ -170,5 +171,5 @@ func jsonPlatformHandler(w http.ResponseWriter, r *http.Request) { } // Serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } diff --git a/admin/json-queries.go b/admin/handlers/json-queries.go similarity index 78% rename from admin/json-queries.go rename to admin/handlers/json-queries.go index 598803c4..35adc505 100644 --- a/admin/json-queries.go +++ b/admin/handlers/json-queries.go @@ -1,10 +1,11 @@ -package main +package handlers import ( "log" "net/http" "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/queries" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" @@ -50,15 +51,15 @@ type QueryTarget struct { } // Handler for JSON queries by target -func jsonQueryHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricJSONReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +func (h *HandlersAdmin) JSONQueryHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricJSONReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } vars := mux.Vars(r) @@ -66,20 +67,20 @@ func jsonQueryHandler(w http.ResponseWriter, r *http.Request) { target, ok := vars["target"] if !ok { log.Println("error getting target") - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Verify target if !QueryTargets[target] { log.Printf("invalid target %s", target) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Retrieve queries for that target - qs, err := queriesmgr.GetQueries(target) + qs, err := h.Queries.GetQueries(target) if err != nil { log.Printf("error getting queries %v", err) - incMetric(metricJSONErr) + h.Inc(metricJSONErr) return } // Prepare data to be returned @@ -97,9 +98,9 @@ func jsonQueryHandler(w http.ResponseWriter, r *http.Request) { data := make(QueryData) data["query"] = q.Query data["name"] = q.Name - data["deflink"], data["dblink"] = queryResultLink(q.Name) + data["deflink"], data["dblink"] = h.queryResultLink(q.Name) // Preparing query targets - ts, _ := queriesmgr.GetTargets(q.Name) + ts, _ := h.Queries.GetTargets(q.Name) _ts := []QueryTarget{} for _, t := range ts { _t := QueryTarget{ @@ -128,5 +129,5 @@ func jsonQueryHandler(w http.ResponseWriter, r *http.Request) { } // Serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } diff --git a/admin/json-stats.go b/admin/handlers/json-stats.go similarity index 53% rename from admin/json-stats.go rename to admin/handlers/json-stats.go index 997d1a0c..4b933417 100644 --- a/admin/json-stats.go +++ b/admin/handlers/json-stats.go @@ -1,10 +1,11 @@ -package main +package handlers import ( "log" "net/http" "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/nodes" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" @@ -19,23 +20,23 @@ var ( } ) -// Handler for platform/environment stats in JSON -func jsonStatsHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// JSONStatsHandler for platform/environment stats in JSON +func (h *HandlersAdmin) JSONStatsHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) vars := mux.Vars(r) // Extract stats target target, ok := vars["target"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting target") return } // Verify target if !StatsTargets[target] { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("invalid target %s", target) return } @@ -43,7 +44,7 @@ func jsonStatsHandler(w http.ResponseWriter, r *http.Request) { // FIXME verify name name, ok := vars["name"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting target name") return } @@ -52,25 +53,25 @@ func jsonStatsHandler(w http.ResponseWriter, r *http.Request) { var err error if target == "environment" { // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, name) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, name) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } - stats, err = nodesmgr.GetStatsByEnv(name, settingsmgr.InactiveHours()) + stats, err = h.Nodes.GetStatsByEnv(name, h.Settings.InactiveHours()) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting stats %v", err) return } } else if target == "platform" { // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricJSONErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricJSONErr) return } - stats, err = nodesmgr.GetStatsByPlatform(name, settingsmgr.InactiveHours()) + stats, err = h.Nodes.GetStatsByPlatform(name, h.Settings.InactiveHours()) if err != nil { log.Printf("error getting stats %v", err) return @@ -78,5 +79,5 @@ func jsonStatsHandler(w http.ResponseWriter, r *http.Request) { } // Serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, stats) - incMetric(metricJSONOK) + h.Inc(metricJSONOK) } diff --git a/admin/handlers-post.go b/admin/handlers/post.go similarity index 56% rename from admin/handlers-post.go rename to admin/handlers/post.go index 81c768f1..f12e9e5c 100644 --- a/admin/handlers-post.go +++ b/admin/handlers/post.go @@ -1,4 +1,4 @@ -package main +package handlers import ( "encoding/base64" @@ -7,133 +7,131 @@ import ( "log" "net/http" + "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/environments" "github.com/jmpsec/osctrl/queries" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/utils" - - "github.com/gorilla/mux" ) -const ( - metricAdminReq = "admin-req" - metricAdminErr = "admin-err" - metricAdminOK = "admin-ok" -) - -// Handler for login page for POST requests -func loginPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// LoginPOSTHandler for login page for POST requests +func (h *HandlersAdmin) LoginPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) var l LoginRequest // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&l); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check credentials - access, user := adminUsers.CheckLoginCredentials(l.Username, l.Password) + access, user := h.Users.CheckLoginCredentials(l.Username, l.Password) if !access { adminErrorResponse(w, "invalid credentials", http.StatusForbidden, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - _, err := sessionsmgr.Save(r, w, user) + permissions, err := h.Users.ConvertPermissions(user.Permissions.RawMessage) + if err != nil { + + } + _, err = h.Sessions.Save(r, w, user, permissions) if err != nil { adminErrorResponse(w, "session error", http.StatusForbidden, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Login response sent") } adminOKResponse(w, "OK") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handle POST requests to logout -func logoutPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// LogoutPOSTHandler for POST requests to logout +func (h *HandlersAdmin) LogoutPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) var l LogoutRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&l); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], l.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], l.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Destroy existing session - if err := sessionsmgr.Destroy(r); err != nil { + if err := h.Sessions.Destroy(r); err != nil { adminErrorResponse(w, "error destroying session", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Logout response sent") } adminOKResponse(w, "OK") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST requests to run queries -func queryRunPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// QueryRunPOSTHandler for POST requests to run queries +func (h *HandlersAdmin) QueryRunPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var q DistributedQueryRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions for query - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&q); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], q.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], q.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // FIXME check validity of query // Query can not be empty if q.Query == "" { adminErrorResponse(w, "query can not be empty", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // FIXME check if query is carve and user has permissions to carve // Prepare and create new query - newQuery := newQueryReady(ctx[ctxUser], q.Query) - if err := queriesmgr.Create(newQuery); err != nil { + newQuery := newQueryReady(ctx[sessions.CtxUser], q.Query) + if err := h.Queries.Create(newQuery); err != nil { adminErrorResponse(w, "error creating query", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Temporary list of UUIDs to calculate Expected @@ -141,16 +139,16 @@ func queryRunPOSTHandler(w http.ResponseWriter, r *http.Request) { // Create environment target if len(q.Environments) > 0 { for _, e := range q.Environments { - if (e != "") && envs.Exists(e) { - if err := queriesmgr.CreateTarget(newQuery.Name, queries.QueryTargetEnvironment, e); err != nil { + if (e != "") && h.Envs.Exists(e) { + if err := h.Queries.CreateTarget(newQuery.Name, queries.QueryTargetEnvironment, e); err != nil { adminErrorResponse(w, "error creating query environment target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - nodes, err := nodesmgr.GetByEnv(e, "active", settingsmgr.InactiveHours()) + nodes, err := h.Nodes.GetByEnv(e, "active", h.Settings.InactiveHours()) if err != nil { adminErrorResponse(w, "error getting nodes by environment", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } for _, n := range nodes { @@ -161,17 +159,18 @@ func queryRunPOSTHandler(w http.ResponseWriter, r *http.Request) { } // Create platform target if len(q.Platforms) > 0 { + platforms, _ := h.Nodes.GetAllPlatforms() for _, p := range q.Platforms { - if (p != "") && checkValidPlatform(p) { - if err := queriesmgr.CreateTarget(newQuery.Name, queries.QueryTargetPlatform, p); err != nil { + if (p != "") && checkValidPlatform(platforms, p) { + if err := h.Queries.CreateTarget(newQuery.Name, queries.QueryTargetPlatform, p); err != nil { adminErrorResponse(w, "error creating query platform target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - nodes, err := nodesmgr.GetByPlatform(p, "active", settingsmgr.InactiveHours()) + nodes, err := h.Nodes.GetByPlatform(p, "active", h.Settings.InactiveHours()) if err != nil { adminErrorResponse(w, "error getting nodes by platform", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } for _, n := range nodes { @@ -183,10 +182,10 @@ func queryRunPOSTHandler(w http.ResponseWriter, r *http.Request) { // Create UUIDs target if len(q.UUIDs) > 0 { for _, u := range q.UUIDs { - if (u != "") && nodesmgr.CheckByUUID(u) { - if err := queriesmgr.CreateTarget(newQuery.Name, queries.QueryTargetUUID, u); err != nil { + if (u != "") && h.Nodes.CheckByUUID(u) { + if err := h.Queries.CreateTarget(newQuery.Name, queries.QueryTargetUUID, u); err != nil { adminErrorResponse(w, "error creating query UUID target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } expected = append(expected, u) @@ -195,66 +194,66 @@ func queryRunPOSTHandler(w http.ResponseWriter, r *http.Request) { } // Create hostnames target if len(q.Hosts) > 0 { - for _, h := range q.Hosts { - if (h != "") && nodesmgr.CheckByHost(h) { - if err := queriesmgr.CreateTarget(newQuery.Name, queries.QueryTargetLocalname, h); err != nil { + for _, _h := range q.Hosts { + if (_h != "") && h.Nodes.CheckByHost(_h) { + if err := h.Queries.CreateTarget(newQuery.Name, queries.QueryTargetLocalname, _h); err != nil { adminErrorResponse(w, "error creating query hostname target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - expected = append(expected, h) + expected = append(expected, _h) } } } // Remove duplicates from expected expectedClear := removeStringDuplicates(expected) // Update value for expected - if err := queriesmgr.SetExpected(newQuery.Name, len(expectedClear)); err != nil { + if err := h.Queries.SetExpected(newQuery.Name, len(expectedClear)); err != nil { adminErrorResponse(w, "error setting expected", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Query run response sent") } adminOKResponse(w, "OK") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST requests to run file carves -func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// CarvesRunPOSTHandler for POST requests to run file carves +func (h *HandlersAdmin) CarvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var c DistributedCarveRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&c); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], c.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], c.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // FIXME check validity of query // Path can not be empty if c.Path == "" { adminErrorResponse(w, "path can not be empty", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } query := generateCarveQuery(c.Path, false) @@ -263,7 +262,7 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { newQuery := queries.DistributedQuery{ Query: query, Name: carveName, - Creator: ctx[ctxUser], + Creator: ctx[sessions.CtxUser], Expected: 0, Executions: 0, Active: true, @@ -272,9 +271,9 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { Type: queries.CarveQueryType, Path: c.Path, } - if err := queriesmgr.Create(newQuery); err != nil { + if err := h.Queries.Create(newQuery); err != nil { adminErrorResponse(w, "error creating carve", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Temporary list of UUIDs to calculate Expected @@ -282,16 +281,16 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { // Create environment target if len(c.Environments) > 0 { for _, e := range c.Environments { - if (e != "") && envs.Exists(e) { - if err := queriesmgr.CreateTarget(carveName, queries.QueryTargetEnvironment, e); err != nil { + if (e != "") && h.Envs.Exists(e) { + if err := h.Queries.CreateTarget(carveName, queries.QueryTargetEnvironment, e); err != nil { adminErrorResponse(w, "error creating carve environment target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - nodes, err := nodesmgr.GetByEnv(e, "active", settingsmgr.InactiveHours()) + nodes, err := h.Nodes.GetByEnv(e, "active", h.Settings.InactiveHours()) if err != nil { adminErrorResponse(w, "error getting nodes by environment", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } for _, n := range nodes { @@ -302,17 +301,18 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { } // Create platform target if len(c.Platforms) > 0 { + platforms, _ := h.Nodes.GetAllPlatforms() for _, p := range c.Platforms { - if (p != "") && checkValidPlatform(p) { - if err := queriesmgr.CreateTarget(carveName, queries.QueryTargetPlatform, p); err != nil { + if (p != "") && checkValidPlatform(platforms, p) { + if err := h.Queries.CreateTarget(carveName, queries.QueryTargetPlatform, p); err != nil { adminErrorResponse(w, "error creating carve platform target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - nodes, err := nodesmgr.GetByPlatform(p, "active", settingsmgr.InactiveHours()) + nodes, err := h.Nodes.GetByPlatform(p, "active", h.Settings.InactiveHours()) if err != nil { adminErrorResponse(w, "error getting nodes by platform", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } for _, n := range nodes { @@ -324,10 +324,10 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { // Create UUIDs target if len(c.UUIDs) > 0 { for _, u := range c.UUIDs { - if (u != "") && nodesmgr.CheckByUUID(u) { - if err := queriesmgr.CreateTarget(carveName, queries.QueryTargetUUID, u); err != nil { + if (u != "") && h.Nodes.CheckByUUID(u) { + if err := h.Queries.CreateTarget(carveName, queries.QueryTargetUUID, u); err != nil { adminErrorResponse(w, "error creating carve UUID target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } expected = append(expected, u) @@ -336,11 +336,11 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { } // Create hostnames target if len(c.Hosts) > 0 { - for _, h := range c.Hosts { - if (h != "") && nodesmgr.CheckByHost(h) { - if err := queriesmgr.CreateTarget(carveName, queries.QueryTargetLocalname, h); err != nil { + for _, _h := range c.Hosts { + if (_h != "") && h.Nodes.CheckByHost(_h) { + if err := h.Queries.CreateTarget(carveName, queries.QueryTargetLocalname, _h); err != nil { adminErrorResponse(w, "error creating carve hostname target", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } @@ -349,312 +349,312 @@ func carvesRunPOSTHandler(w http.ResponseWriter, r *http.Request) { // Remove duplicates from expected expectedClear := removeStringDuplicates(expected) // Update value for expected - if err := queriesmgr.SetExpected(carveName, len(expectedClear)); err != nil { + if err := h.Queries.SetExpected(carveName, len(expectedClear)); err != nil { adminErrorResponse(w, "error setting expected", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Carve run response sent") } adminOKResponse(w, "OK") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST requests to queries -func queryActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// QueryActionsPOSTHandler for POST requests to queries +func (h *HandlersAdmin) QueryActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var q DistributedQueryActionRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions for query - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&q); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], q.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], q.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch q.Action { case "delete": for _, n := range q.Names { - if err := queriesmgr.Delete(n); err != nil { + if err := h.Queries.Delete(n); err != nil { adminErrorResponse(w, "error deleting query", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "queries delete successfully") case "complete": for _, n := range q.Names { - if err := queriesmgr.Complete(n); err != nil { + if err := h.Queries.Complete(n); err != nil { adminErrorResponse(w, "error completing query", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "queries completed successfully") case "activate": for _, n := range q.Names { - if err := queriesmgr.Activate(n); err != nil { + if err := h.Queries.Activate(n); err != nil { adminErrorResponse(w, "error activating query", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "queries activated successfully") } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Query run response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } // Handler for POST requests to carves -func carvesActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +func (h *HandlersAdmin) CarvesActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var q DistributedCarvesActionRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&q); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], q.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], q.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch q.Action { case "delete": for _, n := range q.IDs { - if err := carvesmgr.Delete(n); err != nil { + if err := h.Carves.Delete(n); err != nil { adminErrorResponse(w, "error deleting carve", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "carves delete successfully") case "test": - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Printf("DebugService: testing action") } adminOKResponse(w, "test successful") } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Carves action response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler POST requests for saving configuration -func confPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// ConfPOSTHandler for POST requests for saving configuration +func (h *HandlersAdmin) ConfPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) vars := mux.Vars(r) // Extract environment and verify environmentVar, ok := vars["environment"] - if !ok || !envs.Exists(environmentVar) { + if !ok || !h.Envs.Exists(environmentVar) { adminErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var c ConfigurationRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, environmentVar) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, environmentVar) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&c); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], c.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], c.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } if c.ConfigurationB64 == "" { responseMessage := "empty configuration" utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusInternalServerError, AdminResponse{Message: responseMessage}) - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Printf("DebugService: %s", responseMessage) } - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Decode received configuration configuration, err := base64.StdEncoding.DecodeString(c.ConfigurationB64) if err != nil { adminErrorResponse(w, "error decoding configuration", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Update configuration - if err := envs.UpdateConfiguration(environmentVar, string(configuration)); err != nil { + if err := h.Envs.UpdateConfiguration(environmentVar, string(configuration)); err != nil { adminErrorResponse(w, "error saving configuration", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Configuration response sent") } adminOKResponse(w, "configuration saved successfully") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler POST requests for saving intervals -func intervalsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// IntervalsPOSTHandler for POST requests for saving intervals +func (h *HandlersAdmin) IntervalsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) vars := mux.Vars(r) // Extract environment and verify environmentVar, ok := vars["environment"] - if !ok || !envs.Exists(environmentVar) { + if !ok || !h.Envs.Exists(environmentVar) { adminErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var c IntervalsRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, environmentVar) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, environmentVar) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&c); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], c.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], c.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if err := envs.UpdateIntervals(environmentVar, c.ConfigInterval, c.LogInterval, c.QueryInterval); err != nil { + if err := h.Envs.UpdateIntervals(environmentVar, c.ConfigInterval, c.LogInterval, c.QueryInterval); err != nil { adminErrorResponse(w, "error updating intervals", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // After updating interval, you need to re-generate flags - flags, err := envs.GenerateFlagsEnv(environmentVar, "", "") + flags, err := h.Envs.GenerateFlagsEnv(environmentVar, "", "") if err != nil { adminErrorResponse(w, "error re-generating flags", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Update flags in the newly created environment - if err := envs.UpdateFlags(environmentVar, flags); err != nil { + if err := h.Envs.UpdateFlags(environmentVar, flags); err != nil { adminErrorResponse(w, "error updating flags", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Intervals response sent") } adminOKResponse(w, "intervals saved successfully") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler POST requests for expiring enroll links -func expirationPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// ExpirationPOSTHandler for POST requests for expiring enroll links +func (h *HandlersAdmin) ExpirationPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) vars := mux.Vars(r) // Extract environment and verify environmentVar, ok := vars["environment"] - if !ok || !envs.Exists(environmentVar) { + if !ok || !h.Envs.Exists(environmentVar) { adminErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var e ExpirationRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, environmentVar) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, environmentVar) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&e); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], e.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], e.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch e.Type { case "enroll": switch e.Action { case "expire": - if err := envs.ExpireEnroll(environmentVar); err != nil { + if err := h.Envs.ExpireEnroll(environmentVar); err != nil { adminErrorResponse(w, "error expiring enroll", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "link expired successfully") case "extend": - if err := envs.RotateEnrollPath(environmentVar); err != nil { + if err := h.Envs.RotateEnrollPath(environmentVar); err != nil { adminErrorResponse(w, "error extending enroll", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "link extended successfully") @@ -662,54 +662,54 @@ func expirationPOSTHandler(w http.ResponseWriter, r *http.Request) { case "remove": switch e.Action { case "expire": - if err := envs.ExpireRemove(environmentVar); err != nil { + if err := h.Envs.ExpireRemove(environmentVar); err != nil { adminErrorResponse(w, "error expiring remove", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "link expired successfully") case "extend": - if err := envs.RotateRemove(environmentVar); err != nil { + if err := h.Envs.RotateRemove(environmentVar); err != nil { adminErrorResponse(w, "error extending remove", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "link extended successfully") } } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Expiration response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler POST requests for multi node action -func nodeActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// NodeActionsPOSTHandler for POST requests for multi node action +func (h *HandlersAdmin) NodeActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var m NodeMultiActionRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&m); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], m.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], m.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch m.Action { @@ -717,9 +717,9 @@ func nodeActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { okCount := 0 errCount := 0 for _, u := range m.UUIDs { - if err := nodesmgr.ArchiveDeleteByUUID(u); err != nil { + if err := h.Nodes.ArchiveDeleteByUUID(u); err != nil { errCount++ - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Printf("DebugService: error deleting node %s %v", u, err) } } else { @@ -730,55 +730,55 @@ func nodeActionsPOSTHandler(w http.ResponseWriter, r *http.Request) { adminOKResponse(w, fmt.Sprintf("%d Node(s) have been deleted successfully", okCount)) } else { adminErrorResponse(w, fmt.Sprintf("Error deleting %d node(s)", errCount), http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } case "archive": - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Printf("DebugService: archiving node") } adminOKResponse(w, "node archived successfully") } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Multi-node action response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST request for /environments -func envsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// EnvsPOSTHandler for POST request for /environments +func (h *HandlersAdmin) EnvsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var c EnvironmentsRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&c); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], c.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], c.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch c.Action { case "create": // FIXME verify fields - if !envs.Exists(c.Name) { - env := envs.Empty(c.Name, c.Hostname) + if !h.Envs.Exists(c.Name) { + env := h.Envs.Empty(c.Name, c.Hostname) env.Icon = c.Icon env.Type = c.Type if env.Configuration == "" { @@ -789,291 +789,291 @@ func envsPOSTHandler(w http.ResponseWriter, r *http.Request) { flags, err := environments.GenerateFlags(env, "", "") if err != nil { adminErrorResponse(w, "error generating flags", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } env.Flags = flags } - if err := envs.Create(env); err != nil { + if err := h.Envs.Create(env); err != nil { adminErrorResponse(w, "error creating environment", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "environment created successfully") case "delete": - if c.Name == settingsmgr.DefaultEnv(settings.ServiceAdmin) { + if c.Name == h.Settings.DefaultEnv(settings.ServiceAdmin) { adminErrorResponse(w, "not a good idea", http.StatusInternalServerError, fmt.Errorf("attempt to remove enviornment %s", c.Name)) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if envs.Exists(c.Name) { - if err := envs.Delete(c.Name); err != nil { + if h.Envs.Exists(c.Name) { + if err := h.Envs.Delete(c.Name); err != nil { adminErrorResponse(w, "error deleting environment", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "environment deleted successfully") case "debug": // FIXME verify fields - if envs.Exists(c.Name) { - if err := envs.ChangeDebugHTTP(c.Name, c.DebugHTTP); err != nil { + if h.Envs.Exists(c.Name) { + if err := h.Envs.ChangeDebugHTTP(c.Name, c.DebugHTTP); err != nil { adminErrorResponse(w, "error changing DebugHTTP", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "debug changed successfully") } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Environments response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST request for /settings -func settingsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// SettingsPOSTHandler for POST request for /settings +func (h *HandlersAdmin) SettingsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) vars := mux.Vars(r) // Extract service serviceVar, ok := vars["service"] if !ok { adminErrorResponse(w, "error getting service", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Verify service if !checkTargetService(serviceVar) { adminErrorResponse(w, fmt.Sprintf("unknown service (%s)", serviceVar), http.StatusForbidden, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var s SettingsRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&s); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], s.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], s.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch s.Action { case "add": - if !settingsmgr.VerifyType(s.Type) { + if !h.Settings.VerifyType(s.Type) { adminErrorResponse(w, "invalid type", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var err error switch s.Type { case settings.TypeBoolean: - err = settingsmgr.NewBooleanValue(serviceVar, s.Name, stringToBoolean(s.Value)) + err = h.Settings.NewBooleanValue(serviceVar, s.Name, stringToBoolean(s.Value)) case settings.TypeInteger: - err = settingsmgr.NewIntegerValue(serviceVar, s.Name, stringToInteger(s.Value)) + err = h.Settings.NewIntegerValue(serviceVar, s.Name, stringToInteger(s.Value)) case settings.TypeString: - err = settingsmgr.NewStringValue(serviceVar, s.Name, s.Value) + err = h.Settings.NewStringValue(serviceVar, s.Name, s.Value) } if err != nil { adminErrorResponse(w, "error adding setting", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "setting added successfully") case "change": - if !settingsmgr.VerifyType(s.Type) { + if !h.Settings.VerifyType(s.Type) { adminErrorResponse(w, "invalid type", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var err error switch s.Type { case settings.TypeBoolean: - err = settingsmgr.SetBoolean(s.Boolean, serviceVar, s.Name) + err = h.Settings.SetBoolean(s.Boolean, serviceVar, s.Name) case settings.TypeInteger: - err = settingsmgr.SetInteger(stringToInteger(s.Value), serviceVar, s.Name) + err = h.Settings.SetInteger(stringToInteger(s.Value), serviceVar, s.Name) case settings.TypeString: - err = settingsmgr.SetString(s.Value, serviceVar, s.Name, false) + err = h.Settings.SetString(s.Value, serviceVar, s.Name, false) } if err != nil { adminErrorResponse(w, "error changing setting", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "setting changed successfully") case "delete": - if err := settingsmgr.DeleteValue(serviceVar, s.Name); err != nil { + if err := h.Settings.DeleteValue(serviceVar, s.Name); err != nil { adminErrorResponse(w, "error deleting setting", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } adminOKResponse(w, "setting deleted successfully") } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Settings response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST request for /users -func usersPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// UsersPOSTHandler for POST request for /users +func (h *HandlersAdmin) UsersPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) var u UsersRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&u); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], u.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], u.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } switch u.Action { case "add": // FIXME password complexity? - if adminUsers.Exists(u.Username) { + if h.Users.Exists(u.Username) { adminErrorResponse(w, "error adding user", http.StatusInternalServerError, fmt.Errorf("user %s already exists", u.Username)) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Prepare user to create - newUser, err := adminUsers.New(u.Username, u.Password, u.Email, u.Fullname, u.Admin) + newUser, err := h.Users.New(u.Username, u.Password, u.Email, u.Fullname, u.Admin) if err != nil { adminErrorResponse(w, "error with new user", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Create new user - if err = adminUsers.Create(newUser); err != nil { + if err = h.Users.Create(newUser); err != nil { adminErrorResponse(w, "error creating user", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } if u.Admin { - namesEnvs, err := envs.Names() + namesEnvs, err := h.Envs.Names() if err != nil { adminErrorResponse(w, "error getting environments user", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - perms := adminUsers.GenPermissions(namesEnvs, u.Admin) - if err := adminUsers.ChangePermissions(u.Username, perms); err != nil { + perms := h.Users.GenPermissions(namesEnvs, u.Admin) + if err := h.Users.ChangePermissions(u.Username, perms); err != nil { adminErrorResponse(w, "error changing permissions", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } if u.Token { - token, exp, err := adminUsers.CreateToken(newUser.Username, jwtConfig.HoursToExpire, jwtConfig.JWTSecret) + token, exp, err := h.Users.CreateToken(newUser.Username) if err != nil { adminErrorResponse(w, "error creating token", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if err = adminUsers.UpdateToken(newUser.Username, token, exp); err != nil { + if err = h.Users.UpdateToken(newUser.Username, token, exp); err != nil { adminErrorResponse(w, "error saving token", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "user added successfully") case "edit": if u.Fullname != "" { - if err := adminUsers.ChangeFullname(u.Username, u.Fullname); err != nil { + if err := h.Users.ChangeFullname(u.Username, u.Fullname); err != nil { adminErrorResponse(w, "error changing fullname", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } if u.Email != "" { - if err := adminUsers.ChangeEmail(u.Username, u.Email); err != nil { + if err := h.Users.ChangeEmail(u.Username, u.Email); err != nil { adminErrorResponse(w, "error changing email", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "user updated successfully") case "remove": - if u.Username == ctx[ctxUser] { + if u.Username == ctx[sessions.CtxUser] { adminErrorResponse(w, "not a good idea", http.StatusInternalServerError, fmt.Errorf("attempt to remove current user %s", u.Username)) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if adminUsers.Exists(u.Username) { - if err := adminUsers.Delete(u.Username); err != nil { + if h.Users.Exists(u.Username) { + if err := h.Users.Delete(u.Username); err != nil { adminErrorResponse(w, "error removing user", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } adminOKResponse(w, "user removed successfully") case "admin": - if u.Username == ctx[ctxUser] { + if u.Username == ctx[sessions.CtxUser] { adminErrorResponse(w, "not a good idea", http.StatusInternalServerError, fmt.Errorf("attempt to de-admin current user %s", u.Username)) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if adminUsers.Exists(u.Username) { - if err := adminUsers.ChangeAdmin(u.Username, u.Admin); err != nil { + if h.Users.Exists(u.Username) { + if err := h.Users.ChangeAdmin(u.Username, u.Admin); err != nil { adminErrorResponse(w, "error changing admin", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } if u.Admin { - namesEnvs, err := envs.Names() + namesEnvs, err := h.Envs.Names() if err != nil { adminErrorResponse(w, "error getting environments", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - perms := adminUsers.GenPermissions(namesEnvs, u.Admin) - if err := adminUsers.ChangePermissions(u.Username, perms); err != nil { + perms := h.Users.GenPermissions(namesEnvs, u.Admin) + if err := h.Users.ChangePermissions(u.Username, perms); err != nil { adminErrorResponse(w, "error changing permissions", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - token, exp, err := adminUsers.CreateToken(u.Username, jwtConfig.HoursToExpire, jwtConfig.JWTSecret) + token, exp, err := h.Users.CreateToken(u.Username) if err != nil { adminErrorResponse(w, "error creating token", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if err := adminUsers.UpdateToken(u.Username, token, exp); err != nil { + if err := h.Users.UpdateToken(u.Username, token, exp); err != nil { adminErrorResponse(w, "error saving token", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } } @@ -1081,46 +1081,46 @@ func usersPOSTHandler(w http.ResponseWriter, r *http.Request) { } } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Users response sent") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for POST request for /users/permissions -func permissionsPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// PermissionsPOSTHandler for POST request for /users/permissions +func (h *HandlersAdmin) PermissionsPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) vars := mux.Vars(r) // Extract username and verify usernameVar, ok := vars["username"] - if !ok || !adminUsers.Exists(usernameVar) { + if !ok || !h.Users.Exists(usernameVar) { adminErrorResponse(w, "error getting username", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var p PermissionsRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&p); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], p.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], p.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // TODO verify environments @@ -1129,75 +1129,75 @@ func permissionsPOSTHandler(w http.ResponseWriter, r *http.Request) { Query: p.Query, Carve: p.Carve, } - if err := adminUsers.ChangePermissions(usernameVar, perms); err != nil { + if err := h.Users.ChangePermissions(usernameVar, perms); err != nil { adminErrorResponse(w, "error changing permissions", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Users response sent") } adminOKResponse(w, "OK") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler POST requests enroll data -func enrollPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// EnrollPOSTHandler for POST requests enroll data +func (h *HandlersAdmin) EnrollPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) vars := mux.Vars(r) // Extract environment and verify environmentVar, ok := vars["environment"] - if !ok || !envs.Exists(environmentVar) { + if !ok || !h.Envs.Exists(environmentVar) { adminErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } var e EnrollRequest // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, environmentVar) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, environmentVar) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } if err := json.NewDecoder(r.Body).Decode(&e); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], e.CSRFToken) { + if !sessions.CheckCSRFToken(ctx[sessions.CtxCSRF], e.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } if e.CertificateB64 == "" { adminErrorResponse(w, "empty certificate", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } certificate, err := base64.StdEncoding.DecodeString(e.CertificateB64) if err != nil { adminErrorResponse(w, "error decoding certificate", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if err := envs.UpdateCertificate(environmentVar, string(certificate)); err != nil { + if err := h.Envs.UpdateCertificate(environmentVar, string(certificate)); err != nil { adminErrorResponse(w, "error saving certificate", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Serialize and send response - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Configuration response sent") } adminOKResponse(w, "enroll data saved") - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } diff --git a/admin/postgres.go b/admin/handlers/postgres.go similarity index 64% rename from admin/postgres.go rename to admin/handlers/postgres.go index d5ad3162..097c9e14 100644 --- a/admin/postgres.go +++ b/admin/handlers/postgres.go @@ -1,10 +1,11 @@ -package main +package handlers import ( "encoding/json" "time" "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/postgres" ) // OsqueryResultData to log result data to database @@ -42,29 +43,29 @@ type OsqueryQueryData struct { } // Function to retrieve the last status logs for a given node -func postgresStatusLogs(uuid, environment string, seconds int64) ([]OsqueryStatusData, error) { +func (h *HandlersAdmin) postgresStatusLogs(uuid, environment string, seconds int64) ([]OsqueryStatusData, error) { var logs []OsqueryStatusData minusSeconds := time.Now().Add(time.Duration(-seconds) * time.Second) - if err := db.Where("uuid = ? AND environment = ?", uuid, environment).Where("created_at > ?", minusSeconds).Find(&logs).Error; err != nil { + if err := h.DB.Where("uuid = ? AND environment = ?", uuid, environment).Where("created_at > ?", minusSeconds).Find(&logs).Error; err != nil { return logs, err } return logs, nil } // Function to retrieve the last result logs for a given node -func postgresResultLogs(uuid, environment string, seconds int64) ([]OsqueryResultData, error) { +func (h *HandlersAdmin) postgresResultLogs(uuid, environment string, seconds int64) ([]OsqueryResultData, error) { var logs []OsqueryResultData minusSeconds := time.Now().Add(time.Duration(-seconds) * time.Second) - if err := db.Where("uuid = ? AND environment = ?", uuid, environment).Where("created_at > ?", minusSeconds).Find(&logs).Error; err != nil { + if err := h.DB.Where("uuid = ? AND environment = ?", uuid, environment).Where("created_at > ?", minusSeconds).Find(&logs).Error; err != nil { return logs, err } return logs, nil } // Function to retrieve the query log by name -func postgresQueryLogs(name string) ([]OsqueryQueryData, error) { +func (h *HandlersAdmin) postgresQueryLogs(name string) ([]OsqueryQueryData, error) { var logs []OsqueryQueryData - if err := db.Where("name = ?", name).Find(&logs).Error; err != nil { + if err := h.DB.Where("name = ?", name).Find(&logs).Error; err != nil { return logs, err } return logs, nil diff --git a/admin/handlers-get.go b/admin/handlers/templates.go similarity index 54% rename from admin/handlers-get.go rename to admin/handlers/templates.go index 6b37f3cd..c10d3f11 100644 --- a/admin/handlers-get.go +++ b/admin/handlers/templates.go @@ -1,21 +1,18 @@ -package main +package handlers import ( - "html/template" - "io" "log" "net/http" - "os" - "strconv" "strings" + "text/template" + "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/carves" "github.com/jmpsec/osctrl/environments" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/utils" - - "github.com/gorilla/mux" ) const ( @@ -27,6 +24,22 @@ type TemplateFiles struct { filepaths []string } +// Helper to prepare template metadata +func (h *HandlersAdmin) TemplateMetadata(ctx sessions.ContextValue, version string) TemplateMetadata { + return TemplateMetadata{ + Username: ctx[sessions.CtxUser], + Level: ctx[sessions.CtxLevel], + CSRFToken: ctx[sessions.CtxCSRF], + Service: "osctrl-admin", + Version: version, + TLSDebug: h.Settings.DebugService(settings.ServiceTLS), + AdminDebug: h.Settings.DebugService(settings.ServiceAdmin), + APIDebug: h.Settings.DebugService(settings.ServiceAPI), + AdminDebugHTTP: h.Settings.DebugHTTP(settings.ServiceAdmin), + APIDebugHTTP: h.Settings.DebugHTTP(settings.ServiceAPI), + } +} + // NewTemplateFiles defines based on layout and default static pages func NewTemplateFiles(base string, layoutFilename string) *TemplateFiles { paths := []string{ @@ -42,79 +55,67 @@ func NewTemplateFiles(base string, layoutFilename string) *TemplateFiles { return &tf } -// Handler for login page for GET requests -func loginGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// LoginHandler for login page for GET requests +func (h *HandlersAdmin) LoginHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Prepare template t, err := template.ParseFiles( templatesFilesFolder+"/login.html", templatesFilesFolder+"/components/page-head.html", templatesFilesFolder+"/components/page-js.html") if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting login template: %v", err) return } // Prepare template data templateData := LoginTemplateData{ - Title: "Login to " + projectName, - Project: projectName, + Title: "Login to osctrl", + Project: "osctrl", } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Login template served") } - incMetric(metricAdminOK) -} - -// Handler for the root path -func rootHandler(w http.ResponseWriter, r *http.Request) { - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) - // Redirect to table for active nodes in default environment - defaultEnvironment := settingsmgr.DefaultEnv(settings.ServiceAdmin) - if envs.Exists(defaultEnvironment) { - http.Redirect(w, r, "/environment/"+defaultEnvironment+"/active", http.StatusFound) - } else { - http.Redirect(w, r, "/environments", http.StatusFound) - } + h.Inc(metricAdminOK) } -// Handler for environment view of the table -func environmentHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// EnvironmentHandler for environment view of the table +func (h *HandlersAdmin) EnvironmentHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract environment env, ok := vars["environment"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting environment") return } // Check if environment is valid - if !envs.Exists(env) { - incMetric(metricAdminErr) + if !h.Envs.Exists(env) { + h.Inc(metricAdminErr) log.Printf("error unknown environment (%s)", env) return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, env) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricTokenErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, env) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricTokenErr) return } // Extract target // FIXME verify target target, ok := vars["target"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting target") return } @@ -123,28 +124,28 @@ func environmentHandler(w http.ResponseWriter, r *http.Request) { t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Prepare template data templateData := TableTemplateData{ Title: "Nodes in " + env, - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Selector: "environment", SelectorName: env, Target: target, @@ -152,26 +153,26 @@ func environmentHandler(w http.ResponseWriter, r *http.Request) { Platforms: platforms, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Environment table template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for platform view of the table -func platformHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// PlatformHandler for platform view of the table +func (h *HandlersAdmin) PlatformHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract platform // FIXME verify platform platform, ok := vars["platform"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting platform") return } @@ -179,16 +180,16 @@ func platformHandler(w http.ResponseWriter, r *http.Request) { // FIXME verify target target, ok := vars["target"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting target") return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricTokenErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricTokenErr) return } // Prepare template @@ -201,28 +202,28 @@ func platformHandler(w http.ResponseWriter, r *http.Request) { templatesFilesFolder+"/components/page-header.html", templatesFilesFolder+"/components/page-modals.html") if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Prepare template data templateData := TableTemplateData{ Title: "Nodes in " + platform, - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Selector: "platform", SelectorName: platform, Target: target, @@ -230,26 +231,26 @@ func platformHandler(w http.ResponseWriter, r *http.Request) { Platforms: platforms, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Platform table template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for GET requests to run queries -func queryRunGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// QueryRunGETHandler for GET requests to run queries +func (h *HandlersAdmin) QueryRunGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template @@ -262,28 +263,28 @@ func queryRunGETHandler(w http.ResponseWriter, r *http.Request) { templatesFilesFolder+"/components/page-header.html", templatesFilesFolder+"/components/page-modals.html") if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get all nodes - nodes, err := nodesmgr.Gets("active", settingsmgr.InactiveHours()) + nodes, err := h.Nodes.Gets("active", h.Settings.InactiveHours()) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting all nodes: %v", err) return } @@ -297,116 +298,116 @@ func queryRunGETHandler(w http.ResponseWriter, r *http.Request) { // Prepare template data templateData := QueryRunTemplateData{ Title: "Query osquery Nodes", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, UUIDs: uuids, Hosts: hosts, - Tables: osqueryTables, + Tables: h.OsqueryTables, TablesVersion: osqueryTablesVersion, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Query run template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for GET requests to queries -func queryListGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// QueryListGETHandler for GET requests to queries +func (h *HandlersAdmin) QueryListGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "queries.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Prepare template data templateData := QueryTableTemplateData{ Title: "All on-demand queries", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, Target: "all", } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Query list template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for GET requests to run file carves -func carvesRunGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// CarvesRunGETHandler for GET requests to run file carves +func (h *HandlersAdmin) CarvesRunGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "carves-run.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get all nodes - nodes, err := nodesmgr.Gets("active", settingsmgr.InactiveHours()) + nodes, err := h.Nodes.Gets("active", h.Settings.InactiveHours()) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting all nodes: %v", err) return } @@ -420,95 +421,95 @@ func carvesRunGETHandler(w http.ResponseWriter, r *http.Request) { // Prepare template data templateData := CarvesRunTemplateData{ Title: "Query osquery Nodes", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, UUIDs: uuids, Hosts: hosts, - Tables: osqueryTables, + Tables: h.OsqueryTables, TablesVersion: osqueryTablesVersion, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Query run template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for GET requests to carves -func carvesListGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// CarvesListGETHandler for GET requests to carves +func (h *HandlersAdmin) CarvesListGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "carves.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Prepare template data templateData := CarvesTableTemplateData{ Title: "All carved files", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, Target: "all", } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Carve list template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests to see query results by name -func queryLogsHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// QueryLogsHandler for GET requests to see query results by name +func (h *HandlersAdmin) QueryLogsHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.QueryLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.QueryLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } vars := mux.Vars(r) // Extract name name, ok := vars["name"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting name") return } @@ -516,39 +517,39 @@ func queryLogsHandler(w http.ResponseWriter, r *http.Request) { tempateFiles := NewTemplateFiles(templatesFilesFolder, "queries-logs.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get query by name - query, err := queriesmgr.Get(name) + query, err := h.Queries.Get(name) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting query %v", err) return } // Get query targets - targets, err := queriesmgr.GetTargets(name) + targets, err := h.Queries.GetTargets(name) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting targets %v", err) return } - defLink, dbLink := queryResultLink(query.Name) + defLink, dbLink := h.queryResultLink(query.Name) resLink := "" if defLink != dbLink { resLink = dbLink @@ -556,7 +557,7 @@ func queryLogsHandler(w http.ResponseWriter, r *http.Request) { // Prepare template data templateData := QueryLogsTemplateData{ Title: "Query logs " + query.Name, - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, Query: query, @@ -564,33 +565,33 @@ func queryLogsHandler(w http.ResponseWriter, r *http.Request) { QueryTargets: targets, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Query logs template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests to see carves details by name -func carvesDetailsHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// CarvesDetailsHandler for GET requests to see carves details by name +func (h *HandlersAdmin) CarvesDetailsHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.CarveLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } vars := mux.Vars(r) // Extract name name, ok := vars["name"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting name") return } @@ -598,52 +599,52 @@ func carvesDetailsHandler(w http.ResponseWriter, r *http.Request) { tempateFiles := NewTemplateFiles(templatesFilesFolder, "carves-details.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get query by name - query, err := queriesmgr.Get(name) + query, err := h.Queries.Get(name) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting query %v", err) return } // Get query targets - targets, err := queriesmgr.GetTargets(name) + targets, err := h.Queries.GetTargets(name) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting targets %v", err) return } // Get carves for this query - queryCarves, err := carvesmgr.GetByQuery(name) + queryCarves, err := h.Carves.GetByQuery(name) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting carve %v", err) return } // Get carve blocks by carve blocks := make(map[string][]carves.CarvedBlock) for _, c := range queryCarves { - bs, err := carvesmgr.GetBlocks(c.SessionID) + bs, err := h.Carves.GetBlocks(c.SessionID) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting carve blocks %v", err) break } @@ -652,7 +653,7 @@ func carvesDetailsHandler(w http.ResponseWriter, r *http.Request) { // Prepare template data templateData := CarvesDetailsTemplateData{ Title: "Carve details " + query.Name, - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, Query: query, @@ -661,142 +662,142 @@ func carvesDetailsHandler(w http.ResponseWriter, r *http.Request) { CarveBlocks: blocks, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Carve details template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests for /conf -func confGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// ConfGETHandler for GET requests for /conf +func (h *HandlersAdmin) ConfGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract environment envVar, ok := vars["environment"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("environment is missing") return } // Check if environment is valid - if !envs.Exists(envVar) { - incMetric(metricAdminErr) + if !h.Envs.Exists(envVar) { + h.Inc(metricAdminErr) log.Printf("error unknown environment (%s)", envVar) return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, envVar) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, envVar) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "conf.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting conf template: %v", err) return } // Get stats for all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get stats for all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get configuration JSON - env, err := envs.Get(envVar) + env, err := h.Envs.Get(envVar) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environment %v", err) return } // Prepare template data templateData := ConfTemplateData{ Title: envVar + " Configuration", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environment: env, Environments: envAll, Platforms: platforms, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Conf template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests for /enroll -func enrollGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// EnrollGETHandler for GET requests for /enroll +func (h *HandlersAdmin) EnrollGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract environment envVar, ok := vars["environment"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("environment is missing") return } // Check if environment is valid - if !envs.Exists(envVar) { - incMetric(metricAdminErr) + if !h.Envs.Exists(envVar) { + h.Inc(metricAdminErr) log.Printf("error unknown environment (%s)", envVar) return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, envVar) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, envVar) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "enroll.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting enroll template: %v", err) return } // Get stats for all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get stats for all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get configuration JSON - env, err := envs.Get(envVar) + env, err := h.Envs.Get(envVar) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environment %v", err) return } @@ -807,7 +808,7 @@ func enrollGETHandler(w http.ResponseWriter, r *http.Request) { powershellQuickRemove, _ := environments.QuickRemoveOneLinerPowershell(env) templateData := EnrollTemplateData{ Title: envVar + " Enroll", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), EnvName: envVar, EnrollExpiry: strings.ToUpper(utils.InFutureTime(env.EnrollExpire)), EnrollExpired: environments.IsItExpired(env.EnrollExpire), @@ -824,25 +825,25 @@ func enrollGETHandler(w http.ResponseWriter, r *http.Request) { Platforms: platforms, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Enroll template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler for node view -func nodeHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// NodeHandler for node view +func (h *HandlersAdmin) NodeHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Extract uuid uuid, ok := vars["uuid"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting uuid") return } @@ -850,141 +851,141 @@ func nodeHandler(w http.ResponseWriter, r *http.Request) { funcMap := template.FuncMap{ "pastFutureTimes": utils.PastFutureTimes, "jsonRawIndent": jsonRawIndent, - "statusLogsLink": statusLogsLink, - "resultLogsLink": resultLogsLink, + "statusLogsLink": h.statusLogsLink, + "resultLogsLink": h.resultLogsLink, } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "node.html").filepaths t, err := template.New("node.html").Funcs(funcMap).ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting table template: %v", err) return } // Get node by UUID - node, err := nodesmgr.GetByUUID(uuid) + node, err := h.Nodes.GetByUUID(uuid) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting node %v", err) return } // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.EnvLevel, node.Environment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.EnvLevel, node.Environment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Get all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments%v", err) return } // Get all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Prepare template data templateData := NodeTemplateData{ Title: "Node View " + node.Hostname, - Metadata: templateMetadata(ctx, serviceName, serviceVersion), - Logs: adminConfig.Logging, + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), + Logs: h.AdminConfig.Logging, Node: node, Environments: envAll, Platforms: platforms, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Node template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests for /env -func envsGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// EnvsGETHandler for GET requests for /env +func (h *HandlersAdmin) EnvsGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Prepare template tempateFiles := NewTemplateFiles(templatesFilesFolder, "environments.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments template: %v", err) return } // Get stats for all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get stats for all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Prepare template data templateData := EnvironmentsTemplateData{ Title: "Manage environments", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Environments template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests for /settings -func settingsGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// SettingsGETHandler for GET requests for /settings +func (h *HandlersAdmin) SettingsGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) vars := mux.Vars(r) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Extract service serviceVar, ok := vars["service"] if !ok { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Println("error getting service") return } // Verify service if !checkTargetService(serviceVar) { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error unknown service (%s)", serviceVar) return } @@ -992,40 +993,40 @@ func settingsGETHandler(w http.ResponseWriter, r *http.Request) { tempateFiles := NewTemplateFiles(templatesFilesFolder, "settings.html").filepaths t, err := template.ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments template: %v", err) return } // Get stats for all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { log.Printf("error getting environments %v", err) return } // Get stats for all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get setting values - _settings, err := settingsmgr.RetrieveValues(serviceVar) + _settings, err := h.Settings.RetrieveValues(serviceVar) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting settings: %v", err) return } // Get JSON values - svcJSON, err := settingsmgr.RetrieveAllJSON(serviceVar) + svcJSON, err := h.Settings.RetrieveAllJSON(serviceVar) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting JSON values: %v", err) } // Prepare template data templateData := SettingsTemplateData{ Title: "Manage settings", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Service: serviceVar, Environments: envAll, Platforms: platforms, @@ -1033,26 +1034,26 @@ func settingsGETHandler(w http.ResponseWriter, r *http.Request) { ServiceConfig: toJSONConfigurationService(svcJSON), } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Settings template served") } - incMetric(metricAdminOK) + h.Inc(metricAdminOK) } -// Handler GET requests for /users -func usersGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// UsersGETHandler for GET requests for /users +func (h *HandlersAdmin) UsersGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAdminReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + log.Printf("%s has insuficient permissions", ctx[sessions.CtxUser]) + h.Inc(metricAdminErr) return } // Custom functions to handle formatting @@ -1064,125 +1065,46 @@ func usersGETHandler(w http.ResponseWriter, r *http.Request) { tempateFiles := NewTemplateFiles(templatesFilesFolder, "users.html").filepaths t, err := template.New("users.html").Funcs(funcMap).ParseFiles(tempateFiles...) if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments template: %v", err) return } // Get stats for all environments - envAll, err := envs.All() + envAll, err := h.Envs.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting environments %v", err) return } // Get stats for all platforms - platforms, err := nodesmgr.GetAllPlatforms() + platforms, err := h.Nodes.GetAllPlatforms() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting platforms: %v", err) return } // Get current users - users, err := adminUsers.All() + users, err := h.Users.All() if err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("error getting users: %v", err) return } // Prepare template data templateData := UsersTemplateData{ Title: "Manage users", - Metadata: templateMetadata(ctx, serviceName, serviceVersion), + Metadata: h.TemplateMetadata(ctx, h.ServiceVersion), Environments: envAll, Platforms: platforms, CurrentUsers: users, } if err := t.Execute(w, templateData); err != nil { - incMetric(metricAdminErr) + h.Inc(metricAdminErr) log.Printf("template error %v", err) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Users template served") } - incMetric(metricAdminOK) -} - -// Handler for platform/environment stats in JSON -func permissionsGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) - vars := mux.Vars(r) - // Extract username and verify - usernameVar, ok := vars["username"] - if !ok || !adminUsers.Exists(usernameVar) { - if settingsmgr.DebugService(settings.ServiceAdmin) { - log.Printf("DebugService: error getting username") - } - return - } - // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) - // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) - return - } - // Get permissions - permissions, err := adminUsers.GetPermissions(usernameVar) - if err != nil { - incMetric(metricAdminErr) - log.Printf("error getting permissions %v", err) - } - // Serve JSON - utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, permissions) - incMetric(metricJSONOK) -} - -// Handler for GET requests to download carves -func carvesDownloadHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricAdminReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) - vars := mux.Vars(r) - // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) - // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.CarveLevel, users.NoEnvironment) { - log.Printf("%s has insuficient permissions", ctx[ctxUser]) - incMetric(metricAdminErr) - return - } - // Extract id to download - carveSession, ok := vars["sessionid"] - if !ok { - incMetric(metricAdminErr) - log.Println("error getting carve") - return - } - // Prepare file to download - result, err := carvesmgr.Archive(carveSession, carvedFilesFolder) - if err != nil { - incMetric(metricAdminErr) - log.Printf("error downloading carve - %v", err) - return - } - if settingsmgr.DebugService(settings.ServiceAdmin) { - log.Println("DebugService: Carve download") - } - incMetric(metricAdminOK) - // Send response - w.Header().Set("Content-Description", "File Carve Download") - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", "attachment; filename="+result.File) - w.Header().Set("Content-Transfer-Encoding", "binary") - w.Header().Set("Connection", "Keep-Alive") - w.Header().Set("Expires", "0") - w.Header().Set("Cache-Control", "must-revalidate, post-check=0, pre-check=0") - w.Header().Set("Pragma", "public") - w.Header().Set("Content-Length", strconv.FormatInt(result.Size, 10)) - w.WriteHeader(http.StatusOK) - var fileReader io.Reader - fileReader, _ = os.Open(result.File) - _, _ = io.Copy(w, fileReader) + h.Inc(metricAdminOK) } diff --git a/admin/handlers-tokens.go b/admin/handlers/tokens.go similarity index 57% rename from admin/handlers-tokens.go rename to admin/handlers/tokens.go index 42b320d6..bccbd461 100644 --- a/admin/handlers-tokens.go +++ b/admin/handlers/tokens.go @@ -1,4 +1,4 @@ -package main +package handlers import ( "encoding/json" @@ -7,17 +7,12 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/utils" ) -const ( - metricTokenReq = "admin-token-req" - metricTokenErr = "admin-token-err" - metricTokenOK = "admin-token-ok" -) - // TokenJSON to be used to populate a JSON token type TokenJSON struct { Token string `json:"token"` @@ -25,16 +20,16 @@ type TokenJSON struct { ExpiresTS string `json:"expires_ts"` } -// Handle GET requests for /tokens/{username} -func tokensGETHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricTokenReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false) +// TokensGETHandler for GET requests for /tokens/{username} +func (h *HandlersAdmin) TokensGETHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricTokenReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), false) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { - adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[ctxUser]), http.StatusForbidden, nil) - incMetric(metricAdminErr) + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { + adminErrorResponse(w, fmt.Sprintf("%s has insuficient permissions", ctx[sessions.CtxUser]), http.StatusForbidden, nil) + h.Inc(metricAdminErr) return } vars := mux.Vars(r) @@ -42,15 +37,15 @@ func tokensGETHandler(w http.ResponseWriter, r *http.Request) { username, ok := vars["username"] if !ok { adminErrorResponse(w, "error getting username", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } returned := TokenJSON{} - if adminUsers.Exists(username) { - user, err := adminUsers.Get(username) + if h.Users.Exists(username) { + user, err := h.Users.Get(username) if err != nil { adminErrorResponse(w, "error getting user", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Prepare data to be returned @@ -62,66 +57,66 @@ func tokensGETHandler(w http.ResponseWriter, r *http.Request) { } // Serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, returned) - incMetric(metricTokenOK) + h.Inc(metricTokenOK) } -// Handle POST request for /tokens/{username}/refresh -func tokensPOSTHandler(w http.ResponseWriter, r *http.Request) { - incMetric(metricTokenReq) - utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), true) +// TokensPOSTHandler for POST request for /tokens/{username}/refresh +func (h *HandlersAdmin) TokensPOSTHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricTokenReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAdmin), true) // Get context data - ctx := r.Context().Value(contextKey("session")).(contextValue) + ctx := r.Context().Value(sessions.ContextKey("session")).(sessions.ContextValue) // Check permissions - if !adminUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { + if !h.Users.CheckPermissions(ctx[sessions.CtxUser], users.AdminLevel, users.NoEnvironment) { adminErrorResponse(w, "insuficient permissions", http.StatusForbidden, nil) - incMetric(metricTokenErr) + h.Inc(metricTokenErr) return } vars := mux.Vars(r) // Extract username and verify username, ok := vars["username"] - if !ok || !adminUsers.Exists(username) { + if !ok || !h.Users.Exists(username) { adminErrorResponse(w, "error getting username", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Parse request JSON body - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Decoding POST body") } var t TokenRequest if err := json.NewDecoder(r.Body).Decode(&t); err != nil { adminErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } // Check CSRF Token - if !checkCSRFToken(ctx[ctxCSRF], t.CSRFToken) { + if !checkCSRFToken(ctx[sessions.CtxCSRF], t.CSRFToken) { adminErrorResponse(w, "invalid CSRF token", http.StatusInternalServerError, nil) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - user, err := adminUsers.Get(username) + user, err := h.Users.Get(username) if err != nil { adminErrorResponse(w, "error getting user", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Creating token") } - token, exp, err := adminUsers.CreateToken(user.Username, jwtConfig.HoursToExpire, jwtConfig.JWTSecret) + token, exp, err := h.Users.CreateToken(user.Username) if err != nil { adminErrorResponse(w, "error creating token", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } - if settingsmgr.DebugService(settings.ServiceAdmin) { + if h.Settings.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Updating token") } - if err := adminUsers.UpdateToken(user.Username, token, exp); err != nil { + if err := h.Users.UpdateToken(user.Username, token, exp); err != nil { adminErrorResponse(w, "error updating token", http.StatusInternalServerError, err) - incMetric(metricAdminErr) + h.Inc(metricAdminErr) return } response := TokenResponse{ @@ -131,5 +126,5 @@ func tokensPOSTHandler(w http.ResponseWriter, r *http.Request) { } // Serialize and serve JSON utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, response) - incMetric(metricTokenOK) + h.Inc(metricTokenOK) } diff --git a/admin/types-requests.go b/admin/handlers/types-requests.go similarity index 99% rename from admin/types-requests.go rename to admin/handlers/types-requests.go index 63997461..62a37e4a 100644 --- a/admin/types-requests.go +++ b/admin/handlers/types-requests.go @@ -1,4 +1,4 @@ -package main +package handlers // LoginRequest to receive login credentials type LoginRequest struct { diff --git a/admin/types-templates.go b/admin/handlers/types-templates.go similarity index 98% rename from admin/types-templates.go rename to admin/handlers/types-templates.go index 6e931e96..cdba073c 100644 --- a/admin/types-templates.go +++ b/admin/handlers/types-templates.go @@ -1,13 +1,13 @@ -package main +package handlers import ( - "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/carves" "github.com/jmpsec/osctrl/environments" "github.com/jmpsec/osctrl/nodes" "github.com/jmpsec/osctrl/queries" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/types" + "github.com/jmpsec/osctrl/users" ) // LoginTemplateData for passing data to the login template @@ -77,7 +77,7 @@ type QueryRunTemplateData struct { Platforms []string UUIDs []string Hosts []string - Tables []OsqueryTable + Tables []types.OsqueryTable TablesVersion string Metadata TemplateMetadata } diff --git a/admin/handlers/utils.go b/admin/handlers/utils.go new file mode 100644 index 00000000..cf617be2 --- /dev/null +++ b/admin/handlers/utils.go @@ -0,0 +1,201 @@ +package handlers + +import ( + "bytes" + "crypto/md5" + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "log" + "net/http" + "strconv" + "strings" + + "github.com/jmpsec/osctrl/queries" + "github.com/jmpsec/osctrl/settings" + "github.com/jmpsec/osctrl/types" + "github.com/jmpsec/osctrl/utils" +) + +// Helper to handle admin error responses +func adminErrorResponse(w http.ResponseWriter, msg string, code int, err error) { + log.Printf("%s: %v", msg, err) + utils.HTTPResponse(w, utils.JSONApplicationUTF8, code, AdminResponse{Message: msg}) +} + +// Helper to handle admin ok responses +func adminOKResponse(w http.ResponseWriter, msg string) { + utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, AdminResponse{Message: msg}) +} + +// Helper to verify if a platform is valid +func checkValidPlatform(platforms []string, platform string) bool { + for _, p := range platforms { + if p == platform { + return true + } + } + return false +} + +// Helper to check if the CSRF token is valid +func checkCSRFToken(ctxToken, receivedToken string) bool { + return (strings.TrimSpace(ctxToken) == strings.TrimSpace(receivedToken)) +} + +// Helper to generate a random query name +func generateQueryName() string { + return "query_" + randomForNames() +} + +// Helper to generate a random carve name +func generateCarveName() string { + return "carve_" + randomForNames() +} + +// Helper to generate a random MD5 to be used with queries/carves +func randomForNames() string { + b := make([]byte, 32) + _, _ = rand.Read(b) + hasher := md5.New() + _, _ = hasher.Write([]byte(fmt.Sprintf("%x", b))) + return hex.EncodeToString(hasher.Sum(nil)) +} + +// Helper to generate the carve query +func generateCarveQuery(file string, glob bool) string { + if glob { + return "SELECT * FROM carves WHERE carve=1 AND path LIKE '" + file + "';" + } + return "SELECT * FROM carves WHERE carve=1 AND path = '" + file + "';" +} + +// Helper to determine if a query may be a carve +func newQueryReady(user, query string) queries.DistributedQuery { + if strings.Contains(query, "carve(") || strings.Contains(query, "carve=1") { + return queries.DistributedQuery{ + Query: query, + Name: generateCarveName(), + Creator: user, + Expected: 0, + Executions: 0, + Active: true, + Completed: false, + Deleted: false, + Type: queries.CarveQueryType, + Path: query, + } + } + return queries.DistributedQuery{ + Query: query, + Name: generateQueryName(), + Creator: user, + Expected: 0, + Executions: 0, + Active: true, + Completed: false, + Deleted: false, + Type: queries.StandardQueryType, + } +} + +// Helper to convert a string into integer +func stringToInteger(s string) int64 { + v, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return 0 + } + return v +} + +// Helper to convert a string into boolean +func stringToBoolean(s string) bool { + if s == "yes" || s == "true" || s == "1" { + return true + } + return false +} + +// Helper to remove duplicates from []string +func removeStringDuplicates(s []string) []string { + seen := make(map[string]struct{}, len(s)) + i := 0 + for _, v := range s { + if _, ok := seen[v]; ok { + continue + } + seen[v] = struct{}{} + s[i] = v + i++ + } + return s[:i] +} + +// Helper to verify the service is valid +func checkTargetService(service string) bool { + if service == settings.ServiceTLS { + return true + } + if service == settings.ServiceAdmin { + return true + } + if service == settings.ServiceAPI { + return true + } + return false +} + +// Helper to remove backslashes from text +func removeBackslash(rawString string) string { + return strings.Replace(rawString, "\\", " ", -1) +} + +// Helper to convert json.RawMessage into indented string +func jsonRawIndent(raw json.RawMessage) string { + var out bytes.Buffer + if err := json.Indent(&out, raw, "", " "); err != nil { + return string(raw) + } + return string(out.Bytes()) +} + +// Helper to convert from settings values to JSON configuration +func toJSONConfigurationService(values []settings.SettingValue) types.JSONConfigurationService { + var cfg types.JSONConfigurationService + for _, v := range values { + if v.Name == settings.JSONListener { + cfg.Listener = v.String + } + if v.Name == settings.JSONPort { + cfg.Port = v.String + } + if v.Name == settings.JSONHost { + cfg.Host = v.String + } + if v.Name == settings.JSONAuth { + cfg.Auth = v.String + } + if v.Name == settings.JSONLogging { + cfg.Logging = v.String + } + } + return cfg +} + +// Helper to generate a link to results for on-demand queries +func (h *HandlersAdmin) queryResultLink(name string) (string, string) { + defaultLink := strings.Replace(settings.QueryLink, "{{NAME}}", removeBackslash(name), 1) + dbLink := strings.Replace(h.Settings.QueryResultLink(), "{{NAME}}", removeBackslash(name), 1) + return defaultLink, dbLink +} + +// Helper to generate a link to results for status logs +func (h *HandlersAdmin) statusLogsLink(uuid string) string { + return strings.Replace(h.Settings.StatusLogsLink(), "{{UUID}}", removeBackslash(uuid), 1) +} + +// Helper to generate a link to results for result logs +func (h *HandlersAdmin) resultLogsLink(uuid string) string { + return strings.Replace(h.Settings.ResultLogsLink(), "{{UUID}}", removeBackslash(uuid), 1) +} diff --git a/admin/headers.go b/admin/headers.go index 81e2f603..d0ff508f 100644 --- a/admin/headers.go +++ b/admin/headers.go @@ -14,14 +14,12 @@ func loadHeaders(file string) (types.JSONConfigurationHeaders, error) { log.Printf("Loading %s", file) // Load file and read config viper.SetConfigFile(file) - err := viper.ReadInConfig() - if err != nil { + if err := viper.ReadInConfig(); err != nil { return cfg, err } // Header values headersRaw := viper.Sub(settings.AuthHeaders) - err = headersRaw.Unmarshal(&cfg) - if err != nil { + if err := headersRaw.Unmarshal(&cfg); err != nil { return cfg, err } // No errors! diff --git a/admin/jwt.go b/admin/jwt.go index 167e990b..13c28664 100644 --- a/admin/jwt.go +++ b/admin/jwt.go @@ -1,8 +1,12 @@ package main import ( + "crypto/rsa" + "crypto/tls" + "crypto/x509" "log" + "github.com/dgrijalva/jwt-go" "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/types" "github.com/spf13/viper" @@ -14,17 +18,36 @@ func loadJWTConfiguration(file string) (types.JSONConfigurationJWT, error) { log.Printf("Loading %s", file) // Load file and read config viper.SetConfigFile(file) - err := viper.ReadInConfig() - if err != nil { + if err := viper.ReadInConfig(); err != nil { return cfg, err } // JWT values headersRaw := viper.Sub(settings.AuthJWT) - err = headersRaw.Unmarshal(&cfg) - if err != nil { + if err := headersRaw.Unmarshal(&cfg); err != nil { return cfg, err } - // No errors! return cfg, nil } + +// Helper to parse JWT tokens because the SAML library is total garbage +func parseJWTFromCookie(keypair tls.Certificate, cookie string) (JWTData, error) { + type TokenClaims struct { + jwt.StandardClaims + Attributes map[string][]string `json:"attr"` + } + tokenClaims := TokenClaims{} + token, err := jwt.ParseWithClaims(cookie, &tokenClaims, func(t *jwt.Token) (interface{}, error) { + secretBlock := x509.MarshalPKCS1PrivateKey(keypair.PrivateKey.(*rsa.PrivateKey)) + return secretBlock, nil + }) + if err != nil || !token.Valid { + return JWTData{}, err + } + return JWTData{ + Subject: tokenClaims.Subject, + Email: tokenClaims.Attributes["mail"][0], + Display: tokenClaims.Attributes["displayName"][0], + Username: tokenClaims.Attributes["sAMAccountName"][0], + }, nil +} diff --git a/admin/main.go b/admin/main.go index e2e6ce14..0f083279 100644 --- a/admin/main.go +++ b/admin/main.go @@ -8,6 +8,11 @@ import ( "net/http" "time" + "github.com/crewjam/saml/samlsp" + "github.com/gorilla/mux" + "github.com/jinzhu/gorm" + ahandlers "github.com/jmpsec/osctrl/admin/handlers" + "github.com/jmpsec/osctrl/admin/sessions" "github.com/jmpsec/osctrl/backend" "github.com/jmpsec/osctrl/carves" "github.com/jmpsec/osctrl/environments" @@ -17,10 +22,6 @@ import ( "github.com/jmpsec/osctrl/settings" "github.com/jmpsec/osctrl/types" "github.com/jmpsec/osctrl/users" - - "github.com/crewjam/saml/samlsp" - "github.com/gorilla/mux" - "github.com/jinzhu/gorm" "github.com/spf13/viper" ) @@ -36,6 +37,10 @@ const ( serviceDescription string = "Admin service for osctrl" // Application description appDescription string = serviceDescription + ", a fast and efficient osquery management" +) + +// Paths +const ( // Default endpoint to handle HTTP health healthPath string = "/health" // Default endpoint to handle Login @@ -44,6 +49,12 @@ const ( errorPath string = "/error" // Default endpoint to handle Forbidden(403) errors forbiddenPath string = "/forbidden" + // Default endpoint for favicon + faviconPath string = "/favicon.ico" +) + +// Configuration +const ( // Default service configuration file configurationFile string = "config/" + settings.ServiceAdmin + ".json" // Default DB configuration file @@ -54,10 +65,10 @@ const ( jwtConfigurationFile string = "config/jwt.json" // Default Headers configuration file headersConfigurationFile string = "config/headers.json" - // osquery version to display tables - osqueryTablesVersion string = "4.2.0" - // JSON file with osquery tables data - osqueryTablesFile string = "data/" + osqueryTablesVersion + ".json" +) + +// Random +const ( // Static files folder staticFilesFolder string = "./static" // Carved files folder @@ -68,6 +79,14 @@ const ( defaultInactive int = -72 ) +// osquery +const ( + // osquery version to display tables + osqueryTablesVersion string = "4.2.0" + // JSON file with osquery tables data + osqueryTablesFile string = "data/" + osqueryTablesVersion + ".json" +) + var ( // Wait for backend in seconds backendWait = 7 * time.Second @@ -75,19 +94,20 @@ var ( // Global general variables var ( - adminConfig types.JSONConfigurationService - db *gorm.DB - settingsmgr *settings.Settings - nodesmgr *nodes.NodeManager - queriesmgr *queries.Queries - carvesmgr *carves.Carves - sessionsmgr *SessionManager - envs *environments.Environment - adminUsers *users.UserManager - sessionsTicker *time.Ticker + err error + adminConfig types.JSONConfigurationService + db *gorm.DB + settingsmgr *settings.Settings + nodesmgr *nodes.NodeManager + queriesmgr *queries.Queries + carvesmgr *carves.Carves + sessionsmgr *sessions.SessionManager + envs *environments.Environment + adminUsers *users.UserManager // FIXME this is nasty and should not be a global but here we are - osqueryTables []OsqueryTable - _metrics *metrics.Metrics + osqueryTables []types.OsqueryTable + adminMetrics *metrics.Metrics + handlersAdmin *ahandlers.HandlersAdmin ) // Variables for flags @@ -137,14 +157,12 @@ func loadConfiguration(file, service string) (types.JSONConfigurationService, er log.Printf("Loading %s", file) // Load file and read config viper.SetConfigFile(file) - err := viper.ReadInConfig() - if err != nil { + if err := viper.ReadInConfig(); err != nil { return cfg, err } // Admin values adminRaw := viper.Sub(service) - err = adminRaw.Unmarshal(&cfg) - if err != nil { + if err := adminRaw.Unmarshal(&cfg); err != nil { return cfg, err } // Check if values are valid @@ -154,14 +172,12 @@ func loadConfiguration(file, service string) (types.JSONConfigurationService, er if !validLogging[cfg.Logging] { return cfg, fmt.Errorf("Invalid logging method") } - // No errors! return cfg, nil } // Initialization code func init() { - var err error // Command line flags flag.Usage = adminUsage // Define flags @@ -236,11 +252,11 @@ func main() { } }() // Automigrate tables - if err := automigrateDB(); err != nil { - log.Fatalf("Failed to AutoMigrate: %v", err) - } + //if err := automigrateDB(); err != nil { + // log.Fatalf("Failed to AutoMigrate: %v", err) + //} // Initialize users - adminUsers = users.CreateUserManager(db) + adminUsers = users.CreateUserManager(db, &jwtConfig) // Initialize environment envs = environments.CreateEnvironment(db) // Initialize settings @@ -252,10 +268,18 @@ func main() { // Initialize carves carvesmgr = carves.CreateFileCarves(db) // Initialize sessions - sessionsmgr = CreateSessionManager(db) + sessionsmgr = sessions.CreateSessionManager(db, projectName) // Initialize service settings log.Println("Loading service settings") - loadingSettings() + if err := loadingSettings(settingsmgr); err != nil { + log.Fatalf("Error loading settings - %v", err) + } + // Initialize metrics + log.Println("Loading service metrics") + adminMetrics, err = loadingMetrics(settingsmgr) + if err != nil { + log.Fatalf("Error loading metrics - %v", err) + } // Start SAML Middleware if we are using SAML if adminConfig.Auth == settings.AuthSAML { @@ -280,10 +304,42 @@ func main() { } } + // FIXME Redis cache - Ticker to cleanup sessions + // FIXME splay this? + go func() { + _t := settingsmgr.CleanupSessions() + if _t == 0 { + _t = int64(defaultRefresh) + } + for { + if settingsmgr.DebugService(settings.ServiceAdmin) { + log.Println("DebugService: Cleaning up sessions") + } + sessionsmgr.Cleanup() + time.Sleep(time.Duration(_t) * time.Second) + } + }() + + // Initialize Admin handlers before router + handlersAdmin = ahandlers.CreateHandlersAdmin( + ahandlers.WithDB(db), + ahandlers.WithEnvs(envs), + ahandlers.WithUsers(adminUsers), + ahandlers.WithNodes(nodesmgr), + ahandlers.WithQueries(queriesmgr), + ahandlers.WithCarves(carvesmgr), + ahandlers.WithSettings(settingsmgr), + ahandlers.WithMetrics(adminMetrics), + ahandlers.WithSessions(sessionsmgr), + ahandlers.WithVersion(serviceVersion), + ahandlers.WithOsqueryTables(osqueryTables), + ahandlers.WithAdminConfig(&adminConfig), + ) + + //////////////////////////// ADMIN if settingsmgr.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Creating router") } - // Create router for admin routerAdmin := mux.NewRouter() @@ -291,21 +347,20 @@ func main() { if settingsmgr.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Unauthenticated content") } - // Admin: login only if local auth is enabled if adminConfig.Auth != settings.AuthNone { // login - routerAdmin.HandleFunc(loginPath, loginGETHandler).Methods("GET") - routerAdmin.HandleFunc(loginPath, loginPOSTHandler).Methods("POST") + routerAdmin.HandleFunc(loginPath, handlersAdmin.LoginHandler).Methods("GET") + routerAdmin.HandleFunc(loginPath, handlersAdmin.LoginPOSTHandler).Methods("POST") } // Admin: health of service - routerAdmin.HandleFunc(healthPath, healthHTTPHandler).Methods("GET") + routerAdmin.HandleFunc(healthPath, handlersAdmin.HealthHandler).Methods("GET") // Admin: error - routerAdmin.HandleFunc(errorPath, errorHTTPHandler).Methods("GET") + routerAdmin.HandleFunc(errorPath, handlersAdmin.ErrorHandler).Methods("GET") // Admin: forbidden - routerAdmin.HandleFunc(forbiddenPath, forbiddenHTTPHandler).Methods("GET") + routerAdmin.HandleFunc(forbiddenPath, handlersAdmin.ForbiddenHandler).Methods("GET") // Admin: favicon - routerAdmin.HandleFunc("/favicon.ico", faviconHandler) + routerAdmin.HandleFunc(faviconPath, handlersAdmin.FaviconHandler) // Admin: static routerAdmin.PathPrefix("/static/").Handler( http.StripPrefix("/static", http.FileServer(http.Dir(staticFilesFolder)))) @@ -314,106 +369,82 @@ func main() { if settingsmgr.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Authenticated content") } - // Admin: JSON data for environments - routerAdmin.Handle("/json/environment/{environment}/{target}", handlerAuthCheck(http.HandlerFunc(jsonEnvironmentHandler))).Methods("GET") + routerAdmin.Handle("/json/environment/{environment}/{target}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONEnvironmentHandler))).Methods("GET") // Admin: JSON data for platforms - routerAdmin.Handle("/json/platform/{platform}/{target}", handlerAuthCheck(http.HandlerFunc(jsonPlatformHandler))).Methods("GET") + routerAdmin.Handle("/json/platform/{platform}/{target}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONPlatformHandler))).Methods("GET") // Admin: JSON data for logs - routerAdmin.Handle("/json/logs/{type}/{environment}/{uuid}", handlerAuthCheck(http.HandlerFunc(jsonLogsHandler))).Methods("GET") + routerAdmin.Handle("/json/logs/{type}/{environment}/{uuid}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONLogsHandler))).Methods("GET") // Admin: JSON data for query logs - routerAdmin.Handle("/json/query/{name}", handlerAuthCheck(http.HandlerFunc(jsonQueryLogsHandler))).Methods("GET") + routerAdmin.Handle("/json/query/{name}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONQueryLogsHandler))).Methods("GET") // Admin: JSON data for sidebar stats - routerAdmin.Handle("/json/stats/{target}/{name}", handlerAuthCheck(http.HandlerFunc(jsonStatsHandler))).Methods("GET") + routerAdmin.Handle("/json/stats/{target}/{name}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONStatsHandler))).Methods("GET") // Admin: table for environments - routerAdmin.Handle("/environment/{environment}/{target}", handlerAuthCheck(http.HandlerFunc(environmentHandler))).Methods("GET") + routerAdmin.Handle("/environment/{environment}/{target}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.EnvironmentHandler))).Methods("GET") // Admin: table for platforms - routerAdmin.Handle("/platform/{platform}/{target}", handlerAuthCheck(http.HandlerFunc(platformHandler))).Methods("GET") + routerAdmin.Handle("/platform/{platform}/{target}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.PlatformHandler))).Methods("GET") // Admin: dashboard //routerAdmin.HandleFunc("/dashboard", dashboardHandler).Methods("GET") - routerAdmin.Handle("/dashboard", handlerAuthCheck(http.HandlerFunc(rootHandler))).Methods("GET") + routerAdmin.Handle("/dashboard", handlerAuthCheck(http.HandlerFunc(handlersAdmin.RootHandler))).Methods("GET") // Admin: root - routerAdmin.Handle("/", handlerAuthCheck(http.HandlerFunc(rootHandler))).Methods("GET") + routerAdmin.Handle("/", handlerAuthCheck(http.HandlerFunc(handlersAdmin.RootHandler))).Methods("GET") // Admin: node view - routerAdmin.Handle("/node/{uuid}", handlerAuthCheck(http.HandlerFunc(nodeHandler))).Methods("GET") + routerAdmin.Handle("/node/{uuid}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.NodeHandler))).Methods("GET") // Admin: multi node action - routerAdmin.Handle("/node/actions", handlerAuthCheck(http.HandlerFunc(nodeActionsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/node/actions", handlerAuthCheck(http.HandlerFunc(handlersAdmin.NodeActionsPOSTHandler))).Methods("POST") // Admin: run queries - routerAdmin.Handle("/query/run", handlerAuthCheck(http.HandlerFunc(queryRunGETHandler))).Methods("GET") - routerAdmin.Handle("/query/run", handlerAuthCheck(http.HandlerFunc(queryRunPOSTHandler))).Methods("POST") + routerAdmin.Handle("/query/run", handlerAuthCheck(http.HandlerFunc(handlersAdmin.QueryRunGETHandler))).Methods("GET") + routerAdmin.Handle("/query/run", handlerAuthCheck(http.HandlerFunc(handlersAdmin.QueryRunPOSTHandler))).Methods("POST") // Admin: list queries - routerAdmin.Handle("/query/list", handlerAuthCheck(http.HandlerFunc(queryListGETHandler))).Methods("GET") + routerAdmin.Handle("/query/list", handlerAuthCheck(http.HandlerFunc(handlersAdmin.QueryListGETHandler))).Methods("GET") // Admin: query actions - routerAdmin.Handle("/query/actions", handlerAuthCheck(http.HandlerFunc(queryActionsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/query/actions", handlerAuthCheck(http.HandlerFunc(handlersAdmin.QueryActionsPOSTHandler))).Methods("POST") // Admin: query JSON - routerAdmin.Handle("/query/json/{target}", handlerAuthCheck(http.HandlerFunc(jsonQueryHandler))).Methods("GET") + routerAdmin.Handle("/query/json/{target}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONQueryHandler))).Methods("GET") // Admin: query logs - routerAdmin.Handle("/query/logs/{name}", handlerAuthCheck(http.HandlerFunc(queryLogsHandler))).Methods("GET") + routerAdmin.Handle("/query/logs/{name}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.QueryLogsHandler))).Methods("GET") // Admin: carve files - routerAdmin.Handle("/carves/run", handlerAuthCheck(http.HandlerFunc(carvesRunGETHandler))).Methods("GET") - routerAdmin.Handle("/carves/run", handlerAuthCheck(http.HandlerFunc(carvesRunPOSTHandler))).Methods("POST") + routerAdmin.Handle("/carves/run", handlerAuthCheck(http.HandlerFunc(handlersAdmin.CarvesRunGETHandler))).Methods("GET") + routerAdmin.Handle("/carves/run", handlerAuthCheck(http.HandlerFunc(handlersAdmin.CarvesRunPOSTHandler))).Methods("POST") // Admin: list carves - routerAdmin.Handle("/carves/list", handlerAuthCheck(http.HandlerFunc(carvesListGETHandler))).Methods("GET") + routerAdmin.Handle("/carves/list", handlerAuthCheck(http.HandlerFunc(handlersAdmin.CarvesListGETHandler))).Methods("GET") // Admin: carves actions - routerAdmin.Handle("/carves/actions", handlerAuthCheck(http.HandlerFunc(carvesActionsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/carves/actions", handlerAuthCheck(http.HandlerFunc(handlersAdmin.CarvesActionsPOSTHandler))).Methods("POST") // Admin: carves JSON - routerAdmin.Handle("/carves/json/{target}", handlerAuthCheck(http.HandlerFunc(jsonCarvesHandler))).Methods("GET") + routerAdmin.Handle("/carves/json/{target}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.JSONCarvesHandler))).Methods("GET") // Admin: carves details - routerAdmin.Handle("/carves/details/{name}", handlerAuthCheck(http.HandlerFunc(carvesDetailsHandler))).Methods("GET") + routerAdmin.Handle("/carves/details/{name}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.CarvesDetailsHandler))).Methods("GET") // Admin: carves download - routerAdmin.Handle("/carves/download/{sessionid}", handlerAuthCheck(http.HandlerFunc(carvesDownloadHandler))).Methods("GET") + routerAdmin.Handle("/carves/download/{sessionid}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.CarvesDownloadHandler))).Methods("GET") // Admin: nodes configuration - routerAdmin.Handle("/conf/{environment}", handlerAuthCheck(http.HandlerFunc(confGETHandler))).Methods("GET") - routerAdmin.Handle("/conf/{environment}", handlerAuthCheck(http.HandlerFunc(confPOSTHandler))).Methods("POST") - routerAdmin.Handle("/intervals/{environment}", handlerAuthCheck(http.HandlerFunc(intervalsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/conf/{environment}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.ConfGETHandler))).Methods("GET") + routerAdmin.Handle("/conf/{environment}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.ConfPOSTHandler))).Methods("POST") + routerAdmin.Handle("/intervals/{environment}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.IntervalsPOSTHandler))).Methods("POST") // Admin: nodes enroll - routerAdmin.Handle("/enroll/{environment}", handlerAuthCheck(http.HandlerFunc(enrollGETHandler))).Methods("GET") - routerAdmin.Handle("/enroll/{environment}", handlerAuthCheck(http.HandlerFunc(enrollPOSTHandler))).Methods("POST") - routerAdmin.Handle("/expiration/{environment}", handlerAuthCheck(http.HandlerFunc(expirationPOSTHandler))).Methods("POST") + routerAdmin.Handle("/enroll/{environment}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.EnrollGETHandler))).Methods("GET") + routerAdmin.Handle("/enroll/{environment}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.EnrollPOSTHandler))).Methods("POST") + routerAdmin.Handle("/expiration/{environment}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.ExpirationPOSTHandler))).Methods("POST") // Admin: server settings - routerAdmin.Handle("/settings/{service}", handlerAuthCheck(http.HandlerFunc(settingsGETHandler))).Methods("GET") - routerAdmin.Handle("/settings/{service}", handlerAuthCheck(http.HandlerFunc(settingsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/settings/{service}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.SettingsGETHandler))).Methods("GET") + routerAdmin.Handle("/settings/{service}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.SettingsPOSTHandler))).Methods("POST") // Admin: manage environments - routerAdmin.Handle("/environments", handlerAuthCheck(http.HandlerFunc(envsGETHandler))).Methods("GET") - routerAdmin.Handle("/environments", handlerAuthCheck(http.HandlerFunc(envsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/environments", handlerAuthCheck(http.HandlerFunc(handlersAdmin.EnvsGETHandler))).Methods("GET") + routerAdmin.Handle("/environments", handlerAuthCheck(http.HandlerFunc(handlersAdmin.EnvsPOSTHandler))).Methods("POST") // Admin: manage users - routerAdmin.Handle("/users", handlerAuthCheck(http.HandlerFunc(usersGETHandler))).Methods("GET") - routerAdmin.Handle("/users", handlerAuthCheck(http.HandlerFunc(usersPOSTHandler))).Methods("POST") - routerAdmin.Handle("/users/permissions/{username}", handlerAuthCheck(http.HandlerFunc(permissionsGETHandler))).Methods("GET") - routerAdmin.Handle("/users/permissions/{username}", handlerAuthCheck(http.HandlerFunc(permissionsPOSTHandler))).Methods("POST") + routerAdmin.Handle("/users", handlerAuthCheck(http.HandlerFunc(handlersAdmin.UsersGETHandler))).Methods("GET") + routerAdmin.Handle("/users", handlerAuthCheck(http.HandlerFunc(handlersAdmin.UsersPOSTHandler))).Methods("POST") + routerAdmin.Handle("/users/permissions/{username}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.PermissionsGETHandler))).Methods("GET") + routerAdmin.Handle("/users/permissions/{username}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.PermissionsPOSTHandler))).Methods("POST") // Admin: manage tokens - routerAdmin.Handle("/tokens/{username}", handlerAuthCheck(http.HandlerFunc(tokensGETHandler))).Methods("GET") - routerAdmin.Handle("/tokens/{username}/refresh", handlerAuthCheck(http.HandlerFunc(tokensPOSTHandler))).Methods("POST") + routerAdmin.Handle("/tokens/{username}", handlerAuthCheck(http.HandlerFunc(handlersAdmin.TokensGETHandler))).Methods("GET") + routerAdmin.Handle("/tokens/{username}/refresh", handlerAuthCheck(http.HandlerFunc(handlersAdmin.TokensPOSTHandler))).Methods("POST") // logout - routerAdmin.Handle("/logout", handlerAuthCheck(http.HandlerFunc(logoutPOSTHandler))).Methods("POST") - + routerAdmin.Handle("/logout", handlerAuthCheck(http.HandlerFunc(handlersAdmin.LogoutPOSTHandler))).Methods("POST") // SAML ACS if adminConfig.Auth == settings.AuthSAML { routerAdmin.PathPrefix("/saml/").Handler(samlMiddleware) } - // FIXME Redis cache - Ticker to cleanup sessions - // FIXME splay this? - if settingsmgr.DebugService(settings.ServiceAdmin) { - log.Println("DebugService: Sessions ticker") - } - go func() { - _t := settingsmgr.CleanupSessions() - if _t == 0 { - _t = int64(defaultRefresh) - } - sessionsTicker = time.NewTicker(time.Duration(_t) * time.Second) - for { - select { - case <-sessionsTicker.C: - if settingsmgr.DebugService(settings.ServiceAdmin) { - log.Println("DebugService: Cleaning up sessions") - } - go sessionsmgr.Cleanup() - } - } - }() - // multiple listeners channel finish := make(chan bool) diff --git a/admin/saml.go b/admin/saml.go index 40bedd21..f0267fe2 100644 --- a/admin/saml.go +++ b/admin/saml.go @@ -37,17 +37,14 @@ func loadSAML(file string) (JSONConfigurationSAML, error) { log.Printf("Loading %s", file) // Load file and read config viper.SetConfigFile(file) - err := viper.ReadInConfig() - if err != nil { + if err := viper.ReadInConfig(); err != nil { return cfg, err } // SAML values samlRaw := viper.Sub(settings.AuthSAML) - err = samlRaw.Unmarshal(&cfg) - if err != nil { + if err := samlRaw.Unmarshal(&cfg); err != nil { return cfg, err } - // No errors! return cfg, nil } diff --git a/admin/sessions/go.mod b/admin/sessions/go.mod new file mode 100644 index 00000000..8d9be428 --- /dev/null +++ b/admin/sessions/go.mod @@ -0,0 +1,3 @@ +module github.com/jmpsec/osctrl/admin/sessions + +go 1.12 diff --git a/admin/sessions.go b/admin/sessions/sessions.go similarity index 65% rename from admin/sessions.go rename to admin/sessions/sessions.go index 284f1acd..ca1e1a26 100644 --- a/admin/sessions.go +++ b/admin/sessions/sessions.go @@ -1,9 +1,11 @@ -package main +package sessions import ( + "crypto/rand" "fmt" "log" "net/http" + "strings" "time" "github.com/gorilla/securecookie" @@ -19,23 +21,37 @@ const defaultMaxAge int = 60 * 60 * 2 // 2 hours const defaultPath string = "/" const defaultHTTPOnly bool = true const defaultSecure bool = true -const defaultCookieName string = projectName // SessionManager represent a session's store structure type SessionManager struct { - db *gorm.DB - Codecs []securecookie.Codec - Options *sessions.Options + db *gorm.DB + Codecs []securecookie.Codec + Options *sessions.Options + CookieName string } +const ( + AdminLevel string = "admin" + UserLevel string = "user" + QueryLevel string = "query" + CarveLevel string = "carve" +) + +const ( + CtxUser = "user" + CtxEmail = "email" + CtxCSRF = "csrftoken" + CtxLevel = "level" +) + // sessionValues to keep session values -type sessionValues map[interface{}]interface{} +type SessionValues map[interface{}]interface{} // contextValue to hold session data in the context -type contextValue map[string]string +type ContextValue map[string]string // contextKey to help with the context key, to pass session data -type contextKey string +type ContextKey string // UserSession as abstraction of a session type UserSession struct { @@ -45,11 +61,11 @@ type UserSession struct { UserAgent string ExpiresAt time.Time Cookie string `gorm:"index"` - Values sessionValues `gorm:"-"` + Values SessionValues `gorm:"-"` } // CreateSessionManager creates a new session store in the DB and initialize the tables -func CreateSessionManager(db *gorm.DB) *SessionManager { +func CreateSessionManager(db *gorm.DB, name string) *SessionManager { storeKey := securecookie.GenerateRandomKey(sessionIDLen) st := &SessionManager{ db: db, @@ -60,6 +76,7 @@ func CreateSessionManager(db *gorm.DB) *SessionManager { Secure: defaultSecure, HttpOnly: defaultHTTPOnly, }, + CookieName: name, } // table user_sessions if err := db.AutoMigrate(&UserSession{}).Error; err != nil { @@ -70,7 +87,7 @@ func CreateSessionManager(db *gorm.DB) *SessionManager { // CheckAuth to verify if a session exists/is valid func (sm *SessionManager) CheckAuth(r *http.Request) (bool, UserSession) { - cookie, err := r.Cookie(defaultCookieName) + cookie, err := r.Cookie(sm.CookieName) if err != nil { return false, UserSession{} } @@ -87,7 +104,7 @@ func (sm *SessionManager) Get(cookie string) (UserSession, error) { if err := sm.db.Where("cookie = ?", cookie).Where("expires_at > ?", gorm.NowFunc()).First(&s).Error; err != nil { return s, err } - if err := securecookie.DecodeMulti(defaultCookieName, cookie, &s.Values, sm.Codecs...); err != nil { + if err := securecookie.DecodeMulti(sm.CookieName, cookie, &s.Values, sm.Codecs...); err != nil { return s, err } return s, nil @@ -101,7 +118,7 @@ func (sm *SessionManager) GetByUsername(username string) ([]UserSession, error) } var sessionsFinal []UserSession for _, s := range sessionsRaw { - if err := securecookie.DecodeMulti(defaultCookieName, s.Cookie, &s.Values, sm.Codecs...); err != nil { + if err := securecookie.DecodeMulti(sm.CookieName, s.Cookie, &s.Values, sm.Codecs...); err != nil { return sessionsFinal, err } sessionsFinal = append(sessionsFinal, s) @@ -117,13 +134,13 @@ func (sm *SessionManager) New(r *http.Request, username, level string) (UserSess UserAgent: r.Header.Get("User-Agent"), ExpiresAt: time.Now().Add(time.Duration(defaultMaxAge) * time.Second), } - values := make(sessionValues) + values := make(SessionValues) values["auth"] = true - values[ctxLevel] = level - values[ctxUser] = username - values[ctxCSRF] = generateCSRF() + values[CtxLevel] = level + values[CtxUser] = username + values[CtxCSRF] = GenerateCSRF() session.Values = values - cookie, err := securecookie.EncodeMulti(defaultCookieName, session.Values, sm.Codecs...) + cookie, err := securecookie.EncodeMulti(sm.CookieName, session.Values, sm.Codecs...) if err != nil { return UserSession{}, err } @@ -140,7 +157,7 @@ func (sm *SessionManager) New(r *http.Request, username, level string) (UserSess // Destroy session expires it and it will be cleaned up func (sm *SessionManager) Destroy(r *http.Request) error { - if cookie, err := r.Cookie(defaultCookieName); err == nil { + if cookie, err := r.Cookie(sm.CookieName); err == nil { s, err := sm.Get(cookie.Value) if err != nil { return err @@ -153,17 +170,17 @@ func (sm *SessionManager) Destroy(r *http.Request) error { } // Save session and set cookie header -func (sm *SessionManager) Save(r *http.Request, w http.ResponseWriter, user users.AdminUser) (UserSession, error) { +func (sm *SessionManager) Save(r *http.Request, w http.ResponseWriter, user users.AdminUser, perms users.UserPermissions) (UserSession, error) { var s UserSession - if cookie, err := r.Cookie(defaultCookieName); err != nil { - s, err = sm.New(r, user.Username, levelPermissions(user)) + if cookie, err := r.Cookie(sm.CookieName); err != nil { + s, err = sm.New(r, user.Username, LevelPermissions(user, perms)) if err != nil { return s, err } } else { s, err = sm.Get(cookie.Value) if err != nil { - s, err = sm.New(r, user.Username, levelPermissions(user)) + s, err = sm.New(r, user.Username, LevelPermissions(user, perms)) if err != nil { return s, err } @@ -172,7 +189,7 @@ func (sm *SessionManager) Save(r *http.Request, w http.ResponseWriter, user user return s, fmt.Errorf("Invalid user session (%s)", s.Username) } } - http.SetCookie(w, sessions.NewCookie(defaultCookieName, s.Cookie, sm.Options)) + http.SetCookie(w, sessions.NewCookie(sm.CookieName, s.Cookie, sm.Options)) return s, nil } @@ -181,3 +198,32 @@ func (sm *SessionManager) Save(r *http.Request, w http.ResponseWriter, user user func (sm *SessionManager) Cleanup() { sm.db.Delete(&UserSession{}, "expires_at <= ?", gorm.NowFunc()) } + +// Function to generate a secure CSRF token +func GenerateCSRF() string { + b := make([]byte, 16) + _, _ = rand.Read(b) + return fmt.Sprintf("%x", b) +} + +// Helper to convert permissions for a user to a level for context +func LevelPermissions(user users.AdminUser, perms users.UserPermissions) string { + if user.Admin { + return AdminLevel + } + // Check for query access + if perms.Query { + return QueryLevel + } + // Check for carve access + if perms.Carve { + return CarveLevel + } + // At this point, no access granted + return UserLevel +} + +// Helper to check if the CSRF token is valid +func CheckCSRFToken(ctxToken, receivedToken string) bool { + return (strings.TrimSpace(ctxToken) == strings.TrimSpace(receivedToken)) +} diff --git a/admin/settings.go b/admin/settings.go index 6e52a90f..586990c4 100644 --- a/admin/settings.go +++ b/admin/settings.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "log" "github.com/jmpsec/osctrl/metrics" @@ -8,95 +9,98 @@ import ( ) // Function to load the metrics settings -func loadingMetrics() { +func loadingMetrics(mgr *settings.Settings) (*metrics.Metrics, error) { // Check if service settings for metrics is ready, initialize if so - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.ServiceMetrics) { - if err := settingsmgr.NewBooleanValue(settings.ServiceAdmin, settings.ServiceMetrics, false); err != nil { - log.Printf("Failed to add %s to configuration: %v", settings.ServiceMetrics, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.ServiceMetrics) { + if err := mgr.NewBooleanValue(settings.ServiceAdmin, settings.ServiceMetrics, false); err != nil { + return nil, fmt.Errorf("Failed to add %s to configuration: %v", settings.ServiceMetrics, err) } - } else if settingsmgr.ServiceMetrics(settings.ServiceAdmin) { + } + if mgr.ServiceMetrics(settings.ServiceAdmin) { _mCfg, err := metrics.LoadConfiguration() if err != nil { - if err := settingsmgr.SetBoolean(false, settings.ServiceAdmin, settings.ServiceMetrics); err != nil { - log.Fatalf("Failed to disable metrics: %v", err) + if err := mgr.SetBoolean(false, settings.ServiceAdmin, settings.ServiceMetrics); err != nil { + return nil, fmt.Errorf("Failed to disable metrics: %v", err) } - log.Printf("Failed to initialize metrics: %v", err) - } else { - _metrics, err = metrics.CreateMetrics(_mCfg.Protocol, _mCfg.Host, _mCfg.Port, serviceName) - if err != nil { - log.Fatalf("Failed to initialize metrics: %v", err) - if err := settingsmgr.SetBoolean(false, settings.ServiceAdmin, settings.ServiceMetrics); err != nil { - log.Fatalf("Failed to disable metrics: %v", err) - } + return nil, fmt.Errorf("Failed to initialize metrics: %v", err) + } + _m, err := metrics.CreateMetrics(_mCfg.Protocol, _mCfg.Host, _mCfg.Port, serviceName) + if err != nil { + return nil, fmt.Errorf("Failed to initialize metrics: %v", err) + if err := mgr.SetBoolean(false, settings.ServiceAdmin, settings.ServiceMetrics); err != nil { + return nil, fmt.Errorf("Failed to disable metrics: %v", err) } } + return _m, nil } + return nil, nil } // Function to load the logging settings -func loadingLogging() { +func loadingLoggingSettings(mgr *settings.Settings) error { // Check if logging settings for query results link is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.QueryResultLink) { - if err := settingsmgr.NewStringValue(settings.ServiceAdmin, settings.QueryResultLink, settings.QueryLink); err != nil { - log.Fatalf("Failed to add %s to settings: %v", settings.QueryResultLink, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.QueryResultLink) { + if err := mgr.NewStringValue(settings.ServiceAdmin, settings.QueryResultLink, settings.QueryLink); err != nil { + return fmt.Errorf("Failed to add %s to settings: %v", settings.QueryResultLink, err) } } // Check if logging settings for status logs link is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.StatusLogsLink) { - if err := settingsmgr.NewStringValue(settings.ServiceAdmin, settings.StatusLogsLink, settings.StatusLink); err != nil { - log.Fatalf("Failed to add %s to settings: %v", settings.DebugHTTP, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.StatusLogsLink) { + if err := mgr.NewStringValue(settings.ServiceAdmin, settings.StatusLogsLink, settings.StatusLink); err != nil { + return fmt.Errorf("Failed to add %s to settings: %v", settings.DebugHTTP, err) } } // Check if logging settings for result logs link is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.ResultLogsLink) { - if err := settingsmgr.NewStringValue(settings.ServiceAdmin, settings.ResultLogsLink, settings.ResultsLink); err != nil { - log.Fatalf("Failed to add %s to settings: %v", settings.DebugHTTP, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.ResultLogsLink) { + if err := mgr.NewStringValue(settings.ServiceAdmin, settings.ResultLogsLink, settings.ResultsLink); err != nil { + return fmt.Errorf("Failed to add %s to settings: %v", settings.DebugHTTP, err) } } + return err } // Function to load all settings for the service -func loadingSettings() { +func loadingSettings(mgr *settings.Settings) error { // Check if service settings for debug service is ready - if settingsmgr.DebugService(settings.ServiceAdmin) { + if mgr.DebugService(settings.ServiceAdmin) { log.Println("DebugService: Initializing settings") } // Check if service settings for debug service is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.DebugService) { - if err := settingsmgr.NewBooleanValue(settings.ServiceAdmin, settings.DebugService, false); err != nil { - log.Fatalf("Failed to add %s to settings: %v", settings.DebugService, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.DebugService) { + if err := mgr.NewBooleanValue(settings.ServiceAdmin, settings.DebugService, false); err != nil { + return fmt.Errorf("Failed to add %s to settings: %v", settings.DebugService, err) } } // Check if service settings for debug HTTP is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.DebugHTTP) { - if err := settingsmgr.NewBooleanValue(settings.ServiceAdmin, settings.DebugHTTP, false); err != nil { - log.Fatalf("Failed to add %s to settings: %v", settings.DebugHTTP, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.DebugHTTP) { + if err := mgr.NewBooleanValue(settings.ServiceAdmin, settings.DebugHTTP, false); err != nil { + return fmt.Errorf("Failed to add %s to settings: %v", settings.DebugHTTP, err) } } // Check if service settings for default environment is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.DefaultEnv) { - if err := settingsmgr.NewStringValue(settings.ServiceAdmin, settings.DefaultEnv, "dev"); err != nil { - log.Fatalf("Failed to add %s to settings: %v", settings.DefaultEnv, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.DefaultEnv) { + if err := mgr.NewStringValue(settings.ServiceAdmin, settings.DefaultEnv, "dev"); err != nil { + return fmt.Errorf("Failed to add %s to settings: %v", settings.DefaultEnv, err) } } // Check if service settings for sessions cleanup is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.CleanupSessions) { - if err := settingsmgr.NewIntegerValue(settings.ServiceAdmin, settings.CleanupSessions, int64(defaultRefresh)); err != nil { - log.Fatalf("Failed to add %s to configuration: %v", settings.CleanupSessions, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.CleanupSessions) { + if err := mgr.NewIntegerValue(settings.ServiceAdmin, settings.CleanupSessions, int64(defaultRefresh)); err != nil { + return fmt.Errorf("Failed to add %s to configuration: %v", settings.CleanupSessions, err) } } // Check if service settings for node inactive hours is ready - if !settingsmgr.IsValue(settings.ServiceAdmin, settings.InactiveHours) { - if err := settingsmgr.NewIntegerValue(settings.ServiceAdmin, settings.InactiveHours, int64(defaultInactive)); err != nil { - log.Fatalf("Failed to add %s to configuration: %v", settings.InactiveHours, err) + if !mgr.IsValue(settings.ServiceAdmin, settings.InactiveHours) { + if err := mgr.NewIntegerValue(settings.ServiceAdmin, settings.InactiveHours, int64(defaultInactive)); err != nil { + return fmt.Errorf("Failed to add %s to configuration: %v", settings.InactiveHours, err) } } - // Metrics - loadingMetrics() - // Logging - loadingLogging() + if err := loadingLoggingSettings(mgr); err != nil { + return fmt.Errorf("Failed to load logging settings: %v", err) + } // Write JSON config to settings - if err := settingsmgr.SetAllJSON(settings.ServiceAdmin, adminConfig.Listener, adminConfig.Port, adminConfig.Host, adminConfig.Auth, adminConfig.Logging); err != nil { - log.Fatalf("Failed to add JSON values to configuration: %v", err) + if err := mgr.SetAllJSON(settings.ServiceAdmin, adminConfig.Listener, adminConfig.Port, adminConfig.Host, adminConfig.Auth, adminConfig.Logging); err != nil { + return fmt.Errorf("Failed to add JSON values to configuration: %v", err) } + return nil } diff --git a/admin/templates/carves-details.html b/admin/templates/carves-details.html index 951c997c..1b1b02db 100644 --- a/admin/templates/carves-details.html +++ b/admin/templates/carves-details.html @@ -85,13 +85,13 @@