Bläddra i källkod

use access tokens

Mohammed Nafees 3 år sedan
förälder
incheckning
1ca930893c

+ 20 - 0
api/client/registry.go

@@ -123,6 +123,26 @@ func (c *Client) GetGCRAuthorizationToken(
 	return resp, err
 }
 
+// GetGARAuthorizationToken gets a GAR authorization token
+func (c *Client) GetGARAuthorizationToken(
+	ctx context.Context,
+	projectID uint,
+	req *types.GetRegistryGARTokenRequest,
+) (*types.GetRegistryTokenResponse, error) {
+	resp := &types.GetRegistryTokenResponse{}
+
+	err := c.getRequest(
+		fmt.Sprintf(
+			"/projects/%d/registries/gar/token",
+			projectID,
+		),
+		req,
+		resp,
+	)
+
+	return resp, err
+}
+
 // GetACRAuthorizationToken gets a ACR authorization token
 func (c *Client) GetACRAuthorizationToken(
 	ctx context.Context,

+ 1 - 1
api/server/handlers/registry/create.go

@@ -83,7 +83,7 @@ func (p *RegistryCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 	var err error
 
 	if request.GCPIntegrationID != 0 {
-		_, err = p.Repo().GCPIntegration().ReadGCPIntegration(proj.ID, request.GCPIntegrationID)
+		_, err := p.Repo().GCPIntegration().ReadGCPIntegration(proj.ID, request.GCPIntegrationID)
 
 		if err != nil {
 			if errors.Is(err, gorm.ErrRecordNotFound) {

+ 63 - 0
api/server/handlers/registry/get_token.go

@@ -173,6 +173,69 @@ func (c *RegistryGetGCRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
 	c.WriteResult(w, r, resp)
 }
 
+type RegistryGetGARTokenHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryGetGARTokenHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryGetGARTokenHandler {
+	return &RegistryGetGARTokenHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *RegistryGetGARTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	request := &types.GetRegistryGCRTokenRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// list registries and find one that matches the region
+	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	var token string
+	var expiresAt *time.Time
+
+	for _, reg := range regs {
+		if reg.GCPIntegrationID != 0 && strings.Contains(reg.URL, request.ServerURL) {
+			_reg := registry.Registry(*reg)
+
+			oauthTok, err := _reg.GetGARToken(c.Repo())
+
+			// if the oauth token is not nil, but the error is not nil, we still return the token
+			// but log an error
+			if oauthTok != nil && err != nil {
+				c.HandleAPIErrorNoWrite(w, r, apierrors.NewErrInternal(err))
+			} else if err != nil {
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				return
+			}
+
+			token = oauthTok.AccessToken
+			expiresAt = &oauthTok.Expiry
+			break
+		}
+	}
+
+	resp := &types.GetRegistryTokenResponse{
+		Token:     token,
+		ExpiresAt: expiresAt,
+	}
+
+	c.WriteResult(w, r, resp)
+}
+
 type RegistryGetDOCRTokenHandler struct {
 	handlers.PorterHandlerReadWriter
 }

+ 28 - 0
api/server/router/project.go

@@ -608,6 +608,34 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
+	//  GET /api/projects/{project_id}/registries/gar/token -> registry.NewRegistryGetGARTokenHandler
+	getGARTokenEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries/gar/token",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	getGARTokenHandler := registry.NewRegistryGetGARTokenHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: getGARTokenEndpoint,
+		Handler:  getGARTokenHandler,
+		Router:   r,
+	})
+
 	//  GET /api/projects/{project_id}/registries/acr/token -> registry.NewRegistryGetACRTokenHandler
 	getACRTokenEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{

+ 4 - 0
api/types/registry.go

@@ -180,6 +180,10 @@ type GetRegistryGCRTokenRequest struct {
 	ServerURL string `schema:"server_url"`
 }
 
+type GetRegistryGARTokenRequest struct {
+	ServerURL string `schema:"server_url"`
+}
+
 type GetRegistryECRTokenRequest struct {
 	Region    string `schema:"region"`
 	AccountID string `schema:"account_id"`

+ 38 - 1
cli/cmd/docker/auth.go

@@ -49,8 +49,10 @@ type AuthGetter struct {
 }
 
 func (a *AuthGetter) GetCredentials(serverURL string) (user string, secret string, err error) {
-	if strings.Contains(serverURL, "gcr.io") || strings.Contains(serverURL, "pkg.dev") {
+	if strings.Contains(serverURL, "gcr.io") {
 		return a.GetGCRCredentials(serverURL, a.ProjectID)
+	} else if strings.Contains(serverURL, "pkg.dev") {
+		return a.GetGARCredentials(serverURL, a.ProjectID)
 	} else if strings.Contains(serverURL, "registry.digitalocean.com") {
 		return a.GetDOCRCredentials(serverURL, a.ProjectID)
 	} else if strings.Contains(serverURL, "index.docker.io") {
@@ -97,6 +99,41 @@ func (a *AuthGetter) GetGCRCredentials(serverURL string, projID uint) (user stri
 	return "oauth2accesstoken", token, nil
 }
 
+func (a *AuthGetter) GetGARCredentials(serverURL string, projID uint) (user string, secret string, err error) {
+	if err != nil {
+		return "", "", err
+	}
+
+	cachedEntry := a.Cache.Get(serverURL)
+
+	var token string
+
+	if cachedEntry != nil && cachedEntry.IsValid(time.Now()) {
+		token = cachedEntry.AuthorizationToken
+	} else {
+		// get a token from the server
+		tokenResp, err := a.Client.GetGARAuthorizationToken(context.Background(), projID, &types.GetRegistryGARTokenRequest{
+			ServerURL: serverURL,
+		})
+
+		if err != nil {
+			return "", "", err
+		}
+
+		token = tokenResp.Token
+
+		// set the token in cache
+		a.Cache.Set(serverURL, &AuthEntry{
+			AuthorizationToken: token,
+			RequestedAt:        time.Now(),
+			ExpiresAt:          *tokenResp.ExpiresAt,
+			ProxyEndpoint:      serverURL,
+		})
+	}
+
+	return "oauth2accesstoken", token, nil
+}
+
 func (a *AuthGetter) GetDOCRCredentials(serverURL string, projID uint) (user string, secret string, err error) {
 	cachedEntry := a.Cache.Get(serverURL)
 

+ 20 - 0
internal/registry/registry.go

@@ -211,6 +211,26 @@ func (r *Registry) listGCRRepositories(
 	return res, nil
 }
 
+func (r *Registry) GetGARToken(repo repository.Repository) (*oauth2.Token, error) {
+	getTokenCache := r.getTokenCacheFunc(repo)
+
+	gcp, err := repo.GCPIntegration().ReadGCPIntegration(
+		r.ProjectID,
+		r.GCPIntegrationID,
+	)
+
+	if err != nil {
+		return nil, err
+	}
+
+	// get oauth2 access token
+	return gcp.GetBearerToken(
+		getTokenCache,
+		r.setTokenCacheFunc(repo),
+		"https://www.googleapis.com/auth/cloud-platform",
+	)
+}
+
 func (r *Registry) listGARRepositories(
 	repo repository.Repository,
 ) ([]*ptypes.RegistryRepository, error) {