|
| 1 | +package iam |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "reflect" |
| 6 | + |
| 7 | + "github.com/scaleway/scaleway-cli/v2/core" |
| 8 | + "github.com/scaleway/scaleway-cli/v2/core/human" |
| 9 | + iam "github.com/scaleway/scaleway-sdk-go/api/iam/v1alpha1" |
| 10 | + "github.com/scaleway/scaleway-sdk-go/scw" |
| 11 | +) |
| 12 | + |
| 13 | +type iamGetAPIKeyArgs struct { |
| 14 | + AccessKey string |
| 15 | + WithPolicies bool |
| 16 | +} |
| 17 | + |
| 18 | +type apiKeyOptions struct { |
| 19 | + WithPolicies bool |
| 20 | +} |
| 21 | + |
| 22 | +func WithPolicies(withPolicies bool) apiKeyOptions { |
| 23 | + return apiKeyOptions{ |
| 24 | + WithPolicies: withPolicies, |
| 25 | + } |
| 26 | +} |
| 27 | + |
| 28 | +func getApiKey( |
| 29 | + ctx context.Context, |
| 30 | + api *iam.API, |
| 31 | + accessKey string, |
| 32 | + options apiKeyOptions, |
| 33 | +) (apiKeyResponse, error) { |
| 34 | + var response apiKeyResponse |
| 35 | + apiKey, err := api.GetAPIKey(&iam.GetAPIKeyRequest{ |
| 36 | + AccessKey: accessKey, |
| 37 | + }, scw.WithContext(ctx)) |
| 38 | + if err != nil { |
| 39 | + return response, err |
| 40 | + } |
| 41 | + |
| 42 | + user, err := api.GetUser(&iam.GetUserRequest{ |
| 43 | + UserID: *apiKey.UserID, |
| 44 | + }, scw.WithContext(ctx)) |
| 45 | + if err != nil { |
| 46 | + return response, err |
| 47 | + } |
| 48 | + |
| 49 | + response.APIKey = apiKey |
| 50 | + response.UserType = user.Type |
| 51 | + |
| 52 | + if options.WithPolicies { |
| 53 | + listPolicyRequest := &iam.ListPoliciesRequest{ |
| 54 | + UserIDs: []string{*apiKey.UserID}, |
| 55 | + } |
| 56 | + // if user is owner, list all policies attached to the organization |
| 57 | + // because the user has no policies attached directly |
| 58 | + if user.Type == iam.UserTypeOwner { |
| 59 | + listPolicyRequest.OrganizationID = apiKey.DefaultProjectID |
| 60 | + listPolicyRequest.UserIDs = []string{} |
| 61 | + } |
| 62 | + policies, err := api.ListPolicies( |
| 63 | + listPolicyRequest, |
| 64 | + scw.WithAllPages(), |
| 65 | + scw.WithContext(ctx), |
| 66 | + ) |
| 67 | + if err != nil { |
| 68 | + return response, err |
| 69 | + } |
| 70 | + response.Policies = policies.Policies |
| 71 | + } |
| 72 | + |
| 73 | + return response, nil |
| 74 | +} |
| 75 | + |
| 76 | +type apiKeyResponse struct { |
| 77 | + APIKey *iam.APIKey |
| 78 | + UserType iam.UserType `json:"user_type"` |
| 79 | + Policies []*iam.Policy `json:"policies"` |
| 80 | +} |
| 81 | + |
| 82 | +func apiKeyMarshalerFunc(i interface{}, opt *human.MarshalOpt) (string, error) { |
| 83 | + type tmp apiKeyResponse |
| 84 | + resp := tmp(i.(apiKeyResponse)) |
| 85 | + |
| 86 | + sections := []*human.MarshalSection{ |
| 87 | + { |
| 88 | + FieldName: "UserType", |
| 89 | + Title: "User Type", |
| 90 | + }, |
| 91 | + { |
| 92 | + FieldName: "APIKey", |
| 93 | + Title: "API Key", |
| 94 | + }, |
| 95 | + } |
| 96 | + |
| 97 | + if len(resp.Policies) > 0 { |
| 98 | + sections = append(sections, &human.MarshalSection{ |
| 99 | + FieldName: "Policies", |
| 100 | + Title: "Policies", |
| 101 | + }) |
| 102 | + } |
| 103 | + |
| 104 | + opt.Sections = sections |
| 105 | + |
| 106 | + return human.Marshal(resp, opt) |
| 107 | +} |
| 108 | + |
| 109 | +func iamAPIKeyGetBuilder(c *core.Command) *core.Command { |
| 110 | + human.RegisterMarshalerFunc(apiKeyResponse{}, apiKeyMarshalerFunc) |
| 111 | + |
| 112 | + return &core.Command{ |
| 113 | + Short: `Get an API key`, |
| 114 | + Long: `Retrieve information about an API key, specified by the ` + "`" + `access_key` + "`" + ` parameter. The API key's details, including either the ` + "`" + `user_id` + "`" + ` or ` + "`" + `application_id` + "`" + ` of its bearer are returned in the response. Note that the string value for the ` + "`" + `secret_key` + "`" + ` is nullable, and therefore is not displayed in the response. The ` + "`" + `secret_key` + "`" + ` value is only displayed upon API key creation.`, |
| 115 | + Namespace: "iam", |
| 116 | + Resource: "api-key", |
| 117 | + Verb: "get", |
| 118 | + // Deprecated: false, |
| 119 | + ArgsType: reflect.TypeOf(iamGetAPIKeyArgs{}), |
| 120 | + ArgSpecs: core.ArgSpecs{ |
| 121 | + { |
| 122 | + Name: "access-key", |
| 123 | + Short: `Access key to search for`, |
| 124 | + Required: true, |
| 125 | + Deprecated: false, |
| 126 | + Positional: true, |
| 127 | + }, |
| 128 | + { |
| 129 | + Name: "with-policies", |
| 130 | + Short: `Display policies associated with the API key`, |
| 131 | + Default: core.DefaultValueSetter("false"), |
| 132 | + Required: false, |
| 133 | + Deprecated: false, |
| 134 | + Positional: false, |
| 135 | + }, |
| 136 | + }, |
| 137 | + Run: func(ctx context.Context, args interface{}) (i interface{}, e error) { |
| 138 | + arguments := args.(*iamGetAPIKeyArgs) |
| 139 | + |
| 140 | + client := core.ExtractClient(ctx) |
| 141 | + api := iam.NewAPI(client) |
| 142 | + |
| 143 | + return getApiKey(ctx, api, arguments.AccessKey, apiKeyOptions{ |
| 144 | + WithPolicies: arguments.WithPolicies, |
| 145 | + }) |
| 146 | + }, |
| 147 | + } |
| 148 | +} |
0 commit comments