Skip to content

feat: add admin url variable to separate authn and admin api urls #1129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ The following arguments are supported:

- `client_id` - (Required) The `client_id` for the client that was created in the "Keycloak Setup" section. Use the `admin-cli` client if you are using the password grant. Defaults to the environment variable `KEYCLOAK_CLIENT_ID`.
- `url` - (Required) The URL of the Keycloak instance, before `/auth/admin`. Defaults to the environment variable `KEYCLOAK_URL`.
- `admin_url` - (Optional) The admin URL of the Keycloak instance if different from the main URL, before `/auth/admin`. Defaults to the environment variable `KEYCLOAK_ADMIN_URL`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `admin_url` - (Optional) The admin URL of the Keycloak instance if different from the main URL, before `/auth/admin`. Defaults to the environment variable `KEYCLOAK_ADMIN_URL`.
- `admin_url` - (Optional) The admin URL of the Keycloak instance if different from the base URL, before `/auth/admin`. Defaults to the environment variable `KEYCLOAK_ADMIN_URL`.

- `client_secret` - (Optional) The secret for the client used by the provider for authentication via the client credentials grant. This can be found or changed using the "Credentials" tab in the client settings. Defaults to the environment variable `KEYCLOAK_CLIENT_SECRET`. This attribute is required when using the client credentials grant, and cannot be set when using the password grant.
- `username` - (Optional) The username of the user used by the provider for authentication via the password grant. Defaults to the environment variable `KEYCLOAK_USER`. This attribute is required when using the password grant, and cannot be set when using the client credentials grant.
- `password` - (Optional) The password of the user used by the provider for authentication via the password grant. Defaults to the environment variable `KEYCLOAK_PASSWORD`. This attribute is required when using the password grant, and cannot be set when using the client credentials grant.
Expand Down
15 changes: 10 additions & 5 deletions keycloak/keycloak_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

