mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-03 19:54:22 +08:00
Merge pull request #3441 from gravitl/nmctl-access-token
feat: add support for user access tokens in nmctl
This commit is contained in:
parent
f9bc3a5386
commit
506f73ebb9
9 changed files with 185 additions and 7 deletions
43
cli/cmd/access_token/create.go
Normal file
43
cli/cmd/access_token/create.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package access_token
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/gravitl/netmaker/schema"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var accessTokenCreateCmd = &cobra.Command{
|
||||
Use: "create [token-name]",
|
||||
Short: "Create an access token",
|
||||
Long: `Create an access token for a user`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
userName, _ := cmd.Flags().GetString("user")
|
||||
expiresAt, _ := cmd.Flags().GetString("expires")
|
||||
|
||||
accessToken := &schema.UserAccessToken{}
|
||||
accessToken.Name = args[0]
|
||||
accessToken.UserName = userName
|
||||
|
||||
expTime := time.Now().Add(time.Hour * 24 * 365) // default to 1 year
|
||||
if expiresAt != "" {
|
||||
var err error
|
||||
expTime, err = time.Parse(time.RFC3339, expiresAt)
|
||||
if err != nil {
|
||||
cmd.PrintErrf("Invalid expiration time format. Please use RFC3339 format (e.g. 2024-01-01T00:00:00Z). Using default 1 year.\n")
|
||||
}
|
||||
}
|
||||
accessToken.ExpiresAt = expTime
|
||||
|
||||
functions.PrettyPrint(functions.CreateAccessToken(accessToken))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
accessTokenCreateCmd.Flags().String("user", "", "Username to create token for")
|
||||
accessTokenCreateCmd.Flags().String("expires", "", "Expiration time for the token in RFC3339 format (e.g. 2024-01-01T00:00:00Z). Defaults to 1 year from now.")
|
||||
accessTokenCreateCmd.MarkFlagRequired("user")
|
||||
rootCmd.AddCommand(accessTokenCreateCmd)
|
||||
}
|
23
cli/cmd/access_token/delete.go
Normal file
23
cli/cmd/access_token/delete.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package access_token
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var accessTokenDeleteCmd = &cobra.Command{
|
||||
Use: "delete [ACCESS TOKEN ID]",
|
||||
Short: "Delete an access token",
|
||||
Long: `Delete an access token by ID`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
functions.DeleteAccessToken(args[0])
|
||||
fmt.Println("Access token deleted successfully")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(accessTokenDeleteCmd)
|
||||
}
|
20
cli/cmd/access_token/get.go
Normal file
20
cli/cmd/access_token/get.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package access_token
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var accessTokenGetCmd = &cobra.Command{
|
||||
Use: "get [USERNAME]",
|
||||
Short: "Get a user's access token",
|
||||
Long: `Get a user's access token`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
functions.PrettyPrint(functions.GetAccessToken(args[0]))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(accessTokenGetCmd)
|
||||
}
|
28
cli/cmd/access_token/root.go
Normal file
28
cli/cmd/access_token/root.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package access_token
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "access_token",
|
||||
Short: "Manage Netmaker user access tokens",
|
||||
Long: `Manage a Netmaker user's access tokens. This command allows you to create, delete, and list access tokens for a user.`,
|
||||
}
|
||||
|
||||
// GetRoot returns the root subcommand
|
||||
func GetRoot() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ var (
|
|||
sso bool
|
||||
tenantId string
|
||||
saas bool
|
||||
authToken string
|
||||
)
|
||||
|
||||
var contextSetCmd = &cobra.Command{
|
||||
|
@ -30,13 +31,14 @@ var contextSetCmd = &cobra.Command{
|
|||
Username: username,
|
||||
Password: password,
|
||||
MasterKey: masterKey,
|
||||
AuthToken: authToken,
|
||||
SSO: sso,
|
||||
TenantId: tenantId,
|
||||
Saas: saas,
|
||||
}
|
||||
if !ctx.Saas {
|
||||
if ctx.Username == "" && ctx.MasterKey == "" && !ctx.SSO {
|
||||
log.Fatal("Either username/password or master key is required")
|
||||
if ctx.Username == "" && ctx.MasterKey == "" && !ctx.SSO && ctx.AuthToken == "" {
|
||||
log.Fatal("Either username/password or master key or auth token is required")
|
||||
cmd.Usage()
|
||||
}
|
||||
if ctx.Endpoint == "" {
|
||||
|
@ -49,8 +51,8 @@ var contextSetCmd = &cobra.Command{
|
|||
cmd.Usage()
|
||||
}
|
||||
ctx.Endpoint = fmt.Sprintf(functions.TenantUrlTemplate, tenantId)
|
||||
if ctx.Username == "" && ctx.Password == "" && !ctx.SSO {
|
||||
log.Fatal("Username/password is required for non-SSO SaaS contexts")
|
||||
if ctx.Username == "" && ctx.Password == "" && ctx.AuthToken == "" && !ctx.SSO {
|
||||
log.Fatal("Username/password or authtoken is required for non-SSO SaaS contexts")
|
||||
cmd.Usage()
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +64,7 @@ func init() {
|
|||
contextSetCmd.Flags().StringVar(&endpoint, "endpoint", "", "Endpoint of the API Server")
|
||||
contextSetCmd.Flags().StringVar(&username, "username", "", "Username")
|
||||
contextSetCmd.Flags().StringVar(&password, "password", "", "Password")
|
||||
contextSetCmd.Flags().StringVar(&authToken, "auth_token", "", "Auth Token")
|
||||
contextSetCmd.MarkFlagsRequiredTogether("username", "password")
|
||||
contextSetCmd.Flags().BoolVar(&sso, "sso", false, "Login via Single Sign On (SSO)?")
|
||||
contextSetCmd.Flags().StringVar(&masterKey, "master_key", "", "Master Key")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/cli/cmd/gateway"
|
||||
"os"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/cmd/access_token"
|
||||
"github.com/gravitl/netmaker/cli/cmd/acl"
|
||||
"github.com/gravitl/netmaker/cli/cmd/commons"
|
||||
"github.com/gravitl/netmaker/cli/cmd/context"
|
||||
|
@ -11,12 +11,14 @@ import (
|
|||
"github.com/gravitl/netmaker/cli/cmd/enrollment_key"
|
||||
"github.com/gravitl/netmaker/cli/cmd/ext_client"
|
||||
"github.com/gravitl/netmaker/cli/cmd/failover"
|
||||
"github.com/gravitl/netmaker/cli/cmd/gateway"
|
||||
"github.com/gravitl/netmaker/cli/cmd/host"
|
||||
"github.com/gravitl/netmaker/cli/cmd/metrics"
|
||||
"github.com/gravitl/netmaker/cli/cmd/network"
|
||||
"github.com/gravitl/netmaker/cli/cmd/node"
|
||||
"github.com/gravitl/netmaker/cli/cmd/server"
|
||||
"github.com/gravitl/netmaker/cli/cmd/user"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -57,4 +59,5 @@ func init() {
|
|||
rootCmd.AddCommand(enrollment_key.GetRoot())
|
||||
rootCmd.AddCommand(failover.GetRoot())
|
||||
rootCmd.AddCommand(gateway.GetRoot())
|
||||
rootCmd.AddCommand(access_token.GetRoot())
|
||||
}
|
||||
|
|
58
cli/functions/access_tokens.go
Normal file
58
cli/functions/access_tokens.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/schema"
|
||||
)
|
||||
|
||||
// CreateAccessToken - creates an access token for a user
|
||||
func CreateAccessToken(payload *schema.UserAccessToken) *models.SuccessfulUserLoginResponse {
|
||||
res := request[models.SuccessResponse](http.MethodPost, "/api/v1/users/access_token", payload)
|
||||
if res.Code != http.StatusOK {
|
||||
log.Fatalf("Error creating access token: %s", res.Message)
|
||||
}
|
||||
|
||||
var token models.SuccessfulUserLoginResponse
|
||||
responseBytes, err := json.Marshal(res.Response)
|
||||
if err != nil {
|
||||
log.Fatalf("Error marshaling response: %v", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBytes, &token); err != nil {
|
||||
log.Fatalf("Error unmarshaling token: %v", err)
|
||||
}
|
||||
|
||||
return &token
|
||||
}
|
||||
|
||||
// GetAccessToken - fetch all access tokens per user
|
||||
func GetAccessToken(userName string) []schema.UserAccessToken {
|
||||
res := request[models.SuccessResponse](http.MethodGet, "/api/v1/users/access_token?username="+userName, nil)
|
||||
if res.Code != http.StatusOK {
|
||||
log.Fatalf("Error getting access token: %s", res.Message)
|
||||
}
|
||||
|
||||
var tokens []schema.UserAccessToken
|
||||
responseBytes, err := json.Marshal(res.Response)
|
||||
if err != nil {
|
||||
log.Fatalf("Error marshaling response: %v", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBytes, &tokens); err != nil {
|
||||
log.Fatalf("Error unmarshaling tokens: %v", err)
|
||||
}
|
||||
|
||||
return tokens
|
||||
}
|
||||
|
||||
// DeleteAccessToken - delete an access token
|
||||
func DeleteAccessToken(id string) {
|
||||
res := request[models.SuccessResponse](http.MethodDelete, "/api/v1/users/access_token?id="+id, nil)
|
||||
if res.Code != http.StatusOK {
|
||||
log.Fatalf("Error deleting access token: %s", res.Message)
|
||||
}
|
||||
}
|
|
@ -192,7 +192,7 @@ retry:
|
|||
body := new(T)
|
||||
if len(resBodyBytes) > 0 {
|
||||
if err := json.Unmarshal(resBodyBytes, body); err != nil {
|
||||
log.Fatalf("Error unmarshalling JSON: %s", err)
|
||||
log.Fatalf("Error unmarshalling JSON: %s %s", err, string(resBodyBytes))
|
||||
}
|
||||
}
|
||||
return body
|
||||
|
|
|
@ -163,7 +163,7 @@ func deleteUserAccessTokens(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
err := a.Get(r.Context())
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("id is required"), "badrequest"))
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("token does not exist"), "badrequest"))
|
||||
return
|
||||
}
|
||||
caller, err := logic.GetUser(r.Header.Get("user"))
|
||||
|
|
Loading…
Add table
Reference in a new issue