Skip to content

Commit e15d85e

Browse files
Merge pull request #303 from wttech/feature/auth-user-password-set
Add command: auth user password set
2 parents 01f1f21 + f16e18a commit e15d85e

File tree

3 files changed

+171
-5
lines changed

3 files changed

+171
-5
lines changed

cmd/aem/user.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package main
22

3-
import "github.com/spf13/cobra"
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
)
48

59
func (c *CLI) userCmd() *cobra.Command {
610
cmd := &cobra.Command{
@@ -9,6 +13,7 @@ func (c *CLI) userCmd() *cobra.Command {
913
Aliases: []string{"usr"},
1014
}
1115
cmd.AddCommand(c.userKeyStore())
16+
cmd.AddCommand(c.userPassword())
1217
return cmd
1318
}
1419

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

32+
func (c *CLI) userPassword() *cobra.Command {
33+
cmd := &cobra.Command{
34+
Use: "password",
35+
Short: "User password management",
36+
Aliases: []string{"pwd"},
37+
}
38+
cmd.AddCommand(c.UserPasswordSet())
39+
return cmd
40+
}
41+
2742
func (c *CLI) KeystoreStatus() *cobra.Command {
2843
cmd := &cobra.Command{
2944
Use: "status",
@@ -90,8 +105,49 @@ func (c *CLI) KeystoreCreate() *cobra.Command {
90105
cmd.Flags().String("id", "", "user id")
91106
_ = cmd.MarkFlagRequired("id")
92107
cmd.Flags().String("scope", "", "user scope")
93-
_ = cmd.MarkFlagRequired("scope")
94108
cmd.Flags().String("keystore-password", "", "keystore password")
95109
_ = cmd.MarkFlagRequired("keystore-password")
96110
return cmd
97111
}
112+
113+
func (c *CLI) UserPasswordSet() *cobra.Command {
114+
cmd := &cobra.Command{
115+
Use: "set",
116+
Short: "Set user password. Password is read from input.",
117+
Aliases: []string{"update", "change"},
118+
Run: func(cmd *cobra.Command, args []string) {
119+
instances, err := c.aem.InstanceManager().One()
120+
if err != nil {
121+
c.Error(err)
122+
return
123+
}
124+
125+
id, _ := cmd.Flags().GetString("id")
126+
scope, _ := cmd.Flags().GetString("scope")
127+
128+
var password string
129+
if err := c.ReadInput(&password); err != nil {
130+
c.Fail(fmt.Sprintf("error reading password from input: %s", err))
131+
return
132+
}
133+
134+
changed, err := instances.Auth().UserManager().SetPassword(scope, id, password)
135+
if err != nil {
136+
c.Error(err)
137+
return
138+
}
139+
140+
if changed {
141+
c.Changed("User password changed")
142+
} else {
143+
c.Ok("User password already set")
144+
}
145+
},
146+
}
147+
148+
cmd.Flags().String("id", "", "user id")
149+
_ = cmd.MarkFlagRequired("id")
150+
cmd.Flags().String("scope", "", "user scope")
151+
152+
return cmd
153+
}

pkg/user/status.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package user
2+
3+
import (
4+
"fmt"
5+
"io"
6+
7+
"github.com/wttech/aemc/pkg/common/fmtx"
8+
)
9+
10+
const (
11+
// Repository user types (as stored in JCR)
12+
RepUserType = "rep:User"
13+
RepSystemUserType = "rep:SystemUser"
14+
15+
// Maped user types
16+
UserType = "user"
17+
SystemUserType = "systemUser"
18+
)
19+
20+
type Status struct {
21+
Type string `json:"jcr:primaryType"`
22+
AuthorizableID string `json:"rep:authorizableId"`
23+
}
24+
25+
func UnmarshalStatus(readCloser io.ReadCloser) (*Status, error) {
26+
var status = Status{
27+
Type: "rep:User",
28+
AuthorizableID: "",
29+
}
30+
if err := fmtx.UnmarshalJSON(readCloser, &status); err != nil {
31+
return nil, err
32+
}
33+
34+
switch status.Type {
35+
case RepUserType:
36+
status.Type = UserType
37+
case RepSystemUserType:
38+
status.Type = SystemUserType
39+
default:
40+
return nil, fmt.Errorf("unknown user type: %s", status.Type)
41+
}
42+
43+
return &status, nil
44+
}

pkg/user_manager.go

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package pkg
22

33
import (
44
"fmt"
5+
56
"github.com/wttech/aemc/pkg/keystore"
7+
"github.com/wttech/aemc/pkg/user"
68
)
79

810
type UserManager struct {
@@ -18,7 +20,7 @@ const (
1820
)
1921

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

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

@@ -46,7 +48,7 @@ func (um *UserManager) KeystoreCreate(scope, id, keystorePassword string) (bool,
4648
return false, statusError
4749
}
4850

49-
if statusResponse.Created == true {
51+
if statusResponse.Created {
5052
return false, nil
5153
}
5254

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

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

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

7072
return true, nil
7173
}
74+
75+
func (um *UserManager) ReadState(scope string, id string) (*user.Status, error) {
76+
userPath := assembleUserPath(scope, id)
77+
78+
response, err := um.instance.http.Request().Get(userPath + ".json")
79+
80+
if err != nil {
81+
return nil, fmt.Errorf("%s > cannot read user: %w", um.instance.IDColor(), err)
82+
}
83+
if response.IsError() {
84+
return nil, fmt.Errorf("%s > cannot read user: %s", um.instance.IDColor(), response.Status())
85+
}
86+
87+
result, err := user.UnmarshalStatus(response.RawBody())
88+
89+
if err != nil {
90+
return nil, fmt.Errorf("%s > cannot parse user status response: %w", um.instance.IDColor(), err)
91+
}
92+
93+
return result, nil
94+
}
95+
96+
func (um *UserManager) SetPassword(scope string, id string, password string) (bool, error) {
97+
userStatus, err := um.ReadState(scope, id)
98+
99+
if err != nil {
100+
return false, err
101+
}
102+
103+
userPath := assembleUserPath(scope, id)
104+
105+
passwordCheckResponse, err := um.instance.http.Request().
106+
SetBasicAuth(userStatus.AuthorizableID, password).
107+
Get(userPath + ".json")
108+
109+
if err != nil {
110+
return false, fmt.Errorf("%s > cannot check user password: %w", um.instance.IDColor(), err)
111+
}
112+
if !passwordCheckResponse.IsError() {
113+
return false, nil
114+
}
115+
116+
props := map[string]any{
117+
"rep:password": password,
118+
}
119+
120+
postResponse, err := um.instance.http.RequestFormData(props).Post(userPath)
121+
122+
if err != nil {
123+
return false, fmt.Errorf("%s > cannot set user password: %w", um.instance.IDColor(), err)
124+
}
125+
if postResponse.IsError() {
126+
return false, fmt.Errorf("%s > cannot set user password: %s", um.instance.IDColor(), postResponse.Status())
127+
}
128+
129+
return true, nil
130+
}
131+
132+
func assembleUserPath(scope string, id string) string {
133+
if scope == "" {
134+
return UsersPath + "/" + id
135+
}
136+
return UsersPath + "/" + scope + "/" + id
137+
}

0 commit comments

Comments
 (0)