From 3829f267323566ab13c26ec06b5307138fa06bb9 Mon Sep 17 00:00:00 2001 From: SyniRon <66834451+SyniRon@users.noreply.github.com> Date: Sat, 10 Jan 2026 10:16:52 -0500 Subject: [PATCH 1/3] yeet keycloak auth --- servers/grpc/authentication.go | 64 ++++++---------------------------- 1 file changed, 11 insertions(+), 53 deletions(-) diff --git a/servers/grpc/authentication.go b/servers/grpc/authentication.go index 6f4f64c..7ee52a0 100644 --- a/servers/grpc/authentication.go +++ b/servers/grpc/authentication.go @@ -20,11 +20,8 @@ package grpc import ( "context" - "crypto/tls" - "crypto/x509" - "net/http" + "os" "strings" - "time" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -32,10 +29,7 @@ import ( "google.golang.org/grpc/status" ) -const authServerURL = "https://auth.7cav.us/auth/realms/7cav/check?apiKey=" - -func ValidateToken(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - Info.Println("Checking metadata") +func ValidateToken(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { md, ok := metadata.FromIncomingContext(ctx) if !ok { @@ -50,6 +44,7 @@ func ValidateToken(ctx context.Context, req interface{}, info *grpc.UnaryServerI } authHeader := strings.TrimSpace(authHeaders[0]) + if !isValidToken(authHeader) { Warn.Printf("Unauthorized attempt on method %s", info.FullMethod) return nil, status.Errorf(codes.Unauthenticated, "invalid token") @@ -59,54 +54,17 @@ func ValidateToken(ctx context.Context, req interface{}, info *grpc.UnaryServerI } func isValidToken(authHeader string) bool { - token := strings.TrimPrefix(authHeader, "Bearer ") - if token == "" { - Warn.Println("Empty token provided") - return false - } - if !isPrintableASCII(token) { - Warn.Println("Token contains non-printable ASCII") + expectedSecret := os.Getenv("API_SECRET") + if expectedSecret == "" { + Warn.Println("CRITICAL: API_SECRET is not set in the environment!") return false } - config, err := loadTLSConfig() - if err != nil { - Warn.Printf("Failed to load TLS config: %v", err) - return false - } - - client := &http.Client{ - Transport: &http.Transport{TLSClientConfig: config}, - Timeout: 5 * time.Second, - } - res, err := client.Get(authServerURL + token) - if err != nil { - Warn.Printf("Auth server unreachable: %v", err) + token := strings.TrimPrefix(authHeader, "Bearer ") + if token == "" { + Warn.Println("Empty token provided") return false } - defer func() { - if err := res.Body.Close(); err != nil { - Warn.Printf("Error closing response body: %v", err) - } - }() - - return res.StatusCode == http.StatusOK -} - -func loadTLSConfig() (*tls.Config, error) { - rootCAs, err := x509.SystemCertPool() - if err != nil { - Warn.Printf("Could not load system CA pool: %v", err) - return nil, err - } - return &tls.Config{RootCAs: rootCAs}, nil -} -func isPrintableASCII(s string) bool { - for _, r := range s { - if r < 32 || r > 126 { - return false - } - } - return true -} + return token == expectedSecret +} \ No newline at end of file From 6b2a6359ead8e0383099851c0bd1082bb804b476 Mon Sep 17 00:00:00 2001 From: SyniRon <66834451+SyniRon@users.noreply.github.com> Date: Sat, 10 Jan 2026 10:26:25 -0500 Subject: [PATCH 2/3] version bump --- proto/milpacs.proto | 2 +- servers/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/milpacs.proto b/proto/milpacs.proto index 13e7fcb..2a6765c 100644 --- a/proto/milpacs.proto +++ b/proto/milpacs.proto @@ -29,7 +29,7 @@ import "google/protobuf/empty.proto"; // These annotations are used when generating the OpenAPI file. option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { - version: "1.7.4"; + version: "2.0.0"; }; external_docs: { url: "https://github.com/7cav/api"; diff --git a/servers/server.go b/servers/server.go index 5148e7f..68760de 100644 --- a/servers/server.go +++ b/servers/server.go @@ -38,7 +38,7 @@ import ( "gorm.io/gorm" ) -const version = "1.7.6" +const version = "2.0.0" type MicroServer struct { addr string From e4b66c2455dca066bd98c0845b4a5ecf4bd32e73 Mon Sep 17 00:00:00 2001 From: SyniRon <66834451+SyniRon@users.noreply.github.com> Date: Sat, 10 Jan 2026 10:27:08 -0500 Subject: [PATCH 3/3] prevent unecessary token checking --- servers/grpc/authentication.go | 53 +++++++++++++++------------------- servers/server.go | 13 ++++++++- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/servers/grpc/authentication.go b/servers/grpc/authentication.go index 7ee52a0..69f4b06 100644 --- a/servers/grpc/authentication.go +++ b/servers/grpc/authentication.go @@ -20,7 +20,7 @@ package grpc import ( "context" - "os" + "crypto/subtle" "strings" "google.golang.org/grpc" @@ -29,42 +29,37 @@ import ( "google.golang.org/grpc/status" ) -func ValidateToken(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { +func NewAuthInterceptor(secret string) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + // You can use your global logger here if accessible, or fmt + return nil, status.Errorf(codes.Unauthenticated, "missing metadata") + } - md, ok := metadata.FromIncomingContext(ctx) - if !ok { - Warn.Println("Unauthorized: No metadata found") - return nil, status.Errorf(codes.Unauthenticated, "missing metadata") - } - - authHeaders := md.Get("authorization") - if len(authHeaders) < 1 { - Warn.Println("Unauthorized: Missing authorization header") - return nil, status.Errorf(codes.Unauthenticated, "missing authorization token") - } + authHeaders := md.Get("authorization") + if len(authHeaders) < 1 { + return nil, status.Errorf(codes.Unauthenticated, "missing authorization token") + } - authHeader := strings.TrimSpace(authHeaders[0]) - - if !isValidToken(authHeader) { - Warn.Printf("Unauthorized attempt on method %s", info.FullMethod) - return nil, status.Errorf(codes.Unauthenticated, "invalid token") - } + authHeader := strings.TrimSpace(authHeaders[0]) - return handler(ctx, req) -} + // Pass the baked-in secret to the check + if !isValidToken(authHeader, secret) { + // logic to log warning if needed + return nil, status.Errorf(codes.Unauthenticated, "invalid token") + } -func isValidToken(authHeader string) bool { - expectedSecret := os.Getenv("API_SECRET") - if expectedSecret == "" { - Warn.Println("CRITICAL: API_SECRET is not set in the environment!") - return false + return handler(ctx, req) } +} +func isValidToken(authHeader, secret string) bool { token := strings.TrimPrefix(authHeader, "Bearer ") if token == "" { - Warn.Println("Empty token provided") return false } - - return token == expectedSecret + + // Compare the token against the secret passed from startup + return subtle.ConstantTimeCompare([]byte(token), []byte(secret)) == 1 } \ No newline at end of file diff --git a/servers/server.go b/servers/server.go index 68760de..262e5a0 100644 --- a/servers/server.go +++ b/servers/server.go @@ -61,6 +61,16 @@ var ( Error = log.New(os.Stdout, "ERROR: ", log.LstdFlags) ) +func setupAuth() string { + secret := viper.GetString("API_SECRET") + if secret == "" { + // It is critical to fail fast if this is missing + Error.Println("CRITICAL: API_SECRET is not set in environment/config") + os.Exit(1) + } + return secret +} + func setupRedis() *cache.RedisCache { redisHost := viper.GetString("REDIS_HOST") if redisHost == "" { @@ -135,6 +145,7 @@ func (server *MicroServer) Start() { Error.Fatalf("Failed to listen on %s: %w", server.addr, err) } + apiSecret := setupAuth() ds := setupDatasource() server.cache = setupRedis() go cache.CacheManager(server.cache, ds) @@ -144,7 +155,7 @@ func (server *MicroServer) Start() { // If this needed to change in the future, then we will need to refactor this method opts := []grpc.ServerOption{ // Intercept request to check the token. - grpc.UnaryInterceptor(grpcServices.ValidateToken), + grpc.UnaryInterceptor(grpcServices.NewAuthInterceptor(apiSecret)), //grpc.Creds(creds), }