KevinStephenson
Adding in weaviate code
b110593
raw
history blame
2.87 kB
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package apikey
import (
"crypto/sha256"
"crypto/subtle"
"fmt"
errors "github.com/go-openapi/errors"
"github.com/weaviate/weaviate/entities/models"
"github.com/weaviate/weaviate/usecases/config"
)
type Client struct {
config config.APIKey
keystorage [][sha256.Size]byte
}
func New(cfg config.Config) (*Client, error) {
c := &Client{
config: cfg.Authentication.APIKey,
}
if err := c.validateConfig(); err != nil {
return nil, fmt.Errorf("invalid apikey config: %w", err)
}
c.parseKeys()
return c, nil
}
func (c *Client) parseKeys() {
c.keystorage = make([][sha256.Size]byte, len(c.config.AllowedKeys))
for i, rawKey := range c.config.AllowedKeys {
c.keystorage[i] = sha256.Sum256([]byte(rawKey))
}
}
func (c *Client) validateConfig() error {
if !c.config.Enabled {
// don't validate if this scheme isn't used
return nil
}
if len(c.config.AllowedKeys) < 1 {
return fmt.Errorf("need at least one valid allowed key")
}
for _, key := range c.config.AllowedKeys {
if len(key) == 0 {
return fmt.Errorf("keys cannot have length 0")
}
}
if len(c.config.Users) < 1 {
return fmt.Errorf("need at least one user")
}
for _, key := range c.config.Users {
if len(key) == 0 {
return fmt.Errorf("users cannot have length 0")
}
}
if len(c.config.Users) > 1 && len(c.config.Users) != len(c.config.AllowedKeys) {
return fmt.Errorf("length of users and keys must match, alternatively provide single user for all keys")
}
return nil
}
func (c *Client) ValidateAndExtract(token string, scopes []string) (*models.Principal, error) {
if !c.config.Enabled {
return nil, errors.New(401, "apikey auth is not configured, please try another auth scheme or set up weaviate with apikey configured")
}
tokenPos, ok := c.isTokenAllowed(token)
if !ok {
return nil, errors.New(401, "invalid api key, please provide a valid api key")
}
return &models.Principal{
Username: c.getUser(tokenPos),
}, nil
}
func (c *Client) isTokenAllowed(token string) (int, bool) {
tokenHash := sha256.Sum256([]byte(token))
for i, allowed := range c.keystorage {
if subtle.ConstantTimeCompare(tokenHash[:], allowed[:]) == 1 {
return i, true
}
}
return -1, false
}
func (c *Client) getUser(pos int) string {
// passed validation guarantees that one of those options will work
if pos >= len(c.config.Users) {
return c.config.Users[0]
}
return c.config.Users[pos]
}