create.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package api_token
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "github.com/porter-dev/porter/api/server/handlers"
  7. "github.com/porter-dev/porter/api/server/shared"
  8. "github.com/porter-dev/porter/api/server/shared/apierrors"
  9. "github.com/porter-dev/porter/api/server/shared/config"
  10. "github.com/porter-dev/porter/api/types"
  11. "github.com/porter-dev/porter/internal/auth/token"
  12. "github.com/porter-dev/porter/internal/models"
  13. "github.com/porter-dev/porter/internal/repository"
  14. "golang.org/x/crypto/bcrypt"
  15. "gorm.io/gorm"
  16. )
  17. type APITokenCreateHandler struct {
  18. handlers.PorterHandlerReadWriter
  19. }
  20. func NewAPITokenCreateHandler(
  21. config *config.Config,
  22. decoderValidator shared.RequestDecoderValidator,
  23. writer shared.ResultWriter,
  24. ) *APITokenCreateHandler {
  25. return &APITokenCreateHandler{
  26. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  27. }
  28. }
  29. func (p *APITokenCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  30. user, _ := r.Context().Value(types.UserScope).(*models.User)
  31. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  32. req := &types.CreateAPIToken{}
  33. if ok := p.DecodeAndValidate(w, r, req); !ok {
  34. return
  35. }
  36. // look up the policy and make sure it exists
  37. policy, err := p.Repo().Policy().ReadPolicy(proj.ID, req.PolicyUID)
  38. if err != nil {
  39. if errors.Is(err, gorm.ErrRecordNotFound) {
  40. p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
  41. fmt.Errorf("policy not found in project"),
  42. http.StatusBadRequest,
  43. ))
  44. return
  45. }
  46. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  47. return
  48. }
  49. uid, err := repository.GenerateRandomBytes(16)
  50. if err != nil {
  51. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  52. return
  53. }
  54. secretKey, err := repository.GenerateRandomBytes(16)
  55. if err != nil {
  56. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  57. return
  58. }
  59. // hash the secret key for storage in the db
  60. hashedToken, err := bcrypt.GenerateFromPassword([]byte(secretKey), 8)
  61. if err != nil {
  62. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  63. return
  64. }
  65. apiToken := &models.APIToken{
  66. UniqueID: uid,
  67. ProjectID: proj.ID,
  68. CreatedByUserID: user.ID,
  69. Expiry: &req.ExpiresAt,
  70. Revoked: false,
  71. PolicyUID: policy.UniqueID,
  72. PolicyName: policy.Name,
  73. Name: req.Name,
  74. SecretKey: hashedToken,
  75. }
  76. apiToken, err = p.Repo().APIToken().CreateAPIToken(apiToken)
  77. if err != nil {
  78. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  79. return
  80. }
  81. apiPolicy, err := policy.ToAPIPolicyType()
  82. if err != nil {
  83. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  84. return
  85. }
  86. // generate porter jwt token
  87. jwt, err := token.GetStoredTokenForAPI(user.ID, proj.ID, apiToken.UniqueID, secretKey)
  88. if err != nil {
  89. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  90. return
  91. }
  92. encoded, err := jwt.EncodeToken(p.Config().TokenConf)
  93. if err != nil {
  94. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  95. return
  96. }
  97. p.WriteResult(w, r, apiToken.ToAPITokenType(apiPolicy.Policy, encoded))
  98. }