Skip to content

Commit dd2016e

Browse files
committed
added -r to make it like kubectl get <COMMAND> -n
1 parent 178796a commit dd2016e

File tree

9 files changed

+109
-57
lines changed

9 files changed

+109
-57
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,31 @@
1515
- **Usage**: `create [user, realm, resource, role]`
1616
- **Description**: Creates various entities in Keycloak.
1717
- **Subcommands**:
18-
- `create user`: Creates a new user.
18+
- `create user`: Creates a new user in a specified realm.
19+
- **Flags**: `-u, --username <username>`, `-p, --password <password>`, `-e, --email <email>`, `-r, --realm <realm>`
20+
- **Example**: `./keycloak-api-cli create user -u john -p pass123 -e john@example.com -r myrealm`
1921
- `create realm`: Creates a new realm.
20-
- **Example**: `./keycloak-api-cli create user --config path/to/config.yaml`
22+
- **Example**: `./keycloak-api-cli create realm --config path/to/config.yaml`
2123

2224
### 2. `delete`
2325
- **Usage**: `delete [user, realm, resource, role]`
2426
- **Description**: Deletes entities in Keycloak.
2527
- **Subcommands**:
26-
- `delete user`: Deletes a user.
28+
- `delete user`: Deletes a user from a specified realm.
29+
- **Flags**: `-i, --userid <userID>`, `-u, --username <username>`, `-r, --realm <realm>`
30+
- **Example**: `./keycloak-api-cli delete user -u john -r myrealm`
2731
- `delete realm`: Deletes a realm.
28-
- **Example**: `./keycloak-api-cli delete realm --config path/to/config.yaml`
32+
- **Example**: `./keycloak-api-cli delete realm --config path/to/config.yaml`
2933

3034
### 3. `get`
3135
- **Usage**: `get [users, realms, resources, roles]`
3236
- **Description**: Retrieves information about entities in Keycloak.
3337
- **Subcommands**:
34-
- `get users`: Lists all users in a realm.
38+
- `get users`: Lists all users in a specified realm.
39+
- **Flags**: `-r, --realm <realm>`
40+
- **Example**: `./keycloak-api-cli get users -r myrealm --config path/to/config.yaml`
3541
- `get realms`: Lists all realms.
36-
- **Example**: `./keycloak-api-cli get realms --config path/to/config.yaml`
42+
- **Example**: `./keycloak-api-cli get realms --config path/to/config.yaml`
3743

3844
### 4. Root Command
3945
- **Usage**: `keycloak-api-cli`

cmd/create.go

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"keycloak-api-cli/pkg/keycloak"
99

1010
"github.com/spf13/cobra"
11+
"github.com/spf13/viper"
1112
)
1213

1314

@@ -26,7 +27,7 @@ func CreateCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
2627

2728
// Create Realm
2829
func CreateRealmCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
29-
CreateRealmCommand := &cobra.Command{
30+
realmCmd := &cobra.Command{
3031
Use: "realm",
3132
Short: "Create a new Keycloak realm",
3233
Run: func(cmd *cobra.Command, args []string) {
@@ -40,8 +41,8 @@ func CreateRealmCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
4041
}
4142
},
4243
}
43-
CreateRealmCommand.Flags().StringVarP(&realmName, "name", "n", "", "Name of the realm to create")
44-
return CreateRealmCommand
44+
realmCmd.Flags().StringVarP(&realmName, "name", "n", "", "Name of the realm to create")
45+
return realmCmd
4546
}
4647

