package routebuildermdl import ( "io/ioutil" "mime/multipart" "net/http" "strings" "time" version "github.com/hashicorp/go-version" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/statemdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/authmdl/roleenforcemdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/authmdl/jwtmdl" "github.com/tidwall/gjson" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/servicebuildermdl" "github.com/gin-gonic/gin" ) // Init routing init func Init(o, r, c *gin.RouterGroup, JWTKey string) { o.POST("/mql", OpenHandler) o.POST("/mql/login", loginHandler) o.POST("/mql/state", statemdl.StateHandler) r.POST("/mql", RestrictedHandler) c.POST("/mql", RoleBasedHandler) jwtmdl.GlobalJWTKey = JWTKey } func setResponseHeader(serviceName string) responseData { rd := responseData{} val, ok := GetResponseHeader(serviceName) if ok { rd.ResponseHeader = val } return rd } func isMultipartRequest(header string) bool { return strings.HasPrefix(header, "multipart/form-data") } func executeService(name string, data []byte, isForm bool, formData *multipart.Form, isRestricted, isRoleBased bool, principalObj servicebuildermdl.Principal) (interface{}, *servicebuildermdl.AbstractBusinessLogicHolder, error) { var service interface{} var ab *servicebuildermdl.AbstractBusinessLogicHolder var found bool if isRestricted { if isRoleBased { service, found = roleBasedServices.Get(name) } else { service, found = restrictedServices.Get(name) } } else { service, found = openServices.Get(name) } if !found { loggermdl.LogError("Service Not Found: " + name) return nil, ab, errormdl.Wrap("Service Not Found: " + name) } var result interface{} var serviceError error start := time.Now() tmpServiceCache := service.(ServiceCache) serviceCache := tmpServiceCache if isForm { result, ab, serviceError = serviceCache.FormService(formData, principalObj) } else { // serviceCache := service.(ServiceCache) if serviceCache.IsFormService { result, serviceError = nil, errormdl.Wrap("Form_Header_Missing") loggermdl.LogError("FORM_HEADER_MISSING") } else { if serviceCache.IsMasterService { result, serviceError = serviceCache.MasterService.Run(data, &principalObj) } else { rs := gjson.ParseBytes(data) result, ab, serviceError = serviceCache.Service(&rs, principalObj) } } } servingTime := time.Since(start) // Record State for every service go statemdl.UpdateServiceState(name, servingTime, serviceError, isRestricted, isRoleBased) return result, ab, serviceError } func commonHandler(c *gin.Context, isRestricted, isRoleBased bool, principalObj servicebuildermdl.Principal) { serviceHeader := c.Request.Header.Get("Service-Header") services := strings.Split(serviceHeader, ",") header := c.Request.Header.Get("Content-Type") versionError := appVersioning(c) if versionError != nil { c.JSON(http.StatusExpectationFailed, versionError.Error()) return } responseMap := make(map[string]responseData) if isMultipartRequest(header) { responseDataObj := responseData{} form, multiPartError := c.MultipartForm() if errormdl.CheckErr(multiPartError) != nil { responseDataObj.Error = errormdl.CheckErr(multiPartError).Error() loggermdl.LogError(multiPartError) } for i := 0; i < len(services); i++ { service := services[i] result, ab, err := executeService(service, nil, true, form, isRestricted, isRoleBased, principalObj) if errormdl.CheckErr1(err) != nil { responseDataObj.Error = errormdl.CheckErr1(err).Error() loggermdl.LogError(err) responseDataObj = formatResponse(ab, responseDataObj) } responseDataObj.Result = result responseDataObj = formatResponse(ab, responseDataObj) responseMap[service] = responseDataObj } c.JSON(http.StatusOK, responseMap) return } responseDataObj := responseData{} var reqBody []byte if c.Request.Body != nil { var readError error reqBody, readError = ioutil.ReadAll(c.Request.Body) if errormdl.CheckErr2(readError) != nil { responseDataObj.Error = errormdl.CheckErr2(readError).Error() responseDataObj.ErrorCode = 417 loggermdl.LogError(readError) c.JSON(http.StatusExpectationFailed, responseDataObj) return } } requestBody := gjson.ParseBytes(reqBody) for i := 0; i < len(services); i++ { responseDataObj := responseData{} service := services[i] result, ab, err := executeService(service, []byte(requestBody.Get(service).String()), false, nil, isRestricted, isRoleBased, principalObj) if errormdl.CheckErr3(err) != nil { responseDataObj.Error = errormdl.CheckErr3(err).Error() loggermdl.LogError(err) responseDataObj.ErrorCode = 417 responseDataObj = formatResponse(ab, responseDataObj) } responseDataObj.Result = result responseDataObj = formatResponse(ab, responseDataObj) responseMap[service] = responseDataObj } c.JSON(http.StatusOK, responseMap) return } // OpenHandler for /o func OpenHandler(c *gin.Context) { commonHandler(c, false, false, servicebuildermdl.Principal{}) } // RestrictedHandler for /r func RestrictedHandler(c *gin.Context) { pricipalObj, extractError := extractPricipalObject(c) if extractError != nil { loggermdl.LogError(extractError) c.JSON(http.StatusExpectationFailed, extractError.Error()) return } commonHandler(c, true, false, pricipalObj) } // RoleBasedHandler for /r/c func RoleBasedHandler(c *gin.Context) { pricipalObj, extractError := extractPricipalObject(c) if extractError != nil { loggermdl.LogError(extractError) c.JSON(http.StatusExpectationFailed, extractError.Error()) return } commonHandler(c, true, true, pricipalObj) } func extractPricipalObject(c *gin.Context) (servicebuildermdl.Principal, error) { principal := servicebuildermdl.Principal{} if jwtmdl.GlobalJWTKey == "" { return principal, errormdl.Wrap("No Global JWT key found") } claim, decodeError := jwtmdl.DecodeToken(c.Request) if errormdl.CheckErr(decodeError) != nil { loggermdl.LogError(decodeError) return principal, errormdl.CheckErr(decodeError) } // ba, marshalError := ffjson.Marshal(claim) // if errormdl.CheckErr(marshalError) != nil { // return principal, errormdl.CheckErr(marshalError) // } // unmarshalError := ffjson.Unmarshal(ba, &principal) // if errormdl.CheckErr(unmarshalError) != nil { // return principal, errormdl.CheckErr(unmarshalError) // } // value, ok := gjson.ParseBytes(ba).Value().(servicebuildermdl.Principal) // if !ok { // return principal, errormdl.Wrap("Object is not of type principal") // } groups, grperr := roleenforcemdl.GetGroupNames(claim, "groups") if errormdl.CheckErr(grperr) != nil { loggermdl.LogError(grperr) return principal, errormdl.CheckErr(grperr) } userID, ok := claim["userId"].(string) if !ok || len(userID) < 2 { loggermdl.LogError("Unable to parse UserID from JWT Token") return principal, errormdl.Wrap("Unable to parse UserID from JWT Token") } principal.Groups = groups principal.UserID = userID return principal, nil } // loginHandler - for specially login func loginHandler(c *gin.Context) { if loginService == nil { loggermdl.LogError("NO Login Service found") c.JSON(http.StatusExpectationFailed, "NO Login Service found") return } var reqBody []byte if c.Request.Body != nil { var readError error reqBody, readError = ioutil.ReadAll(c.Request.Body) if errormdl.CheckErr2(readError) != nil { loggermdl.LogError(readError) c.JSON(http.StatusExpectationFailed, readError.Error()) return } } rs := gjson.ParseBytes(reqBody) data, token, loginError := loginService(&rs, servicebuildermdl.Principal{}) if errormdl.CheckErr(loginError) != nil { loggermdl.LogError(loginError) c.JSON(http.StatusExpectationFailed, errormdl.CheckErr(loginError).Error()) return } c.Header("Authorization", token) c.JSON(http.StatusOK, data) } func appVersioning(c *gin.Context) error { if isAppVersionEnabled { appVersion := c.Request.Header.Get("app-version") if appVersion == "" { return errormdl.Wrap("No App version Found in request header") } ver, err := version.NewVersion(appVersion) if errormdl.CheckErr(err) != nil { return errormdl.CheckErr(err) } if isStrictMode { if !ver.Equal(applicationVersion) { return errormdl.Wrap("Application version mismatched") } } else { if ver.GreaterThan(applicationVersion) { return errormdl.Wrap("Server Version is outdated") } if ver.LessThan(minimumSupportedVersion) { return errormdl.Wrap("Client Version is outdated") } } } return nil }