golib/auth/csvauth/token.go

63 lines
1.4 KiB
Go

package csvauth
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
)
// Provided for consistency. Often better to use Authenticate("", token)
func (a *Auth) LoadToken(secret string) (Credential, error) {
var credential Credential
c, err := a.loadAndVerifyToken(secret)
if c != nil {
credential = *c
}
return credential, err
}
// VerifyToken uses a shortened, but timing-safe HMAC to find the token,
// and then verifies it according to the chosen algorithm
func (a *Auth) VerifyToken(secret string) error {
_, err := a.loadAndVerifyToken(secret)
return err
}
func (a *Auth) loadAndVerifyToken(secret string) (*Credential, error) {
hashID := a.tokenCacheID(secret)
a.mux.Lock()
c, ok := a.tokens[hashID]
a.mux.Unlock()
if !ok {
return nil, ErrNotFound
}
if c.plain == "" {
var err error
if c.plain, err = a.maybeDecryptCredential(c); err != nil {
return nil, err
}
}
if err := c.Verify("", secret); err != nil {
return nil, err
}
return &c, nil
}
func (a *Auth) tokenCacheID(secret string) string {
key := a.aes128key[:]
mac := hmac.New(sha256.New, key)
message := []byte(secret)
mac.Write(message)
// attack collisions are possible, but will still fail to pass HMAC
// practical collisions are not possible for the CSV use case
nameBytes := mac.Sum(nil)[:6]
name := base64.RawURLEncoding.EncodeToString(nameBytes)
return name
}