1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-06-25 00:47:17 +02:00
Files
.github
contrib
docs
pkg
apis
authentication
basic
test
basic_suite_test.go
htpasswd.go
htpasswd_test.go
validator.go
cookies
encryption
header
ip
logger
middleware
requests
sessions
upstream
util
validation
providers
testdata
.dockerignore
.gitignore
.golangci.yml
.travis.yml
CHANGELOG.md
CONTRIBUTING.md
Dockerfile
Dockerfile.arm64
Dockerfile.armv6
LICENSE
MAINTAINERS
Makefile
README.md
RELEASE.md
dist.sh
go.mod
go.sum
http.go
http_test.go
logging_handler.go
logging_handler_test.go
main.go
nsswitch.conf
oauthproxy.go
oauthproxy_test.go
templates.go
templates_test.go
validator.go
validator_test.go
version.go
watcher.go
watcher_unsupported.go
oauth2-proxy/pkg/authentication/basic/htpasswd.go

108 lines
2.9 KiB
Go
Raw Normal View History

package basic
import (
2020-07-20 18:49:45 -07:00
// We support SHA1 & bcrypt in HTPasswd
"crypto/sha1" // #nosec G505
"encoding/base64"
"encoding/csv"
"fmt"
"io"
"os"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
"golang.org/x/crypto/bcrypt"
)
// htpasswdMap represents the structure of an htpasswd file.
// Passwords must be generated with -B for bcrypt or -s for SHA1.
type htpasswdMap struct {
users map[string]interface{}
}
// bcryptPass is used to identify bcrypt passwords in the
// htpasswdMap users.
type bcryptPass string
// sha1Pass os used to identify sha1 passwords in the
// htpasswdMap users.
type sha1Pass string
// NewHTPasswdValidator constructs an httpasswd based validator from the file
// at the path given.
func NewHTPasswdValidator(path string) (Validator, error) {
2020-07-20 18:49:45 -07:00
// We allow HTPasswd location via config options
r, err := os.Open(path) // #nosec G304
if err != nil {
return nil, fmt.Errorf("could not open htpasswd file: %v", err)
}
defer func(c io.Closer) {
cerr := c.Close()
if cerr != nil {
logger.Fatalf("error closing the htpasswd file: %v", cerr)
}
}(r)
return newHtpasswd(r)
}
// newHtpasswd consctructs an htpasswd from an io.Reader (an opened file).
func newHtpasswd(file io.Reader) (*htpasswdMap, error) {
csvReader := csv.NewReader(file)
csvReader.Comma = ':'
csvReader.Comment = '#'
csvReader.TrimLeadingSpace = true
records, err := csvReader.ReadAll()
if err != nil {
return nil, fmt.Errorf("could not read htpasswd file: %v", err)
}
return createHtpasswdMap(records)
}
// createHtasswdMap constructs an htpasswdMap from the given records
func createHtpasswdMap(records [][]string) (*htpasswdMap, error) {
h := &htpasswdMap{users: make(map[string]interface{})}
for _, record := range records {
user, realPassword := record[0], record[1]
shaPrefix := realPassword[:5]
if shaPrefix == "{SHA}" {
h.users[user] = sha1Pass(realPassword[5:])
continue
}
bcryptPrefix := realPassword[:4]
if bcryptPrefix == "$2a$" || bcryptPrefix == "$2b$" || bcryptPrefix == "$2x$" || bcryptPrefix == "$2y$" {
h.users[user] = bcryptPass(realPassword)
continue
}
// Password is neither sha1 or bcrypt
// TODO(JoelSpeed): In the next breaking release, make this return an error.
logger.Errorf("Invalid htpasswd entry for %s. Must be a SHA or bcrypt entry.", user)
}
return h, nil
}
// Validate checks a users password against the htpasswd entries
func (h *htpasswdMap) Validate(user string, password string) bool {
realPassword, exists := h.users[user]
if !exists {
return false
}
switch rp := realPassword.(type) {
case sha1Pass:
2020-07-20 18:49:45 -07:00
// We support SHA1 HTPasswd entries
d := sha1.New() // #nosec G401
_, err := d.Write([]byte(password))
if err != nil {
return false
}
return string(rp) == base64.StdEncoding.EncodeToString(d.Sum(nil))
case bcryptPass:
return bcrypt.CompareHashAndPassword([]byte(rp), []byte(password)) == nil
default:
return false
}
}