mirror of
https://gitee.com/milvus-io/milvus.git
synced 2026-01-07 19:31:51 +08:00
issue: #46635 ## Summary - Fix spelling error in constant name: `CredentialSeperator` -> `CredentialSeparator` - Updated all usages across the codebase to use the correct spelling ## Changes - `pkg/util/constant.go`: Renamed the constant - `pkg/util/contextutil/context_util.go`: Updated usage - `pkg/util/contextutil/context_util_test.go`: Updated usage - `internal/proxy/authentication_interceptor.go`: Updated usage - `internal/proxy/util.go`: Updated usage - `internal/proxy/util_test.go`: Updated usage - `internal/proxy/trace_log_interceptor_test.go`: Updated usage - `internal/proxy/accesslog/info/util.go`: Updated usage - `internal/distributed/proxy/service.go`: Updated usage - `internal/distributed/proxy/httpserver/utils.go`: Updated usage ## Test Plan - [x] All references updated consistently - [x] No functional changes - only constant name spelling correction <!-- This is an auto-generated comment: release notes by coderabbit.ai --> - Core invariant: the separator character for credentials remains ":" everywhere — only the exported identifier was renamed from CredentialSeperator → CredentialSeparator; the constant value and split/join semantics are unchanged. - Change (bug fix): corrected the misspelled exported constant in pkg/util/constant.go and updated all references across the codebase (parsing, token construction, header handling and tests) to use the new identifier; this is an identifier rename that removes an inconsistent symbol and prevents compile-time/reference errors. - Logic simplified/redundant work removed: no runtime logic was removed; the simplification is purely maintenance-focused — eliminating a misspelled exported name that could cause developers to introduce duplicate or incorrect constants. - No data loss or behavior regression: runtime code paths are unchanged — e.g., GetAuthInfoFromContext, ParseUsernamePassword, AuthenticationInterceptor, proxy service token construction and access-log extraction still use ":" to split/join credentials; updated and added unit tests (parsing and metadata extraction) exercise these paths and validate identical semantics. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: majiayu000 <1835304752@qq.com> Signed-off-by: lif <1835304752@qq.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
108 lines
3.9 KiB
Go
108 lines
3.9 KiB
Go
package proxy
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
|
"go.uber.org/zap"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/metadata"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
|
"github.com/milvus-io/milvus/internal/proxy/privilege"
|
|
"github.com/milvus-io/milvus/internal/util/hookutil"
|
|
"github.com/milvus-io/milvus/pkg/v2/log"
|
|
"github.com/milvus-io/milvus/pkg/v2/metrics"
|
|
"github.com/milvus-io/milvus/pkg/v2/util"
|
|
"github.com/milvus-io/milvus/pkg/v2/util/crypto"
|
|
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
|
)
|
|
|
|
func parseMD(rawToken string) (username, password string) {
|
|
secrets := strings.SplitN(rawToken, util.CredentialSeparator, 2)
|
|
if len(secrets) < 2 {
|
|
log.Warn("invalid token format, length of secrets less than 2")
|
|
return
|
|
}
|
|
username = secrets[0]
|
|
password = secrets[1]
|
|
return
|
|
}
|
|
|
|
func GrpcAuthInterceptor(authFunc grpc_auth.AuthFunc) grpc.UnaryServerInterceptor {
|
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
|
var newCtx context.Context
|
|
var err error
|
|
if overrideSrv, ok := info.Server.(grpc_auth.ServiceAuthFuncOverride); ok {
|
|
newCtx, err = overrideSrv.AuthFuncOverride(ctx, info.FullMethod)
|
|
} else {
|
|
newCtx, err = authFunc(ctx)
|
|
}
|
|
if err != nil {
|
|
hookutil.GetExtension().ReportRefused(context.Background(), req, &milvuspb.BoolResponse{
|
|
Status: merr.Status(err),
|
|
}, err, info.FullMethod)
|
|
return nil, err
|
|
}
|
|
return handler(newCtx, req)
|
|
}
|
|
}
|
|
|
|
// AuthenticationInterceptor verify based on kv pair <"authorization": "token"> in header
|
|
func AuthenticationInterceptor(ctx context.Context) (context.Context, error) {
|
|
// The keys within metadata.MD are normalized to lowercase.
|
|
// See: https://godoc.org/google.golang.org/grpc/metadata#New
|
|
md, ok := metadata.FromIncomingContext(ctx)
|
|
if !ok {
|
|
return nil, merr.WrapErrIoKeyNotFound("metadata", "auth check failure, due to occurs inner error: missing metadata")
|
|
}
|
|
if globalMetaCache == nil {
|
|
return nil, merr.WrapErrServiceUnavailable("internal: Milvus Proxy is not ready yet. please wait")
|
|
}
|
|
// check rpc call from sdk
|
|
if Params.CommonCfg.AuthorizationEnabled.GetAsBool() {
|
|
authStrArr := md[strings.ToLower(util.HeaderAuthorize)]
|
|
|
|
if len(authStrArr) < 1 {
|
|
log.Warn("key not found in header")
|
|
return nil, status.Error(codes.Unauthenticated, "missing authorization in header")
|
|
}
|
|
|
|
// token format: base64<username:password>
|
|
// token := strings.TrimPrefix(authorization[0], "Bearer ")
|
|
token := authStrArr[0]
|
|
rawToken, err := crypto.Base64Decode(token)
|
|
if err != nil {
|
|
log.Warn("fail to decode the token", zap.Error(err))
|
|
return nil, status.Error(codes.Unauthenticated, "invalid token format")
|
|
}
|
|
|
|
if !strings.Contains(rawToken, util.CredentialSeparator) {
|
|
user, err := VerifyAPIKey(rawToken)
|
|
if err != nil {
|
|
log.Warn("fail to verify apikey", zap.Error(err))
|
|
return nil, status.Error(codes.Unauthenticated, "auth check failure, please check api key is correct")
|
|
}
|
|
metrics.UserRPCCounter.WithLabelValues(user).Inc()
|
|
userToken := fmt.Sprintf("%s%s%s", user, util.CredentialSeparator, util.PasswordHolder)
|
|
md[strings.ToLower(util.HeaderAuthorize)] = []string{crypto.Base64Encode(userToken)}
|
|
md[util.HeaderToken] = []string{rawToken}
|
|
ctx = metadata.NewIncomingContext(ctx, md)
|
|
} else {
|
|
// username+password authentication
|
|
username, password := parseMD(rawToken)
|
|
if !passwordVerify(ctx, username, password, privilege.GetPrivilegeCache()) {
|
|
log.Warn("fail to verify password", zap.String("username", username))
|
|
// NOTE: don't use the merr, because it will cause the wrong retry behavior in the sdk
|
|
return nil, status.Error(codes.Unauthenticated, "auth check failure, please check username and password are correct")
|
|
}
|
|
metrics.UserRPCCounter.WithLabelValues(username).Inc()
|
|
}
|
|
}
|
|
return ctx, nil
|
|
}
|