package routers import ( "reflect" "strings" "cloud.o-forge.io/core/oc-catalog/controllers" "cloud.o-forge.io/core/oc-catalog/models" "github.com/beego/beego/v2/core/logs" beego "github.com/beego/beego/v2/server/web" "github.com/beego/beego/v2/server/web/context" "github.com/beego/beego/v2/server/web/swagger" ) func setStatus403(ctx *context.Context) { ctx.Output.SetStatus(403) ctx.Output.Body([]byte("")) } // TODO: Force swagger regeneration during startup to ensure consistency func initAuthMiddleware() { var FilterAuthTags = func(ctx *context.Context) { patternMatch := ctx.Input.GetData("RouterPattern").(string) patternMatchPath := strings.Replace(patternMatch, rootapi.BasePath, "", 1) //Discovery path if patternMatch == "/" { return } // First letter Uppercase and the rest lowercase reqMethod := strings.ToUpper(string(ctx.Request.Method[0])) + strings.ToLower(string(ctx.Request.Method[1:])) val := reflect.ValueOf(rootapi.Paths[patternMatchPath]). Elem().FieldByName(reqMethod). Elem().Interface().(swagger.Operation) // Make sure never omit a security declaration canaryVar := false for _, securityItem := range val.Security { canaryVar = true for securityItemName := range securityItem { switch t := rootapi.SecurityDefinitions[securityItemName]; t.Type { case "basic": user, pass, containBasic := ctx.Request.BasicAuth() if containBasic { if models.Login(user, pass) { //TODO: Decide behaviour with multiple security return } ctx.Output.SetStatus(403) ctx.Output.Body([]byte("")) //We must create some kind of output to force beego abort the request return } ctx.Output.Header("WWW-Authenticate", `Basic realm="Restricted"`) ctx.Output.SetStatus(401) ctx.Output.Body([]byte("")) //We must create some kind of output to force beego abort the request return case "apiKey": var jwtTokenString string switch t.In { case "header": jwtTokenString = ctx.Request.Header.Get(t.Name) case "query": jwtTokenString = ctx.Request.URL.Query().Get(t.Name) default: logs.Warn("BUG: API auth with token of type " + t.In + " not implemented.") setStatus403(ctx) return } if jwtTokenString != "" { // We have a token _, err := controllers.IsValidToken(jwtTokenString) if err != nil { //Bad token ctx.Output.SetStatus(401) ctx.Output.Body([]byte(err.Error())) return } ctx.Input.SetData("jwtAPIToken", jwtTokenString) return //Go to Controller } // No token at all logs.Debug("No access token provided") setStatus403(ctx) return default: ctx.Output.SetStatus(501) ctx.Output.Body([]byte("Authentication with " + t.Type + " not implemented")) return } } } if canaryVar { // If we are here, that means some Security declaration exist and was skipped. // Must avoid giving access, but should inform about it logs.Critical("Probably a BUG related to authentication process") setStatus403(ctx) } } beego.InsertFilter("/*", beego.BeforeExec, FilterAuthTags) }