2
0

loader.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package policy
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "github.com/porter-dev/porter/api/server/shared/apierrors"
  7. "github.com/porter-dev/porter/api/types"
  8. "github.com/porter-dev/porter/internal/models"
  9. "github.com/porter-dev/porter/internal/repository"
  10. "gorm.io/gorm"
  11. )
  12. type PolicyLoaderOpts struct {
  13. ProjectID, UserID uint
  14. ProjectToken *models.APIToken
  15. }
  16. type PolicyDocumentLoader interface {
  17. LoadPolicyDocuments(opts *PolicyLoaderOpts) ([]*types.PolicyDocument, apierrors.RequestError)
  18. }
  19. // RepoPolicyDocumentLoader loads policy documents by reading from the repository database
  20. type RepoPolicyDocumentLoader struct {
  21. projRepo repository.ProjectRepository
  22. policyRepo repository.PolicyRepository
  23. }
  24. func NewBasicPolicyDocumentLoader(projRepo repository.ProjectRepository, policyRepo repository.PolicyRepository) *RepoPolicyDocumentLoader {
  25. return &RepoPolicyDocumentLoader{projRepo, policyRepo}
  26. }
  27. func (b *RepoPolicyDocumentLoader) LoadPolicyDocuments(
  28. opts *PolicyLoaderOpts,
  29. ) ([]*types.PolicyDocument, apierrors.RequestError) {
  30. if opts.ProjectToken != nil {
  31. // check that the token belongs to the project, in this case it's solely project-scoped
  32. if opts.ProjectID == 0 || opts.ProjectToken.ProjectID == 0 || opts.ProjectID != opts.ProjectToken.ProjectID {
  33. return nil, apierrors.NewErrForbidden(fmt.Errorf("project id %d does not match token id %d", opts.ProjectID, opts.ProjectToken.ProjectID))
  34. }
  35. // load the policy
  36. apiPolicy, reqErr := GetAPIPolicyFromUID(b.policyRepo, opts.ProjectToken.ProjectID, opts.ProjectToken.PolicyUID)
  37. if reqErr != nil {
  38. return nil, reqErr
  39. }
  40. return apiPolicy.Policy, nil
  41. } else if opts.ProjectID != 0 && opts.UserID != 0 {
  42. userID := opts.UserID
  43. projectID := opts.ProjectID
  44. // read role and case on role "kind"
  45. role, err := b.projRepo.ReadProjectRole(projectID, userID)
  46. if err != nil && err == gorm.ErrRecordNotFound {
  47. return nil, apierrors.NewErrForbidden(
  48. fmt.Errorf("user %d does not have a role in project %d", userID, projectID),
  49. )
  50. } else if err != nil {
  51. return nil, apierrors.NewErrInternal(err)
  52. }
  53. // load role based on role kind
  54. switch role.Kind {
  55. case types.RoleAdmin:
  56. return types.AdminPolicy, nil
  57. case types.RoleDeveloper:
  58. return types.DeveloperPolicy, nil
  59. case types.RoleViewer:
  60. return types.ViewerPolicy, nil
  61. default:
  62. return nil, apierrors.NewErrForbidden(
  63. fmt.Errorf("%s role not supported for user %d, project %d", string(role.Kind), userID, projectID),
  64. )
  65. }
  66. }
  67. return nil, apierrors.NewErrForbidden(
  68. fmt.Errorf("policy loader called with invalid arguments"),
  69. )
  70. }
  71. func GetAPIPolicyFromUID(policyRepo repository.PolicyRepository, projectID uint, uid string) (*types.APIPolicy, apierrors.RequestError) {
  72. switch uid {
  73. case "admin":
  74. return &types.APIPolicy{
  75. APIPolicyMeta: &types.APIPolicyMeta{
  76. Name: "admin",
  77. UID: "admin",
  78. },
  79. Policy: types.AdminPolicy,
  80. }, nil
  81. case "developer":
  82. return &types.APIPolicy{
  83. APIPolicyMeta: &types.APIPolicyMeta{
  84. Name: "developer",
  85. UID: "developer",
  86. },
  87. Policy: types.DeveloperPolicy,
  88. }, nil
  89. case "viewer":
  90. return &types.APIPolicy{
  91. APIPolicyMeta: &types.APIPolicyMeta{
  92. Name: "viewer",
  93. UID: "viewer",
  94. },
  95. Policy: types.ViewerPolicy,
  96. }, nil
  97. default:
  98. // look up the policy and make sure it exists
  99. policyModel, err := policyRepo.ReadPolicy(projectID, uid)
  100. if err != nil {
  101. if errors.Is(err, gorm.ErrRecordNotFound) {
  102. return nil, apierrors.NewErrPassThroughToClient(
  103. fmt.Errorf("policy not found in project"),
  104. http.StatusBadRequest,
  105. )
  106. }
  107. return nil, apierrors.NewErrInternal(err)
  108. }
  109. apiPolicy, err := policyModel.ToAPIPolicyType()
  110. if err != nil {
  111. return nil, apierrors.NewErrInternal(err)
  112. }
  113. return apiPolicy, nil
  114. }
  115. }