Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
michalvavrik committed Sep 26, 2023
1 parent 1e3a64b commit 2b4e25d
Show file tree
Hide file tree
Showing 40 changed files with 1,483 additions and 14 deletions.
10 changes: 10 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,16 @@
<artifactId>quarkus-oidc-token-propagation-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-db-token-state-manager</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-db-token-state-manager-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-token-propagation-reactive</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,9 @@ public interface Capability {

String CACHE = QUARKUS_PREFIX + ".cache";
String JDBC_ORACLE = QUARKUS_PREFIX + ".jdbc.oracle";
String REACTIVE_PG_CLIENT = QUARKUS_PREFIX + ".reactive-pg-client";
String REACTIVE_ORACLE_CLIENT = QUARKUS_PREFIX + ".reactive-oracle-client";
String REACTIVE_MYSQL_CLIENT = QUARKUS_PREFIX + ".reactive-mysql-client";
String REACTIVE_MSSQL_CLIENT = QUARKUS_PREFIX + ".reactive-mssql-client";
String REACTIVE_DB2_CLIENT = QUARKUS_PREFIX + ".reactive-db2-client";
}
13 changes: 13 additions & 0 deletions devtools/bom-descriptor-json/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,19 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-db-token-state-manager</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-token-propagation</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,19 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-db-token-state-manager-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-token-propagation-deployment</artifactId>
Expand Down
99 changes: 99 additions & 0 deletions extensions/oidc-db-token-state-manager/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-oidc-db-token-state-manager-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-oidc-db-token-state-manager-deployment</artifactId>
<name>Quarkus - OpenID Connect Database Token State Manager - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-db-token-state-manager</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-deployment</artifactId>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>test-keycloak</id>
<activation>
<property>
<name>test-containers</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>false</skip>
<systemPropertyVariables>
<mssql.image>${mssql.image}</mssql.image>
<db2.image>${db2.image}</db2.image>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.oidc.db.token.state.manager;

import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

