Skip to content

Commit

Permalink
backport commit a00c724 (original author: @syjer)
Browse files Browse the repository at this point in the history
  • Loading branch information
cbellone committed Apr 30, 2023
1 parent 54d0d68 commit cc5b039
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 21 deletions.
29 changes: 14 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ buildscript {
classpath 'org.postgresql:postgresql:42.2.20'
//this is for processing the index.html at compile time
classpath "com.github.alfio-event:alf.io-public-frontend:$alfioPublicFrontendVersion"
classpath "ch.digitalfondue.jfiveparse:jfiveparse:0.9.0"
classpath "ch.digitalfondue.jfiveparse:jfiveparse:1.0.0"
//
}

Expand Down Expand Up @@ -107,45 +107,44 @@ repositories {

dependencies {
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
implementation 'com.auth0:java-jwt:3.19.0'
implementation 'com.auth0:java-jwt:4.2.1'
implementation "com.fasterxml.jackson.core:jackson-core"
implementation "com.fasterxml.jackson.core:jackson-databind"
implementation "org.springframework.boot:spring-boot-properties-migrator", {
exclude module : 'spring-boot-starter-logging'
}
implementation 'org.springframework.session:spring-session:1.3.5.RELEASE'
implementation 'org.springframework.session:spring-session-jdbc'
implementation "ch.digitalfondue.npjt-extra:npjt-extra:2.0.4"
implementation "com.samskivert:jmustache:1.15"
implementation "javax.mail:mail:1.5.0-b01"
implementation 'com.moodysalem:LatLongToTimezoneMaven:1.2'
/**/
implementation 'com.openhtmltopdf:openhtmltopdf-core:1.0.10'
implementation 'com.openhtmltopdf:openhtmltopdf-pdfbox:1.0.10'
implementation 'ch.digitalfondue.jfiveparse:jfiveparse:0.10.0'
implementation 'ch.digitalfondue.jfiveparse:jfiveparse:1.0.0'
/**/
implementation "com.google.zxing:core:3.4.1"
implementation "com.google.zxing:javase:3.4.1"
implementation "com.google.zxing:core:3.5.1"
implementation "com.google.zxing:javase:3.5.1"
implementation "org.flywaydb:flyway-core"
implementation "org.postgresql:postgresql"
implementation "com.zaxxer:HikariCP"

/* https://www.lunasec.io/docs/blog/log4j-zero-day/ */
implementation "org.apache.logging.log4j:log4j-api:2.17.1"
implementation "org.apache.logging.log4j:log4j-core:2.17.1"
implementation "org.apache.logging.log4j:log4j-jul:2.17.1"
implementation "org.apache.logging.log4j:log4j-slf4j-impl:2.17.1"
implementation "org.apache.logging.log4j:log4j-api:2.19.0"
implementation "org.apache.logging.log4j:log4j-core:2.19.0"
implementation "org.apache.logging.log4j:log4j-jul:2.19.0"
implementation "org.apache.logging.log4j:log4j-slf4j-impl:2.19.0"
/**/

implementation "com.stripe:stripe-java:22.3.0"
implementation "com.stripe:stripe-java:22.4.0"
implementation 'com.paypal.sdk:checkout-sdk:1.0.5'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.1', {
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2', {
exclude module: 'gson'
}

implementation "org.apache.commons:commons-lang3:3.12.0"
implementation "org.apache.commons:commons-text:1.9"
implementation 'com.opencsv:opencsv:5.6'
implementation 'com.opencsv:opencsv:5.7.1'
implementation 'commons-codec:commons-codec:1.15'
implementation 'net.sf.biweekly:biweekly:0.6.6'
implementation 'com.atlassian.commonmark:commonmark:0.17.0'
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/alfio/config/MvcConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
Expand All @@ -44,7 +46,7 @@
@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackages = {"alfio.controller", "alfio.config"})
@EnableWebMvc
@EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 4 * 60 * 60) //4h
@EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 4 * 60 * 60, tableName = "ALFIO_SPRING_SESSION") //4h
public class MvcConfiguration implements WebMvcConfigurer {

private final Environment environment;
Expand Down Expand Up @@ -128,4 +130,9 @@ public ViewResolver viewResolver() {
resolver.setViewClass(AbstractUrlBasedView.class);
return resolver;
}

@Bean
public SpringSessionBackedSessionRegistry<?> sessionRegistry(FindByIndexNameSessionRepository<?> sessionRepository) {
return new SpringSessionBackedSessionRegistry<>(sessionRepository);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.Cookie;
Expand All @@ -64,6 +65,7 @@ abstract class AbstractFormBasedWebSecurity extends WebSecurityConfigurerAdapter
private final DataSource dataSource;
private final PasswordEncoder passwordEncoder;
private final PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager;
private final SpringSessionBackedSessionRegistry<?> sessionRegistry;

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
Expand Down Expand Up @@ -156,7 +158,10 @@ protected void configure(HttpSecurity http) throws Exception {
.loginPage("/authentication")
.loginProcessingUrl(AUTHENTICATE)
.failureUrl("/authentication?failed")
.and().logout().permitAll();
.and().logout().permitAll()
.and()
// this allows us to sync between spring session and spring security, thus saving the principal name in the session table
.sessionManagement().maximumSessions(-1).sessionRegistry(sessionRegistry);

http.addFilterBefore(openIdPublicCallbackLoginFilter(publicOpenIdAuthenticationManager), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(openIdPublicAuthenticationFilter(publicOpenIdAuthenticationManager), AnonymousAuthenticationFilter.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.springframework.core.env.Environment;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.sql.DataSource;

Expand All @@ -43,14 +44,16 @@ public FormBasedWebSecurity(Environment environment,
CsrfTokenRepository csrfTokenRepository,
DataSource dataSource,
PasswordEncoder passwordEncoder,
PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager) {
PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager,
SpringSessionBackedSessionRegistry<?> sessionRegistry) {
super(environment,
userManager,
recaptchaService,
configurationManager,
csrfTokenRepository,
dataSource,
passwordEncoder,
publicOpenIdAuthenticationManager);
publicOpenIdAuthenticationManager,
sessionRegistry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.sql.DataSource;

Expand All @@ -52,15 +53,17 @@ public OpenIdAdminWebSecurity(Environment environment,
DataSource dataSource,
PasswordEncoder passwordEncoder,
AdminOpenIdAuthenticationManager adminOpenIdAuthenticationManager,
PublicOpenIdAuthenticationManager openIdAuthenticationManager) {
PublicOpenIdAuthenticationManager openIdAuthenticationManager,
SpringSessionBackedSessionRegistry<?> sessionRegistry) {
super(environment,
userManager,
recaptchaService,
configurationManager,
csrfTokenRepository,
dataSource,
passwordEncoder,
openIdAuthenticationManager);
openIdAuthenticationManager,
sessionRegistry);
this.adminOpenIdAuthenticationManager = adminOpenIdAuthenticationManager;
}

Expand Down
19 changes: 19 additions & 0 deletions src/main/java/alfio/manager/user/UserManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -65,6 +66,7 @@ public class UserManager {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final InvoiceSequencesRepository invoiceSequencesRepository;
private final FindByIndexNameSessionRepository<?> sessionsByPrincipalFinder;


private List<Authority> getUserAuthorities(User user) {
Expand Down Expand Up @@ -317,6 +319,11 @@ public UserWithPassword resetPassword(int userId, Principal principal) {
checkAccessToUserId(principal, userId);
//
User user = internalFindUser(userId);

if (!principal.getName().equals(user.getUsername())) {
invalidateSessionsForUser(user.getUsername());
}

String password = PasswordGenerator.generateRandomPassword();
Validate.isTrue(userRepository.resetPassword(userId, passwordEncoder.encode(password)) == 1, "error during password reset");
return new UserWithPassword(user, password, UUID.randomUUID().toString());
Expand All @@ -338,7 +345,14 @@ public void deleteUser(int userId, Principal principal) {
var currentUsername = principal.getName();
User currentUser = userRepository.findEnabledByUsername(currentUsername).orElseThrow(IllegalArgumentException::new);
Assert.isTrue(userId != currentUser.getId(), "sorry but you cannot delete your own account.");
var userToDelete = userRepository.findById(userId);
userRepository.deleteUserAndReferences(userId);
invalidateSessionsForUser(userToDelete.getUsername());
}

private void invalidateSessionsForUser(String username) {
var sessionsToInvalidate = sessionsByPrincipalFinder.findByPrincipalName(username).keySet();
sessionsToInvalidate.forEach(sessionsByPrincipalFinder::deleteById);
}

public void enable(int userId, boolean status, Principal principal) {
Expand All @@ -350,6 +364,11 @@ public void enable(int userId, boolean status, Principal principal) {
Assert.isTrue(userId != currentUser.getId(), "sorry but you cannot commit suicide");

userRepository.toggleEnabled(userId, status);

if (!status) { // disable user
var userToDisable = userRepository.findById(userId);
invalidateSessionsForUser(userToDisable.getUsername());
}
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--
-- This file is part of alf.io.
--
-- alf.io is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- alf.io is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with alf.io. If not, see <http://www.gnu.org/licenses/>.
--

CREATE TABLE ALFIO_SPRING_SESSION (
PRIMARY_ID CHAR(36) NOT NULL,
SESSION_ID CHAR(36) NOT NULL,
CREATION_TIME BIGINT NOT NULL,
LAST_ACCESS_TIME BIGINT NOT NULL,
MAX_INACTIVE_INTERVAL INT NOT NULL,
EXPIRY_TIME BIGINT NOT NULL,
PRINCIPAL_NAME VARCHAR(100),
CONSTRAINT ALFIO_SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
);

CREATE UNIQUE INDEX ALFIO_SPRING_SESSION_IX1 ON ALFIO_SPRING_SESSION (SESSION_ID);
CREATE INDEX ALFIO_SPRING_SESSION_IX2 ON ALFIO_SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX ALFIO_SPRING_SESSION_IX3 ON ALFIO_SPRING_SESSION (PRINCIPAL_NAME);

CREATE TABLE ALFIO_SPRING_SESSION_ATTRIBUTES (
SESSION_PRIMARY_ID CHAR(36) NOT NULL,
ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
ATTRIBUTE_BYTES BYTEA NOT NULL,
CONSTRAINT ALFIO_SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT ALFIO_SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES ALFIO_SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
7 changes: 7 additions & 0 deletions src/test/java/alfio/TestConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
import alfio.repository.system.ConfigurationRepository;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.session.FindByIndexNameSessionRepository;

import java.time.Duration;
import java.util.Map;
Expand All @@ -54,4 +56,9 @@ ConfigurationManager configurationManager(ConfigurationRepository configurationR
environment,
cache);
}

@Bean
FindByIndexNameSessionRepository<?> sessionsByPrincipalFinder() {
return Mockito.mock(FindByIndexNameSessionRepository.class);
}
}

0 comments on commit cc5b039

Please sign in to comment.