4748
func askForRealmName() string {
@@ -54,30 +55,45 @@ func askForRealmName() string {
5455

5556
// Create user
5657
func CreateUserCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
57-
CreateUserCommand := &cobra.Command{
58+
var (
59+
username string
60+
password string
61+
email string
62+
)
63+
64+
createUserCmd := &cobra.Command{
5865
Use: "user",
5966
Short: "Create a new Keycloak user",
6067
Run: func(cmd *cobra.Command, args []string) {
68+
realm, _ := cmd.Flags().GetString("realm")
69+
if realm == "" {
70+
realm = viper.GetString("default_realm") // Fallback to default realm from config
71+
}
6172
if username == "" {
6273
username = askForUserName()
6374
}
64-
if password == "" {
75+
if password == "" {
6576
password = askForUserPassword()
6677
}
67-
if email == "" {
78+
if email == "" {
6879
email = askForUserEmail()
6980
}
70-
if err := kcClient.CreateUser(username, password, email); err != nil {
71-
fmt.Printf("Error creating user: %v\n", err)
81+
82+
// Ensure to pass the 'realm' along with other parameters
83+
if err := kcClient.CreateUser(realm, username, password, email); err != nil {
84+
fmt.Printf("Error creating user in realm %s: %v\n", realm, err)
7285
} else {
73-
fmt.Println("username", username, "created successfully")
86+
fmt.Println("User", username, "created successfully in realm", realm)
7487
}
7588
},
7689
}
77-
CreateUserCommand.Flags().StringVarP(&realmName, "username", "u", "", "username of the user to create")
78-
CreateUserCommand.Flags().StringVarP(&password, "password", "p", "", "Password for the user")
79-
CreateUserCommand.Flags().StringVarP(&email, "email", "e", "", "Email address of the user")
80-
return CreateUserCommand
90+
91+
createUserCmd.Flags().StringP("realm", "r", "", "Specify the realm to create a user in")
92+
createUserCmd.Flags().StringVarP(&username, "username", "u", "", "Username of the user to create")
93+
createUserCmd.Flags().StringVarP(&password, "password", "p", "", "Password for the user")
94+
createUserCmd.Flags().StringVarP(&email, "email", "e", "", "Email address of the user")
95+
96+
return createUserCmd
8197
}
8298

8399
func askForUserName() string {

cmd/delete.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"keycloak-api-cli/pkg/keycloak"
99

1010
"github.com/spf13/cobra"
11+
"github.com/spf13/viper"
1112
)
1213

1314

@@ -56,21 +57,27 @@ func DeleteRealmCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
5657
// Delete User
5758
func DeleteUserCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
5859
var (
60+
realm string
5961
userID string
6062
username string
6163
)
6264

63-
DeleteUserCommand := &cobra.Command{
65+
deleteUserCmd := &cobra.Command{
6466
Use: "user",
6567
Short: "Delete a Keycloak user by username",
6668
Run: func(cmd *cobra.Command, args []string) {
69+
// Check if the realm flag is set, else use the default realm
70+
realm, _ := cmd.Flags().GetString("realm")
71+
if realm == "" {
72+
realm = viper.GetString("default_realm")
73+
}
6774
if username == "" && userID == "" {
6875
username = askForUserName()
6976
}
7077

7178
if username != "" {
7279
// Use username to retrieve userID
73-
retrievedUserID, err := kcClient.GetUserIDByUsername(username)
80+
retrievedUserID, err := kcClient.GetUserIDByUsername(realm, username)
7481
if err != nil {
7582
fmt.Printf("Error retrieving userID for username %s: %v\n", username, err)
7683
return
@@ -88,14 +95,18 @@ func DeleteUserCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
8895
return
8996
}
9097

91-
if err := kcClient.DeleteUser(userID); err != nil {
98+
if err := kcClient.DeleteUser(realm, userID); err != nil {
9299
fmt.Printf("Error deleting user: %v\n", err)
93100
} else {
94-
fmt.Printf("User %s (userID: %s) deleted successfully\n", username, userID)
101+
fmt.Printf("User %s (userID: %s) deleted successfully in realm %s\n", username, userID, realm)
95102
}
96103
},
97104
}
98-
DeleteUserCommand.Flags().StringVarP(&userID, "userid", "i", "", "ID of the user to delete")
99-
DeleteUserCommand.Flags().StringVarP(&username, "username", "u", "", "Username of the user to delete")
100-
return DeleteUserCommand
105+
106+
deleteUserCmd.Flags().StringVarP(&realm, "realm", "r", "", "Specify the realm to delete the user")
107+
deleteUserCmd.Flags().StringVarP(&userID, "userid", "i", "", "ID of the user to delete")
108+
deleteUserCmd.Flags().StringVarP(&username, "username", "u", "", "Username of the user to delete")
109+
110+
return deleteUserCmd
101111
}
112+

cmd/get.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"keycloak-api-cli/pkg/keycloak"
66

77
"github.com/spf13/cobra"
8+
"github.com/spf13/viper"
89
)
910

1011

@@ -42,19 +43,34 @@ func GetRealmCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
4243
}
4344

4445
func GetUsersCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
45-
return &cobra.Command{
46+
var realm string
47+
usersCmd := &cobra.Command{
4648
Use: "users",
4749
Short: "List all users",
4850
Long: `List all users in the Keycloak instance.`,
4951
Run: func(cmd *cobra.Command, args []string) {
50-
users, err := kcClient.ListUsers()
52+
// Check if the realm flag is set, else use the default realm
53+
realm, _ := cmd.Flags().GetString("realm")
54+
if realm == "" {
55+
realm = viper.GetString("default_realm")
56+
}
57+
58+
// Use the specified or default realm for listing users
59+
users, err := kcClient.ListUsers(realm) // Make sure ListUsers accepts a realm parameter
5160
if err != nil {
52-
fmt.Printf("Error listing users: %v\n", err)
61+
fmt.Printf("Error listing users in realm %s: %v\n", realm, err)
5362
return
5463
}
64+
65+
// Iterate and print details of each user
5566
for _, user := range users {
56-
fmt.Printf("Realm: %s, User Name: %s, User ID: %s\n",kcClient.RealmToEdit, user.Username, user.ID)
67+
fmt.Printf("Realm: %s, User Name: %s, User ID: %s\n", realm, user.Username, user.ID)
5768
}
5869
},
5970
}
71+
72+
// Attach the realm flag to the command
73+
usersCmd.Flags().StringVarP(&realm, "realm", "r", "", "Specify the realm to list users")
74+
75+
return usersCmd
6076
}

example-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ client_secret:
44
username: admin
55
password: admin
66
auth_realm: master
7-
realm_to_edit: master
7+
default_realm: master

pkg/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type KeycloakConfig struct {
1111
Username string `mapstructure:"username"`
1212
Password string `mapstructure:"password"`
1313
AuthRealm string `mapstructure:"auth_realm"`
14-
RealmToEdit string `mapstructure:"realm_to_edit"`
14+
DefaultRealm string `mapstructure:"default_realm"`
1515
}
1616

1717
// LoadConfig loads configuration from config.yaml

pkg/config/config_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ func TestLoadConfig(t *testing.T) {
4545
ClientSecret: "secret",
4646
Username: "user",
4747
Password: "pass",
48-
AuthRealm: "realm-test",
49-
RealmToEdit: "realm-test",
48+
AuthRealm: "realm-test",
49+
DefaultRealm: "realm-test",
5050
}
5151

5252
// Compare the result with the expected configuration

pkg/keycloak/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type KeycloakClient struct {
1818
Client *http.Client
1919
Token string
2020
AuthRealm string
21-
RealmToEdit string
21+
DefaultRealm string
2222
}
2323

2424
// NewClient creates a new instance of KeycloakClient
@@ -29,7 +29,7 @@ func NewClient(cfg config.KeycloakConfig) *KeycloakClient {
2929
Timeout: time.Second * 30,
3030
},
3131
AuthRealm: cfg.AuthRealm,
32-
RealmToEdit: cfg.RealmToEdit,
32+
DefaultRealm: cfg.DefaultRealm,
3333
}
3434
}
3535

pkg/keycloak/users.go

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ type User struct {
1717
}
1818

1919
// CreateUser creates a new user in Keycloak
20-
func (kc *KeycloakClient) CreateUser(username, email, password string) error {
20+
func (kc *KeycloakClient) CreateUser(realm, username, email, password string) error {
2121
userDetails := struct {
22-
Username string `json:"username"`
23-
Email string `json:"email"`
22+
Username string `json:"username"`
23+
Email string `json:"email"`
2424
Credentials []struct {
2525
Type string `json:"type"`
2626
Value string `json:"value"`
@@ -35,13 +35,15 @@ func (kc *KeycloakClient) CreateUser(username, email, password string) error {
3535
Temporary bool `json:"temporary"`
3636
}{
3737
{
38-
Type: "password",
39-
Value: password,
38+
Type: "password",
39+
Value: password,
40+
Temporary: false, // Set to true if you want the user to change password on first login
4041
},
4142
},
4243
}
4344

44-
url := fmt.Sprintf("%s/admin/realms/%s/users", kc.BaseURL, kc.RealmToEdit)
45+
// Use the provided realm in the URL instead of the default realm
46+
url := fmt.Sprintf("%s/admin/realms/%s/users", kc.BaseURL, realm)
4547

4648
// Encode the user details as JSON for the request body
4749
jsonBody, err := json.Marshal(userDetails)
@@ -67,15 +69,17 @@ func (kc *KeycloakClient) CreateUser(username, email, password string) error {
6769
// Check for successful status code, typically 201 for creation
6870
if res.StatusCode != http.StatusCreated {
6971
errorResponse, _ := ioutil.ReadAll(res.Body)
70-
return fmt.Errorf("failed to create user, received status code: %d, error message: %s", res.StatusCode, errorResponse)
72+
return fmt.Errorf("failed to create user in realm %s, received status code: %d, error message: %s", realm, res.StatusCode, string(errorResponse))
7173
}
7274

7375
return nil
7476
}
7577

76-
// ListUsers lists all users in Keycloak
77-
func (kc *KeycloakClient) ListUsers() ([]User, error) {
78-
url := fmt.Sprintf("%s/admin/realms/%s/users", kc.BaseURL, kc.RealmToEdit)
78+
79+
func (kc *KeycloakClient) ListUsers(realm string) ([]User, error) {
80+
// Use the provided realm in the URL instead of the default realm
81+
url := fmt.Sprintf("%s/admin/realms/%s/users", kc.BaseURL, realm)
82+
7983
req, err := http.NewRequest("GET", url, nil)
8084
if err != nil {
8185
return nil, err
@@ -97,8 +101,9 @@ func (kc *KeycloakClient) ListUsers() ([]User, error) {
97101
return users, nil
98102
}
99103

100-
func (kc *KeycloakClient) DeleteUser(userID string) error {
101-
url := fmt.Sprintf("%s/admin/realms/%s/users/%s", kc.BaseURL, kc.RealmToEdit, userID)
104+
105+
func (kc *KeycloakClient) DeleteUser(realm, userID string) error {
106+
url := fmt.Sprintf("%s/admin/realms/%s/users/%s", kc.BaseURL, realm, userID)
102107

103108
req, err := http.NewRequest("DELETE", url, nil)
104109
if err != nil {
@@ -112,19 +117,19 @@ func (kc *KeycloakClient) DeleteUser(userID string) error {
112117
}
113118
defer res.Body.Close()
114119

115-
// Check for successful status code, typically 204 for successful deletion
116120
if res.StatusCode != http.StatusNoContent {
117121
errorResponse, _ := ioutil.ReadAll(res.Body)
118-
return fmt.Errorf("failed to delete user, received status code: %d, error message: %s", res.StatusCode, errorResponse)
122+
return fmt.Errorf("failed to delete user in realm %s, received status code: %d, error message: %s", realm, res.StatusCode, string(errorResponse))
119123
}
120124

121125
return nil
122126
}
123127

124128

129+
125130
// GetUserIDByUsername retrieves the userID based on the provided username
126-
func (kc *KeycloakClient) GetUserIDByUsername(username string) (string, error) {
127-
url := fmt.Sprintf("%s/admin/realms/%s/users", kc.BaseURL, kc.RealmToEdit)
131+
func (kc *KeycloakClient) GetUserIDByUsername(realm, username string) (string, error) {
132+
url := fmt.Sprintf("%s/admin/realms/%s/users", kc.BaseURL, realm)
128133

129134
req, err := http.NewRequest("GET", url, nil)
130135
if err != nil {
@@ -140,23 +145,21 @@ func (kc *KeycloakClient) GetUserIDByUsername(username string) (string, error) {
140145

141146
if res.StatusCode != http.StatusOK {
142147
errorResponse, _ := ioutil.ReadAll(res.Body)
143-
return "", fmt.Errorf("failed to retrieve users, received status code: %d, error message: %s", res.StatusCode, errorResponse)
148+
return "", fmt.Errorf("failed to retrieve users from realm %s, received status code: %d, error message: %s", realm, res.StatusCode, string(errorResponse))
144149
}
145150

146-
// Read the response body and parse it as an array of User objects
147151
var users []User
148152
err = json.NewDecoder(res.Body).Decode(&users)
149153
if err != nil {
150154
return "", err
151155
}
152156

153-
// Search for the user with the matching username
154157
for _, user := range users {
155158
if user.Username == username {
156159
return user.ID, nil
157160
}
158161
}
159162

160-
// If no matching user is found, return an error
161-
return "", fmt.Errorf("user with username %s not found in %s realm", username, kc.RealmToEdit)
163+
return "", fmt.Errorf("user with username %s not found in realm %s", username, realm)
162164
}
165+

0 commit comments

Comments
 (0)