loader.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. projRoleRepo repository.ProjectRoleRepository
  22. policyRepo repository.PolicyRepository
  23. }
  24. func NewBasicPolicyDocumentLoader(projRoleRepo repository.ProjectRoleRepository, policyRepo repository.PolicyRepository) *RepoPolicyDocumentLoader {
  25. return &RepoPolicyDocumentLoader{projRoleRepo, 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. roles, err := b.projRoleRepo.ListAllRolesForUser(projectID, userID)
  45. if err != nil {
  46. return nil, apierrors.NewErrInternal(err)
  47. } else if len(roles) == 0 {
  48. return nil, apierrors.NewErrForbidden(
  49. fmt.Errorf("user does not have any roles assigned in this project"),
  50. )
  51. }
  52. var policies []*types.PolicyDocument
  53. for _, role := range roles {
  54. policy, err := b.policyRepo.ReadPolicy(projectID, role.PolicyUID)
  55. if err != nil {
  56. return nil, apierrors.NewErrInternal(err)
  57. }
  58. policyType, err := policy.ToAPIPolicyType()
  59. if err != nil {
  60. return nil, apierrors.NewErrInternal(err)
  61. }
  62. policies = append(policies, policyType.Policy...)
  63. }
  64. if len(policies) == 0 {
  65. return nil, apierrors.NewErrForbidden(
  66. fmt.Errorf("user does not have any roles assigned in this project"),
  67. )
  68. }
  69. return policies, nil
  70. }
  71. return nil, apierrors.NewErrForbidden(
  72. fmt.Errorf("policy loader called with invalid arguments"),
  73. )
  74. }
  75. func GetAPIPolicyFromUID(policyRepo repository.PolicyRepository, projectID uint, uid string) (*types.APIPolicy, apierrors.RequestError) {
  76. switch uid {
  77. case "admin":
  78. return &types.APIPolicy{
  79. APIPolicyMeta: &types.APIPolicyMeta{
  80. Name: "admin",
  81. UID: "admin",
  82. },
  83. Policy: types.AdminPolicy,
  84. }, nil
  85. case "developer":
  86. return &types.APIPolicy{
  87. APIPolicyMeta: &types.APIPolicyMeta{
  88. Name: "developer",
  89. UID: "developer",
  90. },
  91. Policy: types.DeveloperPolicy,
  92. }, nil
  93. case "viewer":
  94. return &types.APIPolicy{
  95. APIPolicyMeta: &types.APIPolicyMeta{
  96. Name: "viewer",
  97. UID: "viewer",
  98. },
  99. Policy: types.ViewerPolicy,
  100. }, nil
  101. default:
  102. // look up the policy and make sure it exists
  103. policyModel, err := policyRepo.ReadPolicy(projectID, uid)
  104. if err != nil {
  105. if errors.Is(err, gorm.ErrRecordNotFound) {
  106. return nil, apierrors.NewErrPassThroughToClient(
  107. fmt.Errorf("policy not found in project"),
  108. http.StatusBadRequest,
  109. )
  110. }
  111. return nil, apierrors.NewErrInternal(err)
  112. }
  113. apiPolicy, err := policyModel.ToAPIPolicyType()
  114. if err != nil {
  115. return nil, apierrors.NewErrInternal(err)
  116. }
  117. return apiPolicy, nil
  118. }
  119. }