get_token.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package registry
  2. import (
  3. "encoding/base64"
  4. "net/http"
  5. "strings"
  6. "time"
  7. "github.com/aws/aws-sdk-go/service/ecr"
  8. "github.com/porter-dev/porter/api/server/handlers"
  9. "github.com/porter-dev/porter/api/server/shared"
  10. "github.com/porter-dev/porter/api/server/shared/apierrors"
  11. "github.com/porter-dev/porter/api/server/shared/config"
  12. "github.com/porter-dev/porter/api/types"
  13. "github.com/porter-dev/porter/internal/models"
  14. "github.com/porter-dev/porter/internal/oauth"
  15. "github.com/porter-dev/porter/internal/registry"
  16. "github.com/aws/aws-sdk-go/aws/arn"
  17. )
  18. type RegistryGetECRTokenHandler struct {
  19. handlers.PorterHandlerReadWriter
  20. }
  21. func NewRegistryGetECRTokenHandler(
  22. config *config.Config,
  23. decoderValidator shared.RequestDecoderValidator,
  24. writer shared.ResultWriter,
  25. ) *RegistryGetECRTokenHandler {
  26. return &RegistryGetECRTokenHandler{
  27. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  28. }
  29. }
  30. func (c *RegistryGetECRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  31. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  32. request := &types.GetRegistryECRTokenRequest{}
  33. if ok := c.DecodeAndValidate(w, r, request); !ok {
  34. return
  35. }
  36. // list registries and find one that matches the region
  37. regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
  38. if err != nil {
  39. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  40. return
  41. }
  42. var token string
  43. var expiresAt *time.Time
  44. for _, reg := range regs {
  45. if reg.AWSIntegrationID != 0 {
  46. awsInt, err := c.Repo().AWSIntegration().ReadAWSIntegration(reg.ProjectID, reg.AWSIntegrationID)
  47. if err != nil {
  48. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  49. return
  50. }
  51. // if the aws integration doesn't have an ARN populated, populate it
  52. if awsInt.AWSArn == "" {
  53. err = awsInt.PopulateAWSArn()
  54. if err != nil {
  55. continue
  56. }
  57. }
  58. parsedARN, err := arn.Parse(awsInt.AWSArn)
  59. if err != nil {
  60. continue
  61. }
  62. // if the account id is passed as part of the request, verify the account id matches the account id in the ARN
  63. if awsInt.AWSRegion == request.Region && (request.AccountID == "" || request.AccountID == parsedARN.AccountID) {
  64. // get the aws integration and session
  65. sess, err := awsInt.GetSession()
  66. if err != nil {
  67. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  68. return
  69. }
  70. ecrSvc := ecr.New(sess)
  71. output, err := ecrSvc.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
  72. if err != nil {
  73. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  74. return
  75. }
  76. token = *output.AuthorizationData[0].AuthorizationToken
  77. expiresAt = output.AuthorizationData[0].ExpiresAt
  78. }
  79. }
  80. }
  81. resp := &types.GetRegistryTokenResponse{
  82. Token: token,
  83. ExpiresAt: expiresAt,
  84. }
  85. c.WriteResult(w, r, resp)
  86. }
  87. type RegistryGetGCRTokenHandler struct {
  88. handlers.PorterHandlerReadWriter
  89. }
  90. func NewRegistryGetGCRTokenHandler(
  91. config *config.Config,
  92. decoderValidator shared.RequestDecoderValidator,
  93. writer shared.ResultWriter,
  94. ) *RegistryGetGCRTokenHandler {
  95. return &RegistryGetGCRTokenHandler{
  96. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  97. }
  98. }
  99. func (c *RegistryGetGCRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  100. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  101. request := &types.GetRegistryGCRTokenRequest{}
  102. if ok := c.DecodeAndValidate(w, r, request); !ok {
  103. return
  104. }
  105. // list registries and find one that matches the region
  106. regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
  107. if err != nil {
  108. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  109. return
  110. }
  111. var token string
  112. var expiresAt *time.Time
  113. for _, reg := range regs {
  114. if reg.GCPIntegrationID != 0 && strings.Contains(reg.URL, request.ServerURL) {
  115. _reg := registry.Registry(*reg)
  116. oauthTok, err := _reg.GetGCRToken(c.Repo())
  117. // if the oauth token is not nil, but the error is not nil, we still return the token
  118. // but log an error
  119. if oauthTok != nil && err != nil {
  120. c.HandleAPIErrorNoWrite(w, r, apierrors.NewErrInternal(err))
  121. } else if err != nil {
  122. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  123. return
  124. }
  125. token = oauthTok.AccessToken
  126. expiresAt = &oauthTok.Expiry
  127. break
  128. }
  129. }
  130. resp := &types.GetRegistryTokenResponse{
  131. Token: token,
  132. ExpiresAt: expiresAt,
  133. }
  134. c.WriteResult(w, r, resp)
  135. }
  136. type RegistryGetDOCRTokenHandler struct {
  137. handlers.PorterHandlerReadWriter
  138. }
  139. func NewRegistryGetDOCRTokenHandler(
  140. config *config.Config,
  141. decoderValidator shared.RequestDecoderValidator,
  142. writer shared.ResultWriter,
  143. ) *RegistryGetDOCRTokenHandler {
  144. return &RegistryGetDOCRTokenHandler{
  145. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  146. }
  147. }
  148. func (c *RegistryGetDOCRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  149. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  150. request := &types.GetRegistryDOCRTokenRequest{}
  151. if ok := c.DecodeAndValidate(w, r, request); !ok {
  152. return
  153. }
  154. // list registries and find one that matches the region
  155. regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
  156. if err != nil {
  157. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  158. return
  159. }
  160. var token string
  161. var expiresAt *time.Time
  162. for _, reg := range regs {
  163. if reg.DOIntegrationID != 0 && strings.Contains(reg.URL, request.ServerURL) {
  164. oauthInt, err := c.Repo().OAuthIntegration().ReadOAuthIntegration(reg.ProjectID, reg.DOIntegrationID)
  165. if err != nil {
  166. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  167. return
  168. }
  169. tok, expiry, err := oauth.GetAccessToken(
  170. oauthInt.SharedOAuthModel,
  171. c.Config().DOConf,
  172. oauth.MakeUpdateOAuthIntegrationTokenFunction(oauthInt, c.Repo()),
  173. )
  174. if err != nil {
  175. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  176. return
  177. }
  178. token = tok
  179. expiresAt = expiry
  180. break
  181. }
  182. }
  183. resp := &types.GetRegistryTokenResponse{
  184. Token: token,
  185. ExpiresAt: expiresAt,
  186. }
  187. c.WriteResult(w, r, resp)
  188. }
  189. type RegistryGetDockerhubTokenHandler struct {
  190. handlers.PorterHandlerReadWriter
  191. }
  192. func NewRegistryGetDockerhubTokenHandler(
  193. config *config.Config,
  194. decoderValidator shared.RequestDecoderValidator,
  195. writer shared.ResultWriter,
  196. ) *RegistryGetDockerhubTokenHandler {
  197. return &RegistryGetDockerhubTokenHandler{
  198. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  199. }
  200. }
  201. func (c *RegistryGetDockerhubTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  202. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  203. // list registries and find one that matches the region
  204. regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
  205. if err != nil {
  206. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  207. return
  208. }
  209. var token string
  210. var expiresAt *time.Time
  211. for _, reg := range regs {
  212. if reg.BasicIntegrationID != 0 && strings.Contains(reg.URL, "index.docker.io") {
  213. basic, err := c.Repo().BasicIntegration().ReadBasicIntegration(reg.ProjectID, reg.BasicIntegrationID)
  214. if err != nil {
  215. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  216. return
  217. }
  218. token = base64.StdEncoding.EncodeToString([]byte(string(basic.Username) + ":" + string(basic.Password)))
  219. // we'll just set an arbitrary 30-day expiry time (this is not enforced)
  220. timeExpires := time.Now().Add(30 * 24 * 3600 * time.Second)
  221. expiresAt = &timeExpires
  222. }
  223. }
  224. resp := &types.GetRegistryTokenResponse{
  225. Token: token,
  226. ExpiresAt: expiresAt,
  227. }
  228. c.WriteResult(w, r, resp)
  229. }
  230. type RegistryGetACRTokenHandler struct {
  231. handlers.PorterHandlerReadWriter
  232. }
  233. func NewRegistryGetACRTokenHandler(
  234. config *config.Config,
  235. decoderValidator shared.RequestDecoderValidator,
  236. writer shared.ResultWriter,
  237. ) *RegistryGetACRTokenHandler {
  238. return &RegistryGetACRTokenHandler{
  239. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  240. }
  241. }
  242. func (c *RegistryGetACRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  243. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  244. // list registries and find one that matches the region
  245. regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
  246. if err != nil {
  247. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  248. return
  249. }
  250. var token string
  251. var expiresAt *time.Time
  252. for _, reg := range regs {
  253. if reg.AzureIntegrationID != 0 && strings.Contains(reg.URL, "azurecr.io") {
  254. _reg := registry.Registry(*reg)
  255. username, pw, err := _reg.GetACRCredentials(c.Repo())
  256. if err != nil {
  257. continue
  258. }
  259. token = base64.StdEncoding.EncodeToString([]byte(string(username) + ":" + string(pw)))
  260. // we'll just set an arbitrary 30-day expiry time (this is not enforced)
  261. timeExpires := time.Now().Add(30 * 24 * 3600 * time.Second)
  262. expiresAt = &timeExpires
  263. }
  264. }
  265. resp := &types.GetRegistryTokenResponse{
  266. Token: token,
  267. ExpiresAt: expiresAt,
  268. }
  269. c.WriteResult(w, r, resp)
  270. }