type KeycloakClient struct {
baseUrl string
authnUrl string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
authnUrl string
authUrl string

realm string
clientCredentials *ClientCredentials
httpClient *http.Client
Expand Down Expand Up @@ -60,7 +61,7 @@ var redHatSSO7VersionMap = map[int]string{
4: "9.0.17",
}

func NewKeycloakClient(ctx context.Context, url, basePath, clientId, clientSecret, realm, username, password string, initialLogin bool, clientTimeout int, caCert string, tlsInsecureSkipVerify bool, userAgent string, redHatSSO bool, additionalHeaders map[string]string) (*KeycloakClient, error) {
func NewKeycloakClient(ctx context.Context, url, basePath, adminUrl, clientId, clientSecret, realm, username, password string, initialLogin bool, clientTimeout int, caCert string, tlsInsecureSkipVerify bool, userAgent string, redHatSSO bool, additionalHeaders map[string]string) (*KeycloakClient, error) {
clientCredentials := &ClientCredentials{
ClientId: clientId,
ClientSecret: clientSecret,
Expand All @@ -83,9 +84,13 @@ func NewKeycloakClient(ctx context.Context, url, basePath, clientId, clientSecre
if err != nil {
return nil, fmt.Errorf("failed to create http client: %v", err)
}

baseUrl := url + basePath
if adminUrl != "" {
baseUrl = adminUrl + basePath
}
Comment on lines +87 to +90
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
baseUrl := url + basePath
if adminUrl != "" {
baseUrl = adminUrl + basePath
}
authUrl := url + basePath
baseUrl := authUrl
if adminUrl != "" {
baseUrl = adminUrl + basePath
}

keycloakClient := KeycloakClient{
baseUrl: url + basePath,
baseUrl: baseUrl,
authnUrl: url + basePath,
Comment on lines +92 to +93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
baseUrl: baseUrl,
authnUrl: url + basePath,
baseUrl: baseUrl,
authUrl: authUrl,

clientCredentials: clientCredentials,
httpClient: httpClient,
initialLogin: initialLogin,
Expand All @@ -112,7 +117,7 @@ func NewKeycloakClient(ctx context.Context, url, basePath, clientId, clientSecre
}

func (keycloakClient *KeycloakClient) login(ctx context.Context) error {
accessTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.baseUrl, keycloakClient.realm)
accessTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.authnUrl, keycloakClient.realm)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
accessTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.authnUrl, keycloakClient.realm)
accessTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.authUrl, keycloakClient.realm)

accessTokenData := keycloakClient.getAuthenticationFormData()

tflog.Debug(ctx, "Login request", map[string]interface{}{
Expand Down Expand Up @@ -203,7 +208,7 @@ func (keycloakClient *KeycloakClient) login(ctx context.Context) error {
}

func (keycloakClient *KeycloakClient) Refresh(ctx context.Context) error {
refreshTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.baseUrl, keycloakClient.realm)
refreshTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.authnUrl, keycloakClient.realm)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
refreshTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.authnUrl, keycloakClient.realm)
refreshTokenUrl := fmt.Sprintf(tokenUrl, keycloakClient.authUrl, keycloakClient.realm)

refreshTokenData := keycloakClient.getAuthenticationFormData()

tflog.Debug(ctx, "Refresh request", map[string]interface{}{
Expand Down
2 changes: 1 addition & 1 deletion keycloak/keycloak_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestAccKeycloakApiClientRefresh(t *testing.T) {
t.Fatal("KEYCLOAK_CLIENT_TIMEOUT must be an integer")
}

keycloakClient, err := NewKeycloakClient(ctx, os.Getenv("KEYCLOAK_URL"), "", os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), os.Getenv("KEYCLOAK_USER"), os.Getenv("KEYCLOAK_PASSWORD"), true, clientTimeout, "", false, "", false, map[string]string{
keycloakClient, err := NewKeycloakClient(ctx, os.Getenv("KEYCLOAK_URL"), "", os.Getenv("KEYCLOAK_ADMIN_URL"), os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), os.Getenv("KEYCLOAK_USER"), os.Getenv("KEYCLOAK_PASSWORD"), true, clientTimeout, "", false, "", false, map[string]string{
"foo": "bar",
})
if err != nil {
Expand Down
9 changes: 8 additions & 1 deletion provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ func KeycloakProvider(client *keycloak.KeycloakClient) *schema.Provider {
Description: "The base URL of the Keycloak instance, before `/auth`",
DefaultFunc: schema.EnvDefaultFunc("KEYCLOAK_URL", nil),
},
"admin_url": {
Optional: true,
Type: schema.TypeString,
Description: "The admin URL of the Keycloak instance if different from the main URL, before `/auth`",
DefaultFunc: schema.EnvDefaultFunc("KEYCLOAK_ADMIN_URL", nil),
},
"initial_login": {
Optional: true,
Type: schema.TypeBool,
Expand Down Expand Up @@ -207,6 +213,7 @@ func KeycloakProvider(client *keycloak.KeycloakClient) *schema.Provider {

url := data.Get("url").(string)
basePath := data.Get("base_path").(string)
adminUrl := data.Get("admin_url").(string)
clientId := data.Get("client_id").(string)
clientSecret := data.Get("client_secret").(string)
username := data.Get("username").(string)
Expand All @@ -226,7 +233,7 @@ func KeycloakProvider(client *keycloak.KeycloakClient) *schema.Provider {

userAgent := fmt.Sprintf("HashiCorp Terraform/%s (+https://www.terraform.io) Terraform Plugin SDK/%s", provider.TerraformVersion, meta.SDKVersionString())

keycloakClient, err := keycloak.NewKeycloakClient(ctx, url, basePath, clientId, clientSecret, realm, username, password, initialLogin, clientTimeout, rootCaCertificate, tlsInsecureSkipVerify, userAgent, redHatSSO, additionalHeaders)
keycloakClient, err := keycloak.NewKeycloakClient(ctx, url, basePath, adminUrl, clientId, clientSecret, realm, username, password, initialLogin, clientTimeout, rootCaCertificate, tlsInsecureSkipVerify, userAgent, redHatSSO, additionalHeaders)
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Expand Down
2 changes: 1 addition & 1 deletion provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func init() {
}
}

keycloakClient, err = keycloak.NewKeycloakClient(testCtx, os.Getenv("KEYCLOAK_URL"), "", os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), "", "", true, 5, "", false, userAgent, false, map[string]string{
keycloakClient, err = keycloak.NewKeycloakClient(testCtx, os.Getenv("KEYCLOAK_URL"), "", os.Getenv("KEYCLOAK_ADMIN_URL"), os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), "", "", true, 5, "", false, userAgent, false, map[string]string{
"foo": "bar",
})
if err != nil {
Expand Down
Loading