Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion cmd/aem/user.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package main

import "github.com/spf13/cobra"
import (
"fmt"

"github.com/spf13/cobra"
)

func (c *CLI) userCmd() *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -9,6 +13,7 @@ func (c *CLI) userCmd() *cobra.Command {
Aliases: []string{"usr"},
}
cmd.AddCommand(c.userKeyStore())
cmd.AddCommand(c.userPassword())
return cmd
}

Expand All @@ -24,6 +29,16 @@ func (c *CLI) userKeyStore() *cobra.Command {
return cmd
}

func (c *CLI) userPassword() *cobra.Command {
cmd := &cobra.Command{
Use: "password",
Short: "User password management",
Aliases: []string{"pwd"},
}
cmd.AddCommand(c.UserPasswordSet())
return cmd
}

func (c *CLI) KeystoreStatus() *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Expand Down Expand Up @@ -95,3 +110,46 @@ func (c *CLI) KeystoreCreate() *cobra.Command {
_ = cmd.MarkFlagRequired("keystore-password")
return cmd
}

func (c *CLI) UserPasswordSet() *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Short: "Set user password",
Aliases: []string{"update", "change"},
Run: func(cmd *cobra.Command, args []string) {
instances, err := c.aem.InstanceManager().One()
if err != nil {
c.Error(err)
return
}

id, _ := cmd.Flags().GetString("id")
scope, _ := cmd.Flags().GetString("scope")

var password string
if err := c.ReadInput(&password); err != nil {
c.Fail(fmt.Sprintf("error reading password from input: %s", err))
return
}

changed, err := instances.Auth().UserManager().PasswordSet(scope, id, password)
if err != nil {
c.Error(err)
return
}

if changed {
c.Changed("User password changed")
} else {
c.Ok("User password already set")
}
},
}

cmd.Flags().String("id", "", "user id")
_ = cmd.MarkFlagRequired("id")
cmd.Flags().String("scope", "", "user scope")
_ = cmd.MarkFlagRequired("scope")

return cmd
}
34 changes: 34 additions & 0 deletions pkg/user/user_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package user

import (
"fmt"
"io"

"github.com/wttech/aemc/pkg/common/fmtx"
)

type Status struct {
Type string `json:"jcr:primaryType"`
AuthorizableID string `json:"rep:authorizableId"`
}

func UnmarshalStatus(readCloser io.ReadCloser) (*Status, error) {
var status = Status{
Type: "rep:User",
AuthorizableID: "",
}
if err := fmtx.UnmarshalJSON(readCloser, &status); err != nil {
return nil, err
}

switch status.Type {
case "rep:User":
status.Type = "user"
case "rep:SystemUser":
status.Type = "systemUser"
default:
return nil, fmt.Errorf("unknown user type: %s", status.Type)
}

return &status, nil
}
59 changes: 59 additions & 0 deletions pkg/user_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package pkg

import (
"fmt"

"github.com/wttech/aemc/pkg/keystore"
"github.com/wttech/aemc/pkg/user"
)

type UserManager struct {
Expand Down Expand Up @@ -69,3 +71,60 @@ func (um *UserManager) KeystoreCreate(scope, id, keystorePassword string) (bool,

return true, nil
}

func (um *UserManager) ReadState(scope string, id string) (*user.Status, error) {
userPath := UsersPath + "/" + scope + "/" + id

response, err := um.instance.http.Request().Get(userPath + ".json")

if err != nil {
return nil, fmt.Errorf("%s > cannot read user: %w", um.instance.IDColor(), err)
}
if response.IsError() {
return nil, fmt.Errorf("%s > cannot read user: %s", um.instance.IDColor(), response.Status())
}

result, err := user.UnmarshalStatus(response.RawBody())

if err != nil {
return nil, fmt.Errorf("%s > cannot parse user status response: %w", um.instance.IDColor(), err)
}

return result, nil
}

func (um *UserManager) PasswordSet(scope string, id string, password string) (bool, error) {
userStatus, err := um.ReadState(scope, id)

if err != nil {
return false, err
}

userPath := UsersPath + "/" + scope + "/" + id

passwordCheckResponse, err := um.instance.http.Request().
SetBasicAuth(userStatus.AuthorizableID, password).
Get(userPath + ".json")

if err != nil {
return false, fmt.Errorf("%s > cannot check user password: %w", um.instance.IDColor(), passwordCheckError)
}
if !passwordCheckResponse.IsError() {
return false, nil
}

props := map[string]any{
"rep:password": password,
}

postResponse, err := um.instance.http.RequestFormData(props).Post(userPath)

if err != nil {
return false, fmt.Errorf("%s > cannot set user password: %w", um.instance.IDColor(), postError)
}
if postResponse.IsError() {
return false, fmt.Errorf("%s > cannot set user password: %s", um.instance.IDColor(), postResponse.Status())
}

return true, nil
}
Loading