github.com/minio/madmin-go/v2@v2.2.1/policy-commands.go (about) 1 // 2 // Copyright (c) 2015-2022 MinIO, Inc. 3 // 4 // This file is part of MinIO Object Storage stack 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU Affero General Public License as 8 // published by the Free Software Foundation, either version 3 of the 9 // License, or (at your option) any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU Affero General Public License for more details. 15 // 16 // You should have received a copy of the GNU Affero General Public License 17 // along with this program. If not, see <http://www.gnu.org/licenses/>. 18 // 19 20 package madmin 21 22 import ( 23 "context" 24 "encoding/json" 25 "io/ioutil" 26 "net/http" 27 "net/url" 28 "time" 29 ) 30 31 // InfoCannedPolicy - expand canned policy into JSON structure. 32 // 33 // To be DEPRECATED in favor of the implementation in InfoCannedPolicyV2 34 func (adm *AdminClient) InfoCannedPolicy(ctx context.Context, policyName string) ([]byte, error) { 35 queryValues := url.Values{} 36 queryValues.Set("name", policyName) 37 38 reqData := requestData{ 39 relPath: adminAPIPrefix + "/info-canned-policy", 40 queryValues: queryValues, 41 } 42 43 // Execute GET on /minio/admin/v3/info-canned-policy 44 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 45 46 defer closeResponse(resp) 47 if err != nil { 48 return nil, err 49 } 50 51 if resp.StatusCode != http.StatusOK { 52 return nil, httpRespToErrorResponse(resp) 53 } 54 55 return ioutil.ReadAll(resp.Body) 56 } 57 58 // PolicyInfo contains information on a policy. 59 type PolicyInfo struct { 60 PolicyName string 61 Policy json.RawMessage 62 CreateDate time.Time `json:",omitempty"` 63 UpdateDate time.Time `json:",omitempty"` 64 } 65 66 // MarshalJSON marshaller for JSON 67 func (pi PolicyInfo) MarshalJSON() ([]byte, error) { 68 type aliasPolicyInfo PolicyInfo // needed to avoid recursive marshal 69 if pi.CreateDate.IsZero() && pi.UpdateDate.IsZero() { 70 return json.Marshal(&struct { 71 PolicyName string 72 Policy json.RawMessage 73 }{ 74 PolicyName: pi.PolicyName, 75 Policy: pi.Policy, 76 }) 77 } 78 return json.Marshal(aliasPolicyInfo(pi)) 79 } 80 81 // InfoCannedPolicyV2 - get info on a policy including timestamps and policy json. 82 func (adm *AdminClient) InfoCannedPolicyV2(ctx context.Context, policyName string) (*PolicyInfo, error) { 83 queryValues := url.Values{} 84 queryValues.Set("name", policyName) 85 queryValues.Set("v", "2") 86 87 reqData := requestData{ 88 relPath: adminAPIPrefix + "/info-canned-policy", 89 queryValues: queryValues, 90 } 91 92 // Execute GET on /minio/admin/v3/info-canned-policy 93 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 94 95 defer closeResponse(resp) 96 if err != nil { 97 return nil, err 98 } 99 100 if resp.StatusCode != http.StatusOK { 101 return nil, httpRespToErrorResponse(resp) 102 } 103 104 data, err := ioutil.ReadAll(resp.Body) 105 if err != nil { 106 return nil, err 107 } 108 109 var p PolicyInfo 110 err = json.Unmarshal(data, &p) 111 return &p, err 112 } 113 114 // ListCannedPolicies - list all configured canned policies. 115 func (adm *AdminClient) ListCannedPolicies(ctx context.Context) (map[string]json.RawMessage, error) { 116 reqData := requestData{ 117 relPath: adminAPIPrefix + "/list-canned-policies", 118 } 119 120 // Execute GET on /minio/admin/v3/list-canned-policies 121 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 122 123 defer closeResponse(resp) 124 if err != nil { 125 return nil, err 126 } 127 128 if resp.StatusCode != http.StatusOK { 129 return nil, httpRespToErrorResponse(resp) 130 } 131 132 respBytes, err := ioutil.ReadAll(resp.Body) 133 if err != nil { 134 return nil, err 135 } 136 137 policies := make(map[string]json.RawMessage) 138 if err = json.Unmarshal(respBytes, &policies); err != nil { 139 return nil, err 140 } 141 142 return policies, nil 143 } 144 145 // RemoveCannedPolicy - remove a policy for a canned. 146 func (adm *AdminClient) RemoveCannedPolicy(ctx context.Context, policyName string) error { 147 queryValues := url.Values{} 148 queryValues.Set("name", policyName) 149 150 reqData := requestData{ 151 relPath: adminAPIPrefix + "/remove-canned-policy", 152 queryValues: queryValues, 153 } 154 155 // Execute DELETE on /minio/admin/v3/remove-canned-policy to remove policy. 156 resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData) 157 158 defer closeResponse(resp) 159 if err != nil { 160 return err 161 } 162 163 if resp.StatusCode != http.StatusOK { 164 return httpRespToErrorResponse(resp) 165 } 166 167 return nil 168 } 169 170 // AddCannedPolicy - adds a policy for a canned. 171 func (adm *AdminClient) AddCannedPolicy(ctx context.Context, policyName string, policy []byte) error { 172 if policy == nil { 173 return ErrInvalidArgument("policy input cannot be empty") 174 } 175 176 queryValues := url.Values{} 177 queryValues.Set("name", policyName) 178 179 reqData := requestData{ 180 relPath: adminAPIPrefix + "/add-canned-policy", 181 queryValues: queryValues, 182 content: policy, 183 } 184 185 // Execute PUT on /minio/admin/v3/add-canned-policy to set policy. 186 resp, err := adm.executeMethod(ctx, http.MethodPut, reqData) 187 188 defer closeResponse(resp) 189 if err != nil { 190 return err 191 } 192 193 if resp.StatusCode != http.StatusOK { 194 return httpRespToErrorResponse(resp) 195 } 196 197 return nil 198 } 199 200 // SetPolicy - sets the policy for a user or a group. 201 func (adm *AdminClient) SetPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error { 202 queryValues := url.Values{} 203 queryValues.Set("policyName", policyName) 204 queryValues.Set("userOrGroup", entityName) 205 groupStr := "false" 206 if isGroup { 207 groupStr = "true" 208 } 209 queryValues.Set("isGroup", groupStr) 210 211 reqData := requestData{ 212 relPath: adminAPIPrefix + "/set-user-or-group-policy", 213 queryValues: queryValues, 214 } 215 216 // Execute PUT on /minio/admin/v3/set-user-or-group-policy to set policy. 217 resp, err := adm.executeMethod(ctx, http.MethodPut, reqData) 218 defer closeResponse(resp) 219 if err != nil { 220 return err 221 } 222 223 if resp.StatusCode != http.StatusOK { 224 return httpRespToErrorResponse(resp) 225 } 226 return nil 227 } 228 229 func (adm *AdminClient) attachOrDetachPolicyBuiltin(ctx context.Context, isAttach bool, r PolicyAssociationReq) error { 230 err := r.IsValid() 231 if err != nil { 232 return err 233 } 234 235 plainBytes, err := json.Marshal(r) 236 if err != nil { 237 return err 238 } 239 240 encBytes, err := EncryptData(adm.getSecretKey(), plainBytes) 241 if err != nil { 242 return err 243 } 244 245 suffix := "detach" 246 if isAttach { 247 suffix = "attach" 248 } 249 250 reqData := requestData{ 251 relPath: adminAPIPrefix + "/idp/builtin/policy/" + suffix, 252 content: encBytes, 253 } 254 255 resp, err := adm.executeMethod(ctx, http.MethodPost, reqData) 256 defer closeResponse(resp) 257 if err != nil { 258 return err 259 } 260 261 if (isAttach && resp.StatusCode != http.StatusCreated) || 262 (!isAttach && resp.StatusCode != http.StatusNoContent) { 263 return httpRespToErrorResponse(resp) 264 } 265 266 return nil 267 } 268 269 // AttachPolicy - attach policies to a user or group. 270 func (adm *AdminClient) AttachPolicy(ctx context.Context, r PolicyAssociationReq) error { 271 return adm.attachOrDetachPolicyBuiltin(ctx, true, r) 272 } 273 274 // DetachPolicy - detach policies from a user or group. 275 func (adm *AdminClient) DetachPolicy(ctx context.Context, r PolicyAssociationReq) error { 276 return adm.attachOrDetachPolicyBuiltin(ctx, false, r) 277 } 278 279 // GetPolicyEntities - returns builtin policy entities. 280 func (adm *AdminClient) GetPolicyEntities(ctx context.Context, q PolicyEntitiesQuery) (r PolicyEntitiesResult, err error) { 281 params := make(url.Values) 282 params["user"] = q.Users 283 params["group"] = q.Groups 284 params["policy"] = q.Policy 285 286 reqData := requestData{ 287 relPath: adminAPIPrefix + "/idp/builtin/policy-entities", 288 queryValues: params, 289 } 290 291 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 292 defer closeResponse(resp) 293 if err != nil { 294 return r, err 295 } 296 297 if resp.StatusCode != http.StatusOK { 298 return r, httpRespToErrorResponse(resp) 299 } 300 301 content, err := DecryptData(adm.getSecretKey(), resp.Body) 302 if err != nil { 303 return r, err 304 } 305 306 err = json.Unmarshal(content, &r) 307 return r, err 308 }