github.com/minio/console@v1.4.1/api/errors.go (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2022 MinIO, Inc. 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Affero General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "context" 21 "errors" 22 "strings" 23 24 "github.com/minio/minio-go/v7" 25 26 "github.com/minio/console/models" 27 "github.com/minio/madmin-go/v3" 28 ) 29 30 var ( 31 ErrDefault = errors.New("an error occurred, please try again") 32 ErrInvalidLogin = errors.New("invalid Login") 33 ErrForbidden = errors.New("403 Forbidden") 34 ErrBadRequest = errors.New("400 Bad Request") 35 ErrFileTooLarge = errors.New("413 File too Large") 36 ErrInvalidSession = errors.New("invalid session") 37 ErrNotFound = errors.New("not found") 38 ErrGroupAlreadyExists = errors.New("error group name already in use") 39 ErrInvalidErasureCodingValue = errors.New("invalid Erasure Coding Value") 40 ErrBucketBodyNotInRequest = errors.New("error bucket body not in request") 41 ErrBucketNameNotInRequest = errors.New("error bucket name not in request") 42 ErrGroupBodyNotInRequest = errors.New("error group body not in request") 43 ErrGroupNameNotInRequest = errors.New("error group name not in request") 44 ErrPolicyNameNotInRequest = errors.New("error policy name not in request") 45 ErrPolicyBodyNotInRequest = errors.New("error policy body not in request") 46 ErrPolicyNameContainsSpace = errors.New("error policy name cannot contain spaces") 47 ErrInvalidEncryptionAlgorithm = errors.New("error invalid encryption algorithm") 48 ErrSSENotConfigured = errors.New("error server side encryption configuration not found") 49 ErrBucketLifeCycleNotConfigured = errors.New("error bucket life cycle configuration not found") 50 ErrChangePassword = errors.New("error please check your current password") 51 ErrInvalidLicense = errors.New("invalid license key") 52 ErrLicenseNotFound = errors.New("license not found") 53 ErrAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself") 54 ErrAccessDenied = errors.New("access denied") 55 ErrOauth2Provider = errors.New("unable to contact configured identity provider") 56 ErrOauth2Login = errors.New("unable to login using configured identity provider") 57 ErrNonUniqueAccessKey = errors.New("access key already in use") 58 ErrRemoteTierExists = errors.New("specified remote tier already exists") 59 ErrRemoteTierNotFound = errors.New("specified remote tier was not found") 60 ErrRemoteTierUppercase = errors.New("tier name must be in uppercase") 61 ErrRemoteTierBucketNotFound = errors.New("remote tier bucket not found") 62 ErrRemoteInvalidCredentials = errors.New("invalid remote tier credentials") 63 ErrUnableToGetTenantUsage = errors.New("unable to get tenant usage") 64 ErrTooManyNodes = errors.New("cannot request more nodes than what is available in the cluster") 65 ErrTooFewNodes = errors.New("there are not enough nodes in the cluster to support this tenant") 66 ErrTooFewAvailableNodes = errors.New("there is not enough available nodes to satisfy this requirement") 67 ErrFewerThanFourNodes = errors.New("at least 4 nodes are required for a tenant") 68 ErrUnableToGetTenantLogs = errors.New("unable to get tenant logs") 69 ErrUnableToUpdateTenantCertificates = errors.New("unable to update tenant certificates") 70 ErrUpdatingEncryptionConfig = errors.New("unable to update encryption configuration") 71 ErrDeletingEncryptionConfig = errors.New("error disabling tenant encryption") 72 ErrEncryptionConfigNotFound = errors.New("encryption configuration not found") 73 ErrPolicyNotFound = errors.New("policy does not exist") 74 ErrLoginNotAllowed = errors.New("login not allowed") 75 ErrHealthReportFail = errors.New("failure to generate Health report") 76 ) 77 78 type CodedAPIError struct { 79 Code int 80 APIError *models.APIError 81 } 82 83 // ErrorWithContext : 84 func ErrorWithContext(ctx context.Context, err ...interface{}) *CodedAPIError { 85 errorCode := 500 86 errorMessage := ErrDefault.Error() 87 var detailedMessage string 88 var err1 error 89 var exists bool 90 if len(err) > 0 { 91 if err1, exists = err[0].(error); exists { 92 detailedMessage = err1.Error() 93 var lastError error 94 if len(err) > 1 { 95 if err2, lastExists := err[1].(error); lastExists { 96 lastError = err2 97 } 98 } 99 if err1.Error() == ErrForbidden.Error() { 100 errorCode = 403 101 } 102 if err1.Error() == ErrBadRequest.Error() { 103 errorCode = 400 104 } 105 if err1 == ErrNotFound { 106 errorCode = 404 107 errorMessage = ErrNotFound.Error() 108 } 109 if errors.Is(err1, ErrInvalidLogin) { 110 detailedMessage = "" 111 errorCode = 401 112 errorMessage = ErrInvalidLogin.Error() 113 } 114 if strings.Contains(strings.ToLower(err1.Error()), ErrAccessDenied.Error()) { 115 errorCode = 403 116 errorMessage = err1.Error() 117 } 118 // If the last error is ErrInvalidLogin, this is a login failure 119 if errors.Is(lastError, ErrInvalidLogin) { 120 detailedMessage = "" 121 errorCode = 401 122 errorMessage = err1.Error() 123 } 124 if strings.Contains(err1.Error(), ErrLoginNotAllowed.Error()) { 125 detailedMessage = "" 126 errorCode = 400 127 errorMessage = ErrLoginNotAllowed.Error() 128 } 129 // console invalid erasure coding value 130 if errors.Is(err1, ErrInvalidErasureCodingValue) { 131 errorCode = 400 132 errorMessage = ErrInvalidErasureCodingValue.Error() 133 } 134 if errors.Is(err1, ErrBucketBodyNotInRequest) { 135 errorCode = 400 136 errorMessage = ErrBucketBodyNotInRequest.Error() 137 } 138 if errors.Is(err1, ErrBucketNameNotInRequest) { 139 errorCode = 400 140 errorMessage = ErrBucketNameNotInRequest.Error() 141 } 142 if errors.Is(err1, ErrGroupBodyNotInRequest) { 143 errorCode = 400 144 errorMessage = ErrGroupBodyNotInRequest.Error() 145 } 146 if errors.Is(err1, ErrGroupNameNotInRequest) { 147 errorCode = 400 148 errorMessage = ErrGroupNameNotInRequest.Error() 149 } 150 if errors.Is(err1, ErrPolicyNameNotInRequest) { 151 errorCode = 400 152 errorMessage = ErrPolicyNameNotInRequest.Error() 153 } 154 if errors.Is(err1, ErrPolicyBodyNotInRequest) { 155 errorCode = 400 156 errorMessage = ErrPolicyBodyNotInRequest.Error() 157 } 158 if errors.Is(err1, ErrPolicyNameContainsSpace) { 159 errorCode = 400 160 errorMessage = ErrPolicyNameContainsSpace.Error() 161 } 162 // console invalid session errors 163 if errors.Is(err1, ErrInvalidSession) { 164 errorCode = 401 165 errorMessage = ErrInvalidSession.Error() 166 } 167 if errors.Is(err1, ErrGroupAlreadyExists) { 168 errorCode = 400 169 errorMessage = ErrGroupAlreadyExists.Error() 170 } 171 // Bucket life cycle not configured 172 if errors.Is(err1, ErrBucketLifeCycleNotConfigured) { 173 errorCode = 404 174 errorMessage = ErrBucketLifeCycleNotConfigured.Error() 175 } 176 // Encryption not configured 177 if errors.Is(err1, ErrSSENotConfigured) { 178 errorCode = 404 179 errorMessage = ErrSSENotConfigured.Error() 180 } 181 if errors.Is(err1, ErrEncryptionConfigNotFound) { 182 errorCode = 404 183 errorMessage = err1.Error() 184 } 185 // account change password 186 if errors.Is(err1, ErrChangePassword) { 187 errorCode = 403 188 errorMessage = ErrChangePassword.Error() 189 } 190 if madmin.ToErrorResponse(err1).Code == "SignatureDoesNotMatch" { 191 errorCode = 403 192 errorMessage = ErrChangePassword.Error() 193 } 194 if errors.Is(err1, ErrLicenseNotFound) { 195 errorCode = 404 196 errorMessage = ErrLicenseNotFound.Error() 197 } 198 if errors.Is(err1, ErrInvalidLicense) { 199 errorCode = 404 200 errorMessage = ErrInvalidLicense.Error() 201 } 202 if errors.Is(err1, ErrAvoidSelfAccountDelete) { 203 errorCode = 403 204 errorMessage = ErrAvoidSelfAccountDelete.Error() 205 } 206 if errors.Is(err1, ErrAccessDenied) { 207 errorCode = 403 208 errorMessage = ErrAccessDenied.Error() 209 } 210 if errors.Is(err1, ErrPolicyNotFound) { 211 errorCode = 404 212 errorMessage = ErrPolicyNotFound.Error() 213 } 214 if madmin.ToErrorResponse(err1).Code == "AccessDenied" { 215 errorCode = 403 216 errorMessage = ErrAccessDenied.Error() 217 } 218 if madmin.ToErrorResponse(err1).Code == "InvalidAccessKeyId" { 219 220 errorCode = 401 221 errorMessage = ErrInvalidSession.Error() 222 } 223 // console invalid session errors 224 if madmin.ToErrorResponse(err1).Code == "XMinioAdminNoSuchUser" { 225 errorCode = 401 226 errorMessage = ErrInvalidSession.Error() 227 } 228 // tiering errors 229 if err1.Error() == ErrRemoteTierExists.Error() { 230 errorCode = 400 231 errorMessage = err1.Error() 232 } 233 if err1.Error() == ErrRemoteTierNotFound.Error() { 234 errorCode = 400 235 errorMessage = err1.Error() 236 } 237 238 if err1.Error() == ErrRemoteTierUppercase.Error() { 239 errorCode = 400 240 errorMessage = err1.Error() 241 } 242 if err1.Error() == ErrRemoteTierBucketNotFound.Error() { 243 errorCode = 400 244 errorMessage = err1.Error() 245 } 246 if err1.Error() == ErrRemoteInvalidCredentials.Error() { 247 errorCode = 403 248 errorMessage = err1.Error() 249 } 250 if err1.Error() == ErrFileTooLarge.Error() { 251 errorCode = 413 252 errorMessage = err1.Error() 253 } 254 // bucket already exists 255 if minio.ToErrorResponse(err1).Code == "BucketAlreadyOwnedByYou" { 256 errorCode = 400 257 errorMessage = "Bucket already exists" 258 } 259 260 LogError("ErrorWithContext:%v", err...) 261 LogIf(ctx, err1, err...) 262 } 263 264 if len(err) > 1 && err[1] != nil { 265 if err2, ok := err[1].(error); ok { 266 errorMessage = err2.Error() 267 } 268 } 269 } 270 return &CodedAPIError{Code: errorCode, APIError: &models.APIError{Message: errorMessage, DetailedMessage: detailedMessage}} 271 } 272 273 // Error receives an errors object and parse it against k8sErrors, returns the right errors code paired with a generic errors message 274 func Error(err ...interface{}) *CodedAPIError { 275 ctx, cancel := context.WithCancel(context.Background()) 276 defer cancel() 277 return ErrorWithContext(ctx, err...) 278 }