initial commit
This commit is contained in:
118
routers/auth.go
Normal file
118
routers/auth.go
Normal file
@@ -0,0 +1,118 @@
|
||||
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)
|
||||
}
|
||||
129
routers/router.go
Normal file
129
routers/router.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// @APIVersion 1.0.0
|
||||
// @Title oc-catalog API
|
||||
// @Description Backend of the oc-search project
|
||||
// @Contact opencloud@irt-saintexupery.com
|
||||
//// @SecurityDefinition jwtAPIToken apiKey Authorization header "API authentication with JWT tokens"
|
||||
|
||||
package routers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"cloud.o-forge.io/core/oc-catalog/controllers"
|
||||
"cloud.o-forge.io/core/oc-catalog/services"
|
||||
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
|
||||
bee "github.com/beego/bee/v2/generate/swaggergen"
|
||||
|
||||
"github.com/beego/beego/v2/adapter/swagger"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"github.com/beego/beego/v2/server/web/context"
|
||||
)
|
||||
|
||||
var rootapi swagger.Swagger
|
||||
|
||||
func Init() {
|
||||
// Remove old swagger comments
|
||||
err := os.Remove("routers/commentsRouter_controllers.go")
|
||||
if err != nil {
|
||||
logs.Warning("Couldn't remove comments file: " + err.Error())
|
||||
}
|
||||
|
||||
ns := beego.NewNamespace("/v1",
|
||||
beego.NSNamespace("/user",
|
||||
beego.NSInclude(
|
||||
&controllers.UserController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/data",
|
||||
beego.NSInclude(
|
||||
&controllers.DataController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/computing",
|
||||
beego.NSInclude(
|
||||
&controllers.ComputingController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/datacenter",
|
||||
beego.NSInclude(
|
||||
&controllers.DatacenterController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/storage",
|
||||
beego.NSInclude(
|
||||
&controllers.StorageController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/search",
|
||||
beego.NSInclude(
|
||||
&controllers.SearchController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/workspace",
|
||||
beego.NSInclude(
|
||||
&controllers.WorkspaceController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/workflow",
|
||||
beego.NSInclude(
|
||||
&controllers.WorkflowController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/schedule",
|
||||
beego.NSInclude(
|
||||
&controllers.ScheduleController{},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
beego.AddNamespace(ns)
|
||||
|
||||
beego.Get("/", func(ctx *context.Context) {
|
||||
ctx.Output.Body([]byte(services.DC_NAME))
|
||||
})
|
||||
|
||||
// Force regenerate swagger before consuming the data
|
||||
bee.GenerateDocs(".")
|
||||
|
||||
// Open our jsonFile
|
||||
swaggerSchemaPath := "swagger/swagger.json"
|
||||
swaggerFile, err := os.Open(swaggerSchemaPath)
|
||||
// if we os.Open returns an error then handle it
|
||||
if err != nil {
|
||||
logs.Critical("Error opening %v: %v", swaggerSchemaPath, err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// defer the closing of our jsonFile so that we can parse it later on
|
||||
defer swaggerFile.Close()
|
||||
|
||||
byteValue, err := ioutil.ReadAll(swaggerFile)
|
||||
if err != nil {
|
||||
logs.Critical("Error reading %v: %v", swaggerSchemaPath, err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
json.Unmarshal(byteValue, &rootapi)
|
||||
|
||||
// To simplify match of Paths, we must adapt swagger path representation to beego router
|
||||
// For example: /path/{myID} will be /path/:myID
|
||||
for k, v := range rootapi.Paths {
|
||||
if strings.ContainsAny(k, "{}") {
|
||||
newKey := strings.Replace(k, "{", ":", -1)
|
||||
newKey = strings.Replace(newKey, "}", "", -1)
|
||||
|
||||
rootapi.Paths[newKey] = v
|
||||
delete(rootapi.Paths, k)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Init some extra stuff
|
||||
initAuthMiddleware()
|
||||
initUglyFixes()
|
||||
}
|
||||
42
routers/uglyfix.go
Normal file
42
routers/uglyfix.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/v2/server/web/filter/cors"
|
||||
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"github.com/beego/beego/v2/server/web/context"
|
||||
)
|
||||
|
||||
//TODO: This file should never exist. Solve the bugs and avoid using this
|
||||
// [ id id2 id3 ]
|
||||
// id,id2,id3
|
||||
// Some Beego bugs? that we want to fix
|
||||
func initUglyFixes() {
|
||||
var FixParameterArrays = func(ctx *context.Context) {
|
||||
|
||||
for k, v := range ctx.Input.Params() {
|
||||
if strings.HasPrefix(v, "[") && strings.HasSuffix(v, "]") {
|
||||
logs.Warn("BUGFIX: Fixing array interpretation. Should not be done like this")
|
||||
newParam := strings.NewReplacer("[", "", " ", ",", "]", "").Replace(v)
|
||||
ctx.Input.SetParam(k, newParam)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
beego.InsertFilter("/*/multi/:IDs", beego.BeforeExec, FixParameterArrays, beego.WithReturnOnOutput(true))
|
||||
|
||||
// FIXME: We should define CORS properly (maybe more permissive in dev mode?)
|
||||
beego.InsertFilter("*", beego.BeforeStatic, cors.Allow(&cors.Options{
|
||||
AllowAllOrigins: true,
|
||||
AllowMethods: []string{
|
||||
"HEAD",
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
},
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user