github.com/minio/madmin-go@v1.7.5/idp-commands.go (about) 1 // 2 // MinIO Object Storage (c) 2015-2022 MinIO, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 package madmin 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "net/http" 24 "net/url" 25 "strings" 26 "time" 27 28 "github.com/minio/minio-go/v7/pkg/set" 29 ) 30 31 // AddOrUpdateIDPConfig - creates a new or updates an existing IDP 32 // configuration on the server. 33 func (adm *AdminClient) AddOrUpdateIDPConfig(ctx context.Context, cfgType, cfgName, cfgData string, update bool) (restart bool, err error) { 34 encBytes, err := EncryptData(adm.getSecretKey(), []byte(cfgData)) 35 if err != nil { 36 return false, err 37 } 38 39 method := http.MethodPut 40 if update { 41 method = http.MethodPost 42 } 43 44 if cfgName == "" { 45 cfgName = Default 46 } 47 48 h := make(http.Header, 1) 49 h.Add("Content-Type", "application/octet-stream") 50 reqData := requestData{ 51 customHeaders: h, 52 relPath: strings.Join([]string{adminAPIPrefix, "idp-config", cfgType, cfgName}, "/"), 53 content: encBytes, 54 } 55 56 resp, err := adm.executeMethod(ctx, method, reqData) 57 defer closeResponse(resp) 58 if err != nil { 59 return false, err 60 } 61 62 // FIXME: Remove support for this older API in 2023-04 (about 6 months). 63 // 64 // Attempt to fall back to older IDP API. 65 if resp.StatusCode == http.StatusUpgradeRequired { 66 // close old response 67 closeResponse(resp) 68 69 // Fallback is needed for `mc admin idp set myminio openid ...` only, as 70 // this was the only released API supported in the older version. 71 72 queryParams := make(url.Values, 2) 73 queryParams.Set("type", cfgType) 74 queryParams.Set("name", cfgName) 75 reqData := requestData{ 76 customHeaders: h, 77 relPath: adminAPIPrefix + "/idp-config", 78 queryValues: queryParams, 79 content: encBytes, 80 } 81 resp, err = adm.executeMethod(ctx, http.MethodPut, reqData) 82 defer closeResponse(resp) 83 if err != nil { 84 return false, err 85 } 86 } 87 88 if resp.StatusCode != http.StatusOK { 89 return false, httpRespToErrorResponse(resp) 90 } 91 92 return resp.Header.Get(ConfigAppliedHeader) != ConfigAppliedTrue, nil 93 } 94 95 // IDPCfgInfo represents a single configuration or related parameter 96 type IDPCfgInfo struct { 97 Key string `json:"key"` 98 Value string `json:"value"` 99 IsCfg bool `json:"isCfg"` 100 IsEnv bool `json:"isEnv"` // relevant only when isCfg=true 101 } 102 103 // IDPConfig contains IDP configuration information returned by server. 104 type IDPConfig struct { 105 Type string `json:"type"` 106 Name string `json:"name,omitempty"` 107 Info []IDPCfgInfo `json:"info"` 108 } 109 110 // Constants for IDP configuration types. 111 const ( 112 OpenidIDPCfg string = "openid" 113 LDAPIDPCfg string = "ldap" 114 ) 115 116 // ValidIDPConfigTypes - set of valid IDP configs. 117 var ValidIDPConfigTypes = set.CreateStringSet(OpenidIDPCfg, LDAPIDPCfg) 118 119 // GetIDPConfig - fetch IDP config from server. 120 func (adm *AdminClient) GetIDPConfig(ctx context.Context, cfgType, cfgName string) (c IDPConfig, err error) { 121 if !ValidIDPConfigTypes.Contains(cfgType) { 122 return c, fmt.Errorf("Invalid config type: %s", cfgType) 123 } 124 125 if cfgName == "" { 126 cfgName = Default 127 } 128 129 reqData := requestData{ 130 relPath: strings.Join([]string{adminAPIPrefix, "idp-config", cfgType, cfgName}, "/"), 131 } 132 133 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 134 defer closeResponse(resp) 135 if err != nil { 136 return c, err 137 } 138 139 // FIXME: Remove support for this older API in 2023-04 (about 6 months). 140 // 141 // Attempt to fall back to older IDP API. 142 if resp.StatusCode == http.StatusUpgradeRequired { 143 // close old response 144 closeResponse(resp) 145 146 queryParams := make(url.Values, 2) 147 queryParams.Set("type", cfgType) 148 queryParams.Set("name", cfgName) 149 reqData := requestData{ 150 relPath: adminAPIPrefix + "/idp-config", 151 queryValues: queryParams, 152 } 153 resp, err = adm.executeMethod(ctx, http.MethodGet, reqData) 154 defer closeResponse(resp) 155 if err != nil { 156 return c, err 157 } 158 } 159 160 if resp.StatusCode != http.StatusOK { 161 return c, httpRespToErrorResponse(resp) 162 } 163 164 content, err := DecryptData(adm.getSecretKey(), resp.Body) 165 if err != nil { 166 return c, err 167 } 168 169 err = json.Unmarshal(content, &c) 170 return c, err 171 } 172 173 // IDPListItem - represents an item in the List IDPs call. 174 type IDPListItem struct { 175 Type string `json:"type"` 176 Name string `json:"name"` 177 Enabled bool `json:"enabled"` 178 RoleARN string `json:"roleARN,omitempty"` 179 } 180 181 // ListIDPConfig - list IDP configuration on the server. 182 func (adm *AdminClient) ListIDPConfig(ctx context.Context, cfgType string) ([]IDPListItem, error) { 183 if !ValidIDPConfigTypes.Contains(cfgType) { 184 return nil, fmt.Errorf("Invalid config type: %s", cfgType) 185 } 186 187 reqData := requestData{ 188 relPath: strings.Join([]string{adminAPIPrefix, "idp-config", cfgType}, "/"), 189 } 190 191 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 192 defer closeResponse(resp) 193 if err != nil { 194 return nil, err 195 } 196 197 // FIXME: Remove support for this older API in 2023-04 (about 6 months). 198 // 199 // Attempt to fall back to older IDP API. 200 if resp.StatusCode == http.StatusUpgradeRequired { 201 // close old response 202 closeResponse(resp) 203 204 queryParams := make(url.Values, 2) 205 queryParams.Set("type", cfgType) 206 reqData := requestData{ 207 relPath: adminAPIPrefix + "/idp-config", 208 queryValues: queryParams, 209 } 210 resp, err = adm.executeMethod(ctx, http.MethodGet, reqData) 211 defer closeResponse(resp) 212 if err != nil { 213 return nil, err 214 } 215 } 216 217 if resp.StatusCode != http.StatusOK { 218 return nil, httpRespToErrorResponse(resp) 219 } 220 221 content, err := DecryptData(adm.getSecretKey(), resp.Body) 222 if err != nil { 223 return nil, err 224 } 225 226 var lst []IDPListItem 227 err = json.Unmarshal(content, &lst) 228 return lst, err 229 } 230 231 // DeleteIDPConfig - delete an IDP configuration on the server. 232 func (adm *AdminClient) DeleteIDPConfig(ctx context.Context, cfgType, cfgName string) (restart bool, err error) { 233 if cfgName == "" { 234 cfgName = Default 235 } 236 reqData := requestData{ 237 relPath: strings.Join([]string{adminAPIPrefix, "idp-config", cfgType, cfgName}, "/"), 238 } 239 240 resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData) 241 defer closeResponse(resp) 242 if err != nil { 243 return false, err 244 } 245 246 // FIXME: Remove support for this older API in 2023-04 (about 6 months). 247 // 248 // Attempt to fall back to older IDP API. 249 if resp.StatusCode == http.StatusUpgradeRequired { 250 // close old response 251 closeResponse(resp) 252 253 queryParams := make(url.Values, 2) 254 queryParams.Set("type", cfgType) 255 queryParams.Set("name", cfgName) 256 reqData := requestData{ 257 relPath: adminAPIPrefix + "/idp-config", 258 queryValues: queryParams, 259 } 260 resp, err = adm.executeMethod(ctx, http.MethodDelete, reqData) 261 defer closeResponse(resp) 262 if err != nil { 263 return false, err 264 } 265 } 266 267 if resp.StatusCode != http.StatusOK { 268 return false, httpRespToErrorResponse(resp) 269 } 270 271 return resp.Header.Get(ConfigAppliedHeader) != ConfigAppliedTrue, nil 272 } 273 274 // PolicyEntitiesResult - contains response to a policy entities query. 275 type PolicyEntitiesResult struct { 276 Timestamp time.Time `json:"timestamp"` 277 UserMappings []UserPolicyEntities `json:"userMappings,omitempty"` 278 GroupMappings []GroupPolicyEntities `json:"groupMappings,omitempty"` 279 PolicyMappings []PolicyEntities `json:"policyMappings,omitempty"` 280 } 281 282 // UserPolicyEntities - user -> policies mapping 283 type UserPolicyEntities struct { 284 User string `json:"user"` 285 Policies []string `json:"policies"` 286 } 287 288 // GroupPolicyEntities - group -> policies mapping 289 type GroupPolicyEntities struct { 290 Group string `json:"group"` 291 Policies []string `json:"policies"` 292 } 293 294 // PolicyEntities - policy -> user+group mapping 295 type PolicyEntities struct { 296 Policy string `json:"policy"` 297 Users []string `json:"users"` 298 Groups []string `json:"groups"` 299 } 300 301 // PolicyEntitiesQuery - contains request info for policy entities query. 302 type PolicyEntitiesQuery struct { 303 Users []string 304 Groups []string 305 Policy []string 306 } 307 308 // GetLDAPPolicyEntities - returns LDAP policy entities. 309 func (adm *AdminClient) GetLDAPPolicyEntities(ctx context.Context, 310 q PolicyEntitiesQuery, 311 ) (r PolicyEntitiesResult, err error) { 312 params := make(url.Values) 313 params["user"] = q.Users 314 params["group"] = q.Groups 315 params["policy"] = q.Policy 316 317 reqData := requestData{ 318 relPath: adminAPIPrefix + "/idp/ldap/policy-entities", 319 queryValues: params, 320 } 321 322 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 323 defer closeResponse(resp) 324 if err != nil { 325 return r, err 326 } 327 328 if resp.StatusCode != http.StatusOK { 329 return r, httpRespToErrorResponse(resp) 330 } 331 332 content, err := DecryptData(adm.getSecretKey(), resp.Body) 333 if err != nil { 334 return r, err 335 } 336 337 err = json.Unmarshal(content, &r) 338 return r, err 339 }