Skip to content

Commit

Permalink
Improve the Header Authentication Method
Browse files Browse the repository at this point in the history
This adds more of the code needed to properly authenticate a user based on headers present added by a reverse proxy.
  • Loading branch information
Mitchell Grenier committed Sep 27, 2019
1 parent b9ce02d commit d7a86e4
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 7 deletions.
42 changes: 40 additions & 2 deletions cmd/admin/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"log"
"net/http"
"strings"

"github.com/jmpsec/osctrl/pkg/settings"
)
Expand Down Expand Up @@ -102,8 +103,45 @@ func handlerAuthCheck(h http.Handler) http.Handler {
samlMiddleware.RequireAccount(h).ServeHTTP(w, r)
}
case settings.AuthHeaders:
// Access always granted
h.ServeHTTP(w, r)
username := r.Header.Get(headersConfig.TrustedPrefix + headersConfig.UserName)
groups := strings.Split(r.Header.Get(headersConfig.TrustedPrefix + headersConfig.Groups), ",")

if username == "" {
log.Printf("A username is required to use this system.")
w.WriteHeader(http.StatusBadRequest)
return
}

s := make(contextValue)
s["user"] = username

for _, group := range groups {
if (group == headersConfig.AdminGroup) {
s["level"] = adminLevel
// We can break because there is no greater permission level
break
} else if (group == headersConfig.UserGroup) {
s["level"] = 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["level"]; !ok {
w.WriteHeader(http.StatusForbidden)
return
}

err := adminUsers.UpdateMetadata(r.RemoteAddr, r.Header.Get("User-Agent"), username)
if err != nil {
log.Printf("error updating metadata for user %s: %v", username, err)
}

//s["csrftoken"] = session.Values["csrftoken"].(string)
ctx := context.WithValue(r.Context(), contextKey("session"), s)

// Access granted
h.ServeHTTP(w, r.WithContext(ctx))
}
})
}
30 changes: 30 additions & 0 deletions cmd/admin/headers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"log"

"github.com/jmpsec/osctrl/pkg/settings"
"github.com/jmpsec/osctrl/pkg/types"
"github.com/spf13/viper"
)

// Function to load the configuration file
func loadHeaders(file string) (types.JSONConfigurationHeaders, error) {
var cfg types.JSONConfigurationHeaders
log.Printf("Loading %s", file)
// Load file and read config
viper.SetConfigFile(file)
err := viper.ReadInConfig()
if err != nil {
return cfg, err
}
// Header values
headersRaw := viper.Sub(settings.AuthHeaders)
err = headersRaw.Unmarshal(&cfg)
if err != nil {
return cfg, err
}

// No errors!
return cfg, nil
}
33 changes: 28 additions & 5 deletions cmd/admin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const (
dbConfigurationFile string = "config/db.json"
// Default SAML configuration file
samlConfigurationFile string = "config/saml.json"
// Default Headers configuration file
headersConfigurationFile string = "config/headers.json"
// osquery version to display tables
osqueryTablesVersion string = "4.0.1"
// JSON file with osquery tables data
Expand Down Expand Up @@ -87,6 +89,7 @@ var (
configFlag *string
dbFlag *string
samlFlag *string
headersFlag *string
)

// SAML variables
Expand All @@ -96,13 +99,20 @@ var (
samlData samlThings
)

// Valid values for auth and logging in configuration
// Headers variables
var (
headersConfig types.JSONConfigurationHeaders
)

// Valid values for auth in configuration
var validAuth = map[string]bool{
settings.AuthDB: true,
settings.AuthSAML: true,
settings.AuthHeaders: true,
settings.AuthJSON: true,
}

// Valid values for logging in configuration
var validLogging = map[string]bool{
settings.LoggingDB: true,
settings.LoggingSplunk: true,
Expand Down Expand Up @@ -146,6 +156,7 @@ func init() {
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.")
headersFlag = flag.String("H", headersConfigurationFile, "Headers configuration JSON file to use.")
// Parse all flags
flag.Parse()
if *versionFlag {
Expand All @@ -158,17 +169,29 @@ func init() {
if err != nil {
log.Fatalf("Error loading %s - %s", *configFlag, err)
}

// Load osquery tables JSON
osqueryTables, err = loadOsqueryTables(osqueryTablesFile)
if err != nil {
log.Fatalf("Error loading osquery tables %s", 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)
}
return
}
// Load osquery tables JSON
osqueryTables, err = loadOsqueryTables(osqueryTablesFile)
if err != nil {
log.Fatalf("Error loading osquery tables %s", err)

// Load configuration for Headers if enabled
if adminConfig.Auth == settings.AuthHeaders {
headersConfig, err = loadHeaders(*headersFlag)
if err != nil {
log.Fatalf("Error loading %s - %s", *headersFlag, err)
}
return
}
}

Expand Down
14 changes: 14 additions & 0 deletions pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,17 @@ type JSONConfigurationService struct {
Auth string `json:"auth"`
Logging string `json:"logging"`
}

// JSONConfigurationHeaders to keep all SAML details for auth
type JSONConfigurationHeaders struct {
TrustedPrefix string `json:"trustedPrefix"`
AdminGroup string `json:"adminGroup"`
UserGroup string `json:"userGroup"`
Email string `json:"email"`
UserName string `json:"userName"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
DisplayName string `json:"displayName"`
DistinguishedName string `json:"distinguishedName"`
Groups string `json:"groups"`
}

0 comments on commit d7a86e4

Please sign in to comment.