443 lines
10 KiB
Go
443 lines
10 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/influxdata/influx-cli/v2/api"
|
|
"github.com/influxdata/influx-cli/v2/clients"
|
|
"github.com/influxdata/influx-cli/v2/pkg/influxid"
|
|
)
|
|
|
|
type Client struct {
|
|
clients.CLI
|
|
api.AuthorizationsApi
|
|
api.UsersApi
|
|
api.OrganizationsApi
|
|
}
|
|
|
|
const (
|
|
ReadAction = "read"
|
|
WriteAction = "write"
|
|
)
|
|
|
|
type token struct {
|
|
ID string `json:"id"`
|
|
Description string `json:"description"`
|
|
Token string `json:"token"`
|
|
Status string `json:"status"`
|
|
UserName string `json:"userName"`
|
|
UserID string `json:"userID"`
|
|
Permissions []string `json:"permissions"`
|
|
}
|
|
|
|
type printParams struct {
|
|
deleted bool
|
|
token *token
|
|
tokens []token
|
|
}
|
|
|
|
type CreateParams struct {
|
|
clients.OrgParams
|
|
User string
|
|
Description string
|
|
|
|
WriteUserPermission bool
|
|
ReadUserPermission bool
|
|
|
|
WriteBucketsPermission bool
|
|
ReadBucketsPermission bool
|
|
|
|
WriteBucketIds []string
|
|
ReadBucketIds []string
|
|
|
|
WriteTasksPermission bool
|
|
ReadTasksPermission bool
|
|
|
|
WriteTelegrafsPermission bool
|
|
ReadTelegrafsPermission bool
|
|
|
|
WriteOrganizationsPermission bool
|
|
ReadOrganizationsPermission bool
|
|
|
|
WriteDashboardsPermission bool
|
|
ReadDashboardsPermission bool
|
|
|
|
WriteCheckPermission bool
|
|
ReadCheckPermission bool
|
|
|
|
WriteNotificationRulePermission bool
|
|
ReadNotificationRulePermission bool
|
|
|
|
WriteNotificationEndpointPermission bool
|
|
ReadNotificationEndpointPermission bool
|
|
|
|
WriteDBRPPermission bool
|
|
ReadDBRPPermission bool
|
|
}
|
|
|
|
func (c Client) Create(ctx context.Context, params *CreateParams) error {
|
|
|
|
orgID, err := c.getOrgID(ctx, params.OrgParams)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bucketPerms := []struct {
|
|
action string
|
|
perms []string
|
|
}{
|
|
{action: ReadAction, perms: params.ReadBucketIds},
|
|
{action: WriteAction, perms: params.WriteBucketIds},
|
|
}
|
|
|
|
var permissions []api.Permission
|
|
for _, bp := range bucketPerms {
|
|
for _, p := range bp.perms {
|
|
// verify the input ID
|
|
if _, err := influxid.IDFromString(p); err != nil {
|
|
return fmt.Errorf("invalid bucket ID '%s': %w (did you pass a bucket name instead of an ID?)", p, err)
|
|
}
|
|
|
|
newPerm := api.Permission{
|
|
Action: bp.action,
|
|
Resource: makePermResource("buckets", p, orgID),
|
|
}
|
|
permissions = append(permissions, newPerm)
|
|
}
|
|
}
|
|
|
|
providedPerm := []struct {
|
|
readPerm, writePerm bool
|
|
resourceType string
|
|
}{
|
|
{
|
|
readPerm: params.ReadBucketsPermission,
|
|
writePerm: params.WriteBucketsPermission,
|
|
resourceType: "buckets",
|
|
},
|
|
{
|
|
readPerm: params.ReadCheckPermission,
|
|
writePerm: params.WriteCheckPermission,
|
|
resourceType: "checks",
|
|
},
|
|
{
|
|
readPerm: params.ReadDashboardsPermission,
|
|
writePerm: params.WriteDashboardsPermission,
|
|
resourceType: "dashboards",
|
|
},
|
|
{
|
|
readPerm: params.ReadNotificationEndpointPermission,
|
|
writePerm: params.WriteNotificationEndpointPermission,
|
|
resourceType: "notificationEndpoints",
|
|
},
|
|
{
|
|
readPerm: params.ReadNotificationRulePermission,
|
|
writePerm: params.WriteNotificationRulePermission,
|
|
resourceType: "notificationRules",
|
|
},
|
|
{
|
|
readPerm: params.ReadOrganizationsPermission,
|
|
writePerm: params.WriteOrganizationsPermission,
|
|
resourceType: "orgs",
|
|
},
|
|
{
|
|
readPerm: params.ReadTasksPermission,
|
|
writePerm: params.WriteTasksPermission,
|
|
resourceType: "tasks",
|
|
},
|
|
{
|
|
readPerm: params.ReadTelegrafsPermission,
|
|
writePerm: params.WriteTelegrafsPermission,
|
|
resourceType: "telegrafs",
|
|
},
|
|
{
|
|
readPerm: params.ReadUserPermission,
|
|
writePerm: params.WriteUserPermission,
|
|
resourceType: "users",
|
|
},
|
|
{
|
|
readPerm: params.ReadDBRPPermission,
|
|
writePerm: params.WriteDBRPPermission,
|
|
resourceType: "dbrp",
|
|
},
|
|
}
|
|
|
|
for _, provided := range providedPerm {
|
|
var actions []string
|
|
if provided.readPerm {
|
|
actions = append(actions, ReadAction)
|
|
}
|
|
if provided.writePerm {
|
|
actions = append(actions, WriteAction)
|
|
}
|
|
|
|
for _, action := range actions {
|
|
p := api.Permission{
|
|
Action: action,
|
|
Resource: makePermResource(provided.resourceType, "", orgID),
|
|
}
|
|
permissions = append(permissions, p)
|
|
}
|
|
}
|
|
|
|
// Get the user ID because the command only takes a username, not ID
|
|
users, err := c.UsersApi.GetUsers(ctx).Name(params.User).Execute()
|
|
if err != nil || len(users.GetUsers()) == 0 {
|
|
return fmt.Errorf("could not find user with name %q: %w", params.User, err)
|
|
}
|
|
userID := users.GetUsers()[0].GetId()
|
|
|
|
authReq := api.AuthorizationPostRequest{
|
|
OrgID: orgID,
|
|
UserID: &userID,
|
|
Permissions: permissions,
|
|
}
|
|
if params.Description != "" {
|
|
authReq.SetDescription(params.Description)
|
|
}
|
|
|
|
auth, err := c.PostAuthorizations(ctx).AuthorizationPostRequest(authReq).Execute()
|
|
if err != nil {
|
|
return fmt.Errorf("could not write auth with provided arguments: %w", err)
|
|
}
|
|
|
|
ps := make([]string, 0, len(auth.GetPermissions()))
|
|
for _, p := range auth.GetPermissions() {
|
|
ps = append(ps, p.String())
|
|
}
|
|
|
|
return c.printAuth(printParams{
|
|
token: &token{
|
|
ID: auth.GetId(),
|
|
Description: auth.GetDescription(),
|
|
Token: auth.GetToken(),
|
|
Status: auth.GetStatus(),
|
|
UserName: auth.GetUser(),
|
|
UserID: auth.GetUserID(),
|
|
Permissions: ps,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (c Client) Remove(ctx context.Context, authID string) error {
|
|
// check if auth exists first for better error logging, and to
|
|
// acquire the auth that was deleted since the delete
|
|
// request does not return the Authorization object.
|
|
a, err := c.GetAuthorizationsID(ctx, authID).Execute()
|
|
if err != nil {
|
|
return fmt.Errorf("could not find auth with ID %q: %w", authID, err)
|
|
}
|
|
|
|
if err := c.DeleteAuthorizationsID(ctx, authID).Execute(); err != nil {
|
|
return fmt.Errorf("could not remove auth with ID %q: %w", authID, err)
|
|
}
|
|
|
|
ps := make([]string, 0, len(a.Permissions))
|
|
for _, p := range a.Permissions {
|
|
ps = append(ps, p.String())
|
|
}
|
|
|
|
return c.printAuth(printParams{
|
|
deleted: true,
|
|
token: &token{
|
|
ID: a.GetId(),
|
|
Description: a.GetDescription(),
|
|
Token: a.GetToken(),
|
|
Status: a.GetStatus(),
|
|
UserName: a.GetUser(),
|
|
UserID: a.GetUserID(),
|
|
Permissions: ps,
|
|
},
|
|
})
|
|
}
|
|
|
|
type ListParams struct {
|
|
clients.OrgParams
|
|
Id string
|
|
User string
|
|
UserID string
|
|
}
|
|
|
|
func (c Client) List(ctx context.Context, params *ListParams) error {
|
|
|
|
// If ID parameter is set, search by that over other filters
|
|
if params.Id != "" {
|
|
return c.findAuthorization(ctx, params.Id)
|
|
}
|
|
|
|
req := c.GetAuthorizations(ctx)
|
|
if params.User != "" {
|
|
req.User(params.User)
|
|
}
|
|
if params.UserID != "" {
|
|
req.UserID(params.UserID)
|
|
}
|
|
if params.OrgName != "" {
|
|
req.Org(params.OrgName)
|
|
}
|
|
if params.OrgID.Valid() {
|
|
req.OrgID(params.OrgID.String())
|
|
}
|
|
|
|
auths, err := req.Execute()
|
|
if err != nil {
|
|
return fmt.Errorf("could not find authorization with given parameters: %w", err)
|
|
}
|
|
|
|
var tokens []token
|
|
for _, a := range auths.GetAuthorizations() {
|
|
var ps []string
|
|
for _, p := range a.GetPermissions() {
|
|
ps = append(ps, p.String())
|
|
}
|
|
|
|
tokens = append(tokens, token{
|
|
ID: a.GetId(),
|
|
Description: a.GetDescription(),
|
|
Token: a.GetToken(),
|
|
Status: a.GetStatus(),
|
|
UserName: a.GetUser(),
|
|
UserID: a.GetUserID(),
|
|
Permissions: ps,
|
|
})
|
|
}
|
|
|
|
return c.printAuth(printParams{tokens: tokens})
|
|
}
|
|
|
|
func (c Client) findAuthorization(ctx context.Context, authID string) error {
|
|
a, err := c.GetAuthorizationsID(ctx, authID).Execute()
|
|
if err != nil {
|
|
return fmt.Errorf("could not find authorization with ID %q: %w", authID, err)
|
|
}
|
|
|
|
ps := make([]string, 0, len(a.GetPermissions()))
|
|
for _, p := range a.GetPermissions() {
|
|
ps = append(ps, p.String())
|
|
}
|
|
|
|
return c.printAuth(printParams{
|
|
token: &token{
|
|
ID: a.GetId(),
|
|
Description: a.GetDescription(),
|
|
Token: a.GetToken(),
|
|
Status: a.GetStatus(),
|
|
UserName: a.GetUser(),
|
|
UserID: a.GetUserID(),
|
|
Permissions: ps,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (c Client) SetActive(ctx context.Context, authID string, active bool) error {
|
|
|
|
// check if auth exists first for better error logging
|
|
if _, err := c.GetAuthorizationsID(ctx, authID).Execute(); err != nil {
|
|
return fmt.Errorf("could not find auth with ID %q: %w", authID, err)
|
|
}
|
|
|
|
var status string
|
|
if active {
|
|
status = "active"
|
|
} else {
|
|
status = "inactive"
|
|
}
|
|
a, err := c.PatchAuthorizationsID(ctx, authID).
|
|
AuthorizationUpdateRequest(api.AuthorizationUpdateRequest{Status: &status}).
|
|
Execute()
|
|
if err != nil {
|
|
return fmt.Errorf("could not update status of auth with ID %q: %w", authID, err)
|
|
}
|
|
|
|
ps := make([]string, 0, len(a.GetPermissions()))
|
|
for _, p := range a.GetPermissions() {
|
|
ps = append(ps, p.String())
|
|
}
|
|
|
|
return c.printAuth(printParams{
|
|
token: &token{
|
|
ID: a.GetId(),
|
|
Description: a.GetDescription(),
|
|
Token: a.GetToken(),
|
|
Status: a.GetStatus(),
|
|
UserName: a.GetUser(),
|
|
UserID: a.GetUserID(),
|
|
Permissions: ps,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (c Client) printAuth(opts printParams) error {
|
|
if c.PrintAsJSON {
|
|
var v interface{}
|
|
if opts.token != nil {
|
|
v = opts.token
|
|
} else {
|
|
v = opts.tokens
|
|
}
|
|
return c.PrintJSON(v)
|
|
}
|
|
|
|
headers := []string{
|
|
"ID",
|
|
"Description",
|
|
"Token",
|
|
"User Name",
|
|
"User ID",
|
|
"Permissions",
|
|
}
|
|
if opts.deleted {
|
|
headers = append(headers, "Deleted")
|
|
}
|
|
|
|
if opts.token != nil {
|
|
opts.tokens = append(opts.tokens, *opts.token)
|
|
}
|
|
|
|
var rows []map[string]interface{}
|
|
for _, t := range opts.tokens {
|
|
row := map[string]interface{}{
|
|
"ID": t.ID,
|
|
"Description": t.Description,
|
|
"Token": t.Token,
|
|
"User Name": t.UserName,
|
|
"User ID": t.UserID,
|
|
"Permissions": t.Permissions,
|
|
}
|
|
if opts.deleted {
|
|
row["Deleted"] = true
|
|
}
|
|
rows = append(rows, row)
|
|
}
|
|
return c.PrintTable(headers, rows...)
|
|
}
|
|
|
|
func makePermResource(permType string, id string, orgId string) api.PermissionResource {
|
|
return api.PermissionResource{
|
|
Type: permType,
|
|
Id: &id,
|
|
OrgID: &orgId,
|
|
}
|
|
}
|
|
|
|
func (c Client) getOrgID(ctx context.Context, params clients.OrgParams) (string, error) {
|
|
if !params.OrgID.Valid() && params.OrgName == "" && c.ActiveConfig.Org == "" {
|
|
return "", clients.ErrMustSpecifyOrg
|
|
}
|
|
if params.OrgID.Valid() {
|
|
return params.OrgID.String(), nil
|
|
}
|
|
name := params.OrgName
|
|
if name == "" {
|
|
name = c.ActiveConfig.Org
|
|
}
|
|
org, err := c.GetOrgs(ctx).Org(name).Execute()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to lookup org with name %q: %w", name, err)
|
|
}
|
|
if len(org.GetOrgs()) == 0 {
|
|
return "", fmt.Errorf("no organization with name %q: %w", name, err)
|
|
}
|
|
return org.GetOrgs()[0].GetId(), nil
|
|
}
|