2
0

create.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package api_token
  2. import (
  3. "fmt"
  4. "net/http"
  5. "time"
  6. "github.com/porter-dev/porter/api/server/authz/policy"
  7. "github.com/porter-dev/porter/api/server/handlers"
  8. "github.com/porter-dev/porter/api/server/shared"
  9. "github.com/porter-dev/porter/api/server/shared/apierrors"
  10. "github.com/porter-dev/porter/api/server/shared/config"
  11. "github.com/porter-dev/porter/api/types"
  12. "github.com/porter-dev/porter/internal/auth/token"
  13. "github.com/porter-dev/porter/internal/encryption"
  14. "github.com/porter-dev/porter/internal/models"
  15. "golang.org/x/crypto/bcrypt"
  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. if !proj.GetFeatureFlag(models.APITokensEnabled, p.Config().LaunchDarklyClient) {
  33. p.HandleAPIError(w, r, apierrors.NewErrForbidden(fmt.Errorf("api token endpoints are not enabled for this project")))
  34. return
  35. }
  36. req := &types.CreateAPIToken{}
  37. if ok := p.DecodeAndValidate(w, r, req); !ok {
  38. return
  39. }
  40. // if the expiry time is not set, set the expiry to 1 year
  41. if req.ExpiresAt.IsZero() {
  42. req.ExpiresAt = time.Now().Add(time.Hour * 24 * 365)
  43. }
  44. apiPolicy, reqErr := policy.GetAPIPolicyFromUID(p.Repo().Policy(), proj.ID, req.PolicyUID)
  45. if reqErr != nil {
  46. p.HandleAPIError(w, r, reqErr)
  47. return
  48. }
  49. uid, err := encryption.GenerateRandomBytes(16)
  50. if err != nil {
  51. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  52. return
  53. }
  54. secretKey, err := encryption.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: apiPolicy.UID,
  72. PolicyName: apiPolicy.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. // generate porter jwt token
  82. jwt, err := token.GetStoredTokenForAPI(user.ID, proj.ID, apiToken.UniqueID, secretKey)
  83. if err != nil {
  84. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  85. return
  86. }
  87. encoded, err := jwt.EncodeToken(p.Config().TokenConf)
  88. if err != nil {
  89. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  90. return
  91. }
  92. p.WriteResult(w, r, apiToken.ToAPITokenType(apiPolicy.Policy, encoded))
  93. }