Sfoglia il codice sorgente

add policy and api token get and list endpoints

Alexander Belanger 4 anni fa
parent
commit
2075c440ea

+ 82 - 0
api/server/handlers/api_token/get.go

@@ -0,0 +1,82 @@
+package api_token
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+type APITokenGetHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewAPITokenGetHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *APITokenGetHandler {
+	return &APITokenGetHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *APITokenGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	// get the token id from the request
+	tokenID, reqErr := requestutils.GetURLParamString(r, types.URLParamTokenID)
+
+	if reqErr != nil {
+		p.HandleAPIError(w, r, reqErr)
+		return
+	}
+
+	token, err := p.Repo().APIToken().ReadAPIToken(proj.ID, tokenID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("token with id %s not found in project", tokenID),
+				http.StatusNotFound,
+			))
+			return
+		}
+
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	// look up the policy and make sure it exists
+	policy, err := p.Repo().Policy().ReadPolicy(proj.ID, token.PolicyUID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("policy no longer found in project"),
+				http.StatusBadRequest,
+			))
+			return
+		}
+
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	apiPolicy, err := policy.ToAPIPolicyType()
+
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	p.WriteResult(w, r, token.ToAPITokenType(apiPolicy.Policy, ""))
+}

+ 45 - 0
api/server/handlers/api_token/list.go

@@ -0,0 +1,45 @@
+package api_token
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type APITokenListHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewAPITokenListHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *APITokenListHandler {
+	return &APITokenListHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *APITokenListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	tokens, err := p.Repo().APIToken().ListAPITokensByProjectID(proj.ID)
+
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	apiTokens := make([]*types.APITokenMeta, 0)
+
+	for _, tok := range tokens {
+		apiTokens = append(apiTokens, tok.ToAPITokenMetaType())
+	}
+
+	p.WriteResult(w, r, apiTokens)
+}

+ 66 - 0
api/server/handlers/policy/get.go

@@ -0,0 +1,66 @@
+package policy
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+type PolicyGetHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewPolicyGetHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *PolicyGetHandler {
+	return &PolicyGetHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *PolicyGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	// get the token id from the request
+	policyID, reqErr := requestutils.GetURLParamString(r, types.URLParamPolicyID)
+
+	if reqErr != nil {
+		p.HandleAPIError(w, r, reqErr)
+		return
+	}
+
+	policy, err := p.Repo().Policy().ReadPolicy(proj.ID, policyID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("policy with id %s not found in project", policyID),
+				http.StatusNotFound,
+			))
+			return
+		}
+
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	res, err := policy.ToAPIPolicyType()
+
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	p.WriteResult(w, r, res)
+}

+ 45 - 0
api/server/handlers/policy/list.go

@@ -0,0 +1,45 @@
+package policy
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type PolicyListHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewPolicyListHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *PolicyListHandler {
+	return &PolicyListHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *PolicyListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	policies, err := p.Repo().Policy().ListPoliciesByProjectID(proj.ID)
+
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	res := make([]*types.APIPolicyMeta, 0)
+
+	for _, policy := range policies {
+		res = append(res, policy.ToAPIPolicyTypeMeta())
+	}
+
+	p.WriteResult(w, r, res)
+}

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

@@ -921,6 +921,64 @@ func getProjectRoutes(
 		Router:   r,
 		Router:   r,
 	})
 	})
 
 
+	//  GET /api/projects/{project_id}/policy -> policy.NewPolicyListHandler
+	policyListEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbList,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/policy",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.SettingsScope,
+			},
+		},
+	)
+
+	policyListHandler := policy.NewPolicyListHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: policyListEndpoint,
+		Handler:  policyListHandler,
+		Router:   r,
+	})
+
+	//  GET /api/projects/{project_id}/policy/{policy_id} -> policy.NewPolicyGetHandler
+	policyGetEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: fmt.Sprintf("%s/policy/{%s}", relPath, types.URLParamPolicyID),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.SettingsScope,
+			},
+		},
+	)
+
+	policyGetHandler := policy.NewPolicyGetHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: policyGetEndpoint,
+		Handler:  policyGetHandler,
+		Router:   r,
+	})
+
 	//  POST /api/projects/{project_id}/api_token -> api_token.NewAPITokenCreateHandler
 	//  POST /api/projects/{project_id}/api_token -> api_token.NewAPITokenCreateHandler
 	apiTokenCreateEndpoint := factory.NewAPIEndpoint(
 	apiTokenCreateEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{
 		&types.APIRequestMetadata{
@@ -950,5 +1008,63 @@ func getProjectRoutes(
 		Router:   r,
 		Router:   r,
 	})
 	})
 
 
