loader.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. Token *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.Token != nil {
  31. // load the policy
  32. apiPolicy, reqErr := GetAPIPolicyFromUID(b.policyRepo, opts.Token.ProjectID, opts.Token.PolicyUID)
  33. if reqErr != nil {
  34. return nil, reqErr
  35. }
  36. return apiPolicy.Policy, nil
  37. } else if opts.ProjectID != 0 && opts.UserID != 0 {
  38. userID := opts.UserID
  39. projectID := opts.ProjectID
  40. // read role and case on role "kind"
  41. role, err := b.projRepo.ReadProjectRole(projectID, userID)
  42. if err != nil && err == gorm.ErrRecordNotFound {
  43. return nil, apierrors.NewErrForbidden(
  44. fmt.Errorf("user %d does not have a role in project %d", userID, projectID),
  45. )
  46. } else if err != nil {
  47. return nil, apierrors.NewErrInternal(err)
  48. }
  49. // load role based on role kind
  50. switch role.Kind {
  51. case types.RoleAdmin:
  52. return AdminPolicy, nil
  53. case types.RoleDeveloper:
  54. return DeveloperPolicy, nil
  55. case types.RoleViewer:
  56. return ViewerPolicy, nil
  57. default:
  58. return nil, apierrors.NewErrForbidden(
  59. fmt.Errorf("%s role not supported for user %d, project %d", string(role.Kind), userID, projectID),
  60. )
  61. }
  62. }
  63. return nil, apierrors.NewErrForbidden(
  64. fmt.Errorf("policy loader called with invalid arguments"),
  65. )
  66. }
  67. var AdminPolicy = []*types.PolicyDocument{
  68. {
  69. Scope: types.ProjectScope,
  70. Verbs: types.ReadWriteVerbGroup(),
  71. },
  72. }
  73. var DeveloperPolicy = []*types.PolicyDocument{
  74. {
  75. Scope: types.ProjectScope,
  76. Verbs: types.ReadWriteVerbGroup(),
  77. Children: map[types.PermissionScope]*types.PolicyDocument{
  78. types.SettingsScope: {
  79. Scope: types.SettingsScope,
  80. Verbs: types.ReadVerbGroup(),
  81. },
  82. },
  83. },
  84. }
  85. var ViewerPolicy = []*types.PolicyDocument{
  86. {
  87. Scope: types.ProjectScope,
  88. Verbs: types.ReadVerbGroup(),
  89. Children: map[types.PermissionScope]*types.PolicyDocument{
  90. types.SettingsScope: {
  91. Scope: types.SettingsScope,
  92. Verbs: []types.APIVerb{},
  93. },
  94. },
  95. },
  96. }
  97. func GetAPIPolicyFromUID(policyRepo repository.PolicyRepository, projectID uint, uid string) (*types.APIPolicy, apierrors.RequestError) {
  98. switch uid {
  99. case "admin":
  100. return &types.APIPolicy{
  101. APIPolicyMeta: &types.APIPolicyMeta{
  102. Name: "admin",
  103. UID: "admin",
  104. },
  105. Policy: AdminPolicy,
  106. }, nil
  107. case "developer":
  108. return &types.APIPolicy{
  109. APIPolicyMeta: &types.APIPolicyMeta{
  110. Name: "developer",
  111. UID: "developer",
  112. },
  113. Policy: DeveloperPolicy,
  114. }, nil
  115. case "viewer":
  116. return &types.APIPolicy{
  117. APIPolicyMeta: &types.APIPolicyMeta{
  118. Name: "viewer",
  119. UID: "viewer",
  120. },
  121. Policy: ViewerPolicy,
  122. }, nil
  123. default:
  124. // look up the policy and make sure it exists
  125. policyModel, err := policyRepo.ReadPolicy(projectID, uid)
  126. if err != nil {
  127. if errors.Is(err, gorm.ErrRecordNotFound) {
  128. return nil, apierrors.NewErrPassThroughToClient(
  129. fmt.Errorf("policy not found in project"),
  130. http.StatusBadRequest,
  131. )
  132. }
  133. return nil, apierrors.NewErrInternal(err)
  134. }
  135. apiPolicy, err := policyModel.ToAPIPolicyType()
  136. if err != nil {
  137. return nil, apierrors.NewErrInternal(err)
  138. }
  139. return apiPolicy, nil
  140. }
  141. }