// WrapAuthenticate handle wrapper to apply authentication func WrapAuthenticate(hfn http.Handler, cfg config.Config, routeName string) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var errs []ErrorResponse // check if api admin authentication is needed (for tenants etc...) if needsAPIAdmin(routeName) { // Authenticate admin api and check if (authentication.AuthenticateAdmin(r.Header, cfg)) == false { // Because not authenticated respond with error Error(w, r, ErrAuthen, cfg, errs) return } // admin api authenticated so continue serving context.Set(r, "authen", true) context.Set(r, "roles", []string{"super_admin"}) hfn.ServeHTTP(w, r) } else { // authenticate tenant user tenantConf, tErr := authentication.AuthenticateTenant(r.Header, cfg) // If tenant user not authenticated respond with error if tErr != nil { Error(w, r, ErrAuthen, cfg, errs) return } context.Set(r, "roles", tenantConf.Roles) context.Set(r, "tenant_conf", tenantConf) context.Set(r, "authen", true) hfn.ServeHTTP(w, r) } }) }
// Create function is used to implement the create tenant request. // The request is an http POST request with the tenant description // provided as json structure in the request body func Create(r *http.Request, cfg config.Config) (int, http.Header, []byte, error) { //STANDARD DECLARATIONS START code := http.StatusOK h := http.Header{} output := []byte("") err := error(nil) contentType := "text/xml" charset := "utf-8" //STANDARD DECLARATIONS END // Content Negotiation contentType, err = respond.ParseAcceptHeader(r) h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) // if authentication procedure fails then // return unauthorized http status if authentication.AuthenticateAdmin(r.Header, cfg) == false { output, _ = respond.MarshalContent(respond.UnauthorizedMessage, contentType, "", " ") code = http.StatusUnauthorized //If wrong api key is passed we return UNAUTHORIZED http status return code, h, output, err } // Try ingest request body body, err := ioutil.ReadAll(io.LimitReader(r.Body, cfg.Server.ReqSizeLimit)) if err != nil { panic(err) } if err := r.Body.Close(); err != nil { panic(err) } incoming := Tenant{} // Parse body json if err := json.Unmarshal(body, &incoming); err != nil { output, _ = respond.MarshalContent(respond.BadRequestBadJSON, contentType, "", " ") code = http.StatusBadRequest return code, h, output, err } // Try to open the mongo session session, err := mongo.OpenSession(cfg.MongoDB) defer session.Close() if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Check if name exists sameName := []Tenant{} filter := bson.M{"info.name": incoming.Info.Name} err = mongo.Find(session, cfg.MongoDB.Db, "tenants", filter, "name", &sameName) if len(sameName) > 0 { code = http.StatusConflict output, err = createMsgView("Tenant with same name already exists", code) return code, h, output, err } // Generate new id incoming.ID = mongo.NewUUID() incoming.Info.Created = time.Now().Format("2006-01-02 15:04:05") incoming.Info.Updated = incoming.Info.Created err = mongo.Insert(session, cfg.MongoDB.Db, "tenants", incoming) if err != nil { panic(err) } // Create view of the results output, err = createRefView(incoming, "Tenant was succesfully created", 201, r) //Render the results into JSON code = http.StatusCreated return code, h, output, err }
// Delete function used to implement remove tenant request func Delete(r *http.Request, cfg config.Config) (int, http.Header, []byte, error) { //STANDARD DECLARATIONS START code := http.StatusOK h := http.Header{} output := []byte("") err := error(nil) contentType := "text/xml" charset := "utf-8" //STANDARD DECLARATIONS END // Content Negotiation contentType, err = respond.ParseAcceptHeader(r) h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) vars := mux.Vars(r) // if authentication procedure fails then // return unauthorized if authentication.AuthenticateAdmin(r.Header, cfg) == false { output, _ = respond.MarshalContent(respond.UnauthorizedMessage, contentType, "", " ") code = http.StatusUnauthorized //If wrong api key is passed we return UNAUTHORIZED http status return code, h, output, err } // Try to open the mongo session session, err := mongo.OpenSession(cfg.MongoDB) defer session.Close() if err != nil { code = http.StatusInternalServerError return code, h, output, err } filter := bson.M{"id": vars["ID"]} // Retrieve Results from database results := []Tenant{} err = mongo.Find(session, cfg.MongoDB.Db, "tenants", filter, "name", &results) if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Check if nothing found if len(results) < 1 { output, _ = respond.MarshalContent(respond.NotFound, contentType, "", " ") code = http.StatusNotFound return code, h, output, err } mongo.Remove(session, cfg.MongoDB.Db, "tenants", filter) if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Create view of the results output, err = createMsgView("Tenant Successfully Deleted", 200) //Render the results into JSON if err != nil { code = http.StatusInternalServerError return code, h, output, err } h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) return code, h, output, err }
// Update function used to implement update tenant request. // This is an http PUT request that gets a specific tenant's name // as a urlvar parameter input and a json structure in the request // body in order to update the datastore document for the specific // tenant func Update(r *http.Request, cfg config.Config) (int, http.Header, []byte, error) { //STANDARD DECLARATIONS START code := http.StatusOK h := http.Header{} output := []byte("") err := error(nil) contentType := "text/xml" charset := "utf-8" //STANDARD DECLARATIONS END // Content Negotiation contentType, err = respond.ParseAcceptHeader(r) h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) vars := mux.Vars(r) // if authentication procedure fails then // return unauthorized if authentication.AuthenticateAdmin(r.Header, cfg) == false { output, _ = respond.MarshalContent(respond.UnauthorizedMessage, contentType, "", " ") code = http.StatusUnauthorized //If wrong api key is passed we return UNAUTHORIZED http status return code, h, output, err } incoming := Tenant{} // ingest body data body, err := ioutil.ReadAll(io.LimitReader(r.Body, cfg.Server.ReqSizeLimit)) if err != nil { panic(err) } if err := r.Body.Close(); err != nil { panic(err) } // parse body json if err := json.Unmarshal(body, &incoming); err != nil { output, _ = respond.MarshalContent(respond.BadRequestBadJSON, contentType, "", " ") code = http.StatusBadRequest return code, h, output, err } // Try to open the mongo session session, err := mongo.OpenSession(cfg.MongoDB) defer session.Close() if err != nil { code = http.StatusInternalServerError return code, h, output, err } // create filter to retrieve specific profile with id filter := bson.M{"id": vars["ID"]} incoming.ID = vars["ID"] // Retrieve Results from database results := []Tenant{} err = mongo.Find(session, cfg.MongoDB.Db, "tenants", filter, "name", &results) if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Check if nothing found if len(results) < 1 { output, _ = respond.MarshalContent(respond.NotFound, contentType, "", " ") code = http.StatusNotFound return code, h, output, err } // If user chose to change name - check if name already exists if results[0].Info.Name != incoming.Info.Name { sameName := []Tenant{} filter = bson.M{"info.name": incoming.Info.Name} err = mongo.Find(session, cfg.MongoDB.Db, "tenants", filter, "name", &sameName) if len(sameName) > 1 { code = http.StatusConflict output, err = createMsgView("Tenant with same name already exists", code) return code, h, output, err } } // run the update query incoming.Info.Created = results[0].Info.Created incoming.Info.Updated = time.Now().Format("2006-01-02 15:04:05") filter = bson.M{"id": vars["ID"]} err = mongo.Update(session, cfg.MongoDB.Db, "tenants", filter, incoming) if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Create view for response message output, err = createMsgView("Tenant successfully updated", 200) //Render the results into JSON code = http.StatusOK return code, h, output, err }
// ListOne function implement an http GET request that accepts // a name parameter urlvar and retrieves information only for the // specific tenant func ListOne(r *http.Request, cfg config.Config) (int, http.Header, []byte, error) { //STANDARD DECLARATIONS START code := http.StatusOK h := http.Header{} output := []byte("") err := error(nil) contentType := "text/xml" charset := "utf-8" //STANDARD DECLARATIONS END vars := mux.Vars(r) // Content Negotiation contentType, err = respond.ParseAcceptHeader(r) h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) if err != nil { code = http.StatusNotAcceptable output, _ = respond.MarshalContent(respond.NotAcceptableContentType, contentType, "", " ") return code, h, output, err } // if authentication procedure fails then // return unauthorized http status if authentication.AuthenticateAdmin(r.Header, cfg) == false { output, _ = respond.MarshalContent(respond.UnauthorizedMessage, contentType, "", " ") code = http.StatusUnauthorized //If wrong api key is passed we return UNAUTHORIZED http status return code, h, output, err } // Try to open the mongo session session, err := mongo.OpenSession(cfg.MongoDB) defer session.Close() if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Create structure to hold query results results := []Tenant{} // Create a simple query object to query by id query := bson.M{"id": vars["ID"]} // Query collection tenants for the specific tenant id err = mongo.Find(session, cfg.MongoDB.Db, "tenants", query, "name", &results) if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Check if nothing found if len(results) < 1 { output, _ = respond.MarshalContent(respond.NotFound, contentType, "", " ") code = http.StatusNotFound return code, h, output, err } // After successfully retrieving the db results // call the createView function to render them into idented xml output, err = createListView(results, "Success", code) if err != nil { code = http.StatusInternalServerError return code, h, output, err } h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) return code, h, output, err }
// List function that implements the http GET request that retrieves // all avaiable tenant information func List(r *http.Request, cfg config.Config) (int, http.Header, []byte, error) { //STANDARD DECLARATIONS START code := http.StatusOK h := http.Header{} output := []byte("") err := error(nil) contentType := "text/xml" charset := "utf-8" //STANDARD DECLARATIONS END // Content Negotiation contentType, err = respond.ParseAcceptHeader(r) h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) if err != nil { code = http.StatusNotAcceptable output, _ = respond.MarshalContent(respond.NotAcceptableContentType, contentType, "", " ") return code, h, output, err } // if authentication procedure fails then // return unauthorized http status if authentication.AuthenticateAdmin(r.Header, cfg) == false { output, _ = respond.MarshalContent(respond.UnauthorizedMessage, contentType, "", " ") code = http.StatusUnauthorized //If wrong api key is passed we return UNAUTHORIZED http status return code, h, output, err } // Try to open the mongo session session, err := mongo.OpenSession(cfg.MongoDB) defer session.Close() if err != nil { code = http.StatusInternalServerError return code, h, output, err } // Create structure for storing query results results := []Tenant{} // Query tenant collection for all available documents. // nil query param == match everything err = mongo.Find(session, cfg.MongoDB.Db, "tenants", nil, "name", &results) if err != nil { code = http.StatusInternalServerError return code, h, output, err } // After successfully retrieving the db results // call the createView function to render them into idented xml output, err = createListView(results, "Success", code) if err != nil { code = http.StatusInternalServerError return code, h, output, err } h.Set("Content-Type", fmt.Sprintf("%s; charset=%s", contentType, charset)) return code, h, output, err }