Skip to content

Commit

Permalink
Merge pull request #244 from kbss-cvut/upd/spring-6
Browse files Browse the repository at this point in the history
Upd/spring 6
  • Loading branch information
ledsoft authored Sep 15, 2023
2 parents e91deab + 31f0492 commit 53eca79
Show file tree
Hide file tree
Showing 84 changed files with 446 additions and 320 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
- termit-storage:/tmp/termit
restart: always
environment:
TERMIT_REPOSITORY_URL: https://localhost:7200/repositories/termit
TERMIT_REPOSITORY_URL: http://localhost:7200/repositories/termit
DEBUG: "true"
ports:
- "8080:8080"
Expand Down
61 changes: 20 additions & 41 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.13</version>
<version>3.1.2</version>
</parent>

<artifactId>termit</artifactId>
Expand Down Expand Up @@ -37,18 +37,6 @@
<packaging>jar</packaging>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>19.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.github.sgov</groupId>
Expand Down Expand Up @@ -82,7 +70,7 @@
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.12.1</version>
<version>2.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-core -->
Expand Down Expand Up @@ -122,7 +110,7 @@
<dependency>
<groupId>org.eclipse.rdf4j</groupId>
<artifactId>rdf4j-rio-rdfxml</artifactId>
<version>4.3.2</version>
<version>4.3.4</version>
</dependency>


Expand Down Expand Up @@ -156,6 +144,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
Expand All @@ -164,21 +156,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>

<!-- Keycloak -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>

<!-- JWT support for Java -->
Expand Down Expand Up @@ -226,8 +207,8 @@

<!-- Servlet-API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>

Expand All @@ -237,14 +218,14 @@
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>5.0.0-M1</version>
</dependency>

<!-- jsoup for HTML/XML processing -->
Expand Down Expand Up @@ -300,13 +281,10 @@
</dependency>

<!-- Caching -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
Expand Down Expand Up @@ -345,6 +323,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/TermItApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.security.core.context.SecurityContextHolder;

@SpringBootApplication
@EnableConfigurationProperties({Configuration.class, Configuration.Persistence.class, Configuration.Repository.class})
Expand All @@ -17,6 +18,9 @@ protected SpringApplicationBuilder configure(SpringApplicationBuilder applicatio
}

public static void main(String[] args) {
// Ensures security context is propagated to additionally spun threads, e.g., used by @Async methods
// Need to call it here before any of the Spring services depending on security context holder strategy are initialized
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
SpringApplication.run(TermItApplication.class, args);
}
}

This file was deleted.

This file was deleted.

93 changes: 93 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/config/OAuth2SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package cz.cvut.kbss.termit.config;

import cz.cvut.kbss.termit.security.AuthenticationSuccess;
import cz.cvut.kbss.termit.security.HierarchicalRoleBasedAuthorityMapper;
import cz.cvut.kbss.termit.security.SecurityConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.web.cors.CorsConfigurationSource;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@ConditionalOnProperty(prefix = "termit.security", name = "provider", havingValue = "oidc")
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class OAuth2SecurityConfig {

private static final Logger LOG = LoggerFactory.getLogger(OAuth2SecurityConfig.class);

private final AuthenticationSuccess authenticationSuccessHandler;

private final cz.cvut.kbss.termit.util.Configuration config;

@Autowired
public OAuth2SecurityConfig(AuthenticationSuccess authenticationSuccessHandler,
cz.cvut.kbss.termit.util.Configuration config) {
this.authenticationSuccessHandler = authenticationSuccessHandler;
this.config = config;
}

@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
LOG.debug("Using OAuth2/OIDC security.");
http.oauth2ResourceServer(
(auth) -> auth.jwt((jwt) -> jwt.jwtAuthenticationConverter(grantedAuthoritiesExtractor())))
.authorizeHttpRequests((auth) -> auth.requestMatchers("/rest/query").permitAll()
.requestMatchers("/**").permitAll())
.cors((auth) -> auth.configurationSource(corsConfigurationSource()))
.csrf(AbstractHttpConfigurer::disable)
.logout((auth) -> auth.logoutUrl(SecurityConstants.LOGOUT_PATH)
.logoutSuccessHandler(authenticationSuccessHandler));
return http.build();
}