@ConfigMapping(prefix = "quarkus.oidc-db-token-state-manager")
@ConfigRoot
public interface OidcDbTokenStateManagerBuildTimeConfig {

/**
* Whether token state should be stored in the database.
*/
@WithDefault("true")
boolean enabled();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package io.quarkus.oidc.db.token.state.manager;

import static io.quarkus.deployment.Capability.REACTIVE_DB2_CLIENT;
import static io.quarkus.deployment.Capability.REACTIVE_MSSQL_CLIENT;
import static io.quarkus.deployment.Capability.REACTIVE_MYSQL_CLIENT;
import static io.quarkus.deployment.Capability.REACTIVE_ORACLE_CLIENT;
import static io.quarkus.deployment.Capability.REACTIVE_PG_CLIENT;
import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT;

import java.util.function.BooleanSupplier;

import jakarta.enterprise.context.Dependent;
import jakarta.inject.Singleton;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeansRuntimeInitBuildItem;
import io.quarkus.arc.deployment.ValidationPhaseBuildItem;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.annotations.Consume;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.RuntimeConfigSetupCompleteBuildItem;
import io.quarkus.oidc.TokenStateManager;
import io.quarkus.oidc.db.token.state.manager.runtime.OidcDbTokenStateManager;
import io.quarkus.oidc.db.token.state.manager.runtime.OidcDbTokenStateManagerInitializer;
import io.quarkus.oidc.db.token.state.manager.runtime.OidcDbTokenStateManagerInitializer.OidcDbTokenStateManagerInitializerProperties;
import io.quarkus.oidc.db.token.state.manager.runtime.OidcDbTokenStateManagerRecorder;
import io.quarkus.runtime.configuration.ConfigurationException;

@BuildSteps(onlyIf = OidcDbTokenStateManagerProcessor.OidcDbTokenStateManagerEnabled.class)
public class OidcDbTokenStateManagerProcessor {

private static final String[] SUPPORTED_REACTIVE_CLIENTS = new String[] { REACTIVE_PG_CLIENT, REACTIVE_MYSQL_CLIENT,
REACTIVE_MSSQL_CLIENT, REACTIVE_DB2_CLIENT, REACTIVE_ORACLE_CLIENT };

@Record(STATIC_INIT)
@BuildStep
SyntheticBeanBuildItem produceDbTokenStateManagerBean(OidcDbTokenStateManagerRecorder recorder,
ReactiveSqlClientBuildItem sqlClientBuildItem) {
boolean isMySQL = false;
final String insertStatement;
switch (sqlClientBuildItem.reactiveClient) {
case REACTIVE_PG_CLIENT:
insertStatement = "INSERT INTO oidc_db_token_state_manager (id_token, access_token, refresh_token, expires_in) VALUES ($1, $2, $3, $4) RETURNING id";
break;
case REACTIVE_MYSQL_CLIENT:
isMySQL = true;
insertStatement = "INSERT INTO oidc_db_token_state_manager (id_token, access_token, refresh_token, expires_in) VALUES (?, ?, ?, ?)";
break;
case REACTIVE_MSSQL_CLIENT:
insertStatement = "INSERT INTO oidc_db_token_state_manager (id_token, access_token, refresh_token, expires_in) OUTPUT INSERTED.id VALUES (@p1, @p2, @p3, @p4)";
break;
case REACTIVE_DB2_CLIENT:
insertStatement = "SELECT id FROM FINAL TABLE (INSERT INTO oidc_db_token_state_manager (id_token, access_token, refresh_token, expires_in) VALUES (?, ?, ?, ?))";
break;
case REACTIVE_ORACLE_CLIENT:
// FIXME: make this optimal with io.vertx.oracleclient.OraclePrepareOptions.setAutoGeneratedKeysIndexes
// once on Oracle 24.x driver (as 23.4.0.0 will probably not be available for community)
// see https://github.com/eclipse-vertx/vertx-sql-client/issues/1343 for more info
insertStatement = "SELECT INSERT_TOKENS(?, ?, ?, ?) FROM DUAL";
break;
default:
throw new RuntimeException("Unknown Reactive Sql Client " + sqlClientBuildItem.reactiveClient);
}
return SyntheticBeanBuildItem
.configure(OidcDbTokenStateManager.class)
.alternative(true)
.priority(1)
.addType(TokenStateManager.class)
.unremovable()
.scope(Singleton.class)
.supplier(recorder.createTokenStateManager(insertStatement, isMySQL))
.done();
}

@BuildStep
ReactiveSqlClientBuildItem validateReactiveSqlClient(
BuildProducer<ValidationPhaseBuildItem.ValidationErrorBuildItem> validationErrors,
Capabilities capabilities) {
ReactiveSqlClientBuildItem sqlClientDbTable = null;
for (String reactiveClient : SUPPORTED_REACTIVE_CLIENTS) {
if (capabilities.isPresent(reactiveClient)) {
if (sqlClientDbTable == null) {
sqlClientDbTable = new ReactiveSqlClientBuildItem(reactiveClient);
} else {
validationErrors.produce(new ValidationPhaseBuildItem.ValidationErrorBuildItem(
new ConfigurationException("The OpenID Connect Database Token State Manager extension is "
+ "only supported when exactly one Reactive SQL Client extension is present.")));
return null;
}
}
}
if (sqlClientDbTable == null) {
validationErrors.produce(new ValidationPhaseBuildItem.ValidationErrorBuildItem(new ConfigurationException(
"The OpenID Connect Database Token State Manager extension requires Reactive SQL Client extension. "
+ "Please refer to the https://quarkus.io/guides/reactive-sql-clients for more information.")));
}
return sqlClientDbTable;
}

@BuildStep
AdditionalBeanBuildItem makeDbTokenStateManagerInitializerBean() {
return new AdditionalBeanBuildItem(OidcDbTokenStateManagerInitializer.class);
}

@BuildStep
@Record(STATIC_INIT)
SyntheticBeanBuildItem createDbTokenStateInitializerProps(ReactiveSqlClientBuildItem sqlClientBuildItem,
OidcDbTokenStateManagerRecorder recorder) {
final String createTableDdl;
final boolean supportsIfTableNotExists;
boolean isOracleClient = false;
switch (sqlClientBuildItem.reactiveClient) {
case REACTIVE_PG_CLIENT:
createTableDdl = "CREATE TABLE IF NOT EXISTS oidc_db_token_state_manager (" +
"id BIGSERIAL PRIMARY KEY, " +
"id_token VARCHAR, " +
"access_token VARCHAR, " +
"expires_in BIGINT NOT NULL, " +
"refresh_token VARCHAR)";
supportsIfTableNotExists = true;
break;
case REACTIVE_MYSQL_CLIENT:
createTableDdl = "CREATE TABLE IF NOT EXISTS oidc_db_token_state_manager ("
+ "id BIGINT NOT NULL AUTO_INCREMENT, "
+ "id_token VARCHAR(5000) NULL, "
+ "access_token VARCHAR(5000) NULL, "
+ "refresh_token VARCHAR(5000) NULL, "
+ "expires_in BIGINT NOT NULL, "
+ "PRIMARY KEY (id))";
supportsIfTableNotExists = true;
break;
case REACTIVE_MSSQL_CLIENT:
createTableDdl = "CREATE TABLE oidc_db_token_state_manager ("
+ "id BIGINT IDENTITY(1,1) PRIMARY KEY, "
+ "id_token NVARCHAR(MAX), "
+ "access_token NVARCHAR(MAX), "
+ "refresh_token NVARCHAR(MAX), "
+ "expires_in BIGINT NOT NULL)";
supportsIfTableNotExists = false;
break;
case REACTIVE_DB2_CLIENT:
createTableDdl = "CREATE TABLE oidc_db_token_state_manager ("
+ "id BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), "
+ "id_token VARCHAR(4000), "
+ "access_token VARCHAR(4000), "
+ "refresh_token VARCHAR(4000), "
+ "expires_in BIGINT NOT NULL, "
+ "PRIMARY KEY (id))";
supportsIfTableNotExists = false;
break;
case REACTIVE_ORACLE_CLIENT:
createTableDdl = "CREATE TABLE IF NOT EXISTS oidc_db_token_state_manager ("
+ "id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
+ "id_token VARCHAR2(4000), "
+ "access_token VARCHAR2(4000), "
+ "refresh_token VARCHAR2(4000), "
+ "expires_in NUMBER NOT NULL)";
supportsIfTableNotExists = true;
isOracleClient = true;
break;
default:
throw new ConfigurationException("Unknown Reactive Sql Client " + sqlClientBuildItem.reactiveClient);
}
return SyntheticBeanBuildItem
.configure(OidcDbTokenStateManagerInitializerProperties.class)
.supplier(recorder.createDbTokenStateInitializerProps(createTableDdl, supportsIfTableNotExists,
isOracleClient))
.unremovable()
.scope(Dependent.class)
.done();
}

@Consume(RuntimeConfigSetupCompleteBuildItem.class)
@Record(RUNTIME_INIT)
@BuildStep
void validateTenantConfig(OidcDbTokenStateManagerRecorder recorder) {
recorder.validateOidcTenantConfig();
}

@Consume(SyntheticBeansRuntimeInitBuildItem.class)
@Record(RUNTIME_INIT)
@BuildStep
void setSqlClientPool(OidcDbTokenStateManagerRecorder recorder, BeanContainerBuildItem beanContainer) {
recorder.setSqlClientPool(beanContainer.getValue());
}

static final class OidcDbTokenStateManagerEnabled implements BooleanSupplier {

OidcDbTokenStateManagerBuildTimeConfig config;

@Override
public boolean getAsBoolean() {
return config.enabled();
}
}

static final class ReactiveSqlClientBuildItem extends SimpleBuildItem {

private final String reactiveClient;

private ReactiveSqlClientBuildItem(String reactiveClient) {
this.reactiveClient = reactiveClient;
}
}

}
Loading

0 comments on commit 2b4e25d

Please sign in to comment.