-
Notifications
You must be signed in to change notification settings - Fork 119
[WIP] Add Keycloak with Postgres integration #811
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
base: main
Are you sure you want to change the base?
Conversation
- Introduced a new project `CommunityToolkit.Aspire.Keycloak.Postgress` for configuring Keycloak with PostgreSQL. - Added an extension method to simplify Keycloak and Postgres database resource integration. - Updated solution and package references for Aspire dependencies.
Did you test this? |
- Enhanced parameter descriptions in XML documentation. - Updated method to support asynchronous operations. - Introduced additional environment variables for finer-grained database configuration. - Added cancellation token support for improved task management.
I have some problems, i can't access host, can you help me? |
- Simplified XML documentation and parameter descriptions. - Removed exceptions for parent resource validation. - Replaced manual environment variable setup with connection string parsing using `NpgsqlConnectionStringBuilder`. - Introduced optional port parameter for database configuration.
Now it working |
Its worth reading this https://github.com/dotnet/aspire/blob/main/docs/specs/appmodel.md#values-and-references |
Directory.Packages.props
Outdated
@@ -4,12 +4,13 @@ | |||
</PropertyGroup> | |||
<ItemGroup Label="Aspire Packages"> | |||
<!-- Aspire packages --> | |||
<PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" /> | |||
<PackageVersion Include="Aspire.Hosting" Version="9.4.1" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is just done when you were testing, but ensure you roll that back and use the MSBuild variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had error
0>CommunityToolkit.Aspire.Keycloak.Postgres.csproj: Error NU1605 : Warning As Error: Detected package downgrade: Aspire.Hosting from 9.4.1 to 9.4.0. Reference the package directly from the project to select a different version.
CommunityToolkit.Aspire.Keycloak.Postgres -> Aspire.Hosting.Keycloak 9.4.1-preview.1.25408.4 -> Aspire.Hosting (>= 9.4.1)
CommunityToolkit.Aspire.Keycloak.Postgres -> Aspire.Hosting (>= 9.4.0)
0>------- Finished building project: CommunityToolkit.Aspire.Keycloak.Postgres. Succeeded: False. Errors: 1. Warnings: 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main
branch is now updated to 9.4.1 Aspire.
Once there are tests and samples, we can get started on a review of the work. |
This implemenaton needs work:
See dotnet/aspire#8034 for more details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package name should be CommunityToolkit.Aspire.Keycloak.Extensions
, like other extension packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package name should be CommunityToolkit.Aspire.Keycloak.Extensions
, like other extension packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can i name it like CommunityToolkit.Aspire.Keycloak.Extensions.Postgres
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there may be other providers here.
src/CommunityToolkit.Aspire.Keycloak.Postgress/KeycloakPostgresExtension.cs
Outdated
Show resolved
Hide resolved
…sExtension.cs Co-authored-by: Alireza Baloochi <[email protected]>
- Renamed `CommunityToolkit.Aspire.Keycloak.Postgress` to `CommunityToolkit.Aspire.Keycloak.Extensions.Postgres`. - Refactored methods to improve flexibility, including support for different configurations (e.g., development, credentials). - Introduced a dedicated test project `CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.Tests`. - Updated solution, dependencies, and project references accordingly.
I updated, add event as dev and add parameters for production |
/// <returns> | ||
/// The updated resource builder for the Keycloak resource. | ||
/// </returns> | ||
private static void WithPostgres(this IResourceBuilder<KeycloakResource> builder, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will work with dev and production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean void? After that, you can't add other methods, so I returned IResourceBuilder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I mean that this approach using expressions works in both cases and you don’t need 2 implementations for run and publish
/// <returns> | ||
/// The updated resource builder for the Keycloak resource. | ||
/// </returns> | ||
public static IResourceBuilder<KeycloakResource> WithPostgresDev(this IResourceBuilder<KeycloakResource> builder, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need this overload at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You said that event will not work in prod, so I thought that this i will leave for the development environment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right so you don’t need this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be conditional logic to check for the different modes rather than having to call different methods.
$"jdbc:postgresql://{ep.Property(EndpointProperty.Host)}:" + | ||
$"{ep.Property(EndpointProperty.Port)}/{dbName}"); | ||
|
||
builder.WithEnvironment("KC_DB", "postgres") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? Why is this hard coded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if postgres is password protected (which is the default).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
builder.WithEnvironment("KC_DB", "postgres")
You about this? Yeah, it's correct. There are other database vendors, but I'm writing for postgres
All environment variables: https://www.keycloak.org/server/all-config
I wanna make for other vendors such as dev-file (default), dev-mem, mariadb, mssql, mysql, oracle, postgres
(all vendors that support)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if postgres is password protected (which is the default).
public static IResourceBuilder<KeycloakResource> WithPostgres(this IResourceBuilder<KeycloakResource> builder,
IResourceBuilder<PostgresDatabaseResource> database, ParameterResource username, ParameterResource password)
{
ArgumentNullException.ThrowIfNull(username);
ArgumentNullException.ThrowIfNull(password);
WithPostgres(builder, database);
builder.WithEnvironment("KC_DB_USERNAME", username)
.WithEnvironment("KC_DB_PASSWORD", password);
return builder;
}
Here I'm setting by parameter that will set up from user, or what you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a hosting integration by the looks of it, so the project should reflect that.
Also, let's just make it Keycloak.Extensions
so it's not PG specific, as that'll allow for other extensions on Keycloack to be included in here rather than going through a bunch of micro packages.
...ire.Keycloak.Extensions.Postgres/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.csproj
Outdated
Show resolved
Hide resolved
/// <returns> | ||
/// The updated resource builder for the Keycloak resource. | ||
/// </returns> | ||
public static IResourceBuilder<KeycloakResource> WithPostgresDev(this IResourceBuilder<KeycloakResource> builder, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be conditional logic to check for the different modes rather than having to call different methods.
<PropertyGroup> | ||
<TargetFramework>net9.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<IsPackable>false</IsPackable> | ||
</PropertyGroup> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These aren't needed as they are inherited. Check the other test projects and follow their patterns
<PackageReference Include="coverlet.collector" Version="6.0.2"/> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/> | ||
<PackageReference Include="xunit" Version="2.9.2"/> | ||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These will fail the build as CPM dictates versions
Directory.Packages.props
Outdated
@@ -4,12 +4,13 @@ | |||
</PropertyGroup> | |||
<ItemGroup Label="Aspire Packages"> | |||
<!-- Aspire packages --> | |||
<PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" /> | |||
<PackageVersion Include="Aspire.Hosting" Version="9.4.1" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main
branch is now updated to 9.4.1 Aspire.
<PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireVersion)" /> | ||
<PackageVersion Include="Aspire.Hosting.Azure.Storage" Version="$(AspireVersion)" /> | ||
<PackageVersion Include="Aspire.Hosting.Dapr" Version="$(AspireVersion)" /> | ||
<PackageVersion Include="Aspire.Hosting.Azure.AppContainers" Version="$(AspireVersion)" /> | ||
<PackageVersion Include="Aspire.Hosting.Azure.Redis" Version="$(AspireVersion)" /> | ||
<PackageVersion Include="Aspire.Hosting.Keycloak" Version="9.4.1-preview.1.25408.4" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to introduce a MSBuild variable for the preview version of Aspire packages.
Directory.Packages.props
Outdated
@@ -18,6 +19,7 @@ | |||
<PackageVersion Include="Aspire.Hosting.MongoDB" Version="$(AspireVersion)" /> | |||
<PackageVersion Include="Aspire.Hosting.MySql" Version="$(AspireVersion)" /> | |||
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="$(AspireVersion)" /> | |||
<PackageVersion Include="Moq" Version="4.20.72" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be under the Testing
item group
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new Keycloak-PostgreSQL integration that enables configuring Keycloak resources to use PostgreSQL databases within Aspire applications. The integration provides extension methods to set up the necessary JDBC connection strings and environment variables required by Keycloak to connect to PostgreSQL databases.
- Extension methods for integrating Keycloak with PostgreSQL databases
- Support for both development and production scenarios with different credential handling approaches
- Package reference updates to align with Aspire 9.4.1 dependencies
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
src/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres/KeycloakPostgresExtension.cs | Core extension methods for Keycloak-PostgreSQL integration |
src/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.csproj | Project file with necessary Aspire package references |
tests/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.Tests/KeycloakExtensionPostgressTests.cs | Empty test class placeholder |
tests/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.Tests/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.Tests.csproj | Test project configuration |
Directory.Packages.props | Updated Aspire package versions and added new dependencies |
CommunityToolkit.Aspire.slnx | Solution file updated with new projects |
src/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres/KeycloakPostgresExtension.cs
Outdated
Show resolved
Hide resolved
src/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres/KeycloakPostgresExtension.cs
Outdated
Show resolved
Hide resolved
src/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres/KeycloakPostgresExtension.cs
Outdated
Show resolved
Hide resolved
builder.WithEnvironment("KC_DB", "postgres") | ||
.WithEnvironment("KC_DB", "postgres") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The environment variable 'KC_DB' is being set twice with the same value 'postgres'. Remove the duplicate line 68.
builder.WithEnvironment("KC_DB", "postgres") | |
.WithEnvironment("KC_DB", "postgres") |
Copilot uses AI. Check for mistakes.
…oakPostgresExtension.cs Co-authored-by: Copilot <[email protected]>
…oakPostgresExtension.cs Co-authored-by: Copilot <[email protected]>
…oakPostgresExtension.cs Co-authored-by: Copilot <[email protected]>
public static IResourceBuilder<KeycloakResource> WithPostgres(this IResourceBuilder<KeycloakResource> builder,
IDistributedApplicationBuilder appBuilder, bool xaEnabled = false,
string usernameParameter = "keycloak-username", string databaseName = "keycloak-db",
string postgrsName = "keycloak-postgres")
{
var username = appBuilder.AddParameter(usernameParameter, "keycloak-db-user");
var pwd = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(appBuilder, "pg-pass");
var password = appBuilder.CreateResourceBuilder(pwd);
var keycloakPostgres = appBuilder.AddPostgres(postgrsName, username, password);
var db = keycloakPostgres.AddDatabase(databaseName);
builder.WithPostgres(db, username, password, xaEnabled)
.WithReference(db)
.WaitFor(keycloakPostgres);
return builder;
} What you think about this method for easy dev environment? |
builder.WithEnvironment("KC_DB_USERNAME", username.Resource); | ||
builder.WithEnvironment("KC_DB_PASSWORD", password.Resource); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you get these from the database.Parent instead? This overload is about using an existing postgres right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but i need to make task method with async/await. Will it be fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need a task. Look at how the existing postgres integrations work in this project e.g.
Aspire/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs
Line 38 in c7dedf1
public static IResourceBuilder<PostgresServerResource> WithDbGate(this IResourceBuilder<PostgresServerResource> builder, Action<IResourceBuilder<DbGateContainerResource>>? configureContainer = null, string? containerName = null) |
You can see this dbgate extension resolving the username password and endpoints:
Aspire/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs
Lines 108 to 119 in c7dedf1
var userParameter = postgresServer.UserNameParameter is null | |
? ReferenceExpression.Create($"postgres") | |
: ReferenceExpression.Create($"{postgresServer.UserNameParameter}"); | |
// DbGate assumes Postgres is being accessed over a default Aspire container network and hardcodes the resource address | |
// This will need to be refactored once updated service discovery APIs are available | |
context.EnvironmentVariables.Add($"LABEL_postgres{counter}", postgresServer.Name); | |
context.EnvironmentVariables.Add($"SERVER_postgres{counter}", postgresServer.Name); | |
context.EnvironmentVariables.Add($"USER_postgres{counter}", userParameter); | |
context.EnvironmentVariables.Add($"PASSWORD_postgres{counter}", postgresServer.PasswordParameter); | |
context.EnvironmentVariables.Add($"PORT_postgres{counter}", postgresServer.PrimaryEndpoint.TargetPort!.ToString()!); | |
context.EnvironmentVariables.Add($"ENGINE_postgres{counter}", "postgres@dbgate-plugin-postgres"); |
Since you care about this working when deployed as well, you don't need to change the endpoint resolution logic, but you can get the username and password from the postgres server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, i see
…ts/CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.Tests.csproj Co-authored-by: David Fowler <[email protected]>
…ibility - Extracted `WithPostgresData` helper method to reduce redundant code. - Improved default credential handling for Username and Password parameters. - Updated XML documentation for clarity and consistency.
- Removed `CommunityToolkit.Aspire.Keycloak.Extensions.Postgres.Tests`. - Added `WithPostgres` tests to `CommunityToolkit.Aspire.Keycloak.Extensions.Tests`. - Updated solution and project references to reflect restructuring.
- Introduced detailed `README.md` explaining the Keycloak PostgreSQL Aspire extension's features, usage, and API. - Added extensive unit tests in `KeycloakExtensionTests` for validating default credentials, explicit parameters, server parameters, and XA transaction enablement. - Refactored `WithPostgres` method to streamline environment variable configuration and enhance maintainability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR needs an example (like other integrations) and integration tests.
…rameter expectations
…eferences - Introduced `KeycloakWithPostgresIntegrationTest` for verifying Keycloak's behavior with PostgreSQL. - Updated `WithPostgres` method to include a wait condition for database readiness. - Added project reference to `CommunityToolkit.Aspire.Testing` for testing utilities.
I added integration tests and there readme file with examples already exists |
@max2020204 I think @Alirexaa means a runnable sample in the playground, not just a readme. |
Oh, Okey |
- Added example projects under `examples/keycloak-postgres` for showcasing Keycloak integration with PostgreSQL in development and production environments. - Introduced `AppHost` projects with service defaults for common functionalities like OpenTelemetry, resilience, and health checks. - Updated `CommunityToolkit.Aspire.Keycloak.Extensions` with a description and additional package tags for better discoverability. - Registered the new example projects in the solution file.
- Added conditional handling for `RequireHttpsMetadata` in development environments for both Dev and Prod projects. - Updated `Aspire.Hosting` and `Aspire.Keycloak.Authentication` package versions to 9.4.2. - Standardized XML formatting across example project files.
- Switched `Aspire.Hosting` and related package versions to reference `$(AspireVersion)` for consistency. - Downgraded `Aspire.Keycloak.Authentication` from `9.4.2-preview.1.25428.12` to `9.4.1-preview.1.25408.4`.
This PR introduces a new integration project that makes it easier to configure Keycloak to run with a Postgres database in Aspire-based applications.
Summary of changes
Added new project CommunityToolkit.Aspire.Keycloak.Postgres.
Implemented an extension method AddPostgres for IResourceBuilder to configure Keycloak with Postgres database resources:
Sets required environment variables (KC_DB, KC_DB_URL_*, KC_DB_USERNAME, KC_DB_PASSWORD, KC_TRANSACTION_XA_ENABLED).
Includes validation for missing or invalid Postgres server configuration.
Updated solution and package references to align with Aspire 9.4.1 dependencies.
Other information
Project name normalized to Postgres for correctness and consistency.
Extension method returns IResourceBuilder to allow chaining.
Uses proper IValueExpression instead of ToString() for connection strings.
Ensures JDBC-compatible environment variables for Keycloak.