Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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: 58 additions & 2 deletions 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 @@ -90,8 +105,49 @@ func (c *CLI) KeystoreCreate() *cobra.Command {
cmd.Flags().String("id", "", "user id")
_ = cmd.MarkFlagRequired("id")
cmd.Flags().String("scope", "", "user scope")
_ = cmd.MarkFlagRequired("scope")
cmd.Flags().String("keystore-password", "", "keystore password")
_ = cmd.MarkFlagRequired("keystore-password")
return cmd
}

func (c *CLI) UserPasswordSet() *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Short: "Set user password. Password is read from input.",
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().SetPassword(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")

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

import (
"fmt"
"io"

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

const (
// Repository user types (as stored in JCR)
RepUserType = "rep:User"
RepSystemUserType = "rep:SystemUser"

// Maped user types
UserType = "user"
SystemUserType = "systemUser"
)

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 RepUserType:
status.Type = UserType
case RepSystemUserType:
status.Type = SystemUserType
default:
return nil, fmt.Errorf("unknown user type: %s", status.Type)
}

return &status, nil
}
72 changes: 69 additions & 3 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 All @@ -18,7 +20,7 @@ const (
)

func (um *UserManager) KeystoreStatus(scope, id string) (*keystore.Status, error) {
userKeystorePath := UsersPath + "/" + scope + "/" + id + ".ks.json"
userKeystorePath := assembleUserPath(scope, id) + ".ks.json"

response, err := um.instance.http.Request().Get(userKeystorePath)

Expand Down Expand Up @@ -46,7 +48,7 @@ func (um *UserManager) KeystoreCreate(scope, id, keystorePassword string) (bool,
return false, statusError
}

if statusResponse.Created == true {
if statusResponse.Created {
return false, nil
}

Expand All @@ -56,7 +58,7 @@ func (um *UserManager) KeystoreCreate(scope, id, keystorePassword string) (bool,
":operation": "createStore",
}

userKeystoreCreatePath := UsersPath + "/" + scope + "/" + id + ".ks.html"
userKeystoreCreatePath := assembleUserPath(scope, id) + ".ks.html"
postResponse, postError := um.instance.http.Request().SetQueryParams(pathParams).Post(userKeystoreCreatePath)

if postError != nil {
Expand All @@ -69,3 +71,67 @@ func (um *UserManager) KeystoreCreate(scope, id, keystorePassword string) (bool,

return true, nil
}

func (um *UserManager) ReadState(scope string, id string) (*user.Status, error) {
userPath := assembleUserPath(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) SetPassword(scope string, id string, password string) (bool, error) {
userStatus, err := um.ReadState(scope, id)

if err != nil {
return false, err
}

userPath := assembleUserPath(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(), err)
}
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(), err)
}
if postResponse.IsError() {
return false, fmt.Errorf("%s > cannot set user password: %s", um.instance.IDColor(), postResponse.Status())
}

return true, nil
}

func assembleUserPath(scope string, id string) string {
if scope == "" {
return UsersPath + "/" + id
}
return UsersPath + "/" + scope + "/" + id
}
Loading