create.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package api_token
  2. import (
  3. "net/http"
  4. "time"
  5. "github.com/porter-dev/porter/api/server/authz/policy"
  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/encryption"
  13. "github.com/porter-dev/porter/internal/models"
  14. "golang.org/x/crypto/bcrypt"
  15. )
  16. type APITokenCreateHandler struct {
  17. handlers.PorterHandlerReadWriter
  18. }
  19. func NewAPITokenCreateHandler(
  20. config *config.Config,
  21. decoderValidator shared.RequestDecoderValidator,
  22. writer shared.ResultWriter,
  23. ) *APITokenCreateHandler {
  24. return &APITokenCreateHandler{
  25. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  26. }
  27. }
  28. func (p *APITokenCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  29. user, _ := r.Context().Value(types.UserScope).(*models.User)
  30. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  31. req := &types.CreateAPIToken{}
  32. if ok := p.DecodeAndValidate(w, r, req); !ok {
  33. return
  34. }
  35. // if the expiry time is not set, set the expiry to 1 year
  36. if req.ExpiresAt.IsZero() {
  37. req.ExpiresAt = time.Now().Add(time.Hour * 24 * 365)
  38. }
  39. apiPolicy, reqErr := policy.GetAPIPolicyFromUID(p.Repo().Policy(), proj.ID, req.PolicyUID)
  40. if reqErr != nil {
  41. p.HandleAPIError(w, r, reqErr)
  42. return
  43. }
  44. uid, err := encryption.GenerateRandomBytes(16)
  45. if err != nil {
  46. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  47. return
  48. }
  49. secretKey, err := encryption.GenerateRandomBytes(16)
  50. if err != nil {
  51. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  52. return
  53. }
  54. // hash the secret key for storage in the db
  55. hashedToken, err := bcrypt.GenerateFromPassword([]byte(secretKey), 8)
  56. if err != nil {
  57. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  58. return
  59. }
  60. apiToken := &models.APIToken{
  61. UniqueID: uid,
  62. ProjectID: proj.ID,
  63. CreatedByUserID: user.ID,
  64. Expiry: &req.ExpiresAt,
  65. Revoked: false,
  66. PolicyUID: apiPolicy.UID,
  67. PolicyName: apiPolicy.Name,
  68. Name: req.Name,
  69. SecretKey: hashedToken,
  70. }
  71. apiToken, err = p.Repo().APIToken().CreateAPIToken(apiToken)
  72. if err != nil {
  73. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  74. return
  75. }
  76. // generate porter jwt token
  77. jwt, err := token.GetStoredTokenForAPI(user.ID, proj.ID, apiToken.UniqueID, secretKey)
  78. if err != nil {
  79. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  80. return
  81. }
  82. encoded, err := jwt.EncodeToken(p.Config().TokenConf)
  83. if err != nil {
  84. p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  85. return
  86. }
  87. p.WriteResult(w, r, apiToken.ToAPITokenType(apiPolicy.Policy, encoded))
  88. }