github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/api.go (about) 1 // Tyk Gateway API 2 // 3 // The code below describes the Tyk Gateway API 4 // Version: 2.8.0 5 // 6 // Schemes: https, http 7 // Host: localhost 8 // BasePath: /tyk/ 9 // 10 // Consumes: 11 // - application/json 12 // 13 // Produces: 14 // - application/json 15 // 16 // Security: 17 // - api_key: 18 // 19 // SecurityDefinitions: 20 // api_key: 21 // type: apiKey 22 // name: X-Tyk-Authorization 23 // in: header 24 // 25 // swagger:meta 26 package gateway 27 28 import ( 29 "bytes" 30 "context" 31 "encoding/base64" 32 "encoding/json" 33 "errors" 34 "io/ioutil" 35 "net/http" 36 "net/url" 37 "os" 38 "path/filepath" 39 "strconv" 40 "strings" 41 "sync" 42 "syscall" 43 "time" 44 45 "github.com/gorilla/mux" 46 uuid "github.com/satori/go.uuid" 47 "github.com/sirupsen/logrus" 48 "golang.org/x/crypto/bcrypt" 49 50 "github.com/TykTechnologies/tyk/apidef" 51 "github.com/TykTechnologies/tyk/config" 52 "github.com/TykTechnologies/tyk/ctx" 53 "github.com/TykTechnologies/tyk/headers" 54 "github.com/TykTechnologies/tyk/storage" 55 "github.com/TykTechnologies/tyk/user" 56 ) 57 58 // apiModifyKeySuccess represents when a Key modification was successful 59 // 60 // swagger:model apiModifyKeySuccess 61 type apiModifyKeySuccess struct { 62 // in:body 63 Key string `json:"key"` 64 Status string `json:"status"` 65 Action string `json:"action"` 66 KeyHash string `json:"key_hash,omitempty"` 67 } 68 69 // apiStatusMessage represents an API status message 70 // 71 // swagger:model apiStatusMessage 72 type apiStatusMessage struct { 73 Status string `json:"status"` 74 // Response details 75 Message string `json:"message"` 76 } 77 78 func apiOk(msg string) apiStatusMessage { 79 return apiStatusMessage{"ok", msg} 80 } 81 82 func apiError(msg string) apiStatusMessage { 83 return apiStatusMessage{"error", msg} 84 } 85 86 // paginationStatus provides more information about a paginated data set 87 type paginationStatus struct { 88 PageNum int `json:"page_num"` 89 PageTotal int `json:"page_total"` 90 PageSize int `json:"page_size"` 91 } 92 93 type paginatedOAuthClientTokens struct { 94 Pagination paginationStatus 95 Tokens []OAuthClientToken 96 } 97 98 func doJSONWrite(w http.ResponseWriter, code int, obj interface{}) { 99 w.Header().Set(headers.ContentType, headers.ApplicationJSON) 100 w.WriteHeader(code) 101 if err := json.NewEncoder(w).Encode(obj); err != nil { 102 http.Error(w, err.Error(), http.StatusInternalServerError) 103 } 104 if code != http.StatusOK { 105 job := instrument.NewJob("SystemAPIError") 106 job.Event(strconv.Itoa(code)) 107 } 108 } 109 110 type MethodNotAllowedHandler struct{} 111 112 func (m MethodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 113 doJSONWrite(w, http.StatusMethodNotAllowed, apiError("Method not supported")) 114 } 115 116 func addSecureAndCacheHeaders(next http.HandlerFunc) http.HandlerFunc { 117 return func(w http.ResponseWriter, r *http.Request) { 118 // Setting OWASP Secure Headers 119 w.Header().Set("X-Content-Type-Options", "nosniff") 120 w.Header().Set("X-XSS-Protection", "1; mode=block") 121 w.Header().Set("X-Frame-Options", "DENY") 122 w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains") 123 124 // Avoid Caching of tokens 125 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 126 w.Header().Set("Pragma", "no-cache") 127 w.Header().Set("Expires", "0") 128 next(w, r) 129 } 130 } 131 132 func allowMethods(next http.HandlerFunc, methods ...string) http.HandlerFunc { 133 return func(w http.ResponseWriter, r *http.Request) { 134 for _, method := range methods { 135 if r.Method == method { 136 next(w, r) 137 return 138 } 139 } 140 doJSONWrite(w, http.StatusMethodNotAllowed, apiError("Method not supported")) 141 } 142 } 143 144 func getSpecForOrg(orgID string) *APISpec { 145 apisMu.RLock() 146 defer apisMu.RUnlock() 147 for _, v := range apisByID { 148 if v.OrgID == orgID { 149 return v 150 } 151 } 152 153 // If we can't find a spec, it doesn't matter, because we default to Redis anyway, grab whatever you can find 154 for _, v := range apisByID { 155 return v 156 } 157 return nil 158 } 159 160 func checkAndApplyTrialPeriod(keyName, apiId string, newSession *user.SessionState, isHashed bool) { 161 // Check the policies to see if we are forcing an expiry on the key 162 for _, polID := range newSession.PolicyIDs() { 163 policiesMu.RLock() 164 policy, ok := policiesByID[polID] 165 policiesMu.RUnlock() 166 if !ok { 167 continue 168 } 169 // Are we foring an expiry? 170 if policy.KeyExpiresIn > 0 { 171 // We are, does the key exist? 172 _, found := getKeyDetail(keyName, apiId, isHashed) 173 if !found { 174 // this is a new key, lets expire it 175 newSession.Expires = time.Now().Unix() + policy.KeyExpiresIn 176 } 177 } 178 } 179 } 180 181 func applyPoliciesAndSave(keyName string, session *user.SessionState, spec *APISpec, isHashed bool) error { 182 // use basic middleware to apply policies to key/session (it also saves it) 183 mw := BaseMiddleware{ 184 Spec: spec, 185 } 186 if err := mw.ApplyPolicies(session); err != nil { 187 return err 188 } 189 190 lifetime := session.Lifetime(spec.SessionLifetime) 191 if err := spec.SessionManager.UpdateSession(keyName, session, lifetime, isHashed); err != nil { 192 return err 193 } 194 195 return nil 196 } 197 198 func resetAPILimits(accessRights map[string]user.AccessDefinition) { 199 for apiID := range accessRights { 200 // reset API-level limit to nil if it has a zero-value 201 if access := accessRights[apiID]; access.Limit != nil && *access.Limit == (user.APILimit{}) { 202 access.Limit = nil 203 accessRights[apiID] = access 204 } 205 } 206 } 207 208 func doAddOrUpdate(keyName string, newSession *user.SessionState, dontReset bool, isHashed bool) error { 209 // field last_updated plays an important role in in-mem rate limiter 210 // so update last_updated to current timestamp only if suppress_reset wasn't set to 1 211 if !dontReset { 212 newSession.LastUpdated = strconv.Itoa(int(time.Now().Unix())) 213 } 214 215 if len(newSession.AccessRights) > 0 { 216 // reset API-level limit to nil if any has a zero-value 217 resetAPILimits(newSession.AccessRights) 218 // We have a specific list of access rules, only add / update those 219 for apiId := range newSession.AccessRights { 220 apiSpec := getApiSpec(apiId) 221 if apiSpec == nil { 222 log.WithFields(logrus.Fields{ 223 "prefix": "api", 224 "key": keyName, 225 "org_id": newSession.OrgID, 226 "api_id": apiId, 227 "user_id": "system", 228 "user_ip": "--", 229 "path": "--", 230 "server_name": "system", 231 }).Error("Could not add key for this API ID, API doesn't exist.") 232 return errors.New("API must be active to add keys") 233 } 234 checkAndApplyTrialPeriod(keyName, apiId, newSession, isHashed) 235 236 // Lets reset keys if they are edited by admin 237 if !apiSpec.DontSetQuotasOnCreate { 238 // Reset quote by default 239 if !dontReset { 240 apiSpec.SessionManager.ResetQuota(keyName, newSession, isHashed) 241 newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate 242 } 243 244 // apply polices (if any) and save key 245 if err := applyPoliciesAndSave(keyName, newSession, apiSpec, isHashed); err != nil { 246 return err 247 } 248 } 249 } 250 } else { 251 // nothing defined, add key to ALL 252 if !config.Global().AllowMasterKeys { 253 log.Error("Master keys disallowed in configuration, key not added.") 254 return errors.New("Master keys not allowed") 255 } 256 log.Warning("No API Access Rights set, adding key to ALL.") 257 apisMu.RLock() 258 defer apisMu.RUnlock() 259 for _, spec := range apisByID { 260 if !dontReset { 261 spec.SessionManager.ResetQuota(keyName, newSession, isHashed) 262 newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate 263 } 264 checkAndApplyTrialPeriod(keyName, spec.APIID, newSession, isHashed) 265 266 // apply polices (if any) and save key 267 if err := applyPoliciesAndSave(keyName, newSession, spec, isHashed); err != nil { 268 return err 269 } 270 } 271 } 272 273 log.WithFields(logrus.Fields{ 274 "prefix": "api", 275 "key": obfuscateKey(keyName), 276 "expires": newSession.Expires, 277 "org_id": newSession.OrgID, 278 "api_id": "--", 279 "user_id": "system", 280 "user_ip": "--", 281 "path": "--", 282 "server_name": "system", 283 }).Info("Key added or updated.") 284 return nil 285 } 286 287 // ---- TODO: This changes the URL structure of the API completely ---- 288 // ISSUE: If Session stores are stored with API specs, then managing keys will need to be done per store, i.e. add to all stores, 289 // remove from all stores, update to all stores, stores handle quotas separately though because they are localised! Keys will 290 // need to be managed by API, but only for GetDetail, GetList, UpdateKey and DeleteKey 291 292 func setSessionPassword(session *user.SessionState) { 293 session.BasicAuthData.Hash = user.HashBCrypt 294 newPass, err := bcrypt.GenerateFromPassword([]byte(session.BasicAuthData.Password), 10) 295 if err != nil { 296 log.Error("Could not hash password, setting to plaintext, error was: ", err) 297 session.BasicAuthData.Hash = user.HashPlainText 298 return 299 } 300 301 session.BasicAuthData.Password = string(newPass) 302 } 303 304 func getKeyDetail(key, apiID string, hashed bool) (user.SessionState, bool) { 305 sessionManager := FallbackKeySesionManager 306 if spec := getApiSpec(apiID); spec != nil { 307 sessionManager = spec.SessionManager 308 } 309 310 return sessionManager.SessionDetail(key, hashed) 311 } 312 313 func handleAddOrUpdate(keyName string, r *http.Request, isHashed bool) (interface{}, int) { 314 suppressReset := r.URL.Query().Get("suppress_reset") == "1" 315 316 // decode payload 317 newSession := user.SessionState{} 318 319 contents, _ := ioutil.ReadAll(r.Body) 320 r.Body = ioutil.NopCloser(bytes.NewReader(contents)) 321 322 if err := json.Unmarshal(contents, &newSession); err != nil { 323 log.Error("Couldn't decode new session object: ", err) 324 return apiError("Request malformed"), http.StatusBadRequest 325 } 326 327 mw := BaseMiddleware{} 328 mw.ApplyPolicies(&newSession) 329 330 // DO ADD OR UPDATE 331 332 // get original session in case of update and preserve fields that SHOULD NOT be updated 333 originalKey := user.SessionState{} 334 if r.Method == http.MethodPut { 335 found := false 336 for apiID := range newSession.AccessRights { 337 originalKey, found = getKeyDetail(keyName, apiID, isHashed) 338 if found { 339 break 340 } 341 } 342 if !found { 343 log.Error("Could not find key when updating") 344 return apiError("Key is not found"), http.StatusNotFound 345 } 346 347 // don't change fields related to quota and rate limiting if was passed as "suppress_reset=1" 348 if suppressReset { 349 // save existing quota_renews and last_updated if suppress_reset was passed 350 // (which means don't reset quota or rate counters) 351 // - leaving quota_renews as 0 will force quota limiter to start new renewal period 352 // - setting new last_updated with force rate limiter to start new "per" rating period 353 354 // on session level 355 newSession.QuotaRenews = originalKey.QuotaRenews 356 newSession.LastUpdated = originalKey.LastUpdated 357 358 // on ACL API limit level 359 for apiID, access := range originalKey.AccessRights { 360 if access.Limit == nil { 361 continue 362 } 363 if newAccess, ok := newSession.AccessRights[apiID]; ok && newAccess.Limit != nil { 364 newAccess.Limit.QuotaRenews = access.Limit.QuotaRenews 365 newSession.AccessRights[apiID] = newAccess 366 } 367 } 368 } 369 } else { 370 newSession.DateCreated = time.Now() 371 } 372 373 // Update our session object (create it) 374 if newSession.BasicAuthData.Password != "" { 375 // If we are using a basic auth user, then we need to make the keyname explicit against the OrgId in order to differentiate it 376 // Only if it's NEW 377 switch r.Method { 378 case http.MethodPost: 379 keyName = generateToken(newSession.OrgID, keyName) 380 // It's a create, so lets hash the password 381 setSessionPassword(&newSession) 382 case http.MethodPut: 383 if originalKey.BasicAuthData.Password != newSession.BasicAuthData.Password { 384 // passwords dont match assume it's new, lets hash it 385 log.Debug("Passwords dont match, original: ", originalKey.BasicAuthData.Password) 386 log.Debug("New: newSession.BasicAuthData.Password") 387 log.Debug("Changing password") 388 setSessionPassword(&newSession) 389 } 390 } 391 } 392 393 if err := doAddOrUpdate(keyName, &newSession, suppressReset, isHashed); err != nil { 394 return apiError("Failed to create key, ensure security settings are correct."), http.StatusInternalServerError 395 } 396 397 action := "modified" 398 event := EventTokenUpdated 399 if r.Method == http.MethodPost { 400 action = "added" 401 event = EventTokenCreated 402 } 403 FireSystemEvent(event, EventTokenMeta{ 404 EventMetaDefault: EventMetaDefault{Message: "Key modified."}, 405 Org: newSession.OrgID, 406 Key: keyName, 407 }) 408 409 response := apiModifyKeySuccess{ 410 Key: keyName, 411 Status: "ok", 412 Action: action, 413 } 414 415 // add key hash for newly created key 416 if config.Global().HashKeys && r.Method == http.MethodPost { 417 if isHashed { 418 response.KeyHash = keyName 419 } else { 420 response.KeyHash = storage.HashKey(keyName) 421 } 422 } 423 424 return response, http.StatusOK 425 } 426 427 func handleGetDetail(sessionKey, apiID string, byHash bool) (interface{}, int) { 428 if byHash && !config.Global().HashKeys { 429 return apiError("Key requested by hash but key hashing is not enabled"), http.StatusBadRequest 430 } 431 432 sessionManager := FallbackKeySesionManager 433 spec := getApiSpec(apiID) 434 if spec != nil { 435 sessionManager = spec.SessionManager 436 } 437 438 var session user.SessionState 439 var ok bool 440 session, ok = sessionManager.SessionDetail(sessionKey, byHash) 441 442 if !ok { 443 return apiError("Key not found"), http.StatusNotFound 444 } 445 446 quotaKey := QuotaKeyPrefix + storage.HashKey(sessionKey) 447 if byHash { 448 quotaKey = QuotaKeyPrefix + sessionKey 449 } 450 451 if usedQuota, err := sessionManager.Store().GetRawKey(quotaKey); err == nil { 452 qInt, _ := strconv.Atoi(usedQuota) 453 remaining := session.QuotaMax - int64(qInt) 454 455 if remaining < 0 { 456 session.QuotaRemaining = 0 457 } else { 458 session.QuotaRemaining = remaining 459 } 460 } else { 461 log.WithFields(logrus.Fields{ 462 "prefix": "api", 463 "key": obfuscateKey(sessionKey), 464 "message": err, 465 "status": "ok", 466 }).Info("Can't retrieve key quota") 467 } 468 469 // populate remaining quota for API limits (if any) 470 for id, access := range session.AccessRights { 471 if access.Limit == nil { 472 continue 473 } 474 475 limQuotaKey := QuotaKeyPrefix + id + "-" + storage.HashKey(sessionKey) 476 if byHash { 477 limQuotaKey = QuotaKeyPrefix + id + "-" + sessionKey 478 } 479 if usedQuota, err := sessionManager.Store().GetRawKey(limQuotaKey); err == nil { 480 qInt, _ := strconv.Atoi(usedQuota) 481 remaining := access.Limit.QuotaMax - int64(qInt) 482 483 if remaining < 0 { 484 access.Limit.QuotaRemaining = 0 485 } else { 486 access.Limit.QuotaRemaining = remaining 487 } 488 session.AccessRights[id] = access 489 } else { 490 access.Limit.QuotaRemaining = access.Limit.QuotaMax 491 session.AccessRights[id] = access 492 493 log.WithFields(logrus.Fields{ 494 "prefix": "api", 495 "apiID": id, 496 "key": obfuscateKey(sessionKey), 497 "error": err, 498 }).Info("Can't retrieve api limit quota") 499 } 500 } 501 502 mw := BaseMiddleware{Spec: spec} 503 mw.ApplyPolicies(&session) 504 505 log.WithFields(logrus.Fields{ 506 "prefix": "api", 507 "key": obfuscateKey(sessionKey), 508 "status": "ok", 509 }).Info("Retrieved key detail.") 510 511 return session, http.StatusOK 512 } 513 514 // apiAllKeys represents a list of keys in the memory store 515 // swagger:model 516 type apiAllKeys struct { 517 APIKeys []string `json:"keys"` 518 } 519 520 func handleGetAllKeys(filter, apiID string) (interface{}, int) { 521 sessionManager := FallbackKeySesionManager 522 if spec := getApiSpec(apiID); spec != nil { 523 sessionManager = spec.SessionManager 524 } 525 526 sessions := sessionManager.Sessions(filter) 527 528 fixed_sessions := make([]string, 0) 529 for _, s := range sessions { 530 if !strings.HasPrefix(s, QuotaKeyPrefix) && !strings.HasPrefix(s, RateLimitKeyPrefix) { 531 fixed_sessions = append(fixed_sessions, s) 532 } 533 } 534 535 sessionsObj := apiAllKeys{fixed_sessions} 536 537 log.WithFields(logrus.Fields{ 538 "prefix": "api", 539 "status": "ok", 540 }).Info("Retrieved key list.") 541 542 return sessionsObj, http.StatusOK 543 } 544 545 func handleAddKey(keyName, hashedName, sessionString, apiID string) { 546 mw := BaseMiddleware{ 547 Spec: &APISpec{ 548 SessionManager: FallbackKeySesionManager, 549 }, 550 } 551 sess := user.SessionState{} 552 json.Unmarshal([]byte(sessionString), &sess) 553 sess.LastUpdated = strconv.Itoa(int(time.Now().Unix())) 554 var err error 555 if config.Global().HashKeys { 556 err = mw.Spec.SessionManager.UpdateSession(hashedName, &sess, 0, true) 557 } else { 558 err = mw.Spec.SessionManager.UpdateSession(keyName, &sess, 0, false) 559 } 560 if err != nil { 561 log.WithFields(logrus.Fields{ 562 "prefix": "api", 563 "key": obfuscateKey(keyName), 564 "status": "fail", 565 "err": err, 566 }).Error("Failed to update key.") 567 } 568 log.WithFields(logrus.Fields{ 569 "prefix": "RPC", 570 "key": obfuscateKey(keyName), 571 "status": "ok", 572 }).Info("Updated hashed key in slave storage.") 573 } 574 575 func handleDeleteKey(keyName, apiID string, resetQuota bool) (interface{}, int) { 576 if apiID == "-1" { 577 // Go through ALL managed API's and delete the key 578 apisMu.RLock() 579 removed := false 580 for _, spec := range apisByID { 581 if spec.SessionManager.RemoveSession(keyName, false) { 582 removed = true 583 } 584 spec.SessionManager.ResetQuota(keyName, &user.SessionState{}, false) 585 } 586 apisMu.RUnlock() 587 588 if !removed { 589 log.WithFields(logrus.Fields{ 590 "prefix": "api", 591 "key": obfuscateKey(keyName), 592 "status": "fail", 593 }).Error("Failed to remove the key") 594 return apiError("Failed to remove the key"), http.StatusBadRequest 595 } 596 597 log.WithFields(logrus.Fields{ 598 "prefix": "api", 599 "key": keyName, 600 "status": "ok", 601 }).Info("Deleted key across all APIs.") 602 603 return nil, http.StatusOK 604 } 605 606 orgID := "" 607 sessionManager := FallbackKeySesionManager 608 if spec := getApiSpec(apiID); spec != nil { 609 orgID = spec.OrgID 610 sessionManager = spec.SessionManager 611 } 612 613 if !sessionManager.RemoveSession(keyName, false) { 614 log.WithFields(logrus.Fields{ 615 "prefix": "api", 616 "key": obfuscateKey(keyName), 617 "status": "fail", 618 }).Error("Failed to remove the key") 619 return apiError("Failed to remove the key"), http.StatusBadRequest 620 } 621 622 if resetQuota { 623 sessionManager.ResetQuota(keyName, &user.SessionState{}, false) 624 } 625 626 statusObj := apiModifyKeySuccess{ 627 Key: keyName, 628 Status: "ok", 629 Action: "deleted", 630 } 631 632 FireSystemEvent(EventTokenDeleted, EventTokenMeta{ 633 EventMetaDefault: EventMetaDefault{Message: "Key deleted."}, 634 Org: orgID, 635 Key: keyName, 636 }) 637 638 log.WithFields(logrus.Fields{ 639 "prefix": "api", 640 "key": keyName, 641 "status": "ok", 642 }).Info("Deleted key.") 643 644 return statusObj, http.StatusOK 645 } 646 647 func handleDeleteHashedKey(keyName, apiID string, resetQuota bool) (interface{}, int) { 648 if apiID == "-1" { 649 // Go through ALL managed API's and delete the key 650 removed := false 651 apisMu.RLock() 652 for _, spec := range apisByID { 653 if spec.SessionManager.RemoveSession(keyName, true) { 654 removed = true 655 } 656 } 657 apisMu.RUnlock() 658 659 if !removed { 660 log.WithFields(logrus.Fields{ 661 "prefix": "api", 662 "key": obfuscateKey(keyName), 663 "status": "fail", 664 }).Error("Failed to remove the key") 665 return apiError("Failed to remove the key"), http.StatusBadRequest 666 } 667 668 log.WithFields(logrus.Fields{ 669 "prefix": "api", 670 "key": keyName, 671 "status": "ok", 672 }).Info("Deleted hashed key across all APIs.") 673 674 return nil, http.StatusOK 675 } 676 677 sessionManager := FallbackKeySesionManager 678 if spec := getApiSpec(apiID); spec != nil { 679 sessionManager = spec.SessionManager 680 } 681 682 if !sessionManager.RemoveSession(keyName, true) { 683 log.WithFields(logrus.Fields{ 684 "prefix": "api", 685 "key": obfuscateKey(keyName), 686 "status": "fail", 687 }).Error("Failed to remove the key") 688 return apiError("Failed to remove the key"), http.StatusBadRequest 689 } 690 691 if resetQuota { 692 sessionManager.ResetQuota(keyName, &user.SessionState{}, true) 693 } 694 695 statusObj := apiModifyKeySuccess{ 696 Key: keyName, 697 Status: "ok", 698 Action: "deleted", 699 } 700 701 log.WithFields(logrus.Fields{ 702 "prefix": "api", 703 "key": keyName, 704 "status": "ok", 705 }).Info("Deleted hashed key.") 706 707 return statusObj, http.StatusOK 708 } 709 710 func handleGetAPIList() (interface{}, int) { 711 apisMu.RLock() 712 defer apisMu.RUnlock() 713 apiIDList := make([]*apidef.APIDefinition, len(apisByID)) 714 c := 0 715 for _, apiSpec := range apisByID { 716 apiIDList[c] = apiSpec.APIDefinition 717 c++ 718 } 719 return apiIDList, http.StatusOK 720 } 721 722 func handleGetAPI(apiID string) (interface{}, int) { 723 if spec := getApiSpec(apiID); spec != nil { 724 return spec.APIDefinition, http.StatusOK 725 } 726 727 log.WithFields(logrus.Fields{ 728 "prefix": "api", 729 "apiID": apiID, 730 }).Error("API doesn't exist.") 731 return apiError("API not found"), http.StatusNotFound 732 } 733 734 func handleAddOrUpdateApi(apiID string, r *http.Request) (interface{}, int) { 735 if config.Global().UseDBAppConfigs { 736 log.Error("Rejected new API Definition due to UseDBAppConfigs = true") 737 return apiError("Due to enabled use_db_app_configs, please use the Dashboard API"), http.StatusInternalServerError 738 } 739 740 newDef := &apidef.APIDefinition{} 741 if err := json.NewDecoder(r.Body).Decode(newDef); err != nil { 742 log.Error("Couldn't decode new API Definition object: ", err) 743 return apiError("Request malformed"), http.StatusBadRequest 744 } 745 746 if apiID != "" && newDef.APIID != apiID { 747 log.Error("PUT operation on different APIIDs") 748 return apiError("Request APIID does not match that in Definition! For Updtae operations these must match."), http.StatusBadRequest 749 } 750 751 // Create a filename 752 defFilePath := filepath.Join(config.Global().AppPath, newDef.APIID+".json") 753 754 // If it exists, delete it 755 if _, err := os.Stat(defFilePath); err == nil { 756 log.Warning("API Definition with this ID already exists, deleting file...") 757 os.Remove(defFilePath) 758 } 759 760 // unmarshal the object into the file 761 asByte, err := json.MarshalIndent(newDef, "", " ") 762 if err != nil { 763 log.Error("Marshalling of API Definition failed: ", err) 764 return apiError("Marshalling failed"), http.StatusInternalServerError 765 } 766 767 if err := ioutil.WriteFile(defFilePath, asByte, 0644); err != nil { 768 log.Error("Failed to create file! - ", err) 769 return apiError("File object creation failed, write error"), http.StatusInternalServerError 770 } 771 772 action := "modified" 773 if r.Method == "POST" { 774 action = "added" 775 } 776 777 response := apiModifyKeySuccess{ 778 Key: newDef.APIID, 779 Status: "ok", 780 Action: action, 781 } 782 783 return response, http.StatusOK 784 } 785 786 func handleDeleteAPI(apiID string) (interface{}, int) { 787 // Generate a filename 788 defFilePath := filepath.Join(config.Global().AppPath, apiID+".json") 789 790 // If it exists, delete it 791 if _, err := os.Stat(defFilePath); err != nil { 792 log.Warning("File does not exist! ", err) 793 return apiError("Delete failed"), http.StatusInternalServerError 794 } 795 796 os.Remove(defFilePath) 797 798 response := apiModifyKeySuccess{ 799 Key: apiID, 800 Status: "ok", 801 Action: "deleted", 802 } 803 804 return response, http.StatusOK 805 } 806 807 func apiHandler(w http.ResponseWriter, r *http.Request) { 808 apiID := mux.Vars(r)["apiID"] 809 810 var obj interface{} 811 var code int 812 813 switch r.Method { 814 case "GET": 815 if apiID != "" { 816 log.Debug("Requesting API definition for", apiID) 817 obj, code = handleGetAPI(apiID) 818 } else { 819 log.Debug("Requesting API list") 820 obj, code = handleGetAPIList() 821 } 822 case "POST": 823 log.Debug("Creating new definition file") 824 obj, code = handleAddOrUpdateApi(apiID, r) 825 case "PUT": 826 if apiID != "" { 827 log.Debug("Updating existing API: ", apiID) 828 obj, code = handleAddOrUpdateApi(apiID, r) 829 } else { 830 obj, code = apiError("Must specify an apiID to update"), http.StatusBadRequest 831 } 832 case "DELETE": 833 if apiID != "" { 834 log.Debug("Deleting API definition for: ", apiID) 835 obj, code = handleDeleteAPI(apiID) 836 } else { 837 obj, code = apiError("Must specify an apiID to delete"), http.StatusBadRequest 838 } 839 } 840 841 doJSONWrite(w, code, obj) 842 } 843 844 func keyHandler(w http.ResponseWriter, r *http.Request) { 845 keyName := mux.Vars(r)["keyName"] 846 apiID := r.URL.Query().Get("api_id") 847 isHashed := r.URL.Query().Get("hashed") != "" 848 isUserName := r.URL.Query().Get("username") == "true" 849 orgID := r.URL.Query().Get("org_id") 850 851 // check if passed key is user name and convert it to real key with respect to current hashing algorithm 852 origKeyName := keyName 853 if r.Method != http.MethodPost && isUserName { 854 keyName = generateToken(orgID, keyName) 855 } 856 857 var obj interface{} 858 var code int 859 hashKeyFunction := config.Global().HashKeyFunction 860 861 switch r.Method { 862 case http.MethodPost: 863 obj, code = handleAddOrUpdate(keyName, r, isHashed) 864 case http.MethodPut: 865 obj, code = handleAddOrUpdate(keyName, r, isHashed) 866 if code != http.StatusOK && hashKeyFunction != "" { 867 // try to use legacy key format 868 obj, code = handleAddOrUpdate(origKeyName, r, isHashed) 869 } 870 case http.MethodGet: 871 if keyName != "" { 872 // Return single key detail 873 obj, code = handleGetDetail(keyName, apiID, isHashed) 874 if code != http.StatusOK && hashKeyFunction != "" { 875 // try to use legacy key format 876 obj, code = handleGetDetail(origKeyName, apiID, isHashed) 877 } 878 } else { 879 // Return list of keys 880 if config.Global().HashKeys { 881 // get all keys is disabled by default 882 if !config.Global().EnableHashedKeysListing { 883 doJSONWrite( 884 w, 885 http.StatusNotFound, 886 apiError("Hashed key listing is disabled in config (enable_hashed_keys_listing)"), 887 ) 888 return 889 } 890 891 // we don't use filter for hashed keys 892 obj, code = handleGetAllKeys("", apiID) 893 } else { 894 filter := r.URL.Query().Get("filter") 895 obj, code = handleGetAllKeys(filter, apiID) 896 } 897 } 898 899 case http.MethodDelete: 900 // Remove a key 901 if !isHashed { 902 obj, code = handleDeleteKey(keyName, apiID, true) 903 } else { 904 obj, code = handleDeleteHashedKey(keyName, apiID, true) 905 } 906 if code != http.StatusOK && hashKeyFunction != "" { 907 // try to use legacy key format 908 if !isHashed { 909 obj, code = handleDeleteKey(origKeyName, apiID, true) 910 } else { 911 obj, code = handleDeleteHashedKey(origKeyName, apiID, true) 912 } 913 } 914 } 915 916 doJSONWrite(w, code, obj) 917 } 918 919 type PolicyUpdateObj struct { 920 Policy string `json:"policy"` 921 } 922 923 func policyUpdateHandler(w http.ResponseWriter, r *http.Request) { 924 log.Warning("Hashed key change request detected!") 925 926 var policRecord PolicyUpdateObj 927 if err := json.NewDecoder(r.Body).Decode(&policRecord); err != nil { 928 doJSONWrite(w, http.StatusBadRequest, apiError("Couldn't decode instruction")) 929 return 930 } 931 932 keyName := mux.Vars(r)["keyName"] 933 apiID := r.URL.Query().Get("api_id") 934 obj, code := handleUpdateHashedKey(keyName, apiID, policRecord.Policy) 935 936 doJSONWrite(w, code, obj) 937 } 938 939 func handleUpdateHashedKey(keyName, apiID, policyId string) (interface{}, int) { 940 sessionManager := FallbackKeySesionManager 941 if spec := getApiSpec(apiID); spec != nil { 942 sessionManager = spec.SessionManager 943 } 944 945 sess, ok := sessionManager.SessionDetail(keyName, true) 946 if !ok { 947 log.WithFields(logrus.Fields{ 948 "prefix": "api", 949 "key": keyName, 950 "status": "fail", 951 }).Error("Failed to update hashed key.") 952 953 return apiError("Key not found"), http.StatusNotFound 954 } 955 956 // Set the policy 957 sess.LastUpdated = strconv.Itoa(int(time.Now().Unix())) 958 sess.SetPolicies(policyId) 959 960 err := sessionManager.UpdateSession(keyName, &sess, 0, true) 961 if err != nil { 962 log.WithFields(logrus.Fields{ 963 "prefix": "api", 964 "key": keyName, 965 "status": "fail", 966 "err": err, 967 }).Error("Failed to update hashed key.") 968 969 return apiError("Could not write key data"), http.StatusInternalServerError 970 } 971 972 statusObj := apiModifyKeySuccess{ 973 Key: keyName, 974 Status: "ok", 975 Action: "updated", 976 } 977 978 log.WithFields(logrus.Fields{ 979 "prefix": "api", 980 "key": keyName, 981 "status": "ok", 982 }).Info("Updated hashed key.") 983 984 return statusObj, http.StatusOK 985 } 986 987 func orgHandler(w http.ResponseWriter, r *http.Request) { 988 keyName := mux.Vars(r)["keyName"] 989 filter := r.URL.Query().Get("filter") 990 var obj interface{} 991 var code int 992 993 switch r.Method { 994 case "POST", "PUT": 995 obj, code = handleOrgAddOrUpdate(keyName, r) 996 997 case "GET": 998 if keyName != "" { 999 // Return single org detail 1000 obj, code = handleGetOrgDetail(keyName) 1001 } else { 1002 // Return list of keys 1003 obj, code = handleGetAllOrgKeys(filter) 1004 } 1005 1006 case "DELETE": 1007 // Remove a key 1008 obj, code = handleDeleteOrgKey(keyName) 1009 } 1010 1011 doJSONWrite(w, code, obj) 1012 } 1013 1014 func handleOrgAddOrUpdate(keyName string, r *http.Request) (interface{}, int) { 1015 newSession := new(user.SessionState) 1016 1017 if err := json.NewDecoder(r.Body).Decode(newSession); err != nil { 1018 log.Error("Couldn't decode new session object: ", err) 1019 return apiError("Request malformed"), http.StatusBadRequest 1020 } 1021 // Update our session object (create it) 1022 1023 spec := getSpecForOrg(keyName) 1024 var sessionManager SessionHandler 1025 1026 if spec == nil { 1027 log.Warning("Couldn't find org session store in active API list") 1028 if config.Global().SupressDefaultOrgStore { 1029 return apiError("No such organisation found in Active API list"), http.StatusNotFound 1030 } 1031 sessionManager = &DefaultOrgStore 1032 } else { 1033 sessionManager = spec.OrgSessionManager 1034 } 1035 1036 if r.URL.Query().Get("reset_quota") == "1" { 1037 sessionManager.ResetQuota(keyName, newSession, false) 1038 newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate 1039 rawKey := QuotaKeyPrefix + storage.HashKey(keyName) 1040 1041 // manage quotas separately 1042 DefaultQuotaStore.RemoveSession(rawKey, false) 1043 } 1044 1045 err := sessionManager.UpdateSession(keyName, newSession, 0, false) 1046 if err != nil { 1047 return apiError("Error writing to key store " + err.Error()), http.StatusInternalServerError 1048 } 1049 1050 // identify that spec has org session 1051 if spec != nil { 1052 spec.Lock() 1053 spec.OrgHasNoSession = false 1054 spec.Unlock() 1055 } 1056 1057 log.WithFields(logrus.Fields{ 1058 "prefix": "api", 1059 "org": keyName, 1060 "status": "ok", 1061 }).Info("New organization key added or updated.") 1062 1063 action := "modified" 1064 if r.Method == "POST" { 1065 action = "added" 1066 } 1067 1068 response := apiModifyKeySuccess{ 1069 Key: keyName, 1070 Status: "ok", 1071 Action: action, 1072 } 1073 1074 return response, http.StatusOK 1075 } 1076 1077 func handleGetOrgDetail(orgID string) (interface{}, int) { 1078 spec := getSpecForOrg(orgID) 1079 if spec == nil { 1080 return apiError("Org not found"), http.StatusNotFound 1081 } 1082 1083 session, ok := spec.OrgSessionManager.SessionDetail(orgID, false) 1084 if !ok { 1085 log.WithFields(logrus.Fields{ 1086 "prefix": "api", 1087 "org": orgID, 1088 "status": "fail", 1089 "err": "not found", 1090 }).Error("Failed retrieval of record for ORG ID.") 1091 return apiError("Org not found"), http.StatusNotFound 1092 } 1093 log.WithFields(logrus.Fields{ 1094 "prefix": "api", 1095 "org": orgID, 1096 "status": "ok", 1097 }).Info("Retrieved record for ORG ID.") 1098 return session, http.StatusOK 1099 } 1100 1101 func handleGetAllOrgKeys(filter string) (interface{}, int) { 1102 spec := getSpecForOrg("") 1103 if spec == nil { 1104 return apiError("ORG not found"), http.StatusNotFound 1105 } 1106 1107 sessions := spec.OrgSessionManager.Sessions(filter) 1108 fixed_sessions := make([]string, 0) 1109 for _, s := range sessions { 1110 if !strings.HasPrefix(s, QuotaKeyPrefix) && !strings.HasPrefix(s, RateLimitKeyPrefix) { 1111 fixed_sessions = append(fixed_sessions, s) 1112 } 1113 } 1114 sessionsObj := apiAllKeys{fixed_sessions} 1115 return sessionsObj, http.StatusOK 1116 } 1117 1118 func handleDeleteOrgKey(orgID string) (interface{}, int) { 1119 spec := getSpecForOrg(orgID) 1120 if spec == nil { 1121 log.WithFields(logrus.Fields{ 1122 "prefix": "api", 1123 "key": orgID, 1124 "status": "fail", 1125 "err": "not found", 1126 }).Error("Failed to delete org key.") 1127 1128 return apiError("Org not found"), http.StatusNotFound 1129 } 1130 1131 if !spec.OrgSessionManager.RemoveSession(orgID, false) { 1132 return apiError("Failed to remove the key"), http.StatusBadRequest 1133 } 1134 1135 log.WithFields(logrus.Fields{ 1136 "prefix": "api", 1137 "key": orgID, 1138 "status": "ok", 1139 }).Info("Org key deleted.") 1140 1141 // identify that spec has no org session 1142 if spec != nil { 1143 spec.Lock() 1144 spec.OrgHasNoSession = true 1145 spec.Unlock() 1146 } 1147 1148 statusObj := apiModifyKeySuccess{ 1149 Key: orgID, 1150 Status: "ok", 1151 Action: "deleted", 1152 } 1153 return statusObj, http.StatusOK 1154 } 1155 1156 func groupResetHandler(w http.ResponseWriter, r *http.Request) { 1157 log.WithFields(logrus.Fields{ 1158 "prefix": "api", 1159 "status": "ok", 1160 }).Info("Group reload accepted.") 1161 1162 // Signal to the group via redis 1163 MainNotifier.Notify(Notification{Command: NoticeGroupReload}) 1164 1165 log.WithFields(logrus.Fields{ 1166 "prefix": "api", 1167 }).Info("Reloaded URL Structure - Success") 1168 1169 doJSONWrite(w, http.StatusOK, apiOk("")) 1170 } 1171 1172 // resetHandler will try to queue a reload. If fn is nil and block=true 1173 // was in the URL parameters, it will block until the reload is done. 1174 // Otherwise, it won't block and fn will be called once the reload is 1175 // finished. 1176 // 1177 func resetHandler(fn func()) http.HandlerFunc { 1178 return func(w http.ResponseWriter, r *http.Request) { 1179 var wg sync.WaitGroup 1180 1181 if fn == nil && r.URL.Query().Get("block") == "true" { 1182 wg.Add(1) 1183 reloadURLStructure(wg.Done) 1184 } else { 1185 reloadURLStructure(fn) 1186 } 1187 1188 log.WithFields(logrus.Fields{ 1189 "prefix": "api", 1190 }).Info("Reload URL Structure - Scheduled") 1191 1192 wg.Wait() 1193 doJSONWrite(w, http.StatusOK, apiOk("")) 1194 } 1195 } 1196 1197 func hotReloadHandler(w http.ResponseWriter, r *http.Request) { 1198 log.WithFields(logrus.Fields{ 1199 "prefix": "api", 1200 }).Info("Triggering Hot Reload") 1201 doJSONWrite(w, http.StatusOK, apiOk("")) 1202 if err := syscall.Kill(hostDetails.PID, syscall.SIGUSR2); err != nil { 1203 log.Error("Process reload failed: ", err) 1204 } 1205 } 1206 1207 func createKeyHandler(w http.ResponseWriter, r *http.Request) { 1208 newSession := new(user.SessionState) 1209 if err := json.NewDecoder(r.Body).Decode(newSession); err != nil { 1210 log.WithFields(logrus.Fields{ 1211 "prefix": "api", 1212 "status": "fail", 1213 "err": err, 1214 }).Error("Key creation failed.") 1215 doJSONWrite(w, http.StatusInternalServerError, apiError("Unmarshalling failed")) 1216 return 1217 } 1218 1219 newKey := keyGen.GenerateAuthKey(newSession.OrgID) 1220 if newSession.HMACEnabled { 1221 newSession.HmacSecret = keyGen.GenerateHMACSecret() 1222 } 1223 1224 if newSession.Certificate != "" { 1225 newKey = generateToken(newSession.OrgID, newSession.Certificate) 1226 } 1227 1228 newSession.LastUpdated = strconv.Itoa(int(time.Now().Unix())) 1229 newSession.DateCreated = time.Now() 1230 1231 if len(newSession.AccessRights) > 0 { 1232 // reset API-level limit to nil if any has a zero-value 1233 resetAPILimits(newSession.AccessRights) 1234 for apiID := range newSession.AccessRights { 1235 apiSpec := getApiSpec(apiID) 1236 if apiSpec != nil { 1237 checkAndApplyTrialPeriod(newKey, apiID, newSession, false) 1238 // If we have enabled HMAC checking for keys, we need to generate a secret for the client to use 1239 if !apiSpec.DontSetQuotasOnCreate { 1240 // Reset quota by default 1241 apiSpec.SessionManager.ResetQuota(newKey, newSession, false) 1242 newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate 1243 } 1244 // apply polices (if any) and save key 1245 if err := applyPoliciesAndSave(newKey, newSession, apiSpec, false); err != nil { 1246 doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to create key - "+err.Error())) 1247 return 1248 } 1249 } else { 1250 // Use fallback 1251 sessionManager := FallbackKeySesionManager 1252 newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate 1253 sessionManager.ResetQuota(newKey, newSession, false) 1254 err := sessionManager.UpdateSession(newKey, newSession, -1, false) 1255 if err != nil { 1256 doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to create key - "+err.Error())) 1257 return 1258 } 1259 } 1260 } 1261 } else { 1262 if config.Global().AllowMasterKeys { 1263 // nothing defined, add key to ALL 1264 log.WithFields(logrus.Fields{ 1265 "prefix": "api", 1266 "status": "warning", 1267 "org_id": newSession.OrgID, 1268 "api_id": "--", 1269 "user_id": "system", 1270 "user_ip": requestIPHops(r), 1271 "path": "--", 1272 "server_name": "system", 1273 }).Warning("No API Access Rights set on key session, adding key to all APIs.") 1274 1275 apisMu.RLock() 1276 defer apisMu.RUnlock() 1277 for _, spec := range apisByID { 1278 checkAndApplyTrialPeriod(newKey, spec.APIID, newSession, false) 1279 if !spec.DontSetQuotasOnCreate { 1280 // Reset quote by default 1281 spec.SessionManager.ResetQuota(newKey, newSession, false) 1282 newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate 1283 } 1284 // apply polices (if any) and save key 1285 if err := applyPoliciesAndSave(newKey, newSession, spec, false); err != nil { 1286 doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to create key - "+err.Error())) 1287 return 1288 } 1289 } 1290 } else { 1291 log.WithFields(logrus.Fields{ 1292 "prefix": "api", 1293 "status": "error", 1294 "err": "master keys disabled", 1295 "org_id": newSession.OrgID, 1296 "api_id": "--", 1297 "user_id": "system", 1298 "user_ip": requestIPHops(r), 1299 "path": "--", 1300 "server_name": "system", 1301 }).Error("Master keys disallowed in configuration, key not added.") 1302 1303 doJSONWrite(w, http.StatusBadRequest, apiError("Failed to create key, keys must have at least one Access Rights record set.")) 1304 return 1305 } 1306 1307 } 1308 1309 obj := apiModifyKeySuccess{ 1310 Action: "added", 1311 Key: newKey, 1312 Status: "ok", 1313 } 1314 1315 // add key hash to reply 1316 if config.Global().HashKeys { 1317 obj.KeyHash = storage.HashKey(newKey) 1318 } 1319 1320 FireSystemEvent(EventTokenCreated, EventTokenMeta{ 1321 EventMetaDefault: EventMetaDefault{Message: "Key generated."}, 1322 Org: newSession.OrgID, 1323 Key: newKey, 1324 }) 1325 1326 log.WithFields(logrus.Fields{ 1327 "prefix": "api", 1328 "key": obfuscateKey(newKey), 1329 "status": "ok", 1330 "api_id": "--", 1331 "org_id": newSession.OrgID, 1332 "user_id": "system", 1333 "user_ip": requestIPHops(r), 1334 "path": "--", 1335 "server_name": "system", 1336 }).Info("Generated new key: (", obfuscateKey(newKey), ")") 1337 1338 doJSONWrite(w, http.StatusOK, obj) 1339 } 1340 1341 // NewClientRequest is an outward facing JSON object translated from osin OAuthClients 1342 // 1343 // swagger:model NewClientRequest 1344 type NewClientRequest struct { 1345 ClientID string `json:"client_id"` 1346 ClientRedirectURI string `json:"redirect_uri"` 1347 APIID string `json:"api_id,omitempty"` 1348 PolicyID string `json:"policy_id,omitempty"` 1349 ClientSecret string `json:"secret"` 1350 MetaData interface{} `json:"meta_data"` 1351 Description string `json:"description"` 1352 } 1353 1354 func oauthClientStorageID(clientID string) string { 1355 return prefixClient + clientID 1356 } 1357 1358 func createOauthClient(w http.ResponseWriter, r *http.Request) { 1359 var newOauthClient NewClientRequest 1360 if err := json.NewDecoder(r.Body).Decode(&newOauthClient); err != nil { 1361 log.WithFields(logrus.Fields{ 1362 "prefix": "api", 1363 "status": "fail", 1364 "err": err, 1365 }).Error("Failed to create OAuth client") 1366 doJSONWrite(w, http.StatusInternalServerError, apiError("Unmarshalling failed")) 1367 return 1368 } 1369 1370 // Allow the client ID to be set 1371 cleanSting := newOauthClient.ClientID 1372 1373 if newOauthClient.ClientID == "" { 1374 u5 := uuid.NewV4() 1375 cleanSting = strings.Replace(u5.String(), "-", "", -1) 1376 } 1377 1378 // Allow the secret to be set 1379 secret := newOauthClient.ClientSecret 1380 if newOauthClient.ClientSecret == "" { 1381 u5Secret := uuid.NewV4() 1382 secret = base64.StdEncoding.EncodeToString([]byte(u5Secret.String())) 1383 } 1384 1385 newClient := OAuthClient{ 1386 ClientID: cleanSting, 1387 ClientRedirectURI: newOauthClient.ClientRedirectURI, 1388 ClientSecret: secret, 1389 PolicyID: newOauthClient.PolicyID, 1390 MetaData: newOauthClient.MetaData, 1391 Description: newOauthClient.Description, 1392 } 1393 1394 storageID := oauthClientStorageID(newClient.GetId()) 1395 log.WithFields(logrus.Fields{ 1396 "prefix": "api", 1397 }).Debug("Created storage ID: ", storageID) 1398 1399 if newOauthClient.APIID != "" { 1400 // set client only for passed API ID 1401 apiSpec := getApiSpec(newOauthClient.APIID) 1402 if apiSpec == nil { 1403 log.WithFields(logrus.Fields{ 1404 "prefix": "api", 1405 "apiID": newOauthClient.APIID, 1406 "status": "fail", 1407 "err": "API doesn't exist", 1408 }).Error("Failed to create OAuth client") 1409 doJSONWrite(w, http.StatusBadRequest, apiError("API doesn't exist")) 1410 return 1411 } 1412 1413 if !apiSpec.UseOauth2 { 1414 doJSONWrite(w, http.StatusBadRequest, 1415 apiError("API is not OAuth2")) 1416 return 1417 } 1418 1419 err := apiSpec.OAuthManager.OsinServer.Storage.SetClient(storageID, &newClient, true) 1420 if err != nil { 1421 log.WithFields(logrus.Fields{ 1422 "prefix": "api", 1423 "apiID": newOauthClient.APIID, 1424 "status": "fail", 1425 "err": err, 1426 }).Error("Failed to create OAuth client") 1427 doJSONWrite(w, http.StatusInternalServerError, apiError("Failure in storing client data.")) 1428 return 1429 } 1430 } else { 1431 // set client for all APIs from the given policy 1432 policiesMu.RLock() 1433 policy, ok := policiesByID[newClient.PolicyID] 1434 policiesMu.RUnlock() 1435 if !ok { 1436 log.WithFields(logrus.Fields{ 1437 "prefix": "api", 1438 "policyID": newClient.PolicyID, 1439 "status": "fail", 1440 "err": "Policy doesn't exist", 1441 }).Error("Failed to create OAuth client") 1442 doJSONWrite(w, http.StatusBadRequest, apiError("Policy doesn't exist")) 1443 return 1444 } 1445 1446 oauth2 := false 1447 // iterate over APIs and set client for each of them 1448 for apiID := range policy.AccessRights { 1449 apiSpec := getApiSpec(apiID) 1450 if apiSpec == nil { 1451 log.WithFields(logrus.Fields{ 1452 "prefix": "api", 1453 "apiID": apiID, 1454 "status": "fail", 1455 "err": "API doesn't exist", 1456 }).Error("Failed to create OAuth client") 1457 doJSONWrite(w, http.StatusBadRequest, apiError("API doesn't exist")) 1458 return 1459 } 1460 // set oauth client if it is oauth API 1461 if apiSpec.UseOauth2 { 1462 oauth2 = true 1463 err := apiSpec.OAuthManager.OsinServer.Storage.SetClient(storageID, &newClient, true) 1464 if err != nil { 1465 log.WithFields(logrus.Fields{ 1466 "prefix": "api", 1467 "apiID": apiID, 1468 "status": "fail", 1469 "err": err, 1470 }).Error("Failed to create OAuth client") 1471 doJSONWrite(w, http.StatusInternalServerError, apiError("Failure in storing client data.")) 1472 return 1473 } 1474 } 1475 } 1476 1477 if !oauth2 { 1478 doJSONWrite(w, http.StatusBadRequest, 1479 apiError("API is not OAuth2")) 1480 return 1481 } 1482 } 1483 1484 clientData := NewClientRequest{ 1485 ClientID: newClient.GetId(), 1486 ClientSecret: newClient.GetSecret(), 1487 ClientRedirectURI: newClient.GetRedirectUri(), 1488 PolicyID: newClient.GetPolicyID(), 1489 MetaData: newClient.GetUserData(), 1490 Description: newClient.GetDescription(), 1491 } 1492 1493 log.WithFields(logrus.Fields{ 1494 "prefix": "api", 1495 "apiID": newOauthClient.APIID, 1496 "clientID": clientData.ClientID, 1497 "clientRedirectURI": clientData.ClientRedirectURI, 1498 "policyID": clientData.PolicyID, 1499 "description": clientData.Description, 1500 "status": "ok", 1501 }).Info("Created OAuth client") 1502 1503 doJSONWrite(w, http.StatusOK, clientData) 1504 } 1505 1506 // Update Client 1507 func updateOauthClient(keyName, apiID string, r *http.Request) (interface{}, int) { 1508 // read payload 1509 var updateClientData NewClientRequest 1510 if err := json.NewDecoder(r.Body).Decode(&updateClientData); err != nil { 1511 log.WithFields(logrus.Fields{ 1512 "prefix": "api", 1513 "status": "fail", 1514 "err": err, 1515 }).Error("Failed to update OAuth client") 1516 return apiError("Unmarshalling failed"), http.StatusInternalServerError 1517 } 1518 1519 // check API 1520 apiSpec := getApiSpec(apiID) 1521 if apiSpec == nil { 1522 return apiError("API doesn't exist"), http.StatusNotFound 1523 } 1524 1525 // check policy 1526 if updateClientData.PolicyID != "" { 1527 policiesMu.RLock() 1528 policy, ok := policiesByID[updateClientData.PolicyID] 1529 policiesMu.RUnlock() 1530 if !ok { 1531 return apiError("Policy doesn't exist"), http.StatusNotFound 1532 } 1533 if _, ok := policy.AccessRights[apiID]; !ok { 1534 return apiError("Policy access rights doesn't contain API this OAuth client belongs to"), 1535 http.StatusBadRequest 1536 } 1537 if len(policy.AccessRights) != 1 { 1538 return apiError("Policy access rights should contain only one API"), http.StatusBadRequest 1539 } 1540 } 1541 1542 // get existing version of oauth-client 1543 storageID := oauthClientStorageID(keyName) 1544 client, err := apiSpec.OAuthManager.OsinServer.Storage.GetExtendedClientNoPrefix(storageID) 1545 if err != nil { 1546 return apiError("OAuth Client ID not found"), http.StatusNotFound 1547 } 1548 1549 // update client 1550 updatedClient := OAuthClient{ 1551 ClientID: client.GetId(), 1552 ClientSecret: client.GetSecret(), // DO NOT update 1553 ClientRedirectURI: updateClientData.ClientRedirectURI, // update 1554 PolicyID: updateClientData.PolicyID, // update 1555 MetaData: client.GetUserData(), // DO NOT update 1556 Description: updateClientData.Description, // update 1557 } 1558 1559 err = apiSpec.OAuthManager.OsinServer.Storage.SetClient(storageID, &updatedClient, true) 1560 if err != nil { 1561 log.WithFields(logrus.Fields{ 1562 "prefix": "api", 1563 "apiID": apiID, 1564 "status": "fail", 1565 "err": err, 1566 }).Error("Failed to update OAuth client") 1567 return apiError("Failure in storing client data"), http.StatusInternalServerError 1568 } 1569 1570 // invalidate tokens if we had a new policy 1571 if prevPolicy := client.GetPolicyID(); prevPolicy != "" && prevPolicy != updatedClient.PolicyID { 1572 tokenList, err := apiSpec.OAuthManager.OsinServer.Storage.GetClientTokens(updatedClient.ClientID) 1573 if err != nil { 1574 log.WithError(err).Warning("Could not get list of tokens for updated OAuth client") 1575 } 1576 for _, token := range tokenList { 1577 if err := apiSpec.OAuthManager.OsinServer.Storage.RemoveAccess(token.Token); err != nil { 1578 log.WithError(err).Warning("Could not remove token for updated OAuth client policy") 1579 } 1580 } 1581 } 1582 1583 // convert to outbound format 1584 replyData := NewClientRequest{ 1585 ClientID: updatedClient.GetId(), 1586 ClientSecret: updatedClient.GetSecret(), 1587 ClientRedirectURI: updatedClient.GetRedirectUri(), 1588 PolicyID: updatedClient.GetPolicyID(), 1589 MetaData: updatedClient.GetUserData(), 1590 Description: updatedClient.GetDescription(), 1591 } 1592 1593 return replyData, http.StatusOK 1594 } 1595 1596 func invalidateOauthRefresh(w http.ResponseWriter, r *http.Request) { 1597 apiID := r.URL.Query().Get("api_id") 1598 if apiID == "" { 1599 doJSONWrite(w, http.StatusBadRequest, apiError("Missing parameter api_id")) 1600 return 1601 } 1602 apiSpec := getApiSpec(apiID) 1603 1604 log.WithFields(logrus.Fields{ 1605 "prefix": "api", 1606 "apiID": apiID, 1607 }).Debug("Looking for refresh token in API Register") 1608 1609 if apiSpec == nil { 1610 log.WithFields(logrus.Fields{ 1611 "prefix": "api", 1612 "apiID": apiID, 1613 "status": "fail", 1614 "err": "API not found", 1615 }).Error("Failed to invalidate refresh token") 1616 1617 doJSONWrite(w, http.StatusNotFound, apiError("API for this refresh token not found")) 1618 return 1619 } 1620 1621 if apiSpec.OAuthManager == nil { 1622 log.WithFields(logrus.Fields{ 1623 "prefix": "api", 1624 "apiID": apiID, 1625 "status": "fail", 1626 "err": "API is not OAuth", 1627 }).Error("Failed to invalidate refresh token") 1628 1629 doJSONWrite(w, http.StatusBadRequest, apiError("OAuth is not enabled on this API")) 1630 return 1631 } 1632 1633 keyName := mux.Vars(r)["keyName"] 1634 err := apiSpec.OAuthManager.OsinServer.Storage.RemoveRefresh(keyName) 1635 if err != nil { 1636 log.WithFields(logrus.Fields{ 1637 "prefix": "api", 1638 "apiID": apiID, 1639 "status": "fail", 1640 "err": err, 1641 }).Error("Failed to invalidate refresh token") 1642 1643 doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to invalidate refresh token")) 1644 return 1645 } 1646 1647 success := apiModifyKeySuccess{ 1648 Key: keyName, 1649 Status: "ok", 1650 Action: "deleted", 1651 } 1652 1653 log.WithFields(logrus.Fields{ 1654 "prefix": "api", 1655 "apiID": apiID, 1656 "token": keyName, 1657 "status": "ok", 1658 }).Info("Invalidated refresh token") 1659 1660 doJSONWrite(w, http.StatusOK, success) 1661 } 1662 1663 func oAuthClientHandler(w http.ResponseWriter, r *http.Request) { 1664 apiID := mux.Vars(r)["apiID"] 1665 keyName := mux.Vars(r)["keyName"] 1666 1667 var obj interface{} 1668 var code int 1669 switch r.Method { 1670 case http.MethodGet: 1671 if keyName != "" { 1672 // Return single client detail 1673 obj, code = getOauthClientDetails(keyName, apiID) 1674 } else { 1675 // Return list of keys 1676 obj, code = getOauthClients(apiID) 1677 } 1678 case http.MethodPut: 1679 // Update client 1680 obj, code = updateOauthClient(keyName, apiID, r) 1681 case http.MethodDelete: 1682 // Remove a key 1683 obj, code = handleDeleteOAuthClient(keyName, apiID) 1684 } 1685 1686 doJSONWrite(w, code, obj) 1687 } 1688 1689 func oAuthClientTokensHandler(w http.ResponseWriter, r *http.Request) { 1690 apiID := mux.Vars(r)["apiID"] 1691 keyName := mux.Vars(r)["keyName"] 1692 1693 apiSpec := getApiSpec(apiID) 1694 if apiSpec == nil { 1695 log.WithFields(logrus.Fields{ 1696 "prefix": "api", 1697 "apiID": apiID, 1698 "status": "fail", 1699 "client": keyName, 1700 "err": "not found", 1701 }).Error("Failed to retrieve OAuth tokens") 1702 doJSONWrite(w, http.StatusNotFound, apiError("OAuth Client ID not found")) 1703 return 1704 } 1705 1706 if p := r.URL.Query().Get("page"); p != "" { 1707 page := 1 1708 1709 queryPage, err := strconv.Atoi(p) 1710 if err == nil { 1711 page = queryPage 1712 } 1713 1714 if page <= 0 { 1715 page = 1 1716 } 1717 1718 tokens, totalPages, err := apiSpec.OAuthManager.OsinServer.Storage.GetPaginatedClientTokens(keyName, page) 1719 if err != nil { 1720 doJSONWrite(w, http.StatusInternalServerError, apiError("Get client tokens failed")) 1721 return 1722 } 1723 1724 doJSONWrite(w, http.StatusOK, paginatedOAuthClientTokens{ 1725 Pagination: paginationStatus{ 1726 PageSize: 100, 1727 PageNum: page, 1728 PageTotal: totalPages, 1729 }, 1730 Tokens: tokens, 1731 }) 1732 1733 return 1734 } 1735 1736 tokens, err := apiSpec.OAuthManager.OsinServer.Storage.GetClientTokens(keyName) 1737 if err != nil { 1738 doJSONWrite(w, http.StatusInternalServerError, apiError("Get client tokens failed")) 1739 return 1740 } 1741 1742 doJSONWrite(w, http.StatusOK, tokens) 1743 } 1744 1745 // Get client details 1746 func getOauthClientDetails(keyName, apiID string) (interface{}, int) { 1747 storageID := oauthClientStorageID(keyName) 1748 apiSpec := getApiSpec(apiID) 1749 if apiSpec == nil { 1750 log.WithFields(logrus.Fields{ 1751 "prefix": "api", 1752 "apiID": apiID, 1753 "status": "fail", 1754 "client": keyName, 1755 "err": "not found", 1756 }).Error("Failed to retrieve OAuth client details") 1757 return apiError("OAuth Client ID not found"), http.StatusNotFound 1758 } 1759 1760 clientData, err := apiSpec.OAuthManager.OsinServer.Storage.GetExtendedClientNoPrefix(storageID) 1761 if err != nil { 1762 return apiError("OAuth Client ID not found"), http.StatusNotFound 1763 } 1764 reportableClientData := NewClientRequest{ 1765 ClientID: clientData.GetId(), 1766 ClientSecret: clientData.GetSecret(), 1767 ClientRedirectURI: clientData.GetRedirectUri(), 1768 PolicyID: clientData.GetPolicyID(), 1769 MetaData: clientData.GetUserData(), 1770 Description: clientData.GetDescription(), 1771 } 1772 1773 log.WithFields(logrus.Fields{ 1774 "prefix": "api", 1775 "apiID": apiID, 1776 "status": "ok", 1777 "client": keyName, 1778 }).Info("Retrieved OAuth client ID") 1779 1780 return reportableClientData, http.StatusOK 1781 } 1782 1783 // Delete Client 1784 func handleDeleteOAuthClient(keyName, apiID string) (interface{}, int) { 1785 storageID := oauthClientStorageID(keyName) 1786 1787 apiSpec := getApiSpec(apiID) 1788 if apiSpec == nil { 1789 log.WithFields(logrus.Fields{ 1790 "prefix": "api", 1791 "apiID": apiID, 1792 "status": "fail", 1793 "client": keyName, 1794 "err": "not found", 1795 }).Error("Failed to delete OAuth client") 1796 1797 return apiError("OAuth Client ID not found"), http.StatusNotFound 1798 } 1799 1800 err := apiSpec.OAuthManager.OsinServer.Storage.DeleteClient(storageID, true) 1801 if err != nil { 1802 return apiError("Delete failed"), http.StatusInternalServerError 1803 } 1804 1805 statusObj := apiModifyKeySuccess{ 1806 Key: keyName, 1807 Status: "ok", 1808 Action: "deleted", 1809 } 1810 1811 log.WithFields(logrus.Fields{ 1812 "prefix": "api", 1813 "apiID": apiID, 1814 "status": "ok", 1815 "client": keyName, 1816 }).Info("Deleted OAuth client") 1817 1818 return statusObj, http.StatusOK 1819 } 1820 1821 const oAuthNotPropagatedErr = "OAuth client list isn't available or hasn't been propagated yet." 1822 1823 // List Clients 1824 func getOauthClients(apiID string) (interface{}, int) { 1825 filterID := prefixClient 1826 1827 apiSpec := getApiSpec(apiID) 1828 if apiSpec == nil { 1829 log.WithFields(logrus.Fields{ 1830 "prefix": "api", 1831 "apiID": apiID, 1832 "status": "fail", 1833 "err": "API not found", 1834 }).Error("Failed to retrieve OAuth client list.") 1835 1836 return apiError("OAuth Client ID not found"), http.StatusNotFound 1837 } 1838 1839 if apiSpec.OAuthManager == nil { 1840 log.WithFields(logrus.Fields{ 1841 "prefix": "api", 1842 "apiID": apiID, 1843 "status": "fail", 1844 "err": "API not found", 1845 }).Error("Failed to retrieve OAuth client list.") 1846 1847 return apiError(oAuthNotPropagatedErr), http.StatusBadRequest 1848 } 1849 1850 clientData, err := apiSpec.OAuthManager.OsinServer.Storage.GetClients(filterID, true) 1851 if err != nil { 1852 log.WithFields(logrus.Fields{ 1853 "prefix": "api", 1854 "apiID": apiID, 1855 "status": "fail", 1856 "err": err, 1857 }).Error("Failed to report OAuth client list") 1858 1859 return apiError("OAuth slients not found"), http.StatusNotFound 1860 } 1861 clients := []NewClientRequest{} 1862 for _, osinClient := range clientData { 1863 reportableClientData := NewClientRequest{ 1864 ClientID: osinClient.GetId(), 1865 ClientSecret: osinClient.GetSecret(), 1866 ClientRedirectURI: osinClient.GetRedirectUri(), 1867 PolicyID: osinClient.GetPolicyID(), 1868 MetaData: osinClient.GetUserData(), 1869 Description: osinClient.GetDescription(), 1870 } 1871 1872 clients = append(clients, reportableClientData) 1873 } 1874 log.WithFields(logrus.Fields{ 1875 "prefix": "api", 1876 "apiID": apiID, 1877 "status": "ok", 1878 }).Info("Retrieved OAuth client list") 1879 1880 return clients, http.StatusOK 1881 } 1882 1883 func healthCheckhandler(w http.ResponseWriter, r *http.Request) { 1884 if !config.Global().HealthCheck.EnableHealthChecks { 1885 doJSONWrite(w, http.StatusBadRequest, apiError("Health checks are not enabled for this node")) 1886 return 1887 } 1888 apiID := r.URL.Query().Get("api_id") 1889 if apiID == "" { 1890 doJSONWrite(w, http.StatusBadRequest, apiError("missing api_id parameter")) 1891 return 1892 } 1893 apiSpec := getApiSpec(apiID) 1894 if apiSpec == nil { 1895 doJSONWrite(w, http.StatusNotFound, apiError("API ID not found")) 1896 return 1897 } 1898 health, _ := apiSpec.Health.ApiHealthValues() 1899 doJSONWrite(w, http.StatusOK, health) 1900 } 1901 1902 func userRatesCheck(w http.ResponseWriter, r *http.Request) { 1903 session := ctxGetSession(r) 1904 if session == nil { 1905 doJSONWrite(w, http.StatusBadRequest, apiError("Health checks are not enabled for this node")) 1906 return 1907 } 1908 1909 returnSession := PublicSession{} 1910 returnSession.Quota.QuotaRenews = session.QuotaRenews 1911 returnSession.Quota.QuotaRemaining = session.QuotaRemaining 1912 returnSession.Quota.QuotaMax = session.QuotaMax 1913 returnSession.RateLimit.Rate = session.Rate 1914 returnSession.RateLimit.Per = session.Per 1915 1916 doJSONWrite(w, http.StatusOK, returnSession) 1917 } 1918 1919 func invalidateCacheHandler(w http.ResponseWriter, r *http.Request) { 1920 apiID := mux.Vars(r)["apiID"] 1921 1922 keyPrefix := "cache-" + apiID 1923 matchPattern := keyPrefix + "*" 1924 store := storage.RedisCluster{KeyPrefix: keyPrefix, IsCache: true} 1925 1926 if ok := store.DeleteScanMatch(matchPattern); !ok { 1927 err := errors.New("scan/delete failed") 1928 var orgid string 1929 if spec := getApiSpec(apiID); spec != nil { 1930 orgid = spec.OrgID 1931 } 1932 log.WithFields(logrus.Fields{ 1933 "prefix": "api", 1934 "api_id": apiID, 1935 "status": "fail", 1936 "err": err, 1937 "org_id": orgid, 1938 "user_id": "system", 1939 "user_ip": requestIPHops(r), 1940 "path": "--", 1941 "server_name": "system", 1942 }).Error("Failed to delete cache: ", err) 1943 1944 doJSONWrite(w, http.StatusInternalServerError, apiError("Cache invalidation failed")) 1945 return 1946 } 1947 1948 doJSONWrite(w, http.StatusOK, apiOk("cache invalidated")) 1949 } 1950 1951 // TODO: Don't modify http.Request values in-place. We must right now 1952 // because our middleware design doesn't pass around http.Request 1953 // pointers, so we have no way to modify the pointer in a middleware. 1954 // 1955 // If we ever redesign middlewares - or if we find another workaround - 1956 // revisit this. 1957 func setContext(r *http.Request, ctx context.Context) { 1958 r2 := r.WithContext(ctx) 1959 *r = *r2 1960 } 1961 func setCtxValue(r *http.Request, key, val interface{}) { 1962 setContext(r, context.WithValue(r.Context(), key, val)) 1963 } 1964 1965 func ctxGetData(r *http.Request) map[string]interface{} { 1966 if v := r.Context().Value(ctx.ContextData); v != nil { 1967 return v.(map[string]interface{}) 1968 } 1969 return nil 1970 } 1971 1972 func ctxSetData(r *http.Request, m map[string]interface{}) { 1973 if m == nil { 1974 panic("setting a nil context ContextData") 1975 } 1976 setCtxValue(r, ctx.ContextData, m) 1977 } 1978 1979 func ctxGetSession(r *http.Request) *user.SessionState { 1980 return ctx.GetSession(r) 1981 } 1982 1983 func ctxSetSession(r *http.Request, s *user.SessionState, token string, scheduleUpdate bool) { 1984 ctx.SetSession(r, s, token, scheduleUpdate) 1985 } 1986 1987 func ctxScheduleSessionUpdate(r *http.Request) { 1988 setCtxValue(r, ctx.UpdateSession, true) 1989 } 1990 1991 func ctxDisableSessionUpdate(r *http.Request) { 1992 setCtxValue(r, ctx.UpdateSession, false) 1993 } 1994 1995 func ctxSessionUpdateScheduled(r *http.Request) bool { 1996 if v := r.Context().Value(ctx.UpdateSession); v != nil { 1997 return v.(bool) 1998 } 1999 return false 2000 } 2001 2002 func ctxGetAuthToken(r *http.Request) string { 2003 return ctx.GetAuthToken(r) 2004 } 2005 2006 func ctxGetTrackedPath(r *http.Request) string { 2007 if v := r.Context().Value(ctx.TrackThisEndpoint); v != nil { 2008 return v.(string) 2009 } 2010 return "" 2011 } 2012 2013 func ctxSetTrackedPath(r *http.Request, p string) { 2014 if p == "" { 2015 panic("setting a nil context TrackThisEndpoint") 2016 } 2017 setCtxValue(r, ctx.TrackThisEndpoint, p) 2018 } 2019 2020 func ctxGetDoNotTrack(r *http.Request) bool { 2021 return r.Context().Value(ctx.DoNotTrackThisEndpoint) == true 2022 } 2023 2024 func ctxSetDoNotTrack(r *http.Request, b bool) { 2025 setCtxValue(r, ctx.DoNotTrackThisEndpoint, b) 2026 } 2027 2028 func ctxGetVersionInfo(r *http.Request) *apidef.VersionInfo { 2029 if v := r.Context().Value(ctx.VersionData); v != nil { 2030 return v.(*apidef.VersionInfo) 2031 } 2032 return nil 2033 } 2034 2035 func ctxSetVersionInfo(r *http.Request, v *apidef.VersionInfo) { 2036 setCtxValue(r, ctx.VersionData, v) 2037 } 2038 2039 func ctxSetOrigRequestURL(r *http.Request, url *url.URL) { 2040 setCtxValue(r, ctx.OrigRequestURL, url) 2041 } 2042 2043 func ctxGetOrigRequestURL(r *http.Request) *url.URL { 2044 if v := r.Context().Value(ctx.OrigRequestURL); v != nil { 2045 if urlVal, ok := v.(*url.URL); ok { 2046 return urlVal 2047 } 2048 } 2049 2050 return nil 2051 } 2052 2053 func ctxSetUrlRewritePath(r *http.Request, path string) { 2054 setCtxValue(r, ctx.UrlRewritePath, path) 2055 } 2056 2057 func ctxGetUrlRewritePath(r *http.Request) string { 2058 if v := r.Context().Value(ctx.UrlRewritePath); v != nil { 2059 if strVal, ok := v.(string); ok { 2060 return strVal 2061 } 2062 } 2063 return "" 2064 } 2065 2066 func ctxSetCheckLoopLimits(r *http.Request, b bool) { 2067 setCtxValue(r, ctx.CheckLoopLimits, b) 2068 } 2069 2070 // Should we check Rate limits and Quotas? 2071 func ctxCheckLimits(r *http.Request) bool { 2072 // If looping disabled, allow all 2073 if !ctxLoopingEnabled(r) { 2074 return true 2075 } 2076 2077 if v := r.Context().Value(ctx.CheckLoopLimits); v != nil { 2078 return v.(bool) 2079 } 2080 2081 return false 2082 } 2083 2084 func ctxSetRequestMethod(r *http.Request, path string) { 2085 setCtxValue(r, ctx.RequestMethod, path) 2086 } 2087 2088 func ctxGetRequestMethod(r *http.Request) string { 2089 if v := r.Context().Value(ctx.RequestMethod); v != nil { 2090 if strVal, ok := v.(string); ok { 2091 return strVal 2092 } 2093 } 2094 return r.Method 2095 } 2096 2097 func ctxGetDefaultVersion(r *http.Request) bool { 2098 return r.Context().Value(ctx.VersionDefault) != nil 2099 } 2100 2101 func ctxSetDefaultVersion(r *http.Request) { 2102 setCtxValue(r, ctx.VersionDefault, true) 2103 } 2104 2105 func ctxLoopingEnabled(r *http.Request) bool { 2106 return ctxLoopLevel(r) > 0 2107 } 2108 2109 func ctxLoopLevel(r *http.Request) int { 2110 if v := r.Context().Value(ctx.LoopLevel); v != nil { 2111 if intVal, ok := v.(int); ok { 2112 return intVal 2113 } 2114 } 2115 2116 return 0 2117 } 2118 2119 func ctxSetLoopLevel(r *http.Request, value int) { 2120 setCtxValue(r, ctx.LoopLevel, value) 2121 } 2122 2123 func ctxIncLoopLevel(r *http.Request, loopLimit int) { 2124 ctxSetLoopLimit(r, loopLimit) 2125 ctxSetLoopLevel(r, ctxLoopLevel(r)+1) 2126 } 2127 2128 func ctxLoopLevelLimit(r *http.Request) int { 2129 if v := r.Context().Value(ctx.LoopLevelLimit); v != nil { 2130 if intVal, ok := v.(int); ok { 2131 return intVal 2132 } 2133 } 2134 2135 return 0 2136 } 2137 2138 func ctxSetLoopLimit(r *http.Request, limit int) { 2139 // Can be set only one time per request 2140 if ctxLoopLevelLimit(r) == 0 && limit > 0 { 2141 setCtxValue(r, ctx.LoopLevelLimit, limit) 2142 } 2143 } 2144 2145 func ctxThrottleLevelLimit(r *http.Request) int { 2146 if v := r.Context().Value(ctx.ThrottleLevelLimit); v != nil { 2147 if intVal, ok := v.(int); ok { 2148 return intVal 2149 } 2150 } 2151 2152 return 0 2153 } 2154 2155 func ctxThrottleLevel(r *http.Request) int { 2156 if v := r.Context().Value(ctx.ThrottleLevel); v != nil { 2157 if intVal, ok := v.(int); ok { 2158 return intVal 2159 } 2160 } 2161 2162 return 0 2163 } 2164 2165 func ctxSetThrottleLimit(r *http.Request, limit int) { 2166 // Can be set only one time per request 2167 if ctxThrottleLevelLimit(r) == 0 && limit > 0 { 2168 setCtxValue(r, ctx.ThrottleLevelLimit, limit) 2169 } 2170 } 2171 2172 func ctxSetThrottleLevel(r *http.Request, value int) { 2173 setCtxValue(r, ctx.ThrottleLevel, value) 2174 } 2175 2176 func ctxIncThrottleLevel(r *http.Request, throttleLimit int) { 2177 ctxSetThrottleLimit(r, throttleLimit) 2178 ctxSetThrottleLevel(r, ctxThrottleLevel(r)+1) 2179 } 2180 2181 func ctxTraceEnabled(r *http.Request) bool { 2182 return r.Context().Value(ctx.Trace) != nil 2183 } 2184 2185 func ctxSetTrace(r *http.Request) { 2186 setCtxValue(r, ctx.Trace, true) 2187 }