| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- package policy
- import (
- "errors"
- "fmt"
- "net/http"
- "github.com/porter-dev/porter/api/server/shared/apierrors"
- "github.com/porter-dev/porter/api/types"
- "github.com/porter-dev/porter/internal/models"
- "github.com/porter-dev/porter/internal/repository"
- "gorm.io/gorm"
- )
- type PolicyLoaderOpts struct {
- ProjectID, UserID uint
- ProjectToken *models.APIToken
- }
- type PolicyDocumentLoader interface {
- LoadPolicyDocuments(opts *PolicyLoaderOpts) ([]*types.PolicyDocument, apierrors.RequestError)
- }
- // RepoPolicyDocumentLoader loads policy documents by reading from the repository database
- type RepoPolicyDocumentLoader struct {
- projRepo repository.ProjectRepository
- policyRepo repository.PolicyRepository
- }
- func NewBasicPolicyDocumentLoader(projRepo repository.ProjectRepository, policyRepo repository.PolicyRepository) *RepoPolicyDocumentLoader {
- return &RepoPolicyDocumentLoader{projRepo, policyRepo}
- }
- func (b *RepoPolicyDocumentLoader) LoadPolicyDocuments(
- opts *PolicyLoaderOpts,
- ) ([]*types.PolicyDocument, apierrors.RequestError) {
- if opts.ProjectToken != nil {
- // check that the token belongs to the project, in this case it's solely project-scoped
- if opts.ProjectID == 0 || opts.ProjectToken.ProjectID == 0 || opts.ProjectID != opts.ProjectToken.ProjectID {
- return nil, apierrors.NewErrForbidden(fmt.Errorf("project id %d does not match token id %d", opts.ProjectID, opts.ProjectToken.ProjectID))
- }
- // load the policy
- apiPolicy, reqErr := GetAPIPolicyFromUID(b.policyRepo, opts.ProjectToken.ProjectID, opts.ProjectToken.PolicyUID)
- if reqErr != nil {
- return nil, reqErr
- }
- return apiPolicy.Policy, nil
- } else if opts.ProjectID != 0 && opts.UserID != 0 {
- userID := opts.UserID
- projectID := opts.ProjectID
- // read role and case on role "kind"
- role, err := b.projRepo.ReadProjectRole(projectID, userID)
- if err != nil && err == gorm.ErrRecordNotFound {
- return nil, apierrors.NewErrForbidden(
- fmt.Errorf("user %d does not have a role in project %d", userID, projectID),
- )
- } else if err != nil {
- return nil, apierrors.NewErrInternal(err)
- }
- // load role based on role kind
- switch role.Kind {
- case types.RoleAdmin:
- return types.AdminPolicy, nil
- case types.RoleDeveloper:
- return types.DeveloperPolicy, nil
- case types.RoleViewer:
- return types.ViewerPolicy, nil
- default:
- return nil, apierrors.NewErrForbidden(
- fmt.Errorf("%s role not supported for user %d, project %d", string(role.Kind), userID, projectID),
- )
- }
- }
- return nil, apierrors.NewErrForbidden(
- fmt.Errorf("policy loader called with invalid arguments"),
- )
- }
- func GetAPIPolicyFromUID(policyRepo repository.PolicyRepository, projectID uint, uid string) (*types.APIPolicy, apierrors.RequestError) {
- switch uid {
- case "admin":
- return &types.APIPolicy{
- APIPolicyMeta: &types.APIPolicyMeta{
- Name: "admin",
- UID: "admin",
- },
- Policy: types.AdminPolicy,
- }, nil
- case "developer":
- return &types.APIPolicy{
- APIPolicyMeta: &types.APIPolicyMeta{
- Name: "developer",
- UID: "developer",
- },
- Policy: types.DeveloperPolicy,
- }, nil
- case "viewer":
- return &types.APIPolicy{
- APIPolicyMeta: &types.APIPolicyMeta{
- Name: "viewer",
- UID: "viewer",
- },
- Policy: types.ViewerPolicy,
- }, nil
- default:
- // look up the policy and make sure it exists
- policyModel, err := policyRepo.ReadPolicy(projectID, uid)
- if err != nil {
- if errors.Is(err, gorm.ErrRecordNotFound) {
- return nil, apierrors.NewErrPassThroughToClient(
- fmt.Errorf("policy not found in project"),
- http.StatusBadRequest,
- )
- }
- return nil, apierrors.NewErrInternal(err)
- }
- apiPolicy, err := policyModel.ToAPIPolicyType()
- if err != nil {
- return nil, apierrors.NewErrInternal(err)
- }
- return apiPolicy, nil
- }
- }
|