Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Auth via kratos #1702

Open
wants to merge 11 commits into
base: sc-poc
Choose a base branch
from
7 changes: 2 additions & 5 deletions sc-poc/cmd/spacectl/commands/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down Expand Up @@ -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
}
17 changes: 11 additions & 6 deletions sc-poc/managers/apis/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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...)

Expand Down
66 changes: 54 additions & 12 deletions sc-poc/managers/configman/common/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
}),
},
}

Expand All @@ -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,
}),
},
}

Expand All @@ -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,
})),
},
}

Expand Down Expand Up @@ -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)
Expand Down
19 changes: 10 additions & 9 deletions sc-poc/modules/auth/handler_auth_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -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)
93 changes: 93 additions & 0 deletions sc-poc/modules/auth/handler_kratos_auth_verify.go
Original file line number Diff line number Diff line change
@@ -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)
3 changes: 2 additions & 1 deletion sc-poc/modules/auth/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{})
Expand Down
31 changes: 20 additions & 11 deletions sc-poc/utils/caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down