aboutsummaryrefslogtreecommitdiff
path: root/app/controllers/api_account_list.go
blob: 4835d0cbc2fd211c5a662500347b2d88106f501b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package controllers

import (
	"context"
	"net/http"

	"code.crute.us/mcrute/cloud-identity-broker/app"
	"code.crute.us/mcrute/cloud-identity-broker/app/middleware"
	"code.crute.us/mcrute/cloud-identity-broker/app/models"

	"code.crute.us/mcrute/golib/echo/controller"
	"github.com/labstack/echo/v4"
)

type jsonAccount struct {
	Vendor               string `json:"vendor,omitempty"`
	AccountNumber        int    `json:"account_number"`
	ShortName            string `json:"short_name"`
	Name                 string `json:"name"`
	SelfUrl              string `json:"url"`
	ConsoleUrl           string `json:"get_console_url,omitempty"`
	ConsoleRedirectUrl   string `json:"console_redirect_url,omitempty"`
	CredentialsUrl       string `json:"credentials_url"`
	GlobalCredentialsUrl string `json:"global_credential_url,omitempty"`
}

func jsonAccountFromAccount(c echo.Context, a *models.Account) *jsonAccount {
	u := app.AppURL{}

	return &jsonAccount{
		AccountNumber:        a.AccountNumber,
		ShortName:            a.ShortName,
		Name:                 a.Name,
		SelfUrl:              u.Account(c, "aws", &a.ShortName),
		ConsoleUrl:           u.AccountConsole(c, "aws", a.ShortName, false),
		ConsoleRedirectUrl:   u.AccountConsole(c, "aws", a.ShortName, true),
		CredentialsUrl:       u.AccountCredentials(c, "aws", a.ShortName, ""),
		GlobalCredentialsUrl: u.AccountCredentials(c, "aws", a.ShortName, "global"),
	}
}

type APIAccountListHandler struct {
	store models.AccountStore
}

func NewAPIAccountListHandler(s models.AccountStore) echo.HandlerFunc {
	al := &APIAccountListHandler{store: s}
	h := &controller.ContentTypeNegotiatingHandler{
		DefaultHandler: al.HandleV1,
		Handlers: map[string]echo.HandlerFunc{
			contentTypeV1: al.HandleV1,
			contentTypeV2: al.HandleV2,
		},
	}
	return h.Handle
}

// getAccountList returns the account list. This does the same work that
// GetContext would do for most AWSAPI handlers but is a little different
// because it deals with lists of accounts.
//
// Authorization of the account is handled within the store. The store will not
// return accounts for which the user does not have access.
func (h *APIAccountListHandler) getAccountList(c echo.Context) ([]*models.Account, error) {
	principal, err := middleware.GetAuthorizedPrincipal(c)
	if err != nil {
		return nil, echo.ErrUnauthorized
	}

	accounts, err := h.store.ListForUser(context.Background(), principal)
	if err != nil {
		c.Logger().Errorf("Unable to load account list: %w", err)
		return nil, echo.ErrInternalServerError
	}

	return accounts, nil
}

// HandleV1 returns a list of JSON account objects
func (h *APIAccountListHandler) HandleV1(c echo.Context) error {
	accounts, err := h.getAccountList(c)
	if err != nil {
		return err
	}

	out := []*jsonAccount{}
	for _, a := range accounts {
		ja := jsonAccountFromAccount(c, a)
		ja.Vendor = "aws"
		out = append(out, ja)
	}

	return c.JSON(http.StatusOK, out)
}

// HandleV2 returns a map of lists of account objects. the key to the map is
// the short name of the cloud provider.
func (h *APIAccountListHandler) HandleV2(c echo.Context) error {
	accounts, err := h.getAccountList(c)
	if err != nil {
		return err
	}

	out := map[string][]*jsonAccount{
		"aws": []*jsonAccount{},
	}
	for _, a := range accounts {
		ja := jsonAccountFromAccount(c, a)
		out["aws"] = append(out["aws"], ja)
	}

	return c.JSON(http.StatusOK, out)
}