github-code-scanning[bot] commented on code in PR #7749:
URL: https://github.com/apache/trafficcontrol/pull/7749#discussion_r1307563918


##########
traffic_ops/traffic_ops_golang/apitenant/tenant.go:
##########
@@ -336,3 +341,462 @@
 WHERE id=:id`
        return query
 }
+
+func selectMaxLastUpdatedQuery(where string) string {
+       tableName := "tenant"
+       return `SELECT max(t) from (
+               SELECT max(last_updated) as t from ` + tableName + ` q ` + 
where +
+               ` UNION ALL
+       select max(last_updated) as t from last_deleted l where l.table_name='` 
+ tableName + `') as res`
+}
+
+// CreateTenant [Version : V5] function Process the *http.Request and creates 
new tenant
+func CreateTenant(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       tx := inf.Tx.Tx
+
+       defer r.Body.Close()
+
+       tenant, readValErr := readAndValidateJsonStruct(r)
+       if readValErr != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, readValErr, nil)
+               return
+       }
+
+       // Check if tenant is tenable
+       authorized, err := isTenantAuthorizedV5(&tenant, inf.User, tx)
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("checking tenant authorized: "+err.Error()))
+               return
+       }
+       if !authorized {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusForbidden, 
errors.New("not authorized on this tenant"), nil)
+               return
+       }
+
+       resultRows, err := inf.Tx.NamedQuery(insertQuery(), tenant)
+       if err != nil {
+               userErr, sysErr, errCode = api.ParseDBError(err)
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer resultRows.Close()
+
+       var id int
+       lastUpdated := time.Time{}
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := resultRows.Scan(&id, &lastUpdated); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, errors.New("tenant create scanning: "+err.Error()))
+                       return
+               }
+       }
+
+       if rowsAffected == 0 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("tenant create: no tenant was inserted, no id was returned"))
+               return
+       } else if rowsAffected > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("too many ids returned from tenant insert"))
+               return
+       }
+       tenant.ID = &id
+       tenant.LastUpdated = &lastUpdated
+
+       alerts := tc.CreateAlerts(tc.SuccessLevel, "tenant was created.")
+       api.WriteAlertsObj(w, r, http.StatusOK, alerts, tenant)
+       changeLogMsg := fmt.Sprintf("TENANT: %s, ID: %d, ACTION: Created 
tenant", *tenant.Name, *tenant.ID)
+       api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx)
+       return
+}
+
+// GetTenant [Version : V5] function Process the *http.Request and writes the 
response. It uses getTenant function.
+func GetTenant(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       tx := inf.Tx.Tx
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       user, _ := auth.GetCurrentUser(r.Context())
+       tenantID := user.TenantID
+       if tenantID == auth.TenantIDInvalid {
+               return
+       }
+
+       code := http.StatusOK
+       useIMS := false
+       config, e := api.GetConfig(r.Context())
+       if e == nil && config != nil {
+               useIMS = config.UseIMS
+       } else {
+               log.Warnf("Couldn't get config %v", e)
+       }
+
+       var maxTime *time.Time
+       var usrErr error
+       var syErr error
+
+       var tenants []tc.TenantV5
+
+       api.DefaultSort(inf, "name")
+       tenants, usrErr, syErr, code, maxTime = getTenants(inf.Tx, inf.Params, 
useIMS, r.Header, tenantID)
+       if usrErr != nil {
+               api.HandleErr(w, r, tx, code, fmt.Errorf("read tenant: get 
tenant: "+usrErr.Error()), nil)
+       }
+       if syErr != nil {
+               api.HandleErr(w, r, tx, code, nil, fmt.Errorf("read tenant: get 
tenant: "+syErr.Error()))
+       }
+       if maxTime != nil && api.SetLastModifiedHeader(r, useIMS) {
+               api.AddLastModifiedHdr(w, *maxTime)
+               w.WriteHeader(http.StatusNotModified)
+               return
+       }
+
+       tenantNames := map[int]*string{}
+       for _, it := range tenants {
+               tenantNames[*it.ID] = it.Name
+       }
+       for _, it := range tenants {
+               if it.ParentID == nil || tenantNames[*it.ParentID] == nil {
+                       // root tenant has no parent
+                       continue
+               }
+               p := *tenantNames[*it.ParentID]
+               it.ParentName = &p // copy
+       }
+       api.WriteResp(w, r, tenants)
+}
+
+func getTenants(tx *sqlx.Tx, params map[string]string, useIMS bool, header 
http.Header, id int) ([]tc.TenantV5, error, error, int, *time.Time) {
+       tenants := make([]tc.TenantV5, 0)
+       code := http.StatusOK
+
+       var maxTime time.Time
+       var runSecond bool
+
+       // Query Parameters to Database Query column mappings
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "active":      {Column: "q.active", Checker: nil},
+               "name":        {Column: "q.name", Checker: nil},
+               "parent_name": {Column: "p.name", Checker: nil},
+               "id":          {Column: "q.id", Checker: api.IsInt},
+               "parent_id":   {Column: "q.parent_id", Checker: api.IsInt},
+       }
+       if _, ok := params["orderby"]; !ok {
+               params["orderby"] = "name"
+       }
+
+       where, orderBy, pagination, queryValues, errs := 
dbhelpers.BuildWhereAndOrderByAndPagination(params, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, util.JoinErrs(errs), nil, http.StatusBadRequest, nil
+       }
+
+       if useIMS {
+               runSecond, maxTime = ims.TryIfModifiedSinceQuery(tx, header, 
queryValues, selectMaxLastUpdatedQuery(where))
+               if !runSecond {
+                       log.Debugln("IMS HIT")
+                       code = http.StatusNotModified
+                       return tenants, nil, nil, code, &maxTime
+               }
+               log.Debugln("IMS MISS")
+       } else {
+               log.Debugln("Non IMS request")
+       }
+
+       // Case where we need to run the second query
+       query := selectQuery(id) + where + orderBy + pagination
+       rows, err := tx.NamedQuery(query, queryValues)

Review Comment:
   ## Database query built from user-controlled sources
   
   This query depends on a [user-provided value](1).
   
   [Show more 
details](https://github.com/apache/trafficcontrol/security/code-scanning/305)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@trafficcontrol.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to