+	//  GET /api/projects/{project_id}/api_token -> api_token.NewAPITokenListHandler
+	apiTokenListEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbList,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: fmt.Sprintf("%s/api_token", relPath),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.SettingsScope,
+			},
+		},
+	)
+
+	apiTokenListHandler := api_token.NewAPITokenListHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: apiTokenListEndpoint,
+		Handler:  apiTokenListHandler,
+		Router:   r,
+	})
+
+	//  GET /api/projects/{project_id}/api_token/{api_token_id} -> api_token.NewAPITokenGetHandler
+	apiTokenGetEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: fmt.Sprintf("%s/api_token/{%s}", relPath, types.URLParamTokenID),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.SettingsScope,
+			},
+		},
+	)
+
+	apiTokenGetHandler := api_token.NewAPITokenGetHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: apiTokenGetEndpoint,
+		Handler:  apiTokenGetHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 	return routes, newPath
 }
 }

+ 4 - 1
api/types/api_token.go

@@ -2,10 +2,13 @@ package types
 
 
 import "time"
 import "time"
 
 
+const URLParamTokenID URLParam = "api_token_id"
+
 type APITokenMeta struct {
 type APITokenMeta struct {
 	CreatedAt time.Time `json:"created_at"`
 	CreatedAt time.Time `json:"created_at"`
 	ExpiresAt time.Time `json:"expires_at"`
 	ExpiresAt time.Time `json:"expires_at"`
 
 
+	ID         string `json:"id"`
 	PolicyName string `json:"policy_name"`
 	PolicyName string `json:"policy_name"`
 	PolicyUID  string `json:"policy_uid"`
 	PolicyUID  string `json:"policy_uid"`
 	Name       string `json:"name"`
 	Name       string `json:"name"`
@@ -15,7 +18,7 @@ type APIToken struct {
 	*APITokenMeta
 	*APITokenMeta
 
 
 	Policy []*PolicyDocument `json:"policy"`
 	Policy []*PolicyDocument `json:"policy"`
-	Token  string            `json:"token"`
+	Token  string            `json:"token,omitempty"`
 }
 }
 
 
 type CreateAPIToken struct {
 type CreateAPIToken struct {

+ 2 - 0
api/types/policy.go

@@ -93,6 +93,8 @@ type CreatePolicy struct {
 	Policy []*PolicyDocument `json:"policy" form:"required"`
 	Policy []*PolicyDocument `json:"policy" form:"required"`
 }
 }
 
 
+const URLParamPolicyID URLParam = "policy_id"
+
 type APIPolicyMeta struct {
 type APIPolicyMeta struct {
 	CreatedAt time.Time `json:"created_at"`
 	CreatedAt time.Time `json:"created_at"`
 	UpdatedAt time.Time `json:"updated_at"`
 	UpdatedAt time.Time `json:"updated_at"`

+ 1 - 0
internal/models/api_token.go

@@ -31,6 +31,7 @@ func (p *APIToken) IsExpired() bool {
 
 
 func (p *APIToken) ToAPITokenMetaType() *types.APITokenMeta {
 func (p *APIToken) ToAPITokenMetaType() *types.APITokenMeta {
 	return &types.APITokenMeta{
 	return &types.APITokenMeta{
+		ID:         p.UniqueID,
 		CreatedAt:  p.CreatedAt,
 		CreatedAt:  p.CreatedAt,
 		ExpiresAt:  *p.Expiry,
 		ExpiresAt:  *p.Expiry,
 		PolicyName: p.PolicyName,
 		PolicyName: p.PolicyName,