Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the Header Authentication Method #16

Merged
merged 3 commits into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 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,57 @@ 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), ",")
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
}

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 {
http.Redirect(w, r, forbiddenPath, http.StatusForbidden)
return
}

if !adminUsers.Exists(username) {
log.Printf("User not found, creating: %s", username)
_, err := adminUsers.New(username, "", fullname, (s["level"] == adminLevel))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one string parameter missing, also my bad since I forgot that .New() just creates the AdminUser structure, and in order to complete the creation of the user, it needs a subsequent call to .Create(), for example:

email := r.Header.Get(headersConfig.TrustedPrefix + headersConfig.Email)
newUser, err := adminUsers.New(username, "", email, fullname, (s["level"] == adminLevel))
if err != nil {
  log.Printf("Error with new user %s: %v", username, err)
  http.Redirect(w, r, forbiddenPath, http.StatusFound)
  return
}
if err := adminUsers.Create(newUser); err != nil {
  log.Printf("Error creating user %s: %v", username, err)
  http.Redirect(w, r, forbiddenPath, http.StatusFound)
  return
}


if err != nil {
log.Printf("Error creating user %s: %v", username, err)
http.Redirect(w, r, forbiddenPath, http.StatusFound)
return
}
} else {
if err := adminUsers.UpdateMetadata(r.RemoteAddr, r.Header.Get("User-Agent"), username); err != nil {
log.Printf("error updating metadata for user %s: %v", username, err)
}
}

// _, session := sessionsmgr.CheckAuth(r)
// 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"`
}