Skip to content

Commit

Permalink
Lots of changes in metrics and SAML
Browse files Browse the repository at this point in the history
  • Loading branch information
javuto committed Sep 9, 2019
1 parent 9937073 commit e1d177f
Show file tree
Hide file tree
Showing 16 changed files with 334 additions and 88 deletions.
50 changes: 49 additions & 1 deletion cmd/admin/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,55 @@ func handlerAuthCheck(h http.Handler) http.Handler {
// Access granted
h.ServeHTTP(w, r.WithContext(ctx))
case settings.AuthSAML:
samlMiddleware.RequireAccount(h).ServeHTTP(w, r)
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, forbiddenPath, http.StatusFound)
return
}
jwtdata, err := parseJWTFromCookie(samlData.KeyPair, cookiev.Value)
if err != nil {
log.Printf("error parsing JWT: %v", err)
http.Redirect(w, r, forbiddenPath, http.StatusFound)
return
}
// Check if user is already authenticated
authenticated, session := sessionsmgr.CheckAuth(r)
if !authenticated {
// Create user if it does not exist
if !adminUsers.Exists(jwtdata.Username) {
log.Printf("user not found: %s", jwtdata.Username)
http.Redirect(w, r, forbiddenPath, http.StatusFound)
return
}
u, err := adminUsers.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 = sessionsmgr.Save(r, w, u)
if err != nil {
log.Printf("session error: %v", err)
}
}
// Update metadata for the user
err = adminUsers.UpdateMetadata(session.IPAddress, session.UserAgent, session.Username)
if err != nil {
log.Printf("error updating metadata for user %s: %v", session.Username, err)
}
// Set middleware values
s := make(contextValue)
s["user"] = session.Username
s["csrftoken"] = session.Values["csrftoken"].(string)
ctx := context.WithValue(r.Context(), contextKey("session"), s)
// Access granted
samlMiddleware.RequireAccount(h).ServeHTTP(w, r.WithContext(ctx))
} else {
samlMiddleware.RequireAccount(h).ServeHTTP(w, r)
}
case settings.AuthHeaders:
// Access always granted
h.ServeHTTP(w, r)
Expand Down
2 changes: 1 addition & 1 deletion cmd/admin/handlers-post.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func loginPOSTHandler(w http.ResponseWriter, r *http.Request) {
} else {
// Check credentials
if access, user := adminUsers.CheckLoginCredentials(l.Username, l.Password); access {
err = sessionsmgr.Save(r, w, user)
_, err = sessionsmgr.Save(r, w, user)
if err != nil {
responseMessage = "session error"
responseCode = http.StatusForbidden
Expand Down
8 changes: 8 additions & 0 deletions cmd/admin/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func errorHTTPHandler(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]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
w.WriteHeader(http.StatusForbidden)
_, _ = w.Write([]byte("❌"))
}

// Handler for the favicon
func faviconHandler(w http.ResponseWriter, r *http.Request) {
utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAdmin), false)
Expand Down
19 changes: 19 additions & 0 deletions cmd/admin/json-carves.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ type CarveJSON struct {
Created CreationTimes `json:"created"`
Status string `json:"status"`
Progress CarveProgress `json:"progress"`
Targets []CarveTarget `json:"targets"`
}

// CarveTarget to be returned with the JSON data for a carve
type CarveTarget struct {
Type string `json:"type"`
Value string `json:"value"`
}

// Handler for JSON carves by target
Expand Down Expand Up @@ -89,6 +96,17 @@ func jsonCarvesHandler(w http.ResponseWriter, r *http.Request) {
data := make(CarveData)
data["path"] = q.Path
data["name"] = q.Name
// Preparing query targets
ts, _ := queriesmgr.GetTargets(q.Name)
_ts := []CarveTarget{}
for _, t := range ts {
_t := CarveTarget{
Type: t.Type,
Value: t.Value,
}
_ts = append(_ts, _t)
}
// Preparing JSON
_c := CarveJSON{
Name: q.Name,
Creator: q.Creator,
Expand All @@ -99,6 +117,7 @@ func jsonCarvesHandler(w http.ResponseWriter, r *http.Request) {
},
Status: status,
Progress: progress,
Targets: _ts,
}
cJSON = append(cJSON, _c)
}
Expand Down
20 changes: 20 additions & 0 deletions cmd/admin/json-queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ type QueryJSON struct {
Created CreationTimes `json:"created"`
Status string `json:"status"`
Progress QueryProgress `json:"progress"`
Targets []QueryTarget `json:"targets"`
}

// QueryTarget to be returned with the JSON data for a query
type QueryTarget struct {
Type string `json:"type"`
Value string `json:"value"`
}

// Handler for JSON queries by target
Expand Down Expand Up @@ -70,13 +77,25 @@ func jsonQueryHandler(w http.ResponseWriter, r *http.Request) {
if q.Completed {
status = queries.StatusComplete
}
// Prepare progress data
progress := make(QueryProgress)
progress["expected"] = q.Expected
progress["executions"] = q.Executions
progress["errors"] = q.Errors
data := make(QueryData)
data["query"] = q.Query
data["name"] = q.Name
// Preparing query targets
ts, _ := queriesmgr.GetTargets(q.Name)
_ts := []QueryTarget{}
for _, t := range ts {
_t := QueryTarget{
Type: t.Type,
Value: t.Value,
}
_ts = append(_ts, _t)
}
// Preparing JSON
_q := QueryJSON{
Name: q.Name,
Creator: q.Creator,
Expand All @@ -87,6 +106,7 @@ func jsonQueryHandler(w http.ResponseWriter, r *http.Request) {
},
Status: status,
Progress: progress,
Targets: _ts,
}
qJSON = append(qJSON, _q)
}
Expand Down
77 changes: 36 additions & 41 deletions cmd/admin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ package main

import (
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"log"
"net/http"
"net/url"
"time"

"github.com/jmpsec/osctrl/pkg/carves"
Expand Down Expand Up @@ -41,12 +38,18 @@ const (
appDescription string = serviceDescription + ", a fast and efficient osquery management"
// Default endpoint to handle HTTP health
healthPath string = "/health"
// Default endpoint to handle HTTP errors
// Default endpoint to handle Login
loginPath string = "/login"
// Default endpoint to handle HTTP(500) errors
errorPath string = "/error"
// Default endpoint to handle Forbidden(403) errors
forbiddenPath string = "/forbidden"
// Default service configuration file
configurationFile string = "config/" + settings.ServiceAdmin + ".json"
// Default DB configuration file
dbConfigurationFile string = "config/db.json"
// Default SAML configuration file
samlConfigurationFile string = "config/saml.json"
// osquery version to display tables
osqueryTablesVersion string = "3.3.2"
// JSON file with osquery tables data
Expand All @@ -61,11 +64,9 @@ const (
defaultInactive int = -72
)

// Global variables
// Global general variables
var (
adminConfig types.JSONConfigurationService
samlMiddleware *samlsp.Middleware
samlConfig JSONConfigurationSAML
db *gorm.DB
settingsmgr *settings.Settings
nodesmgr *nodes.NodeManager
Expand All @@ -85,6 +86,14 @@ var (
versionFlag *bool
configFlag *string
dbFlag *string
samlFlag *string
)

// SAML variables
var (
samlMiddleware *samlsp.Middleware
samlConfig JSONConfigurationSAML
samlData samlThings
)

// Valid values for auth and logging in configuration
Expand Down Expand Up @@ -121,16 +130,7 @@ func loadConfiguration(file, service string) (types.JSONConfigurationService, er
if !validLogging[cfg.Logging] {
return cfg, fmt.Errorf("Invalid logging method")
}
// Load configuration for the auth method
/*
if adminConfig.Auth == settings.AuthSAML {
samlRaw := viper.Sub(settings.AuthSAML)
err = samlRaw.Unmarshal(&samlConfig)
if err != nil {
return cfg, err
}
}
*/

// No errors!
return cfg, nil
}
Expand All @@ -144,6 +144,7 @@ func init() {
versionFlag = flag.Bool("v", false, "Displays the binary version.")
configFlag = flag.String("c", configurationFile, "Service configuration JSON file to use.")
dbFlag = flag.String("D", dbConfigurationFile, "DB configuration JSON file to use.")
samlFlag = flag.String("S", samlConfigurationFile, "SAML configuration JSON file to use.")
// Parse all flags
flag.Parse()
if *versionFlag {
Expand All @@ -156,6 +157,13 @@ func init() {
if err != nil {
log.Fatalf("Error loading %s - %s", *configFlag, err)
}
// Load configuration for SAML if enabled
if adminConfig.Auth == settings.AuthSAML {
samlConfig, err = loadSAML(*samlFlag)
if err != nil {
log.Fatalf("Error loading %s - %s", *samlFlag, err)
}
}
// Load osquery tables JSON
osqueryTables, err = loadOsqueryTables(osqueryTablesFile)
if err != nil {
Expand Down Expand Up @@ -205,32 +213,17 @@ func main() {
if settingsmgr.DebugService(settings.ServiceAdmin) {
log.Println("DebugService: SAML keypair")
}
// Load Keypair to Sign SAML Request.
// Initialize SAML keypair to sign SAML Request.
var err error
var rootURL *url.URL
var idpMetadataURL *url.URL
var keyPair tls.Certificate
keyPair, err = tls.LoadX509KeyPair(samlConfig.CertPath, samlConfig.KeyPath)
if err != nil {
log.Fatal(err)
}
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
log.Fatal(err)
}
idpMetadataURL, err = url.Parse(samlConfig.MetaDataURL)
if err != nil {
log.Fatal(err)
}
rootURL, err = url.Parse(samlConfig.RootURL)
samlData, err = keypairSAML(samlConfig)
if err != nil {
log.Fatal(err)
log.Fatalf("Can not initialize SAML keypair %s", err)
}
samlMiddleware, err = samlsp.New(samlsp.Options{
URL: *rootURL,
Key: keyPair.PrivateKey.(*rsa.PrivateKey),
Certificate: keyPair.Leaf,
IDPMetadataURL: idpMetadataURL,
URL: *samlData.RootURL,
Key: samlData.KeyPair.PrivateKey.(*rsa.PrivateKey),
Certificate: samlData.KeyPair.Leaf,
IDPMetadataURL: samlData.IdpMetadataURL,
AllowIDPInitiated: true,
})
if err != nil {
Expand All @@ -253,13 +246,15 @@ func main() {
// Admin: login only if local auth is enabled
if adminConfig.Auth != settings.AuthNone {
// login
routerAdmin.HandleFunc("/login", loginGETHandler).Methods("GET")
routerAdmin.HandleFunc("/login", loginPOSTHandler).Methods("POST")
routerAdmin.HandleFunc(loginPath, loginGETHandler).Methods("GET")
routerAdmin.HandleFunc(loginPath, loginPOSTHandler).Methods("POST")
}
// Admin: health of service
routerAdmin.HandleFunc(healthPath, healthHTTPHandler).Methods("GET")
// Admin: error
routerAdmin.HandleFunc(errorPath, errorHTTPHandler).Methods("GET")
// Admin: forbidden
routerAdmin.HandleFunc(forbiddenPath, forbiddenHTTPHandler).Methods("GET")
// Admin: favicon
routerAdmin.HandleFunc("/favicon.ico", faviconHandler)
// Admin: static
Expand Down
Loading

0 comments on commit e1d177f

Please sign in to comment.