private CorsConfigurationSource corsConfigurationSource() {
return SecurityConfig.createCorsConfiguration(config.getCors());
}

private Converter<Jwt, AbstractAuthenticationToken> grantedAuthoritiesExtractor() {
return source -> {
final Collection<SimpleGrantedAuthority> authorities = new GrantedAuthoritiesExtractor().convert(source);
return new JwtAuthenticationToken(source, authorities);
};
}

private class GrantedAuthoritiesExtractor implements Converter<Jwt, Collection<SimpleGrantedAuthority>> {
public Collection<SimpleGrantedAuthority> convert(Jwt jwt) {
final List<SimpleGrantedAuthority> allAuths = (
(Map<String, Collection<?>>) jwt.getClaims().getOrDefault(
OAuth2SecurityConfig.this.config.getSecurity().getRoleClaim(), Collections.emptyMap())
).getOrDefault("roles", Collections.emptyList())
.stream()
.map(Object::toString)
.map(SimpleGrantedAuthority::new).toList();
return new HierarchicalRoleBasedAuthorityMapper().mapAuthorities(allAuths);
}
}
}
24 changes: 13 additions & 11 deletions src/main/java/cz/cvut/kbss/termit/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
Expand All @@ -46,10 +47,10 @@
import java.util.Arrays;
import java.util.Collections;

@ConditionalOnProperty(prefix = "keycloak", name = "enabled", havingValue = "false", matchIfMissing = true)
@ConditionalOnProperty(prefix = "termit.security", name = "provider", havingValue = "internal", matchIfMissing = true)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity
public class SecurityConfig {

private static final Logger LOG = LoggerFactory.getLogger(SecurityConfig.class);
Expand Down Expand Up @@ -87,13 +88,13 @@ public SecurityConfig(AuthenticationProvider authenticationProvider,
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
LOG.debug("Using internal security mechanisms.");
final AuthenticationManager authManager = buildAuthenticationManager(http);
http.authorizeRequests().antMatchers("/rest/query").permitAll().and().cors().and().csrf()
.disable()
.authorizeRequests().antMatchers("/**").permitAll()
.and().exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and().cors().configurationSource(corsConfigurationSource()).and().csrf().disable()
.logout().logoutUrl(SecurityConstants.LOGOUT_PATH).logoutSuccessHandler(authenticationSuccessHandler)
.and()
http.authorizeHttpRequests((auth) -> auth.requestMatchers("/rest/query").permitAll()
.requestMatchers("/**").permitAll())
.cors((auth) -> auth.configurationSource(corsConfigurationSource()))
.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(ehc -> ehc.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
.logout((auth) -> auth.logoutUrl(SecurityConstants.LOGOUT_PATH)
.logoutSuccessHandler(authenticationSuccessHandler))
.authenticationManager(authManager)
.addFilter(authenticationFilter(authManager))
.addFilter(new JwtAuthorizationFilter(authManager, jwtUtils, userDetailsService, objectMapper));
Expand All @@ -107,7 +108,8 @@ private AuthenticationManager buildAuthenticationManager(HttpSecurity http) thro
}

private JwtAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) {
final JwtAuthenticationFilter authenticationFilter = new JwtAuthenticationFilter(authenticationManager, jwtUtils);
final JwtAuthenticationFilter authenticationFilter = new JwtAuthenticationFilter(authenticationManager,
jwtUtils);
authenticationFilter.setFilterProcessesUrl(SecurityConstants.LOGIN_PATH);
authenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
authenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
Expand Down
Loading

0 comments on commit 53eca79

Please sign in to comment.