Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

auth-bypassing-ip-list #50

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
29 changes: 19 additions & 10 deletions app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ import (

// Config represents the configuration of the server application.
type Config struct {
Address string
Port string
Prefix string
Dir string
TLS *TLS
Log Logging
Realm string
Users map[string]*UserInfo
Cors Cors
Address string
Port string
Prefix string
Dir string
TLS *TLS
Log Logging
Realm string
Users map[string]*UserInfo
Authentication_Bypass_IP_Addresses []string
Cors Cors
}

// Logging allows definition for logging each CRUD method.
Expand Down Expand Up @@ -99,6 +100,7 @@ func setDefaults() {
viper.SetDefault("Prefix", "")
viper.SetDefault("Dir", "/tmp")
viper.SetDefault("Users", nil)
viper.SetDefault("Authentication_Bypass_IP_Addresses", nil)
viper.SetDefault("TLS", nil)
viper.SetDefault("Realm", "dave")
viper.SetDefault("Log.Error", true)
Expand All @@ -110,7 +112,14 @@ func setDefaults() {
}

// AuthenticationNeeded returns whether users are defined and authentication is required
func (cfg *Config) AuthenticationNeeded() bool {
func (cfg *Config) AuthenticationNeeded(requestIpAddress string) bool {
if cfg.Authentication_Bypass_IP_Addresses != nil {
for _, bypass_ip := range cfg.Authentication_Bypass_IP_Addresses {
if bypass_ip == requestIpAddress {
return false
}
}
}
return cfg.Users != nil && len(cfg.Users) != 0
}

Expand Down
27 changes: 20 additions & 7 deletions app/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package app
import (
"context"
"fmt"
"net"
"net/http"
"strings"

"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
"net/http"
"strings"
)

type contextKey int
Expand Down Expand Up @@ -39,8 +41,8 @@ func NewBasicAuthWebdavHandler(a *App) http.Handler {
})
}

func authenticate(config *Config, username, password string) (*AuthInfo, error) {
if !config.AuthenticationNeeded() {
func authenticate(config *Config, username, password string, requestIpAddress string) (*AuthInfo, error) {
if !config.AuthenticationNeeded(requestIpAddress) {
return &AuthInfo{Username: "", Authenticated: false}, nil
}

Expand Down Expand Up @@ -72,6 +74,11 @@ func AuthFromContext(ctx context.Context) *AuthInfo {
}

func handle(ctx context.Context, w http.ResponseWriter, req *http.Request, a *App) {
requestIpAddress, _, ipFetchError := net.SplitHostPort(req.RemoteAddr)
if ipFetchError != nil {
log.WithError(ipFetchError).Error("Error fetching remote address ??")
}

// handle a preflight if such a CORS request would be allowed
if req.Method == "OPTIONS" {
if a.Config.Cors.Origin == req.Header.Get("Origin") &&
Expand All @@ -83,7 +90,7 @@ func handle(ctx context.Context, w http.ResponseWriter, req *http.Request, a *Ap
}

// if there are no users, we don't need authentication here
if !a.Config.AuthenticationNeeded() {
if !a.Config.AuthenticationNeeded(requestIpAddress) {
a.Handler.ServeHTTP(w, req.WithContext(ctx))
return
}
Expand All @@ -94,7 +101,7 @@ func handle(ctx context.Context, w http.ResponseWriter, req *http.Request, a *Ap
return
}

authInfo, err := authenticate(a.Config, username, password)
authInfo, err := authenticate(a.Config, username, password, requestIpAddress)
if err != nil {
ipAddr := req.Header.Get("X-Forwarded-For")
if len(ipAddr) == 0 {
Expand All @@ -120,7 +127,13 @@ func handle(ctx context.Context, w http.ResponseWriter, req *http.Request, a *Ap
}

func httpAuth(r *http.Request, config *Config) (string, string, bool) {
if config.AuthenticationNeeded() {

requestIpAddress, _, ipFetchError := net.SplitHostPort(r.RemoteAddr)
if ipFetchError != nil {
log.WithError(ipFetchError).Error("Error fetching remote address ??")
}

if config.AuthenticationNeeded(requestIpAddress) {
username, password, ok := r.BasicAuth()
return username, password, ok
}
Expand Down
3 changes: 2 additions & 1 deletion app/security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ func TestAuthenticate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := authenticate(tt.args.config, tt.args.username, tt.args.password)
requestIpAddress := "" // todo: test Authentication_Bypass_IP_Addresses, somehow..
got, err := authenticate(tt.args.config, tt.args.username, tt.args.password, requestIpAddress)
if (err != nil) != tt.wantErr {
t.Errorf("authenticate() name = %v, error = %v, wantErr %v", tt.name, err, tt.wantErr)
return
Expand Down
10 changes: 10 additions & 0 deletions examples/config-sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ users:
password: "$2a$10$yITzSSNJZAdDZs8iVBQzkuZCzZ49PyjTiPIrmBUKUpB0pwX7eySvW"


# ---------------------------------- Authentication bypass IP Addresses --------

# A list of IP addresses that bypass authentication
#
#Authentication_Bypass_IP_Addresses:
# - '127.0.0.1'
# - '::1'
# - '984.49.158.188'


# ---------------------------------- Logging -----------------------------------
#
# Seperated loglevels for file / directory operations. All set to false per
Expand Down