diff --git a/sc-poc/cmd/spacectl/commands/run/run.go b/sc-poc/cmd/spacectl/commands/run/run.go index ab6886bec..d3b31978e 100644 --- a/sc-poc/cmd/spacectl/commands/run/run.go +++ b/sc-poc/cmd/spacectl/commands/run/run.go @@ -32,6 +32,8 @@ func NewCommand() *cobra.Command { _ = viper.BindPFlag("admin.username", cmd.Flags().Lookup("admin.username")) _ = viper.BindPFlag("admin.password", cmd.Flags().Lookup("admin.password")) + _ = viper.BindPFlag("kratos.enable", cmd.Flags().Lookup("kratos-enable")) + _ = viper.BindPFlag("kratos.endpoint", cmd.Flags().Lookup("kratos-endpoint")) }, RunE: func(cmd *cobra.Command, args []string) error { if !cmd.Flags().Changed("admin.secret") { @@ -93,10 +95,5 @@ func NewCommand() *cobra.Command { cmd.Flags().StringP("config-path", "", "./sc-config", "Directory to use to manage SpaceCloud configuration") cmd.Flags().StringP("debounce-interval", "", "500ms", "Debounce interval in milliseconds") - // Auth - cmd.Flags().StringP("admin.secret", "", "", "Set admin secret") - cmd.Flags().StringP("admin.username", "", "", "Set admin username") - cmd.Flags().StringP("admin.password", "", "", "Set admin password") - return cmd } diff --git a/sc-poc/managers/apis/helpers.go b/sc-poc/managers/apis/helpers.go index 204551ce7..07cacf3c9 100644 --- a/sc-poc/managers/apis/helpers.go +++ b/sc-poc/managers/apis/helpers.go @@ -115,15 +115,20 @@ func prepareRoute(api *API, path string, methods []string, headers map[string][] params["name"] = p.Name // Append the plugin to the handler's array - apiRoute.HandlersRaw = append(apiRoute.HandlersRaw, utils.GetCaddyHandler(fmt.Sprintf("plugin_%s", p.Driver), params)...) + apiRoute.HandlersRaw = append(apiRoute.HandlersRaw, utils.GetCaddyHandlers(utils.Handler{ + HandlerName: fmt.Sprintf("plugin_%s", p.Driver), + Params: params, + })...) } // Finally comes the main api route - apiHandler := utils.GetCaddyHandler("api", map[string]interface{}{ - "path": path, - "indexes": indexes, - "app": api.app, - "name": api.Name, + apiHandler := utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "api", + Params: map[string]interface{}{ + "path": path, + "indexes": indexes, + "app": api.app, + "name": api.Name}, }) apiRoute.HandlersRaw = append(apiRoute.HandlersRaw, apiHandler...) diff --git a/sc-poc/managers/configman/common/http.go b/sc-poc/managers/configman/common/http.go index b0d06c3f4..dd65ec515 100644 --- a/sc-poc/managers/configman/common/http.go +++ b/sc-poc/managers/configman/common/http.go @@ -44,8 +44,11 @@ func getRootRoutes(config ConfigType) caddyhttp.RouteList { return caddyhttp.RouteList{ // Routes for CORS caddyhttp.Route{ - Group: "cors", - HandlersRaw: utils.GetCaddyHandler("cors", nil), + Group: "cors", + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "cors", + Params: nil, + }), }, // TODO: Fix this @@ -74,12 +77,18 @@ func getAdminRoutes() caddyhttp.Route { caddyhttp.Route{ Group: "admin_login", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{"/sc/v1/login"}, []string{http.MethodPost}, nil), - HandlersRaw: utils.GetCaddyHandler("admin_login", nil), + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "admin_login", + Params: nil, + }), }, caddyhttp.Route{ Group: "admin_refresh", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{"/sc/v1/refresh-token"}, []string{http.MethodGet}, nil), - HandlersRaw: utils.GetCaddyHandler("admin_refresh", nil), + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "admin_refresh", + Params: nil, + }), }, } @@ -97,15 +106,33 @@ func getAdminRoutes() caddyhttp.Route { } func getAPIRoutes() caddyhttp.Route { + routes := []utils.Handler{ + { + HandlerName: "jwt_auth_verify", + Params: nil, + }, + } + + if viper.GetBool("kratos.enable") { + route := utils.Handler{ + HandlerName: "kratos_auth_verify", + Params: nil, + } + routes = append(routes, route) + } + // Make route list for the sub router routeList := caddyhttp.RouteList{ caddyhttp.Route{ Group: "api_auth", - HandlersRaw: utils.GetCaddyHandler("auth_verify", nil), + HandlersRaw: utils.GetCaddyHandlers(routes...), }, caddyhttp.Route{ - Group: "api_route", - HandlersRaw: utils.GetCaddyHandler("root_api", nil), + Group: "api_route", + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "root_api", + Params: nil, + }), }, } @@ -128,12 +155,18 @@ func getSourceRoutes() caddyhttp.Route { caddyhttp.Route{ Group: "source_lists", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{"/sc/v1/sources"}, []string{http.MethodGet}, nil), - HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandler("list_sources", nil)), + HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "list_sources", + Params: nil, + })), }, caddyhttp.Route{ Group: "source_plugins", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{"/sc/v1/plugins"}, []string{http.MethodGet}, nil), - HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandler("list_plugins", nil)), + HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "list_plugins", + Params: nil, + })), }, } @@ -163,21 +196,30 @@ func getConfigRoutes() caddyhttp.Route { getRoute := caddyhttp.Route{ Group: "config_get", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{path}, []string{http.MethodGet}, nil), - HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandler("config_get", data)), + HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "config_get", + Params: data, + })), } // Route for Apply operation applyRoute := caddyhttp.Route{ Group: "config_apply", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{path}, []string{http.MethodPut}, nil), - HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandler("config_apply", data)), + HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "config_apply", + Params: data, + })), } // Route for Delete operation deleteRoute := caddyhttp.Route{ Group: "config_delete", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{path}, []string{http.MethodDelete}, nil), - HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandler("config_delete", data)), + HandlersRaw: addAuthenticateSCUserPluginMiddleware(utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "config_delete", + Params: data, + })), } configRoutes = append(configRoutes, getRoute, applyRoute, deleteRoute) diff --git a/sc-poc/modules/auth/handler_auth_verify.go b/sc-poc/modules/auth/handler_auth_verify.go index c74002c4b..c45f228d2 100644 --- a/sc-poc/modules/auth/handler_auth_verify.go +++ b/sc-poc/modules/auth/handler_auth_verify.go @@ -13,23 +13,24 @@ import ( "github.com/spacecloud-io/space-cloud/utils" ) -// AuthVerifyHandler is responsible to authenticate the incoming request +// JWTAuthVerifyHandler is responsible to authenticate the incoming request // on a best effort basis -type AuthVerifyHandler struct { +type JWTAuthVerifyHandler struct { logger *zap.Logger + authApp *App providerMan *provider.App } // CaddyModule returns the Caddy module information. -func (AuthVerifyHandler) CaddyModule() caddy.ModuleInfo { +func (JWTAuthVerifyHandler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ - ID: "http.handlers.sc_auth_verify_handler", - New: func() caddy.Module { return new(AuthVerifyHandler) }, + ID: "http.handlers.sc_jwt_auth_verify_handler", + New: func() caddy.Module { return new(JWTAuthVerifyHandler) }, } } // Provision sets up the auth verify module. -func (h *AuthVerifyHandler) Provision(ctx caddy.Context) error { +func (h *JWTAuthVerifyHandler) Provision(ctx caddy.Context) error { h.logger = ctx.Logger(h) // Get the provider manager @@ -42,7 +43,7 @@ func (h *AuthVerifyHandler) Provision(ctx caddy.Context) error { } // ServeHTTP handles the http request -func (h *AuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { +func (h *JWTAuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { // Get the auth app ws := source.GetWorkspaceNameFromHeaders(r) app, err := h.providerMan.GetProvider(ws, "auth") @@ -73,5 +74,5 @@ func (h *AuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, ne } // Interface guard -var _ caddy.Provisioner = (*AuthVerifyHandler)(nil) -var _ caddyhttp.MiddlewareHandler = (*AuthVerifyHandler)(nil) +var _ caddy.Provisioner = (*JWTAuthVerifyHandler)(nil) +var _ caddyhttp.MiddlewareHandler = (*JWTAuthVerifyHandler)(nil) diff --git a/sc-poc/modules/auth/handler_kratos_auth_verify.go b/sc-poc/modules/auth/handler_kratos_auth_verify.go new file mode 100644 index 000000000..5cc850125 --- /dev/null +++ b/sc-poc/modules/auth/handler_kratos_auth_verify.go @@ -0,0 +1,93 @@ +package auth + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "github.com/spf13/viper" + "go.uber.org/zap" + + "github.com/spacecloud-io/space-cloud/modules/auth/types" + "github.com/spacecloud-io/space-cloud/utils" +) + +// KratosAuthVerifyHandler is responsible to authenticate the incoming request +// using Kratos +type KratosAuthVerifyHandler struct { + logger *zap.Logger + //authApp *App +} + +// CaddyModule returns the Caddy module information. +func (KratosAuthVerifyHandler) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "http.handlers.sc_kratos_auth_verify_handler", + New: func() caddy.Module { return new(KratosAuthVerifyHandler) }, + } +} + +// Provision sets up the auth verify module. +func (h *KratosAuthVerifyHandler) Provision(ctx caddy.Context) error { + h.logger = ctx.Logger(h) + + return nil +} + +// ServeHTTP handles the http request +func (h *KratosAuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { + // Prepare authentication object + result := types.AuthResult{} + // Check if token is present in the header + + var foo map[string]interface{} + client := &http.Client{} + + kratosEndpoint := viper.GetString("kratos.endpoint") + // Create a new GET request to the /sessions/whoami endpoint + req, err := http.NewRequest("GET", kratosEndpoint+"/sessions/whoami", nil) + if err != nil { + fmt.Println("Error creating GET request:", err) + return err + } + if cookie := r.Header.Get("Cookie"); len(cookie) != 0 { + req.Header.Set("Cookie", cookie) + } + if cookie := r.Header.Get("Cookie"); len(cookie) != 0 { + req.Header.Set("Cookie", cookie) + } + if token, p := getTokenFromHeader(r); p { + req.Header.Set("Authorization", "Bearer "+token) + } + //token := "ory_st_94jGcnytycUNCtKIVchOfiyWrs8wlJYY" + //req.Header.Set("Authorization", "Bearer "+token) + // Send the request + resp, err := client.Do(req) + if err != nil { + fmt.Println("Error sending GET request:", err) + return err + } + defer resp.Body.Close() + + // Read the response body + err = json.NewDecoder(resp.Body).Decode(&foo) + //body, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + return err + } + // Print the response body + //fmt.Println(string(body)) + j, _ := json.MarshalIndent(foo, "", " ") + fmt.Println(string(j)) + + // Add the result in the context object + r = utils.StoreAuthenticationResult(r, &result) + return next.ServeHTTP(w, r) +} + +// Interface guard +var _ caddy.Provisioner = (*KratosAuthVerifyHandler)(nil) +var _ caddyhttp.MiddlewareHandler = (*KratosAuthVerifyHandler)(nil) diff --git a/sc-poc/modules/auth/init.go b/sc-poc/modules/auth/init.go index a0f1fa066..a84b5a41c 100644 --- a/sc-poc/modules/auth/init.go +++ b/sc-poc/modules/auth/init.go @@ -8,7 +8,8 @@ import ( func init() { provider.Register("auth", 99) caddy.RegisterModule(App{}) - caddy.RegisterModule(AuthVerifyHandler{}) + caddy.RegisterModule(JWTAuthVerifyHandler{}) + caddy.RegisterModule(KratosAuthVerifyHandler{}) caddy.RegisterModule(OPAPlugin{}) caddy.RegisterModule(DenyUser{}) caddy.RegisterModule(AuthenticateUser{}) diff --git a/sc-poc/utils/caddy.go b/sc-poc/utils/caddy.go index 10cdd33e8..071748de7 100644 --- a/sc-poc/utils/caddy.go +++ b/sc-poc/utils/caddy.go @@ -60,20 +60,29 @@ func GetByteStringArray(val ...string) []byte { return data } -// GetCaddyHandler returns a marshaled caddy handler config -func GetCaddyHandler(handlerName string, params map[string]interface{}) []json.RawMessage { - handler := make(map[string]interface{}) +type Handler struct { + HandlerName string + Params map[string]interface{} +} - // Add the handler name / identifier - handler["handler"] = fmt.Sprintf("sc_%s_handler", handlerName) +// GetCaddyHandlers returns marshaled caddy handlers config +func GetCaddyHandlers(routes ...Handler) []json.RawMessage { + handlers := []json.RawMessage{} + for _, route := range routes { + handler := make(map[string]interface{}) - // Add the params the handler needs - for k, v := range params { - handler[k] = v - } + // Add the handler name / identifier + handler["handler"] = fmt.Sprintf("sc_%s_handler", route.HandlerName) - data, _ := json.Marshal(handler) - return []json.RawMessage{data} + // Add the params the handler needs + for k, v := range route.Params { + handler[k] = v + } + data, _ := json.Marshal(handler) + handlers = append(handlers, data) + + } + return handlers } // GetCaddySubrouter returns a marshaled caddy subrouter