From 828a044a6744b2ba098cb5bea813123ba5d87352 Mon Sep 17 00:00:00 2001 From: Peter Grlica Date: Wed, 1 Sep 2021 14:11:59 +0200 Subject: [PATCH] Added oauth2 outbound auth handler --- automation/automation/oauth2_handler.gen.go | 170 ++++++++++++++++++++ automation/automation/oauth2_handler.go | 88 ++++++++++ automation/automation/oauth2_handler.yaml | 29 ++++ automation/service/service.go | 1 + 4 files changed, 288 insertions(+) create mode 100644 automation/automation/oauth2_handler.gen.go create mode 100644 automation/automation/oauth2_handler.go create mode 100644 automation/automation/oauth2_handler.yaml diff --git a/automation/automation/oauth2_handler.gen.go b/automation/automation/oauth2_handler.gen.go new file mode 100644 index 000000000..3515c127b --- /dev/null +++ b/automation/automation/oauth2_handler.gen.go @@ -0,0 +1,170 @@ +package automation + +// This file is auto-generated. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Definitions file that controls how this file is generated: +// automation/automation/oauth2_handler.yaml + +import ( + "context" + atypes "github.com/cortezaproject/corteza-server/automation/types" + "github.com/cortezaproject/corteza-server/pkg/expr" + "github.com/cortezaproject/corteza-server/pkg/wfexec" +) + +var _ wfexec.ExecResponse + +type ( + oauth2HandlerRegistry interface { + AddFunctions(ff ...*atypes.Function) + Type(ref string) expr.Type + } +) + +func (h oauth2Handler) register() { + h.reg.AddFunctions( + h.Authenticate(), + ) +} + +type ( + oauth2AuthenticateArgs struct { + hasClient bool + Client string + + hasSecret bool + Secret string + + hasScope bool + Scope string + + hasTokenUrl bool + TokenUrl string + } + + oauth2AuthenticateResults struct { + AccessToken string + RefreshToken string + Token interface{} + } +) + +// Authenticate function Authentication: OAUTH2 +// +// expects implementation of authenticate function: +// func (h oauth2Handler) authenticate(ctx context.Context, args *oauth2AuthenticateArgs) (results *oauth2AuthenticateResults, err error) { +// return +// } +func (h oauth2Handler) Authenticate() *atypes.Function { + return &atypes.Function{ + Ref: "oauth2Authenticate", + Kind: "function", + Labels: map[string]string(nil), + Meta: &atypes.FunctionMeta{ + Short: "Authentication: OAUTH2", + }, + + Parameters: []*atypes.Param{ + { + Name: "client", + Types: []string{"String"}, Required: true, + }, + { + Name: "secret", + Types: []string{"String"}, Required: true, + }, + { + Name: "scope", + Types: []string{"String"}, Required: true, + }, + { + Name: "tokenUrl", + Types: []string{"String"}, Required: true, + }, + }, + + Results: []*atypes.Param{ + + { + Name: "accessToken", + Types: []string{"String"}, + }, + + { + Name: "refreshToken", + Types: []string{"String"}, + }, + + { + Name: "token", + Types: []string{"Any"}, + }, + }, + + Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) { + var ( + args = &oauth2AuthenticateArgs{ + hasClient: in.Has("client"), + hasSecret: in.Has("secret"), + hasScope: in.Has("scope"), + hasTokenUrl: in.Has("tokenUrl"), + } + ) + + if err = in.Decode(args); err != nil { + return + } + + var results *oauth2AuthenticateResults + if results, err = h.authenticate(ctx, args); err != nil { + return + } + + out = &expr.Vars{} + + { + // converting results.AccessToken (string) to String + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("String").Cast(results.AccessToken); err != nil { + return + } else if err = expr.Assign(out, "accessToken", tval); err != nil { + return + } + } + + { + // converting results.RefreshToken (string) to String + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("String").Cast(results.RefreshToken); err != nil { + return + } else if err = expr.Assign(out, "refreshToken", tval); err != nil { + return + } + } + + { + // converting results.Token (interface{}) to Any + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("Any").Cast(results.Token); err != nil { + return + } else if err = expr.Assign(out, "token", tval); err != nil { + return + } + } + + return + }, + } +} diff --git a/automation/automation/oauth2_handler.go b/automation/automation/oauth2_handler.go new file mode 100644 index 000000000..09ea56edd --- /dev/null +++ b/automation/automation/oauth2_handler.go @@ -0,0 +1,88 @@ +package automation + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strings" + + "github.com/cortezaproject/corteza-server/pkg/http/auth" + "golang.org/x/oauth2" +) + +type ( + secureStoragerTodo struct{} + + oauth2Handler struct { + reg oauth2HandlerRegistry + } +) + +func Oauth2Handler(reg oauth2HandlerRegistry) *oauth2Handler { + h := &oauth2Handler{ + reg: reg, + } + + h.register() + return h +} + +func (h oauth2Handler) authenticate(ctx context.Context, args *oauth2AuthenticateArgs) (res *oauth2AuthenticateResults, err error) { + var ( + u *url.URL + token *oauth2.Token + ) + + if !args.hasClient { + err = fmt.Errorf("could not init auth, client key missing") + return + } + + if !args.hasSecret { + err = fmt.Errorf("could not init auth, secret key missing") + return + } + + if !args.hasScope { + err = fmt.Errorf("could not init auth, scope missing") + return + } + + if !args.hasTokenUrl { + err = fmt.Errorf("could not init auth, token url missing") + return + } + + if u, err = url.Parse(args.TokenUrl); err != nil { + err = fmt.Errorf("could not init auth, token url invalid: %s", err) + return + } + + params := auth.Oauth2Params{ + Client: args.Client, + Secret: args.Secret, + Scope: strings.Fields(args.Scope), + TokenUrl: u, + } + + servicer, err := auth.NewOauth2(params, http.DefaultClient, secureStoragerTodo{}) + + if err != nil { + err = fmt.Errorf("could not init servicer: %s", err) + return + } + + // call servicer, fetch the token + if token, err = servicer.Do(ctx); err != nil { + return + } + + res = &oauth2AuthenticateResults{ + AccessToken: token.AccessToken, + RefreshToken: token.RefreshToken, + Token: token, + } + + return +} diff --git a/automation/automation/oauth2_handler.yaml b/automation/automation/oauth2_handler.yaml new file mode 100644 index 000000000..a584232f5 --- /dev/null +++ b/automation/automation/oauth2_handler.yaml @@ -0,0 +1,29 @@ +functions: + authenticate: + meta: + short: "Authentication: OAUTH2" + params: + client: + required: true + types: + - { wf: String } + secret: + required: true + types: + - { wf: String } + scope: + required: true + types: + - { wf: String } + tokenUrl: + required: true + types: + - { wf: String } + results: + accessToken: + wf: String + refreshToken: + wf: String + token: + wf: Any + diff --git a/automation/service/service.go b/automation/service/service.go index f60a41569..25b9ce91e 100644 --- a/automation/service/service.go +++ b/automation/service/service.go @@ -121,6 +121,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock automation.LogHandler(Registry()) automation.QueueHandler(Registry()) automation.JsenvHandler(Registry()) + automation.Oauth2Handler(Registry()) automation.LoopHandler(Registry(), DefaultWorkflow.parser) automation.CorredorHandler(Registry(), corredor.Service()) automation.EmailHandler(Registry())