Skip to content
Open
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
77 changes: 69 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,63 @@
# Keycloak API CLI Application

The Keycloak API CLI is a command-line tool that allows you to interact with the Keycloak authentication and authorization server. It simplifies the management of Keycloak entities, making it efficient for tasks such as creating users, realms, resources, and roles.

## Table of Contents

- [Keycloak API CLI Application](#keycloak-api-cli-application)
- [Table of Contents](#table-of-contents)
- [Setup and Execution](#setup-and-execution)
- [Available Commands](#available-commands)
- [1. `create`](#1-create)
- [2. `delete`](#2-delete)
- [3. `get`](#3-get)
- [4. `retrieve token`](#4-retrieve-token)
- [5. Root Command](#5-root-command)
- [Additional Notes](#additional-notes)
- [General Overview of Cobra and Viper](#general-overview-of-cobra-and-viper)
- [Cobra and Viper in This Application](#cobra-and-viper-in-this-application)
- [Why This CLI is Useful](#why-this-cli-is-useful)

## Setup and Execution
1. **Install Go** - Ensure Go (version 1.21.4 or higher) is installed.

To get started with the Keycloak API CLI, follow these steps:

1. **Install Go** - Ensure Go (version 1.21.4 or higher) is installed on your system.

2. **Clone the Repository** - Clone the application repository to your local machine.
3. **Install Dependencies** - Run `go mod tidy` in the project directory to install necessary dependencies.
4. **Configuration** - Edit the `config.yaml` file with appropriate Keycloak server details and credentials.
5. **Build the Application** - Run `go build .` in the project directory to build the executable.
6. **Make the Build Executable** - Use `chmod +x keycloak-api-cli` (or the name of your built executable) to make it executable.
7. **Running the Application** - Execute the built application. Use `./keycloak-api-cli --config path/to/config.yaml` to specify the configuration file.

3. **Install Dependencies** - Run the following command in the project directory to install the necessary dependencies:

```bash
go mod tidy
```

4. **Configuration** - Edit the `config.yaml` file with the appropriate Keycloak server details and credentials.

5. **Build the Application** - Run the following command in the project directory to build the executable:

```bash
go build .
```

6. **Make the Build Executable** - Use the following command to make the executable file executable:

```bash
chmod +x keycloak-api-cli
```

7. **Running the Application** - Execute the built application. You can specify the configuration file using the `--config` flag. Example usage:

```bash
./keycloak-api-cli --config path/to/config.yaml
```

## Available Commands

The Keycloak API CLI provides several commands to interact with Keycloak entities. Here are the available commands:

### 1. `create`

- **Usage**: `create [user, realm, resource, role]`
- **Description**: Creates various entities in Keycloak.
- **Subcommands**:
Expand All @@ -22,6 +68,7 @@
- **Example**: `./keycloak-api-cli create realm --config path/to/config.yaml`

### 2. `delete`

- **Usage**: `delete [user, realm, resource, role]`
- **Description**: Deletes entities in Keycloak.
- **Subcommands**:
Expand All @@ -32,6 +79,7 @@
- **Example**: `./keycloak-api-cli delete realm --config path/to/config.yaml`

### 3. `get`

- **Usage**: `get [users, realms, resources, roles]`
- **Description**: Retrieves information about entities in Keycloak.
- **Subcommands**:
Expand All @@ -41,10 +89,23 @@
- `get realms`: Lists all realms.
- **Example**: `./keycloak-api-cli get realms --config path/to/config.yaml`

### 4. Root Command
### 4. `retrieve token`

- **Usage**: `retrieve token`
- **Description**: Retrieves an authentication token from Keycloak.
- **Flags**:
- `-c, --config`: Specifies the path to the configuration file (e.g., `path/to/config.yaml`).

Example usage:

```bash
./keycloak-api-cli retrieve token --config example-config.yaml
```

### 5. Root Command
- **Usage**: `keycloak-api-cli`
- **Description**: Base command for Keycloak API interactions.
- **Integrated Commands**: Includes `create`, `delete`, and `get`.
- **Integrated Commands**: Includes `create`, `delete`, `get` and `retrieve token`.
- **Example**: `./keycloak-api-cli --help`

## Additional Notes
Expand Down
2 changes: 0 additions & 2 deletions cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ func GetCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
return GetCommand
}



// List Realm
func GetRealmCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
return &cobra.Command{
Expand Down
35 changes: 35 additions & 0 deletions cmd/retrieve-token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cmd

import (
"fmt"
"keycloak-api-cli/pkg/keycloak"

"github.com/spf13/cobra"
)


// GetCommand creates and returns a new list command
func RetrieveCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
RetrieveCommand := &cobra.Command{
Use: "retrieve [token]",
Short: "retrieve token in Keycloak",
}
RetrieveCommand.AddCommand(RetrieveTokenCommand(kcClient))

return RetrieveCommand
}

// Retrieve Token Command
func RetrieveTokenCommand(kcClient *keycloak.KeycloakClient) *cobra.Command {
return &cobra.Command{
Use: "token",
Short: "Retrieve token in Keycloak",
Run: func(cmd *cobra.Command, args []string) {
if kcClient.Token == "" {
fmt.Println("Error: Token doesn't exist")
return
}
fmt.Printf(kcClient.Token)
},
}
}
25 changes: 10 additions & 15 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var rootCmd = &cobra.Command{
}

func Execute(kcClient *keycloak.KeycloakClient) {
rootCmd.AddCommand(RetrieveCommand(kcClient))
rootCmd.AddCommand(GetCommand(kcClient))
rootCmd.AddCommand(CreateCommand(kcClient))
rootCmd.AddCommand(DeleteCommand(kcClient))
Expand All @@ -35,31 +36,25 @@ func Execute(kcClient *keycloak.KeycloakClient) {
}

func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "./config.yaml", "config file (default is $HOME/.keycloak-api-cli.yaml)")

cobra.OnInitialize(initConfig)
// Set the default to an empty string
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
}

func initConfig() {

if cfgFile != "" {
fmt.Println("Using config file:", cfgFile)
// Use the specified config file
fmt.Println("Using specified config file:", cfgFile)
viper.SetConfigFile(cfgFile)
} else {
home, err := os.UserHomeDir()
if err != nil {
fmt.Println("Unable to find home directory:", err)
os.Exit(1)
}
fmt.Println("Looking for config file in home directory:", home)
viper.AddConfigPath(home)
viper.SetConfigName("config.yaml")
defaultConfig := "./config.yaml"
fmt.Println("Using default config file:", defaultConfig)
viper.SetConfigFile(defaultConfig)
}

viper.AutomaticEnv()

err := viper.ReadInConfig()
if err != nil {
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Failed to read config file:", err)
os.Exit(1)
} else {
Expand Down
2 changes: 1 addition & 1 deletion example-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
url: http://localhost:8080/auth
url: http://localhost:8080
client_id: admin-cli
client_secret:
username: admin
Expand Down
18 changes: 12 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
package main

import (
"flag"
"log"
"keycloak-api-cli/cmd"
"keycloak-api-cli/pkg/keycloak"
"keycloak-api-cli/pkg/config"
)

func main() {
// Load your configuration (modify as per your configuration logic)
cfg, err := config.LoadConfig()
// Define a command-line flag for the config file
var cfgFile string
flag.StringVar(&cfgFile, "config", "config.yaml", "path to config file")
flag.Parse()

// Load your configuration using the specified config file
cfg, err := config.LoadConfig(cfgFile)
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}

// Initialize Keycloak client
kcClient := keycloak.NewClient(cfg)
err = kcClient.Authenticate(cfg)
if err != nil {
log.Fatalf("Failed to authenticate: %v", err)
}
err = kcClient.Authenticate(cfg)
if err != nil {
log.Fatalf("Failed to authenticate: %v", err)
}

// Execute the root command with the Keycloak client
cmd.Execute(kcClient)
Expand Down
18 changes: 11 additions & 7 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"fmt"
"github.com/spf13/viper"
)

Expand All @@ -15,17 +16,20 @@ type KeycloakConfig struct {
}

// LoadConfig loads configuration from config.yaml
func LoadConfig() (KeycloakConfig, error) {
func LoadConfig(configFile string) (KeycloakConfig, error) {
var config KeycloakConfig

// Set default configurations
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.SetConfigFile(configFile) // Set the configuration file
viper.AutomaticEnv()

if err := viper.ReadInConfig(); err != nil {
return config, err
return config, fmt.Errorf("failed to load config file '%s': %v", configFile, err)
}

err := viper.Unmarshal(&config)
return config, err
}
if err != nil {
return config, fmt.Errorf("error unmarshalling config: %v", err)
}

return config, nil
}