fix(auth): reject invalid bearer tokens instead of falling back
Modify the authentication handler to return an unauthorized error when an invalid or disabled bearer token is provided, rather than silently falling back to an anonymous request. This ensures that clients attempting to authenticate but failing (due to expired, malformed, or disabled tokens) are explicitly notified of the auth failure instead of proceeding anonymously. True anonymous requests without any Authorization header remain supported.
This commit is contained in:
113
backend/libs/services/storage_s3.go
Normal file
113
backend/libs/services/storage_s3.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
)
|
||||
|
||||
type s3StorageBackend struct {
|
||||
cfg StorageBackendConfig
|
||||
client *minio.Client
|
||||
}
|
||||
|
||||
func newS3StorageBackend(cfg StorageBackendConfig) (*s3StorageBackend, error) {
|
||||
endpoint := normalizeS3Endpoint(cfg.Endpoint)
|
||||
client, err := minio.New(endpoint, &minio.Options{
|
||||
Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
|
||||
Secure: cfg.UseSSL,
|
||||
Region: cfg.Region,
|
||||
BucketLookup: s3BucketLookup(cfg.PathStyle),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3StorageBackend{cfg: cfg, client: client}, nil
|
||||
}
|
||||
|
||||
func (b *s3StorageBackend) ID() string { return b.cfg.ID }
|
||||
func (b *s3StorageBackend) Type() string { return StorageBackendS3 }
|
||||
|
||||
func (b *s3StorageBackend) Put(ctx context.Context, key string, body io.Reader, size int64, contentType string) error {
|
||||
opts := minio.PutObjectOptions{ContentType: contentType}
|
||||
_, err := b.client.PutObject(ctx, b.cfg.Bucket, cleanObjectKey(key), body, size, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *s3StorageBackend) Get(ctx context.Context, key string) (StorageObject, error) {
|
||||
object, err := b.client.GetObject(ctx, b.cfg.Bucket, cleanObjectKey(key), minio.GetObjectOptions{})
|
||||
if err != nil {
|
||||
return StorageObject{}, err
|
||||
}
|
||||
info, err := object.Stat()
|
||||
if err != nil {
|
||||
object.Close()
|
||||
return StorageObject{}, err
|
||||
}
|
||||
return StorageObject{Key: key, Size: info.Size, ContentType: info.ContentType, ModTime: info.LastModified, Body: object}, nil
|
||||
}
|
||||
|
||||
func (b *s3StorageBackend) Delete(ctx context.Context, key string) error {
|
||||
return b.client.RemoveObject(ctx, b.cfg.Bucket, cleanObjectKey(key), minio.RemoveObjectOptions{})
|
||||
}
|
||||
|
||||
func (b *s3StorageBackend) DeletePrefix(ctx context.Context, prefix string) error {
|
||||
prefix = strings.TrimSuffix(cleanObjectKey(prefix), "/") + "/"
|
||||
objects := b.client.ListObjects(ctx, b.cfg.Bucket, minio.ListObjectsOptions{Prefix: prefix, Recursive: true})
|
||||
for object := range objects {
|
||||
if object.Err != nil {
|
||||
return object.Err
|
||||
}
|
||||
if err := b.Delete(ctx, object.Key); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *s3StorageBackend) Usage(ctx context.Context) (int64, error) {
|
||||
var total int64
|
||||
for object := range b.client.ListObjects(ctx, b.cfg.Bucket, minio.ListObjectsOptions{Recursive: true}) {
|
||||
if object.Err != nil {
|
||||
return 0, object.Err
|
||||
}
|
||||
total += object.Size
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (b *s3StorageBackend) Test(ctx context.Context) error {
|
||||
exists, err := b.client.BucketExists(ctx, b.cfg.Bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("bucket %q does not exist", b.cfg.Bucket)
|
||||
}
|
||||
key := ".warpbox-storage-test-" + randomID(6)
|
||||
if err := b.Put(ctx, key, bytes.NewReader([]byte("ok")), 2, "text/plain"); err != nil {
|
||||
return err
|
||||
}
|
||||
return b.Delete(ctx, key)
|
||||
}
|
||||
|
||||
func s3BucketLookup(pathStyle bool) minio.BucketLookupType {
|
||||
if pathStyle {
|
||||
return minio.BucketLookupPath
|
||||
}
|
||||
return minio.BucketLookupAuto
|
||||
}
|
||||
|
||||
func normalizeS3Endpoint(endpoint string) string {
|
||||
endpoint = strings.TrimSpace(endpoint)
|
||||
if parsed, err := url.Parse(endpoint); err == nil && parsed.Host != "" {
|
||||
return parsed.Host
|
||||
}
|
||||
return strings.TrimPrefix(strings.TrimPrefix(endpoint, "https://"), "http://")
|
||||
}
|
||||
Reference in New Issue
Block a user