cli_login.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package user
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "time"
  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/models"
  14. "github.com/porter-dev/porter/internal/repository"
  15. )
  16. type CLILoginHandler struct {
  17. handlers.PorterHandlerReader
  18. }
  19. func NewCLILoginHandler(
  20. config *config.Config,
  21. decoderValidator shared.RequestDecoderValidator,
  22. writer shared.ResultWriter,
  23. ) *CLILoginHandler {
  24. return &CLILoginHandler{
  25. PorterHandlerReader: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  26. }
  27. }
  28. func (c *CLILoginHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  29. request := &types.CLILoginUserRequest{}
  30. ok := c.DecodeAndValidate(w, r, request)
  31. if !ok {
  32. return
  33. }
  34. user, _ := r.Context().Value(types.UserScope).(*models.User)
  35. // generate the token
  36. jwt, err := token.GetTokenForUser(user.ID)
  37. if err != nil {
  38. err = fmt.Errorf("CLI token creation failed: %s", err.Error())
  39. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  40. return
  41. }
  42. encoded, err := jwt.EncodeToken(c.Config().TokenConf)
  43. if err != nil {
  44. err = fmt.Errorf("CLI token encoding failed: %s", err.Error())
  45. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  46. return
  47. }
  48. // generate 64 characters long authorization code
  49. code, err := repository.GenerateRandomBytes(32)
  50. if err != nil {
  51. err = fmt.Errorf("CLI random code generation failed: %s", err.Error())
  52. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  53. return
  54. }
  55. expiry := time.Now().Add(30 * time.Second)
  56. // create auth code object and send back authorization code
  57. authCode := &models.AuthCode{
  58. Token: encoded,
  59. AuthorizationCode: code,
  60. Expiry: &expiry,
  61. }
  62. authCode, err = c.Repo().AuthCode().CreateAuthCode(authCode)
  63. if err != nil {
  64. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  65. return
  66. }
  67. http.Redirect(w, r, fmt.Sprintf("%s/?code=%s", request.Redirect, url.QueryEscape(authCode.AuthorizationCode)), 302)
  68. }
  69. type CLILoginExchangeHandler struct {
  70. handlers.PorterHandlerReadWriter
  71. }
  72. func NewCLILoginExchangeHandler(
  73. config *config.Config,
  74. decoderValidator shared.RequestDecoderValidator,
  75. writer shared.ResultWriter,
  76. ) *CLILoginExchangeHandler {
  77. return &CLILoginExchangeHandler{
  78. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  79. }
  80. }
  81. func (c *CLILoginExchangeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  82. request := &types.CLILoginExchangeRequest{}
  83. ok := c.DecodeAndValidate(w, r, request)
  84. if !ok {
  85. return
  86. }
  87. // look up the auth code and exchange it for a token
  88. authCode, err := c.Repo().AuthCode().ReadAuthCode(request.AuthorizationCode)
  89. if err != nil || authCode.IsExpired() {
  90. http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
  91. return
  92. }
  93. res := &types.CLILoginExchangeResponse{
  94. Token: authCode.Token,
  95. }
  96. c.WriteResult(w, r, res)
  97. }