mirror of
https://github.com/therootcompany/golib.git
synced 2025-10-07 01:28:19 +00:00
ref!(envauth): change Verify return from bool to error
This commit is contained in:
parent
0893b3cb2d
commit
e8fbe603af
@ -12,7 +12,7 @@ creds := envauth.BasicCredentials{
|
||||
Password: os.Getenv("BASIC_AUTH_PASSWORD"),
|
||||
}
|
||||
|
||||
verified := creds.Verify("username", "password")
|
||||
err := creds.Verify("username", "password")
|
||||
```
|
||||
|
||||
## Basic Credentials: Username + Password
|
||||
@ -44,12 +44,17 @@ func main() {
|
||||
Password: password,
|
||||
}
|
||||
|
||||
verified := creds.Verify("api", "secret")
|
||||
if verified {
|
||||
println("Authentication successful")
|
||||
} else {
|
||||
println("Authentication failed")
|
||||
if err := creds.Verify("api", "secret"); err != nil {
|
||||
switch err {
|
||||
case envauth.ErrUnauthorized:
|
||||
println("Authentication failed")
|
||||
default:
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
println("Authentication successful")
|
||||
}
|
||||
```
|
||||
|
||||
@ -104,11 +109,16 @@ func main() {
|
||||
Iterations: iterations,
|
||||
}
|
||||
|
||||
verified := creds.Verify("api", "secret")
|
||||
if verified {
|
||||
println("Authentication successful")
|
||||
} else {
|
||||
println("Authentication failed")
|
||||
if err := creds.Verify("api", "secret"); err != nil {
|
||||
switch err {
|
||||
case envauth.ErrUnauthorized:
|
||||
println("Authentication failed")
|
||||
default:
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
println("Authentication successful")
|
||||
}
|
||||
```
|
||||
|
@ -4,10 +4,13 @@ import (
|
||||
"crypto/pbkdf2"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrUnauthorized = errors.New("unauthorized")
|
||||
|
||||
type BasicAuthVerifier interface {
|
||||
Verify(string, string) bool
|
||||
Verify(string, string) error
|
||||
}
|
||||
|
||||
// BasicCredentials holds user credentials
|
||||
@ -18,9 +21,9 @@ type BasicCredentials struct {
|
||||
|
||||
// Returns true if username and password match.
|
||||
// Uses SHA-256 and constant-time techniques to avoid revealing whether the username or password matches through timing attacks.
|
||||
func (c BasicCredentials) Verify(username string, password string) bool {
|
||||
func (c BasicCredentials) Verify(username string, password string) error {
|
||||
if len(password) == 0 {
|
||||
return false
|
||||
return ErrUnauthorized
|
||||
}
|
||||
|
||||
equal := 1
|
||||
@ -38,7 +41,10 @@ func (c BasicCredentials) Verify(username string, password string) bool {
|
||||
v = subtle.ConstantTimeCompare(knownPasswordHash[:], passwordHash[:]) // 1 if same
|
||||
equal = subtle.ConstantTimeSelect(v, equal, 0) // v ? x : y
|
||||
|
||||
return equal == 1
|
||||
if equal == 1 {
|
||||
return nil
|
||||
}
|
||||
return ErrUnauthorized
|
||||
}
|
||||
|
||||
// PBKDF2Credentials holds user credentials
|
||||
@ -51,24 +57,24 @@ type PBKDF2Credentials struct {
|
||||
|
||||
// Returns true if username and password match.
|
||||
// Uses PBKDF2 and constant-time techniques to avoid revealing whether the username or password matches through timing attacks.
|
||||
func (c PBKDF2Credentials) Verify(username string, password string) bool {
|
||||
func (c PBKDF2Credentials) Verify(username string, password string) error {
|
||||
keyLen := len(c.DerivedKey)
|
||||
dkKnownUser, err := pbkdf2.Key(sha256.New, c.Username, c.Salt, c.Iterations, keyLen)
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
|
||||
if len(password) == 0 {
|
||||
return false
|
||||
return ErrUnauthorized
|
||||
}
|
||||
|
||||
dkUser, err := pbkdf2.Key(sha256.New, username, c.Salt, c.Iterations, keyLen)
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
dkPass, err := pbkdf2.Key(sha256.New, password, c.Salt, c.Iterations, keyLen)
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
|
||||
equal := 1
|
||||
@ -79,7 +85,11 @@ func (c PBKDF2Credentials) Verify(username string, password string) bool {
|
||||
v = subtle.ConstantTimeCompare(dkPass, c.DerivedKey) // 1 if same
|
||||
equal = subtle.ConstantTimeSelect(v, equal, 0) // v ? x : y
|
||||
|
||||
return equal == 1
|
||||
if equal == 1 {
|
||||
return nil
|
||||
}
|
||||
return ErrUnauthorized
|
||||
|
||||
}
|
||||
|
||||
func (c PBKDF2Credentials) DeriveKey(username string, password string, keyLen int) ([]byte, error) {
|
||||
|
@ -14,50 +14,50 @@ func TestBasicCredentials_Verify(t *testing.T) {
|
||||
creds BasicCredentials
|
||||
username string
|
||||
password string
|
||||
want bool
|
||||
want error
|
||||
}{
|
||||
{
|
||||
name: "empty username, correct password",
|
||||
creds: BasicCredentials{Username: "", Password: "secret"},
|
||||
username: "",
|
||||
password: "secret",
|
||||
want: true,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "correct username, correct password",
|
||||
creds: BasicCredentials{Username: "user", Password: "secret"},
|
||||
username: "user",
|
||||
password: "secret",
|
||||
want: true,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "incorrect username, correct password",
|
||||
creds: BasicCredentials{Username: "user", Password: "secret"},
|
||||
username: "wrong",
|
||||
password: "secret",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "correct username, incorrect password",
|
||||
creds: BasicCredentials{Username: "user", Password: "secret"},
|
||||
username: "user",
|
||||
password: "wrong",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "correct username, empty password",
|
||||
creds: BasicCredentials{Username: "user", Password: "secret"},
|
||||
username: "user",
|
||||
password: "",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.creds.Verify(tt.username, tt.password)
|
||||
if got != tt.want {
|
||||
t.Errorf("Verify(%q, %q) = %v; want %v", tt.username, tt.password, got, tt.want)
|
||||
err := tt.creds.Verify(tt.username, tt.password)
|
||||
if err != tt.want {
|
||||
t.Errorf("Verify(%q, %q) = %v; want %v", tt.username, tt.password, err, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -78,57 +78,57 @@ func TestPBKDF2Credentials_Verify(t *testing.T) {
|
||||
creds PBKDF2Credentials
|
||||
username string
|
||||
password string
|
||||
want bool
|
||||
want error
|
||||
}{
|
||||
{
|
||||
name: "empty username, correct password",
|
||||
creds: PBKDF2Credentials{Username: "", DerivedKey: secretDigest, Salt: salt, Iterations: 1000},
|
||||
username: "",
|
||||
password: "secret",
|
||||
want: true,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "correct username, correct password",
|
||||
creds: PBKDF2Credentials{Username: "user", DerivedKey: secretDigest, Salt: salt, Iterations: 1000},
|
||||
username: "user",
|
||||
password: "secret",
|
||||
want: true,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "incorrect username, correct password",
|
||||
creds: PBKDF2Credentials{Username: "user", DerivedKey: secretDigest, Salt: salt, Iterations: 1000},
|
||||
username: "wrong",
|
||||
password: "secret",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "correct username, incorrect password",
|
||||
creds: PBKDF2Credentials{Username: "user", DerivedKey: secretDigest, Salt: salt, Iterations: 1000},
|
||||
username: "user",
|
||||
password: "wrong",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "correct username, empty password",
|
||||
creds: PBKDF2Credentials{Username: "user", DerivedKey: secretDigest, Salt: salt, Iterations: 1000},
|
||||
username: "user",
|
||||
password: "",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "empty username, empty pre-computed digest",
|
||||
creds: PBKDF2Credentials{Username: "", DerivedKey: emptyDigest, Salt: salt, Iterations: 1000},
|
||||
username: "",
|
||||
password: "",
|
||||
want: false,
|
||||
want: ErrUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.creds.Verify(tt.username, tt.password)
|
||||
if got != tt.want {
|
||||
t.Errorf("Verify(%q, %q) = %v; want %v", tt.username, tt.password, got, tt.want)
|
||||
err := tt.creds.Verify(tt.username, tt.password)
|
||||
if err != tt.want {
|
||||
t.Errorf("Verify(%q, %q) = %v; want %v", tt.username, tt.password, err, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user