[
https://issues.apache.org/jira/browse/KNOX-3355?focusedWorklogId=1031668&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1031668
]
ASF GitHub Bot logged work on KNOX-3355:
----------------------------------------
Author: ASF GitHub Bot
Created on: 22/Jul/26 13:18
Start Date: 22/Jul/26 13:18
Worklog Time Spent: 10m
Work Description: smolnar82 commented on code in PR #1315:
URL: https://github.com/apache/knox/pull/1315#discussion_r3630454860
##########
gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/trustedoidcissuer/JdbcTrustedOidcIssuerService.java:
##########
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package org.apache.knox.gateway.services.knoxidf.trustedoidcissuer;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.database.DataSourceProvider;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.services.ServiceLifecycleException;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.util.knoxidf.KnoxIDFConstants;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * JDBC-backed implementation of {@link TrustedOidcIssuerService}.
+ * <p>
+ * Maintains an in-memory registry snapshot as an {@link AtomicReference} to
an immutable
+ * {@link Map}. Reads ({@link #isTrusted}, {@link #isDynamicJwks}, {@link
#list}) are
+ * lock-free and always see a consistent snapshot. Writes ({@link #register},
+ * {@link #deregister}) are synchronized: the DB is committed first, then the
snapshot is
+ * rebuilt from a fresh SELECT to guarantee the in-memory state cannot diverge
from
+ * persistent storage.
+ * <p>
+ * HA note: each Knox node maintains its own snapshot. A registration on node
A updates
+ * that node's snapshot immediately; other nodes' snapshots remain stale until
restart.
+ */
+public class JdbcTrustedOidcIssuerService implements TrustedOidcIssuerService {
+
+ private static final TrustedOidcIssuerServiceMessages LOG =
+ MessagesFactory.get(TrustedOidcIssuerServiceMessages.class);
+
+ static final String MAX_TRUSTED_ISSUERS_CONFIG =
"gateway.trustedoidcissuer.max.issuers";
+ private static final int DEFAULT_MAX_TRUSTED_ISSUERS = 10_000;
+
+ private final AtomicBoolean initialized = new AtomicBoolean(false);
+ private final Lock initLock = new ReentrantLock(true);
+
+ private final AtomicReference<Map<String, TrustedOidcIssuer>>
registrySnapshot =
+ new AtomicReference<>(Collections.emptyMap());
+
+ private AliasService aliasService;
+ private TrustedOidcIssuerDatabase database;
+ private OIDCDiscoveryHelper discoveryHelper;
+ private int maxTrustedIssuers;
+
+ @Override
+ public void init(GatewayConfig config, Map<String, String> options) throws
ServiceLifecycleException {
+ if (!initialized.get()) {
+ initLock.lock();
+ try {
+ if (aliasService == null) {
+ throw new ServiceLifecycleException("The required AliasService
reference has not been set.");
+ }
+ try {
+ int maxIssuers = DEFAULT_MAX_TRUSTED_ISSUERS;
+ long cacheTtlSecs =
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CACHE_TTL_SECS;
+ int connectTimeoutMs =
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CONNECT_TIMEOUT_MS;
+ int readTimeoutMs =
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_READ_TIMEOUT_MS;
+
+ if (config instanceof Configuration) {
+ final Configuration conf = (Configuration) config;
+ maxIssuers = conf.getInt(MAX_TRUSTED_ISSUERS_CONFIG,
DEFAULT_MAX_TRUSTED_ISSUERS);
+ cacheTtlSecs =
conf.getLong(KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DISCOVERY_CACHE_TTL_SECS,
+
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CACHE_TTL_SECS);
+ connectTimeoutMs =
conf.getInt(KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DISCOVERY_CONNECT_TIMEOUT_MS,
+
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CONNECT_TIMEOUT_MS);
+ readTimeoutMs =
conf.getInt(KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DISCOVERY_READ_TIMEOUT_MS,
+
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_READ_TIMEOUT_MS);
+ }
+
+ this.maxTrustedIssuers = maxIssuers;
+ this.database = new TrustedOidcIssuerDatabase(
+ DataSourceProvider.getDataSource(config, aliasService),
config.getDatabaseType());
+ this.discoveryHelper = new OIDCDiscoveryHelper(this, cacheTtlSecs,
+ OIDCDiscoveryHelper.buildHttpClient(connectTimeoutMs,
readTimeoutMs));
+ reloadRegistrySnapshot();
+ initialized.set(true);
+ } catch (ServiceLifecycleException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ServiceLifecycleException("Error initializing
JdbcTrustedOidcIssuerService: " + e, e);
+ }
+ } finally {
+ initLock.unlock();
+ }
+ }
+ }
+
+ @Override
+ public void start() throws ServiceLifecycleException {
+ }
+
+ @Override
+ public void stop() throws ServiceLifecycleException {
+ }
+
+ public void setAliasService(AliasService aliasService) {
+ this.aliasService = aliasService;
+ }
+
+ protected AliasService getAliasService() {
+ return aliasService;
+ }
+
+ @Override
+ public boolean isTrusted(String issuerUrl) {
+ return registrySnapshot.get().containsKey(issuerUrl);
+ }
+
+ @Override
+ public boolean isDynamicJwks(String issuerUrl) {
+ final TrustedOidcIssuer entry = registrySnapshot.get().get(issuerUrl);
+ return entry != null && entry.isDynamicJwks();
+ }
+
+ @Override
+ public Optional<String> resolveJwksUri(String issuerUrl) {
+ return discoveryHelper.discoverJwksUri(issuerUrl);
+ }
+
+ @Override
+ public synchronized void register(TrustedOidcIssuer issuer) {
+ if (registrySnapshot.get().size() >= maxTrustedIssuers) {
+ throw new IllegalStateException(
+ "Cannot register issuer: MAX_TRUSTED_ISSUERS (" + maxTrustedIssuers
+ ") reached");
+ }
+ try {
+ database.insert(issuer);
+ } catch (SQLException e) {
+ LOG.errorRegisteringIssuer(issuer.getIssuerUrl(), e.getMessage(), e);
+ throw new RuntimeException("Error registering trusted OIDC issuer: " +
issuer.getIssuerUrl(), e);
+ }
+ reloadRegistrySnapshot();
+ }
+
+ @Override
+ public synchronized void deregister(String issuerUrl) {
+ try {
+ database.delete(issuerUrl);
+ } catch (SQLException e) {
+ LOG.errorDeregisteringIssuer(issuerUrl, e.getMessage(), e);
+ throw new RuntimeException("Error deregistering trusted OIDC issuer: " +
issuerUrl, e);
+ }
+ reloadRegistrySnapshot();
+ discoveryHelper.invalidate(issuerUrl);
+ }
+
+ @Override
+ public void refreshJwksUri(String issuerUrl) {
+ if (isDynamicJwks(issuerUrl)) {
+ discoveryHelper.invalidate(issuerUrl);
+ }
+ }
+
+ @Override
+ public List<TrustedOidcIssuer> list() {
+ return new ArrayList<>(registrySnapshot.get().values());
+ }
+
+ /**
+ * Rebuilds the registry snapshot from the current DB state.
+ * Called on init, after register, and after deregister.
+ * Synchronized on this to prevent concurrent rebuilds from interleaving
with mutations.
+ */
+ private synchronized void reloadRegistrySnapshot() {
+ try {
+ final Map<String, TrustedOidcIssuer> fresh =
database.selectAll().stream()
+ .collect(Collectors.toMap(TrustedOidcIssuer::getIssuerUrl,
Function.identity()));
+ registrySnapshot.set(Collections.unmodifiableMap(fresh));
+ } catch (Exception e) {
Review Comment:
The class javadoc states the snapshot is rebuilt after each write "to
guarantee the in-memory state cannot diverge from persistent storage." But:
```
public synchronized void register(TrustedOidcIssuer issuer) {
...
database.insert(issuer); // committed
reloadRegistrySnapshot(); // if the SELECT fails here, it's caught
+ logged, not rethrown
}
```
If the reload `SELECT` fails after a successful insert, `register()` returns
normally (caller thinks it succeeded), the row is in the DB, but
i`sTrusted(url) returns false` until the next successful mutation or a restart.
That's a silent divergence - exactly what the javadoc promises can't happen.
Consider propagating the failure (or at least having register/deregister
surface it) rather than logging and returning success.
##########
gateway-util-common/src/main/java/org/apache/knox/gateway/util/knoxidf/KnoxIDFConstants.java:
##########
@@ -57,4 +57,17 @@ public interface KnoxIDFConstants {
String FEDERATED_OP_CONFIG_NAMES = FEDERATED_OP_CONFIG_PREFIX + "names";
String TOKEN_EXCHANGE_TOPOLOGY_NAME = "token.exchange.topology.name";
+
+ // TrustedOidcIssuerService gateway-level params (read from GatewayConfig
/ gateway-site.xml)
+ String TRUSTED_OIDC_ISSUER_DISCOVERY_CACHE_TTL_SECS =
+ "gateway.trustedoidcissuer.discovery.cache.ttl.secs";
+ String TRUSTED_OIDC_ISSUER_DISCOVERY_CONNECT_TIMEOUT_MS =
+ "gateway.trustedoidcissuer.discovery.connect.timeout.ms";
+ String TRUSTED_OIDC_ISSUER_DISCOVERY_READ_TIMEOUT_MS =
+ "gateway.trustedoidcissuer.discovery.read.timeout.ms";
Review Comment:
They belong to `GatewayConfig.java`, just like any other gateway-level
config names.
##########
gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/trustedoidcissuer/JdbcTrustedOidcIssuerService.java:
##########
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package org.apache.knox.gateway.services.knoxidf.trustedoidcissuer;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.database.DataSourceProvider;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.services.ServiceLifecycleException;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.util.knoxidf.KnoxIDFConstants;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * JDBC-backed implementation of {@link TrustedOidcIssuerService}.
+ * <p>
+ * Maintains an in-memory registry snapshot as an {@link AtomicReference} to
an immutable
+ * {@link Map}. Reads ({@link #isTrusted}, {@link #isDynamicJwks}, {@link
#list}) are
+ * lock-free and always see a consistent snapshot. Writes ({@link #register},
+ * {@link #deregister}) are synchronized: the DB is committed first, then the
snapshot is
+ * rebuilt from a fresh SELECT to guarantee the in-memory state cannot diverge
from
+ * persistent storage.
+ * <p>
+ * HA note: each Knox node maintains its own snapshot. A registration on node
A updates
+ * that node's snapshot immediately; other nodes' snapshots remain stale until
restart.
+ */
+public class JdbcTrustedOidcIssuerService implements TrustedOidcIssuerService {
+
+ private static final TrustedOidcIssuerServiceMessages LOG =
+ MessagesFactory.get(TrustedOidcIssuerServiceMessages.class);
+
+ static final String MAX_TRUSTED_ISSUERS_CONFIG =
"gateway.trustedoidcissuer.max.issuers";
+ private static final int DEFAULT_MAX_TRUSTED_ISSUERS = 10_000;
+
+ private final AtomicBoolean initialized = new AtomicBoolean(false);
+ private final Lock initLock = new ReentrantLock(true);
+
+ private final AtomicReference<Map<String, TrustedOidcIssuer>>
registrySnapshot =
+ new AtomicReference<>(Collections.emptyMap());
+
+ private AliasService aliasService;
+ private TrustedOidcIssuerDatabase database;
+ private OIDCDiscoveryHelper discoveryHelper;
+ private int maxTrustedIssuers;
+
+ @Override
+ public void init(GatewayConfig config, Map<String, String> options) throws
ServiceLifecycleException {
+ if (!initialized.get()) {
+ initLock.lock();
+ try {
+ if (aliasService == null) {
+ throw new ServiceLifecycleException("The required AliasService
reference has not been set.");
+ }
+ try {
+ int maxIssuers = DEFAULT_MAX_TRUSTED_ISSUERS;
+ long cacheTtlSecs =
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CACHE_TTL_SECS;
+ int connectTimeoutMs =
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CONNECT_TIMEOUT_MS;
+ int readTimeoutMs =
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_READ_TIMEOUT_MS;
+
+ if (config instanceof Configuration) {
+ final Configuration conf = (Configuration) config;
+ maxIssuers = conf.getInt(MAX_TRUSTED_ISSUERS_CONFIG,
DEFAULT_MAX_TRUSTED_ISSUERS);
+ cacheTtlSecs =
conf.getLong(KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DISCOVERY_CACHE_TTL_SECS,
+
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CACHE_TTL_SECS);
+ connectTimeoutMs =
conf.getInt(KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DISCOVERY_CONNECT_TIMEOUT_MS,
+
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_CONNECT_TIMEOUT_MS);
+ readTimeoutMs =
conf.getInt(KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DISCOVERY_READ_TIMEOUT_MS,
+
KnoxIDFConstants.TRUSTED_OIDC_ISSUER_DEFAULT_DISCOVERY_READ_TIMEOUT_MS);
+ }
+
+ this.maxTrustedIssuers = maxIssuers;
+ this.database = new TrustedOidcIssuerDatabase(
+ DataSourceProvider.getDataSource(config, aliasService),
config.getDatabaseType());
+ this.discoveryHelper = new OIDCDiscoveryHelper(this, cacheTtlSecs,
+ OIDCDiscoveryHelper.buildHttpClient(connectTimeoutMs,
readTimeoutMs));
+ reloadRegistrySnapshot();
+ initialized.set(true);
+ } catch (ServiceLifecycleException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ServiceLifecycleException("Error initializing
JdbcTrustedOidcIssuerService: " + e, e);
+ }
+ } finally {
+ initLock.unlock();
+ }
+ }
+ }
+
+ @Override
+ public void start() throws ServiceLifecycleException {
+ }
+
+ @Override
+ public void stop() throws ServiceLifecycleException {
+ }
+
+ public void setAliasService(AliasService aliasService) {
+ this.aliasService = aliasService;
+ }
+
+ protected AliasService getAliasService() {
+ return aliasService;
+ }
+
+ @Override
+ public boolean isTrusted(String issuerUrl) {
+ return registrySnapshot.get().containsKey(issuerUrl);
+ }
+
+ @Override
+ public boolean isDynamicJwks(String issuerUrl) {
+ final TrustedOidcIssuer entry = registrySnapshot.get().get(issuerUrl);
+ return entry != null && entry.isDynamicJwks();
+ }
Review Comment:
`fetchJwksUri` strips a trailing slash before building the discovery URL
(`issuerUrl.replaceAll("/$", "")`), but the registry key is the raw string. So
an issuer registered as `https://idp.example.com/` won't match an `iss` claim
of `https://idp.example.com` (or vice-versa), and there's no normalization at
`register()` either.
OIDC does require exact `iss` matching, so this may be intentional - but if
so, it's worth a comment, and if not, normalizing on both write and lookup
would avoid a frustrating "why isn't my trusted issuer trusted" class of bug.
##########
pom.xml:
##########
@@ -259,6 +259,7 @@
<mina.version>2.2.8</mina.version>
<netty.version>4.1.127.Final</netty.version>
<nimbus-jose-jwt.version>10.9.1</nimbus-jose-jwt.version>
+ <oauth2-oidc-sdk.version>11.37.2</oauth2-oidc-sdk.version>
Review Comment:
Please move this new attribute below to honor the alphabetical order we try
to keep. Thanks!
##########
gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/trustedoidcissuer/TrustedOidcIssuerDatabase.java:
##########
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package org.apache.knox.gateway.services.knoxidf.trustedoidcissuer;
+
+import org.apache.knox.gateway.database.DatabaseType;
+import org.apache.knox.gateway.database.KnoxDatabase;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JDBC helper for the {@code TRUSTED_OIDC_ISSUERS} table.
+ * All SQL uses {@link PreparedStatement} with {@code ?} parameters only.
+ * Uses {@link ResultSet#getBoolean(String)} for the {@code dynamic_jwks}
column,
+ * which correctly maps both BOOLEAN (standard/Derby) and NUMBER(1) (Oracle)
values.
+ */
+class TrustedOidcIssuerDatabase extends KnoxDatabase {
+
+ static final String TABLE_NAME = "TRUSTED_OIDC_ISSUERS";
+
+ private static final String INSERT_SQL =
+ "INSERT INTO " + TABLE_NAME + " (issuer_url, dynamic_jwks, cluster_name,
registered_at, registered_by) VALUES (?, ?, ?, ?, ?)";
+ private static final String DELETE_SQL =
+ "DELETE FROM " + TABLE_NAME + " WHERE issuer_url = ?";
+ private static final String SELECT_ALL_SQL =
+ "SELECT issuer_url, dynamic_jwks, cluster_name, registered_at,
registered_by FROM " + TABLE_NAME;
+ private static final String COUNT_SQL =
+ "SELECT COUNT(*) FROM " + TABLE_NAME;
+
+ TrustedOidcIssuerDatabase(DataSource dataSource, String dbType) throws
Exception {
+ super(dataSource);
+ final DatabaseType databaseType = DatabaseType.fromString(dbType);
+ createTableIfNotExists(TABLE_NAME,
databaseType.trustedOidcIssuersTableSql());
+ }
+
+ void insert(TrustedOidcIssuer issuer) throws SQLException {
+ try (Connection connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(INSERT_SQL)) {
+ ps.setString(1, issuer.getIssuerUrl());
+ ps.setBoolean(2, issuer.isDynamicJwks());
+ ps.setString(3, issuer.getClusterName());
+ ps.setTimestamp(4, Timestamp.from(issuer.getRegisteredAt()));
+ ps.setString(5, issuer.getRegisteredBy());
+ ps.executeUpdate();
+ }
+ }
+
+ void delete(String issuerUrl) throws SQLException {
+ try (Connection connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(DELETE_SQL)) {
+ ps.setString(1, issuerUrl);
+ ps.executeUpdate();
+ }
+ }
+
+ List<TrustedOidcIssuer> selectAll() throws SQLException {
+ final List<TrustedOidcIssuer> result = new ArrayList<>();
+ try (Connection connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(SELECT_ALL_SQL);
+ ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ result.add(new TrustedOidcIssuer(
+ rs.getString("issuer_url"),
+ rs.getBoolean("dynamic_jwks"),
+ rs.getString("cluster_name"),
+ rs.getTimestamp("registered_at").toInstant(),
+ rs.getString("registered_by")
+ ));
+ }
+ }
+ return result;
+ }
+
+ int count() throws SQLException {
+ try (Connection connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(COUNT_SQL);
+ ResultSet rs = ps.executeQuery()) {
+ return rs.next() ? rs.getInt(1) : 0;
+ }
+ }
Review Comment:
This method seems to be unused -> you may want to remove it.
Issue Time Tracking
-------------------
Worklog Id: (was: 1031668)
Time Spent: 2h 20m (was: 2h 10m)
> Trusted OIDC Issuer service and storage for Knox IDF
> ----------------------------------------------------
>
> Key: KNOX-3355
> URL: https://issues.apache.org/jira/browse/KNOX-3355
> Project: Apache Knox
> Issue Type: Task
> Components: JWT
> Reporter: Harrison Sheinblatt
> Assignee: Harrison Sheinblatt
> Priority: Major
> Time Spent: 2h 20m
> Remaining Estimate: 0h
>
> Create the storage layer and service for Trusted OIDC Issuers. Will include:
> TRUSTED_OIDC_ISSUERS schema, ServiceType, POJO, TrustedOidcIssuerService
> interface, JDBC impl, factory.
> Filter and admin interface use will be in another task.
> Implementation tasks for KNOX-3349.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)