From 889cab1364f60614ec3d4685716d15cf55acaba7 Mon Sep 17 00:00:00 2001 From: jay-dee7 Date: Mon, 25 Dec 2023 19:52:56 +0530 Subject: [PATCH] feat: CORS for ConnectRPC APIs Signed-off-by: jay-dee7 --- auth/helpers.go | 2 +- go.mod | 2 +- go.sum | 2 ++ router/github.go | 20 ++++++++++++- router/router.go | 2 ++ router/vuln_scanning_routes.go | 31 +++++++++++++++++++- services/yor/clair/v1/server/clair.go | 7 ++++- services/yor/clair/v1/server/interceptors.go | 15 ++++++---- 8 files changed, 70 insertions(+), 11 deletions(-) diff --git a/auth/helpers.go b/auth/helpers.go index a2a3c6ec..7d7c29bb 100644 --- a/auth/helpers.go +++ b/auth/helpers.go @@ -118,7 +118,7 @@ func NewWebLoginToken(opts *WebLoginJWTOptions) (string, error) { hasher := sha256.New() hasher.Write(pubkeyDER) - raw := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + raw := jwt.NewWithClaims(jwt.SigningMethodRS256, &claims) raw.Header["kid"] = KeyIDEncode(hasher.Sum(nil)[:30]) token, err := raw.SignedString(opts.Privkey) if err != nil { diff --git a/go.mod b/go.mod index a3e5d4a4..b6ced963 100644 --- a/go.mod +++ b/go.mod @@ -169,7 +169,7 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rs/cors v1.7.0 // indirect + github.com/rs/cors v1.10.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect diff --git a/go.sum b/go.sum index 8df09f2d..b1758a03 100644 --- a/go.sum +++ b/go.sum @@ -662,6 +662,8 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= diff --git a/router/github.go b/router/github.go index 9963d22f..02f426d1 100644 --- a/router/github.go +++ b/router/github.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "net/http" + "strings" "github.com/containerish/OpenRegistry/config" github_actions_server "github.com/containerish/OpenRegistry/services/kon/github_actions/v1/server" @@ -13,6 +14,7 @@ import ( "github.com/containerish/OpenRegistry/vcs/github" "github.com/fatih/color" "github.com/labstack/echo/v4" + "github.com/rs/cors" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" ) @@ -26,6 +28,7 @@ func RegisterGitHubRoutes( allowedEndpoints []string, usersStore vcs.VCSStore, automationStore automation.BuildAutomationStore, + allowedOrigins []string, ) { if cfg != nil && cfg.Enabled { ghAppApi := github.NewGithubApp( @@ -47,7 +50,22 @@ func RegisterGitHubRoutes( go func() { addr := net.JoinHostPort(cfg.Host, fmt.Sprintf("%d", cfg.Port)) color.Green("connect-go GitHub Automation gRPC service running on: %s", addr) - if err := http.ListenAndServe(addr, h2c.NewHandler(githubMux, &http2.Server{})); err != nil { + ghCors := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowOriginFunc: func(origin string) bool { + return strings.HasSuffix(origin, "openregistry.dev") || + strings.HasSuffix(origin, "cntr.sh") || + strings.HasSuffix(origin, "openregistry-web.pages.dev") + }, + AllowedMethods: []string{ + http.MethodOptions, http.MethodGet, http.MethodPost, + }, + AllowedHeaders: []string{"*"}, + AllowCredentials: true, + Debug: true, + }) + handler := ghCors.Handler(h2c.NewHandler(githubMux, &http2.Server{})) + if err := http.ListenAndServe(addr, handler); err != nil { color.Red("connect-go GitHub Automation service listen error: %s", err) } }() diff --git a/router/router.go b/router/router.go index 792b505f..eeb16367 100644 --- a/router/router.go +++ b/router/router.go @@ -70,6 +70,7 @@ func Register( logger, registryStore.GetLayersLinksForManifest, dfs.GeneratePresignedURL, + cfg.WebAppConfig.AllowedEndpoints, ) if cfg.Integrations.GetGithubConfig() != nil && cfg.Integrations.GetGithubConfig().Enabled { @@ -82,6 +83,7 @@ func Register( cfg.WebAppConfig.AllowedEndpoints, usersStore, automationStore, + cfg.WebAppConfig.AllowedEndpoints, ) } diff --git a/router/vuln_scanning_routes.go b/router/vuln_scanning_routes.go index 4f98f0b1..cc2d2079 100644 --- a/router/vuln_scanning_routes.go +++ b/router/vuln_scanning_routes.go @@ -4,12 +4,14 @@ import ( "fmt" "net" "net/http" + "strings" "github.com/containerish/OpenRegistry/config" "github.com/containerish/OpenRegistry/services/yor/clair/v1/server" "github.com/containerish/OpenRegistry/store/v1/users" "github.com/containerish/OpenRegistry/telemetry" "github.com/fatih/color" + "github.com/rs/cors" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" ) @@ -21,6 +23,7 @@ func RegisterVulnScaningRoutes( logger telemetry.Logger, layerLinkReader server.LayerLinkReader, prePresignedURLGenerator server.PresignedURLGenerator, + allowedOrigins []string, ) { if clairConfig != nil && clairConfig.Enabled { clairApi := server.NewClairClient( @@ -33,8 +36,34 @@ func RegisterVulnScaningRoutes( ) go func() { addr := net.JoinHostPort(clairConfig.Host, fmt.Sprintf("%d", clairConfig.Port)) + vulnScanningCors := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowOriginFunc: func(origin string) bool { + return strings.HasSuffix(origin, "openregistry.dev") || + strings.HasSuffix(origin, "cntr.sh") || + strings.HasSuffix(origin, "openregistry-web.pages.dev") || + strings.Contains(origin, "localhost") + }, + AllowedMethods: []string{ + http.MethodOptions, http.MethodGet, http.MethodPost, + }, + AllowedHeaders: []string{ + "Origin", + "Content-Type", + "Authorization", + "Connect-Protocol-Version", + "Connect-Timeout-Ms", + "Grpc-Timeout", + "X-Grpc-Web", + "X-User-Agent", + }, + AllowCredentials: true, + Debug: true, + }) + + handler := h2c.NewHandler(vulnScanningCors.Handler(clairApi), &http2.Server{}) color.Green("connect-go Clair gRPC service running on: %s", addr) - if err := http.ListenAndServe(addr, h2c.NewHandler(clairApi, &http2.Server{})); err != nil { + if err := http.ListenAndServe(addr, handler); err != nil { color.Red("connect-go listen error: %s", err) } }() diff --git a/services/yor/clair/v1/server/clair.go b/services/yor/clair/v1/server/clair.go index 21309aaf..8e339f35 100644 --- a/services/yor/clair/v1/server/clair.go +++ b/services/yor/clair/v1/server/clair.go @@ -165,7 +165,12 @@ func (c *clair) submitManifest( return nil, err } - return res.Body, nil + if res.StatusCode >= 200 && res.StatusCode <= 300 { + return res.Body, nil + } + + return nil, fmt.Errorf("ERR_SUBMIT_MANIFEST_TO_SCAN: CODE: %d", res.StatusCode) + } func (c *clair) newClairRequest(ctx context.Context, method string, url string, body io.Reader) (*http.Request, error) { diff --git a/services/yor/clair/v1/server/interceptors.go b/services/yor/clair/v1/server/interceptors.go index 64da34bb..899eced5 100644 --- a/services/yor/clair/v1/server/interceptors.go +++ b/services/yor/clair/v1/server/interceptors.go @@ -42,15 +42,18 @@ func (c *clair) NewJWTInterceptor() connect.UnaryInterceptorFunc { } func (c *clair) getTokenFromReq(req connect.AnyRequest, jwtSigningPubKey *rsa.PublicKey) (uuid.UUID, error) { - token, err := c.tryTokenFromReqHeaders(req, jwtSigningPubKey) - if err != nil { - token, err = c.tryTokenFromReqCookies(req, jwtSigningPubKey) - if err != nil { - return uuid.Nil, fmt.Errorf("getTokenFromReq: tryTokenFromReqCookies: %w", err) + tokenFromHeaders, headerErr := c.tryTokenFromReqHeaders(req, jwtSigningPubKey) + if headerErr != nil { + tokenFromCookies, cookieErr := c.tryTokenFromReqCookies(req, jwtSigningPubKey) + if cookieErr != nil { + return uuid.Nil, fmt.Errorf( + "getTokenFromReq: tryTokenFromReqCookies: %w - tryTokenFromReqHeaders: %w", cookieErr, headerErr, + ) } + return tokenFromCookies, nil } - return token, nil + return tokenFromHeaders, nil } func (c *clair) tryTokenFromReqCookies(req connect.AnyRequest, jwtSigningPubKey *rsa.PublicKey) (uuid.UUID, error) {