implement file-based basic auth
This commit is contained in:
parent
0b4d62892c
commit
679a43789c
102
auth.go
102
auth.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"errors"
|
||||
|
@ -8,9 +9,11 @@ import (
|
|||
"strconv"
|
||||
"encoding/base64"
|
||||
"crypto/subtle"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"bufio"
|
||||
)
|
||||
|
||||
const AUTH_REQUIRED_MSG = "Proxy authentication required."
|
||||
const AUTH_REQUIRED_MSG = "Proxy authentication required.\n"
|
||||
|
||||
type Auth interface {
|
||||
Validate(wr http.ResponseWriter, req *http.Request) bool
|
||||
|
@ -24,8 +27,9 @@ func NewAuth(paramstr string) (Auth, error) {
|
|||
|
||||
switch strings.ToLower(url.Scheme) {
|
||||
case "static":
|
||||
auth, err := NewStaticAuth(url)
|
||||
return auth, err
|
||||
return NewStaticAuth(url)
|
||||
case "basicfile":
|
||||
return NewBasicFileAuth(url)
|
||||
case "none":
|
||||
return NoAuth{}, nil
|
||||
default:
|
||||
|
@ -97,6 +101,98 @@ func (auth *StaticAuth) Validate(wr http.ResponseWriter, req *http.Request) bool
|
|||
}
|
||||
}
|
||||
|
||||
type BasicAuth struct {
|
||||
users map[string][]byte
|
||||
hiddenDomain string
|
||||
}
|
||||
|
||||
func NewBasicFileAuth(param_url *url.URL) (*BasicAuth, error) {
|
||||
filename := param_url.Path
|
||||
values, err := url.ParseQuery(param_url.RawQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
users := make(map[string][]byte)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
continue
|
||||
}
|
||||
pair := strings.SplitN(line, ":", 2)
|
||||
if len(pair) != 2 {
|
||||
return nil, errors.New("Malformed login and password line")
|
||||
}
|
||||
login := pair[0]
|
||||
password := pair[1]
|
||||
users[login] = []byte(password)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
return nil, errors.New("No password lines were read from file")
|
||||
}
|
||||
return &BasicAuth{
|
||||
users: users,
|
||||
hiddenDomain: strings.ToLower(values.Get("hidden_domain")),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (auth *BasicAuth) Validate(wr http.ResponseWriter, req *http.Request) bool {
|
||||
hdr := req.Header.Get("Proxy-Authorization")
|
||||
if hdr == "" {
|
||||
requireBasicAuth(wr, req, auth.hiddenDomain)
|
||||
return false
|
||||
}
|
||||
hdr_parts := strings.SplitN(hdr, " ", 2)
|
||||
if len(hdr_parts) != 2 || strings.ToLower(hdr_parts[0]) != "basic" {
|
||||
requireBasicAuth(wr, req, auth.hiddenDomain)
|
||||
return false
|
||||
}
|
||||
|
||||
token := hdr_parts[1]
|
||||
data, err := base64.StdEncoding.DecodeString(token)
|
||||
if err != nil {
|
||||
requireBasicAuth(wr, req, auth.hiddenDomain)
|
||||
return false
|
||||
}
|
||||
|
||||
pair := strings.SplitN(string(data), ":", 2)
|
||||
if len(pair) != 2 {
|
||||
requireBasicAuth(wr, req, auth.hiddenDomain)
|
||||
return false
|
||||
}
|
||||
|
||||
login := pair[0]
|
||||
password := pair[1]
|
||||
|
||||
hashedPassword, ok := auth.users[login]
|
||||
if !ok {
|
||||
requireBasicAuth(wr, req, auth.hiddenDomain)
|
||||
return false
|
||||
}
|
||||
|
||||
if bcrypt.CompareHashAndPassword(hashedPassword, []byte(password)) == nil {
|
||||
if auth.hiddenDomain != "" &&
|
||||
(req.Host == auth.hiddenDomain || req.URL.Host == auth.hiddenDomain) {
|
||||
http.Error(wr, "Browser auth triggered!", http.StatusGone)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type NoAuth struct {}
|
||||
|
||||
func (_ NoAuth) Validate(wr http.ResponseWriter, req *http.Request) bool {
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,3 +1,5 @@
|
|||
module github.com/Snawoot/dumbproxy
|
||||
|
||||
go 1.13
|
||||
|
||||
require golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
Loading…
Reference in New Issue