diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
index fc9c1770..cb6bcbec 100644
--- a/.github/workflows/codecov.yml
+++ b/.github/workflows/codecov.yml
@@ -22,10 +22,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
cache: maven
- name: Runs Elasticsearch
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 895d47c8..68520db4 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -19,10 +19,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
cache: maven
- name: Build with Maven
@@ -39,10 +39,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
cache: maven
- name: Test with Maven
@@ -59,10 +59,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
cache: maven
- name: Runs Elasticsearch
diff --git a/Dockerfile b/Dockerfile
index 32ce67b1..7c49fc29 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,12 +1,12 @@
# syntax=docker/dockerfile:1
-FROM eclipse-temurin:17-jdk AS builder
+FROM eclipse-temurin:21-jdk AS builder
WORKDIR /build
RUN apt-get update && apt-get install -y maven
COPY . .
RUN mvn --batch-mode --update-snapshots clean package -DskipTests
-FROM eclipse-temurin:17-jre AS runner
+FROM eclipse-temurin:21-jre AS runner
WORKDIR /app
COPY --from=builder /build/target/ChannelFinder-*.jar ./channelfinder.jar
CMD ["java", "-jar", "/app/channelfinder.jar", "--spring.config.name=application"]
diff --git a/README.md b/README.md
index be565d34..1973b2c0 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ For using docker containers there is a barebones [docker compose file](./compose
* Prerequisites
- * JDK 17
+ * JDK 21
* Elastic version 8.11.x
* **For authN/authZ using LDAP:** LDAP server, e.g. OpenLDAP
@@ -62,7 +62,7 @@ Options:
#### Running
```bash
-sudo apt-get install openjdk-17-jre git curl wget
+sudo apt-get install openjdk-21-jre git curl wget
sudo systemctl start elasticsearch # Or other command to run elastic search
# Replace verison with the release you want
@@ -98,7 +98,7 @@ and [Eclipse](https://eclipseide.org/).
* Prerequisites
- * JDK 17
+ * JDK 21
* Maven (via package manager or via the wrapper `./mvnw`) (version specified
in [the wrapper properties](./.mvn/wrapper/maven-wrapper.properties))
diff --git a/pom.xml b/pom.xml
index 4336b1ba..08b1214d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,12 +35,14 @@
UTF-8
- 2.7.18
+ 3.4.4
+ 2.18.3
8.11.2
5.10.0
true
true
true
+ 21
${git.commit.time}
@@ -84,12 +86,12 @@
com.fasterxml.jackson.core
jackson-databind
- 2.16.0
+ ${jackson.version}
com.fasterxml.jackson.core
jackson-core
- 2.16.0
+ ${jackson.version}
jakarta.json
@@ -347,10 +349,10 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ 3.14.0
- 17
- 17
+ ${java.version}
+ ${java.version}
${project.build.sourceEncoding}
@@ -452,7 +454,7 @@
-Xdoclint:none
- 17
+ ${java.version}
diff --git a/src/main/java/org/phoebus/channelfinder/configuration/ElasticConfig.java b/src/main/java/org/phoebus/channelfinder/configuration/ElasticConfig.java
index 736e1186..a7fc37e1 100644
--- a/src/main/java/org/phoebus/channelfinder/configuration/ElasticConfig.java
+++ b/src/main/java/org/phoebus/channelfinder/configuration/ElasticConfig.java
@@ -24,14 +24,14 @@
import co.elastic.clients.transport.endpoints.BooleanResponse;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.ServletContextEvent;
+import jakarta.servlet.ServletContextListener;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
diff --git a/src/main/java/org/phoebus/channelfinder/configuration/WebSecurityConfig.java b/src/main/java/org/phoebus/channelfinder/configuration/WebSecurityConfig.java
index 4fe197da..83a4470e 100644
--- a/src/main/java/org/phoebus/channelfinder/configuration/WebSecurityConfig.java
+++ b/src/main/java/org/phoebus/channelfinder/configuration/WebSecurityConfig.java
@@ -1,34 +1,50 @@
package org.phoebus.channelfinder.configuration;
+import static org.springframework.security.config.Customizer.withDefaults;
+
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.*;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.http.HttpMethod;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.ProviderManager;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
+import org.springframework.security.ldap.authentication.BindAuthenticator;
+import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.SecurityFilterChain;
@Configuration
-public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.csrf().disable();
- http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
- http.authorizeRequests().anyRequest().authenticated();
- http.httpBasic();
+public class WebSecurityConfig {
+
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ return http.csrf(csrf -> csrf.disable())
+ .sessionManagement(
+ session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
+ .httpBasic(withDefaults())
+ .build();
}
- @Override
- public void configure(WebSecurity web) throws Exception {
+ @Bean
+ public WebSecurityCustomizer ignoringCustomizer() {
// Authentication and Authorization is only needed for non search/query operations
- web.ignoring().antMatchers(HttpMethod.GET, "/**");
+ return web -> web.ignoring().requestMatchers(HttpMethod.GET, "/**");
}
/** External LDAP configuration properties */
@@ -83,71 +99,99 @@ public void configure(WebSecurity web) throws Exception {
@Value("${file.auth.enabled:true}")
boolean file_enabled;
- @Override
- public void configure(AuthenticationManagerBuilder auth) throws Exception {
+ @Bean
+ public AuthenticationManager authenticationManager(
+ AuthenticationConfiguration configuration, List providers) {
+ return new ProviderManager(providers);
+ }
- if (ldap_enabled) {
- DefaultSpringSecurityContextSource contextSource =
- new DefaultSpringSecurityContextSource(ldap_url);
- contextSource.afterPropertiesSet();
+ @Bean
+ @ConditionalOnProperty(name = "ldap.enabled", havingValue = "true")
+ public AuthenticationProvider ldapAuthProvider() {
- DefaultLdapAuthoritiesPopulator myAuthPopulator =
- new DefaultLdapAuthoritiesPopulator(contextSource, ldap_groups_search_base);
- myAuthPopulator.setGroupSearchFilter(ldap_groups_search_pattern);
- myAuthPopulator.setSearchSubtree(true);
- myAuthPopulator.setIgnorePartialResultException(true);
+ DefaultSpringSecurityContextSource contextSource =
+ new DefaultSpringSecurityContextSource(ldap_url);
+ contextSource.afterPropertiesSet();
- auth.ldapAuthentication()
- .userDnPatterns(ldap_user_dn_pattern)
- .ldapAuthoritiesPopulator(myAuthPopulator)
- .contextSource(contextSource);
- }
+ DefaultLdapAuthoritiesPopulator authPopulator =
+ new DefaultLdapAuthoritiesPopulator(contextSource, ldap_groups_search_base);
+ authPopulator.setGroupSearchFilter(ldap_groups_search_pattern);
+ authPopulator.setSearchSubtree(true);
+ authPopulator.setIgnorePartialResultException(true);
- if (embedded_ldap_enabled) {
- DefaultSpringSecurityContextSource contextSource =
- new DefaultSpringSecurityContextSource(embedded_ldap_url);
- contextSource.afterPropertiesSet();
-
- DefaultLdapAuthoritiesPopulator myAuthPopulator =
- new DefaultLdapAuthoritiesPopulator(contextSource, embedded_ldap_groups_search_base);
- myAuthPopulator.setGroupSearchFilter(embedded_ldap_groups_search_pattern);
- myAuthPopulator.setSearchSubtree(true);
- myAuthPopulator.setIgnorePartialResultException(true);
-
- auth.ldapAuthentication()
- .userDnPatterns(embedded_ldap_user_dn_pattern)
- .ldapAuthoritiesPopulator(myAuthPopulator)
- .groupSearchBase("ou=Group")
- .contextSource(contextSource);
- }
+ BindAuthenticator bindAuthenticator = new BindAuthenticator(contextSource);
+ bindAuthenticator.setUserDnPatterns(new String[] {ldap_user_dn_pattern});
+
+ return new LdapAuthenticationProvider(bindAuthenticator, authPopulator);
+ }
+
+ @Bean
+ @ConditionalOnProperty(name = "embedded_ldap.enabled", havingValue = "true")
+ public AuthenticationProvider embeddedLdapAuthProvider() {
+
+ DefaultSpringSecurityContextSource contextSource =
+ new DefaultSpringSecurityContextSource(embedded_ldap_url);
+ contextSource.afterPropertiesSet();
+
+ DefaultLdapAuthoritiesPopulator authPopulator =
+ new DefaultLdapAuthoritiesPopulator(contextSource, embedded_ldap_groups_search_base);
+ authPopulator.setGroupSearchFilter(embedded_ldap_groups_search_pattern);
+ authPopulator.setSearchSubtree(true);
+ authPopulator.setIgnorePartialResultException(true);
- if (demo_auth_enabled) {
- // read from configuration, no default content
- // interpret users, pwds, roles
- // user may have multiple roles
-
- if (demo_auth_users != null
- && demo_auth_pwds != null
- && demo_auth_roles != null
- && demo_auth_users.length > 0
- && demo_auth_users.length == demo_auth_pwds.length
- && demo_auth_pwds.length == demo_auth_roles.length) {
-
- for (int i = 0; i < demo_auth_users.length; i++) {
- String[] userroles = demo_auth_roles[i].split(demo_auth_delimiter_roles);
- if (userroles != null && userroles.length > 0) {
- auth.inMemoryAuthentication()
- .withUser(demo_auth_users[i])
- .password(encoder().encode(demo_auth_pwds[i]))
- .roles(userroles);
- }
- }
- }
+ BindAuthenticator bindAuthenticator = new BindAuthenticator(contextSource);
+ bindAuthenticator.setUserDnPatterns(new String[] {embedded_ldap_user_dn_pattern});
+
+ return new LdapAuthenticationProvider(bindAuthenticator, authPopulator);
+ }
+
+ @Bean
+ @Conditional(EmbeddedLdapCondition.class)
+ public AuthenticationProvider demoAuthProvider() {
+
+ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+ PasswordEncoder encoder = encoder();
+
+ for (int i = 0; i < demo_auth_users.length; i++) {
+ String[] userroles = demo_auth_roles[i].split(demo_auth_delimiter_roles);
+
+ manager.createUser(
+ User.withUsername(demo_auth_users[i])
+ .password(encoder.encode(demo_auth_pwds[i]))
+ .roles(userroles)
+ .build());
}
+
+ DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+ provider.setUserDetailsService(manager);
+ provider.setPasswordEncoder(encoder);
+ return provider;
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
+
+ private static class EmbeddedLdapCondition implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+
+ Environment environment = context.getEnvironment();
+
+ Boolean isDemoAuthEnabled =
+ environment.getProperty("demo_auth.enabled", Boolean.class, false);
+ String[] demoAuthPwds = environment.getProperty("demo_auth.pwds", String[].class);
+ String[] demoAuthRoles = environment.getProperty("demo_auth.roles", String[].class);
+ String[] demoAuthUsers = environment.getProperty("demo_auth.users", String[].class);
+
+ return isDemoAuthEnabled
+ && !ArrayUtils.isEmpty(demoAuthUsers)
+ && !ArrayUtils.isEmpty(demoAuthPwds)
+ && !ArrayUtils.isEmpty(demoAuthRoles)
+ && demoAuthUsers.length == demoAuthPwds.length
+ && demoAuthPwds.length == demoAuthRoles.length;
+ }
+ }
}
diff --git a/src/main/java/org/phoebus/channelfinder/repository/ChannelRepository.java b/src/main/java/org/phoebus/channelfinder/repository/ChannelRepository.java
index d2f8d903..10a4877d 100644
--- a/src/main/java/org/phoebus/channelfinder/repository/ChannelRepository.java
+++ b/src/main/java/org/phoebus/channelfinder/repository/ChannelRepository.java
@@ -29,6 +29,7 @@
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.annotation.PreDestroy;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -48,7 +49,6 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
-import javax.annotation.PreDestroy;
import org.phoebus.channelfinder.common.CFResourceDescriptors;
import org.phoebus.channelfinder.common.TextUtil;
import org.phoebus.channelfinder.configuration.ElasticConfig;
diff --git a/src/main/java/org/phoebus/channelfinder/rest/controller/ChannelController.java b/src/main/java/org/phoebus/channelfinder/rest/controller/ChannelController.java
index 1fbb4a99..57c3267f 100644
--- a/src/main/java/org/phoebus/channelfinder/rest/controller/ChannelController.java
+++ b/src/main/java/org/phoebus/channelfinder/rest/controller/ChannelController.java
@@ -2,6 +2,7 @@
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
+import jakarta.servlet.ServletContext;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
@@ -10,7 +11,6 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
-import javax.servlet.ServletContext;
import org.phoebus.channelfinder.common.TextUtil;
import org.phoebus.channelfinder.entity.Channel;
import org.phoebus.channelfinder.entity.Property;
diff --git a/src/main/java/org/phoebus/channelfinder/service/ChannelFinderEpicsService.java b/src/main/java/org/phoebus/channelfinder/service/ChannelFinderEpicsService.java
index a1a3dc73..d553b0a1 100644
--- a/src/main/java/org/phoebus/channelfinder/service/ChannelFinderEpicsService.java
+++ b/src/main/java/org/phoebus/channelfinder/service/ChannelFinderEpicsService.java
@@ -1,5 +1,7 @@
package org.phoebus.channelfinder.service;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -7,8 +9,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
import org.epics.pva.data.PVABoolArray;
import org.epics.pva.data.PVAStringArray;
import org.epics.pva.data.PVAStructure;
diff --git a/src/main/java/org/phoebus/channelfinder/service/MetricsService.java b/src/main/java/org/phoebus/channelfinder/service/MetricsService.java
index 0d78df12..e07ec114 100644
--- a/src/main/java/org/phoebus/channelfinder/service/MetricsService.java
+++ b/src/main/java/org/phoebus/channelfinder/service/MetricsService.java
@@ -4,6 +4,7 @@
import io.micrometer.core.instrument.ImmutableTag;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
+import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -12,7 +13,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
-import javax.annotation.PostConstruct;
import org.phoebus.channelfinder.repository.ChannelRepository;
import org.phoebus.channelfinder.repository.PropertyRepository;
import org.phoebus.channelfinder.repository.TagRepository;
diff --git a/src/test/java/org/phoebus/channelfinder/processors/ChannelProcessorControllerIT.java b/src/test/java/org/phoebus/channelfinder/processors/ChannelProcessorControllerIT.java
index 020a5eac..c0d889cc 100644
--- a/src/test/java/org/phoebus/channelfinder/processors/ChannelProcessorControllerIT.java
+++ b/src/test/java/org/phoebus/channelfinder/processors/ChannelProcessorControllerIT.java
@@ -5,6 +5,7 @@
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import java.util.Base64;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -21,7 +22,6 @@
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
-import org.springframework.util.Base64Utils;
@ExtendWith(SpringExtension.class)
@WebMvcTest(ChannelProcessorController.class)
@@ -31,7 +31,7 @@
class ChannelProcessorControllerIT {
protected static final String AUTHORIZATION =
- "Basic " + Base64Utils.encodeToString("admin:adminPass".getBytes());
+ "Basic " + Base64.getEncoder().encodeToString("admin:adminPass".getBytes());
@Autowired protected MockMvc mockMvc;
@MockBean IChannelScroll channelScroll;
diff --git a/src/test/resources/Dockerfile b/src/test/resources/Dockerfile
index 959ae56d..69f0bcf6 100644
--- a/src/test/resources/Dockerfile
+++ b/src/test/resources/Dockerfile
@@ -16,7 +16,7 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# ------------------------------------------------------------------------------
-FROM eclipse-temurin:17-jre
+FROM eclipse-temurin:21-jre
# deployment unit
COPY ../../../target/ChannelFinder-*.jar /channelfinder/ChannelFinder-*.jar