diff --git a/cmd/accounts/cmd/cfg.go b/cmd/accounts/cmd/cfg.go index c8a06618..95870289 100644 --- a/cmd/accounts/cmd/cfg.go +++ b/cmd/accounts/cmd/cfg.go @@ -4,25 +4,22 @@ import ( "os" ) -var cfg = New() - // DB ... type DB struct { - Username string - Password string - Port int - Database string + Username string `envconfig:"TYPHOON_DB_USERNAME" default:"example"` + Password string `envconfig:"TYPHOON_DB_PASSWORD" default:"example"` + Port int `envconfig:"TYPHOON_DB_PORT" default:"5432"` + Database string `envconfig:"TYPHOON_DB_DATABASE" default:"example"` } // Nats ... type Nats struct { - Credentials string - Url string + Credentials string `envconfig:"TYPHOON_NATS_CREDENTIALS" default:"sys.creds"` + Url string `envconfig:"TYPHOON_NATS_URL" default:"nats://localhost:4222"` } // Flags contains the command line flags. type Flags struct { - Addr string DB *DB Nats *Nats } diff --git a/cmd/accounts/cmd/root.go b/cmd/accounts/cmd/root.go index 6ef8af09..3d6971ef 100644 --- a/cmd/accounts/cmd/root.go +++ b/cmd/accounts/cmd/root.go @@ -2,29 +2,42 @@ package cmd import ( "context" - "log" "strings" + "github.com/zeiss/typhoon/internal/accounts/adapters" + "github.com/zeiss/typhoon/internal/accounts/controllers" + "github.com/zeiss/typhoon/internal/accounts/models" + "github.com/katallaxie/pkg/server" + "github.com/kelseyhightower/envconfig" "github.com/nats-io/nats.go" "github.com/spf13/cobra" ) +var cfg = New() + func init() { - Root.PersistentFlags().StringVar(&cfg.Flags.Addr, "addr", ":8080", "addr") Root.PersistentFlags().StringVar(&cfg.Flags.DB.Database, "db-database", cfg.Flags.DB.Database, "Database name") Root.PersistentFlags().StringVar(&cfg.Flags.DB.Username, "db-username", cfg.Flags.DB.Username, "Database user") Root.PersistentFlags().StringVar(&cfg.Flags.DB.Password, "db-password", cfg.Flags.DB.Password, "Database password") Root.PersistentFlags().IntVar(&cfg.Flags.DB.Port, "db-port", cfg.Flags.DB.Port, "Database port") - Root.PersistentFlags().StringVar(&cfg.Flags.Nats.Credentials, "credentials", cfg.Flags.Nats.Credentials, "credentials file") - Root.PersistentFlags().StringVar(&cfg.Flags.Nats.Url, "url", cfg.Flags.Nats.Url, "url") + Root.PersistentFlags().StringVar(&cfg.Flags.Nats.Credentials, "nats-credentials", cfg.Flags.Nats.Credentials, "credentials file") + Root.PersistentFlags().StringVar(&cfg.Flags.Nats.Url, "nats-url", cfg.Flags.Nats.Url, "url") Root.SilenceUsage = true } var Root = &cobra.Command{ + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + err := envconfig.Process("", cfg.Flags) + if err != nil { + return err + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { - srv := NewWebSrv(cfg) + srv := NewAccountSrv(cfg) s, _ := server.WithContext(cmd.Context()) s.Listen(srv, false) @@ -33,36 +46,67 @@ var Root = &cobra.Command{ }, } -var _ server.Listener = (*AccountServ)(nil) +var _ server.Listener = (*AccountSrv)(nil) -// AccountServ is the server that implements the Noop interface. -type AccountServ struct { +// AccountSrv is the server that implements the Noop interface. +type AccountSrv struct { cfg *Config } -// NewWebSrv returns a new instance of AccountServ. -func NewWebSrv(cfg *Config) *AccountServ { - return &AccountServ{cfg} +// NewAccountSrv returns a new instance of AccountServ. +func NewAccountSrv(cfg *Config) *AccountSrv { + return &AccountSrv{cfg} } // Start starts the server. -func (s *AccountServ) Start(ctx context.Context, ready server.ReadyFunc, run server.RunFunc) func() error { +func (s *AccountSrv) Start(ctx context.Context, ready server.ReadyFunc, run server.RunFunc) func() error { return func() error { + db := adapters.NewDB(nil) + ac := controllers.NewAccountsController(db) + lh := adapters.NewAccountLookupRequestHandler(ac) + nc, err := nats.Connect(cfg.Flags.Nats.Url, nats.UserCredentials(cfg.Flags.Nats.Credentials)) if err != nil { return err } - sub, err := nc.Subscribe("$SYS.REQ.ACCOUNT.*.CLAIMS.LOOKUP", func(msg *nats.Msg) { - accountId := strings.TrimSuffix(strings.TrimPrefix(msg.Subject, "$SYS.REQ.ACCOUNT."), ".CLAIMS.LOOKUP") - log.Println("account lookup", "accountId", accountId) - }) + sub, err := nc.SubscribeSync("$SYS.REQ.ACCOUNT.*.CLAIMS.LOOKUP") if err != nil { return err } - <-ctx.Done() + for { + select { + case <-ctx.Done(): + return sub.Unsubscribe() + default: + } + + msg, err := sub.NextMsgWithContext(ctx) + if err != nil { + return err + } - return sub.Unsubscribe() + err = msg.InProgress() + if err != nil { + return err + } + + accountId := strings.TrimSuffix(strings.TrimPrefix(msg.Subject, "$SYS.REQ.ACCOUNT."), ".CLAIMS.LOOKUP") + accountJWTToken, err := lh.HandleLookupRequest(ctx, models.AccountPublicKey(accountId)) + if err != nil { + return err + } + + err = msg.Respond([]byte(accountJWTToken)) + if err != nil { + return err + } + + err = msg.Ack(nats.Context(ctx)) + if err != nil { + return err + } + } } } diff --git a/internal/accounts/adapters/db.go b/internal/accounts/adapters/db.go new file mode 100644 index 00000000..0c93b7a1 --- /dev/null +++ b/internal/accounts/adapters/db.go @@ -0,0 +1,27 @@ +package adapters + +import ( + "context" + + "github.com/zeiss/typhoon/internal/accounts/models" + "github.com/zeiss/typhoon/internal/accounts/ports" + + "gorm.io/gorm" +) + +var _ ports.Accounts = (*DB)(nil) + +// DB ... +type DB struct { + conn *gorm.DB +} + +// NewDB ... +func NewDB(conn *gorm.DB) *DB { + return &DB{conn} +} + +// GetToken ... +func (db *DB) GetToken(ctx context.Context, account models.AccountPublicKey) (models.AccountToken, error) { + return models.AccountToken(""), nil +} diff --git a/internal/accounts/adapters/lookup.go b/internal/accounts/adapters/lookup.go new file mode 100644 index 00000000..da4dcb74 --- /dev/null +++ b/internal/accounts/adapters/lookup.go @@ -0,0 +1,23 @@ +package adapters + +import ( + "context" + + "github.com/zeiss/typhoon/internal/accounts/controllers" + "github.com/zeiss/typhoon/internal/accounts/models" +) + +// AccountLookupRequestHandler ... +type AccountLookupRequestHandler struct { + ctrl controllers.AccountsController +} + +// NewAccountLookupRequestHandler ... +func NewAccountLookupRequestHandler(ctrl controllers.AccountsController) *AccountLookupRequestHandler { + return &AccountLookupRequestHandler{ctrl: ctrl} +} + +// HandleLookupRequest ... +func (h *AccountLookupRequestHandler) HandleLookupRequest(ctx context.Context, accountPublicKey models.AccountPublicKey) (models.AccountToken, error) { + return h.ctrl.GetToken(ctx, accountPublicKey) +} diff --git a/internal/accounts/controllers/accounts.go b/internal/accounts/controllers/accounts.go new file mode 100644 index 00000000..475f5412 --- /dev/null +++ b/internal/accounts/controllers/accounts.go @@ -0,0 +1,28 @@ +package controllers + +import ( + "context" + + "github.com/zeiss/typhoon/internal/accounts/models" + "github.com/zeiss/typhoon/internal/accounts/ports" +) + +// AccountsController ... +type AccountsController interface { + GetToken(ctx context.Context, accountPublicKey models.AccountPublicKey) (models.AccountToken, error) +} + +// AccountsController ... +type accountsController struct { + db ports.Accounts +} + +// NewAccountsController ... +func NewAccountsController(db ports.Accounts) *accountsController { + return &accountsController{db: db} +} + +// GetToken ... +func (c *accountsController) GetToken(ctx context.Context, pubkey models.AccountPublicKey) (models.AccountToken, error) { + return c.db.GetToken(ctx, pubkey) +} diff --git a/internal/accounts/models/account.go b/internal/accounts/models/account.go new file mode 100644 index 00000000..374a7e07 --- /dev/null +++ b/internal/accounts/models/account.go @@ -0,0 +1,11 @@ +package models + +import "strings" + +// AccountPublicKey ... +type AccountPublicKey string + +// String ... +func (a AccountPublicKey) String() string { + return strings.TrimSpace(string(a)) +} diff --git a/internal/accounts/models/token.go b/internal/accounts/models/token.go new file mode 100644 index 00000000..837efca6 --- /dev/null +++ b/internal/accounts/models/token.go @@ -0,0 +1,11 @@ +package models + +import "strings" + +// AccountToken ... +type AccountToken string + +// String ... +func (a AccountToken) String() string { + return strings.TrimSpace(string(a)) +} diff --git a/internal/accounts/ports/accounts.go b/internal/accounts/ports/accounts.go new file mode 100644 index 00000000..a2d5cafe --- /dev/null +++ b/internal/accounts/ports/accounts.go @@ -0,0 +1,13 @@ +package ports + +import ( + "context" + + "github.com/zeiss/typhoon/internal/accounts/models" +) + +// Accounts ... +type Accounts interface { + // GetToken returns the token for the given account. + GetToken(ctx context.Context, account models.AccountPublicKey) (models.AccountToken, error) +} diff --git a/internal/accounts/ports/repos.go b/internal/accounts/ports/repos.go new file mode 100644 index 00000000..00eb1974 --- /dev/null +++ b/internal/accounts/ports/repos.go @@ -0,0 +1,4 @@ +package ports + +// Repositories ... +type Repositories interface{} diff --git a/internal/accounts/services/lookup.go b/internal/accounts/services/lookup.go new file mode 100644 index 00000000..bbef88bc --- /dev/null +++ b/internal/accounts/services/lookup.go @@ -0,0 +1,9 @@ +package services + +// LookupService ... +type LookupService struct{} + +// NewLookupService ... +func NewLookupService() *LookupService { + return &LookupService{} +} diff --git a/internal/api/controllers/accounts.go b/internal/api/controllers/accounts.go index 04aa4ad0..33c0c88b 100644 --- a/internal/api/controllers/accounts.go +++ b/internal/api/controllers/accounts.go @@ -9,7 +9,6 @@ import ( "github.com/nats-io/nkeys" "github.com/zeiss/typhoon/internal/api/models" "github.com/zeiss/typhoon/internal/api/ports" - "github.com/zeiss/typhoon/internal/utils" openapi "github.com/zeiss/typhoon/pkg/apis" ) @@ -133,24 +132,25 @@ func (c *AccountsController) UpdateAccount(ctx context.Context, req UpdateOperat if err != nil { return nil, err } - - if len(*req.Body.Claims.Exports) > 0 { - for _, e := range *req.Body.Claims.Exports { - export := &jwt.Export{ - Name: utils.PtrStr(e.Name), - Subject: jwt.Subject(utils.PtrStr(e.Subject)), - Type: jwt.ExportType(*e.Type), - ResponseType: jwt.ResponseType(*e.ResponseType), - AccountTokenPosition: *e.AccountTokenPosition, - Info: jwt.Info{ - Description: utils.PtrStr(e.Info.Description), - InfoURL: utils.PtrStr(e.Info.InfoUrl), - }, - } - - ac.Exports.Add(export) - } - } + ac.Exports = make([]*jwt.Export, 0) + + // if len(*req.Body.Claims.Exports) > 0 { + // for _, e := range *req.Body.Claims.Exports { + // export := &jwt.Export{ + // Name: utils.PtrStr(e.Name), + // Subject: jwt.Subject(utils.PtrStr(e.Subject)), + // Type: jwt.ExportType(*e.Type), + // ResponseType: jwt.ResponseType(*e.ResponseType), + // AccountTokenPosition: *e.AccountTokenPosition, + // Info: jwt.Info{ + // Description: utils.PtrStr(e.Info.Description), + // InfoURL: utils.PtrStr(e.Info.InfoUrl), + // }, + // } + + // ac.Exports.Add(export) + // } + // } token, err := ac.Encode(osk) if err != nil {