feat: authenticate users and agents requests
This commit is contained in:
@ -17,7 +17,6 @@ import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/machineid"
|
||||
"github.com/pkg/errors"
|
||||
_ "github.com/santhosh-tekuri/jsonschema/v5/httploader"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
@ -20,12 +20,17 @@ func GetCommand() *cli.Command {
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
agentID, err := agentFlag.AssertAgentID(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL)
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agent, err := client.GetAgent(ctx.Context, agentID)
|
||||
if err != nil {
|
||||
|
@ -18,7 +18,13 @@ func QueryCommand() *cli.Command {
|
||||
Flags: clientFlag.ComposeFlags(),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
client := client.New(baseFlags.ServerURL)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agents, _, err := client.QueryAgents(ctx.Context)
|
||||
if err != nil {
|
||||
|
@ -26,6 +26,11 @@ func UpdateCommand() *cli.Command {
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
agentID, err := agentFlag.AssertAgentID(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
@ -38,7 +43,7 @@ func UpdateCommand() *cli.Command {
|
||||
options = append(options, client.WithAgentStatus(status))
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL)
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agent, err := client.UpdateAgent(ctx.Context, agentID, options...)
|
||||
if err != nil {
|
||||
|
@ -2,9 +2,13 @@ package flag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format/table"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@ -28,6 +32,17 @@ func ComposeFlags(flags ...cli.Flag) []cli.Flag {
|
||||
Usage: fmt.Sprintf("use `MODE` as output mode (available: %s)", []format.OutputMode{format.OutputModeCompact, format.OutputModeWide}),
|
||||
Value: string(format.OutputModeCompact),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "use `TOKEN` as authentification token",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token-file",
|
||||
Usage: "use `TOKEN_FILE` as file containing the authentification token",
|
||||
Value: ".emissary-token",
|
||||
TakesFile: true,
|
||||
},
|
||||
}
|
||||
|
||||
flags = append(flags, baseFlags...)
|
||||
@ -39,16 +54,43 @@ type BaseFlags struct {
|
||||
ServerURL string
|
||||
Format format.Format
|
||||
OutputMode format.OutputMode
|
||||
Token string
|
||||
TokenFile string
|
||||
}
|
||||
|
||||
func GetBaseFlags(ctx *cli.Context) *BaseFlags {
|
||||
serverURL := ctx.String("server")
|
||||
rawFormat := ctx.String("format")
|
||||
rawOutputMode := ctx.String("output-mode")
|
||||
tokenFile := ctx.String("token-file")
|
||||
token := ctx.String("token")
|
||||
|
||||
return &BaseFlags{
|
||||
ServerURL: serverURL,
|
||||
Format: format.Format(rawFormat),
|
||||
OutputMode: format.OutputMode(rawOutputMode),
|
||||
Token: token,
|
||||
TokenFile: tokenFile,
|
||||
}
|
||||
}
|
||||
|
||||
func GetToken(flags *BaseFlags) (string, error) {
|
||||
if flags.Token != "" {
|
||||
return flags.Token, nil
|
||||
}
|
||||
|
||||
if flags.TokenFile == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
rawToken, err := ioutil.ReadFile(flags.TokenFile)
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
if rawToken == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(rawToken)), nil
|
||||
}
|
||||
|
54
internal/command/server/auth/create_token.go
Normal file
54
internal/command/server/auth/create_token.go
Normal file
@ -0,0 +1,54 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth/user"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/common"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func CreateTokenCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "create-token",
|
||||
Usage: "Create a new authentification token",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "role",
|
||||
Usage: fmt.Sprintf("associate `ROLE` to the token (available: %v)", []user.Role{user.RoleReader, user.RoleWriter}),
|
||||
Value: string(user.RoleReader),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "subject",
|
||||
Usage: "associate `SUBJECT` to the token",
|
||||
Value: fmt.Sprintf("user-%s", shortuuid.New()),
|
||||
},
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
conf, err := common.LoadConfig(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not load configuration")
|
||||
}
|
||||
|
||||
subject := ctx.String("subject")
|
||||
role := ctx.String("role")
|
||||
|
||||
key, err := jwk.LoadOrGenerate(string(conf.Server.PrivateKeyPath), jwk.DefaultKeySize)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
token, err := user.GenerateToken(ctx.Context, key, string(conf.Server.Issuer), subject, user.Role(role))
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
fmt.Println(token)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
15
internal/command/server/auth/root.go
Normal file
15
internal/command/server/auth/root.go
Normal file
@ -0,0 +1,15 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Root() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "auth",
|
||||
Usage: "Authentication related commands",
|
||||
Subcommands: []*cli.Command{
|
||||
CreateTokenCommand(),
|
||||
},
|
||||
}
|
||||
}
|
@ -36,8 +36,8 @@ func MigrateCommand() *cli.Command {
|
||||
return errors.Wrap(err, "Could not load configuration")
|
||||
}
|
||||
|
||||
driver := string(conf.Database.Driver)
|
||||
dsn := string(conf.Database.DSN)
|
||||
driver := string(conf.Server.Database.Driver)
|
||||
dsn := string(conf.Server.Database.DSN)
|
||||
|
||||
migr, err := migrate.New("migrations", driver, dsn)
|
||||
if err != nil {
|
||||
|
@ -20,10 +20,10 @@ func PingCommand() *cli.Command {
|
||||
return errors.Wrap(err, "Could not load configuration")
|
||||
}
|
||||
|
||||
logger.Info(ctx.Context, "connecting to database", logger.F("dsn", conf.Database.DSN))
|
||||
logger.Info(ctx.Context, "connecting to database", logger.F("dsn", conf.Server.Database.DSN))
|
||||
|
||||
driver := string(conf.Database.Driver)
|
||||
dsn := string(conf.Database.DSN)
|
||||
driver := string(conf.Server.Database.Driver)
|
||||
dsn := string(conf.Server.Database.DSN)
|
||||
|
||||
db, err := sql.Open(driver, dsn)
|
||||
if err != nil {
|
||||
@ -40,7 +40,7 @@ func PingCommand() *cli.Command {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info(ctx.Context, "connection succeeded", logger.F("dsn", conf.Database.DSN))
|
||||
logger.Info(ctx.Context, "connection succeeded", logger.F("dsn", conf.Server.Database.DSN))
|
||||
|
||||
return nil
|
||||
},
|
||||
|
@ -18,8 +18,8 @@ func ResetCommand() *cli.Command {
|
||||
return errors.Wrap(err, "Could not load configuration")
|
||||
}
|
||||
|
||||
driver := string(conf.Database.Driver)
|
||||
dsn := string(conf.Database.DSN)
|
||||
driver := string(conf.Server.Database.Driver)
|
||||
dsn := string(conf.Server.Database.DSN)
|
||||
|
||||
migr, err := migrate.New("migrations", driver, dsn)
|
||||
if err != nil {
|
||||
|
@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/config"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/server/auth"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/server/database"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@ -14,6 +15,7 @@ func Root() *cli.Command {
|
||||
RunCommand(),
|
||||
database.Root(),
|
||||
config.Root(),
|
||||
auth.Root(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ func RunCommand() *cli.Command {
|
||||
logger.SetLevel(logger.Level(conf.Logger.Level))
|
||||
|
||||
srv := server.New(
|
||||
server.WithConfig(conf),
|
||||
server.WithConfig(conf.Server),
|
||||
)
|
||||
|
||||
addrs, srvErrs := srv.Start(ctx.Context)
|
||||
|
Reference in New Issue
Block a user