From cede5e5383468f5873bf257e44ea7cf7f662f1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francesco=20Chicchiricc=C3=B2?= Date: Thu, 20 Jul 2023 13:24:37 +0200 Subject: [PATCH] Upgrading Spring Boot, Wicket and friends, Swagger UI, MySQL JDBC driver and PDFBox --- .../html/form/preview/BinaryPDFPreviewer.java | 21 ++++----- .../core/logic/NetworkServiceLogic.java | 16 +++---- .../api/dao/NetworkServiceDAO.java | 2 + .../jpa/dao/JPANetworkServiceDAO.java | 12 +++++ .../jpa/entity/JPANetworkService.java | 4 +- .../spring/security/WebSecurityContext.java | 6 ++- pom.xml | 16 +++---- wa/starter/pom.xml | 4 ++ .../syncope/wa/starter/config/WAContext.java | 45 +++++++++++++++++++ 9 files changed, 94 insertions(+), 32 deletions(-) diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java index b701a036648..1dc1b599d8d 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java @@ -21,14 +21,11 @@ import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.time.Instant; import org.apache.pdfbox.Loader; import org.apache.pdfbox.cos.COSObject; -import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.pdmodel.DefaultResourceCache; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.graphics.PDXObject; @@ -63,15 +60,13 @@ public BinaryPDFPreviewer(final String mimeType) { public Component preview(final byte[] uploadedBytes) { firstPage = null; - try (InputStream bais = new ByteArrayInputStream(uploadedBytes); - PDDocument document = Loader.loadPDF(bais, MemoryUsageSetting.setupTempFileOnly())) { - + try (PDDocument document = Loader.loadPDF(uploadedBytes)) { document.setResourceCache(new DefaultResourceCache() { @Override - public void put(final COSObject indirect, final PDXObject xobject) throws IOException { + public void put(final COSObject indirect, final PDXObject xobject) { + // no cache } - }); if (document.isEncrypted()) { LOG.info("Document is encrypted, no preview is possible"); @@ -96,15 +91,15 @@ public void put(final COSObject indirect, final PDXObject xobject) throws IOExce return this.addOrReplace(previewContainer); } - private static class ThumbnailImageResource extends DynamicImageResource implements Serializable { + protected static class ThumbnailImageResource extends DynamicImageResource implements Serializable { private static final long serialVersionUID = 923201517955737928L; - private final transient BufferedImage image; + protected final transient BufferedImage image; - private transient byte[] thumbnail; + protected transient byte[] thumbnail; - ThumbnailImageResource(final BufferedImage image) { + protected ThumbnailImageResource(final BufferedImage image) { this.image = image; } @@ -117,7 +112,7 @@ protected byte[] getImageData(final IResource.Attributes attributes) { return thumbnail; } - private BufferedImage getScaledImageInstance() { + protected BufferedImage getScaledImageInstance() { int originalWidth = image.getWidth(); int originalHeight = image.getHeight(); diff --git a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java index 15a0d1443a4..030107e661d 100644 --- a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java +++ b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java @@ -74,19 +74,19 @@ public NetworkService get(final NetworkService.Type serviceType) { @PreAuthorize("@environment.getProperty('keymaster.username') == authentication.name") public void register(final NetworkService networkService) { - unregister(networkService); + if (serviceDAO.findAll(networkService.getType()).stream(). + noneMatch(s -> s.getAddress().equals(networkService.getAddress()))) { - NetworkServiceEntity service = entityFactory.newNetworkService(); - service.setType(networkService.getType()); - service.setAddress(networkService.getAddress()); - serviceDAO.save(service); + NetworkServiceEntity service = entityFactory.newNetworkService(); + service.setType(networkService.getType()); + service.setAddress(networkService.getAddress()); + serviceDAO.save(service); + } } @PreAuthorize("@environment.getProperty('keymaster.username') == authentication.name") public void unregister(final NetworkService networkService) { - serviceDAO.findAll(networkService.getType()).stream(). - filter(service -> service.getAddress().equals(networkService.getAddress())). - forEach(service -> serviceDAO.delete(service)); + serviceDAO.deleteAll(networkService); } @Override diff --git a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/api/dao/NetworkServiceDAO.java b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/api/dao/NetworkServiceDAO.java index ccf27351126..a1996f3173f 100644 --- a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/api/dao/NetworkServiceDAO.java +++ b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/api/dao/NetworkServiceDAO.java @@ -29,4 +29,6 @@ public interface NetworkServiceDAO extends DAO { NetworkServiceEntity save(NetworkServiceEntity service); void delete(NetworkServiceEntity service); + + int deleteAll(NetworkService service); } diff --git a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPANetworkServiceDAO.java b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPANetworkServiceDAO.java index 2a4a43494b3..422208a5199 100644 --- a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPANetworkServiceDAO.java +++ b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPANetworkServiceDAO.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.core.persistence.jpa.dao; +import jakarta.persistence.Query; import jakarta.persistence.TypedQuery; import java.util.List; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; @@ -47,4 +48,15 @@ public NetworkServiceEntity save(final NetworkServiceEntity service) { public void delete(final NetworkServiceEntity service) { entityManager().remove(service); } + + @Override + public int deleteAll(final NetworkService service) { + Query query = entityManager().createQuery( + "DELETE FROM " + JPANetworkService.class.getSimpleName() + + " e WHERE e.type=:serviceType AND e.address=:address"); + query.setParameter("serviceType", service.getType()); + query.setParameter("address", service.getAddress()); + + return query.executeUpdate(); + } } diff --git a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANetworkService.java b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANetworkService.java index 279829682a6..aae6d533fbb 100644 --- a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANetworkService.java +++ b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANetworkService.java @@ -22,12 +22,14 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import jakarta.validation.constraints.NotNull; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.core.persistence.api.entity.NetworkServiceEntity; @Entity -@Table(name = JPANetworkService.TABLE) +@Table(name = JPANetworkService.TABLE, uniqueConstraints = + @UniqueConstraint(columnNames = { "type", "address" })) public class JPANetworkService extends AbstractGeneratedKeyEntity implements NetworkServiceEntity { private static final long serialVersionUID = 8742750097008236475L; diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java index b80795640c5..5833899dcd5 100644 --- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java +++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java @@ -49,6 +49,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.firewall.DefaultHttpFirewall; import org.springframework.security.web.firewall.HttpFirewall; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) @@ -103,8 +104,9 @@ public SecurityFilterChain filterChain( http.addFilterBefore(mustChangePasswordFilter, AuthorizationFilter.class); http.authorizeHttpRequests(customizer -> customizer. - requestMatchers("/actuator/**").hasAuthority(IdRepoEntitlement.ANONYMOUS). - requestMatchers("/**").permitAll()); + requestMatchers(AntPathRequestMatcher.antMatcher("/actuator/**")). + hasAuthority(IdRepoEntitlement.ANONYMOUS). + requestMatchers(AntPathRequestMatcher.antMatcher("/**")).permitAll()); http.securityContext(AbstractHttpConfigurer::disable); http.sessionManagement(AbstractHttpConfigurer::disable); http.headers(AbstractHttpConfigurer::disable); diff --git a/pom.xml b/pom.xml index 748cfb01d20..24ecbc0d8c2 100644 --- a/pom.xml +++ b/pom.xml @@ -413,7 +413,7 @@ under the License. 1.75 9.31 - 3.1.1 + 3.1.2 4.0.6 4.0.0-SNAPSHOT @@ -438,7 +438,7 @@ under the License. 2.2.220 2.2.15 - 5.1.0 + 5.1.3 1.3.8 1.4.1-1 @@ -452,10 +452,10 @@ under the License. 4.1.2 10.0.0-M1 - 10.0.0-SNAPSHOT - 10.0.0-SNAPSHOT - 7.0.0-SNAPSHOT - 4.0.0-SNAPSHOT + 10.0.0-M1 + 10.0.0-M1 + 7.0.0 + 4.0.0-M1 4.13.0 @@ -496,7 +496,7 @@ under the License. 11 42.6.0 - 8.0.33 + 8.1.0 3.1.4 12.2.0.jre 23.2.0.0 @@ -1077,7 +1077,7 @@ under the License. org.apache.pdfbox pdfbox - 3.0.0-alpha3 + 3.0.0-beta1 diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml index 12eca30fdf5..e4c8a26aca1 100644 --- a/wa/starter/pom.xml +++ b/wa/starter/pom.xml @@ -123,6 +123,10 @@ under the License. org.apereo.cas cas-server-core-web + + org.apereo.cas + cas-server-core-web-api + org.apereo.cas cas-server-core-webflow diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java index d5d6b3c2266..c27b2c4a88c 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java +++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java @@ -21,6 +21,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.warrenstrange.googleauth.IGoogleAuthenticator; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; @@ -100,8 +101,11 @@ import org.apereo.cas.support.saml.web.idp.profile.builders.enc.SamlIdPObjectSigner; import org.apereo.cas.util.DateTimeUtils; import org.apereo.cas.util.LdapUtils; +import org.apereo.cas.util.RandomUtils; import org.apereo.cas.util.crypto.CipherExecutor; +import org.apereo.cas.web.ProtocolEndpointWebSecurityConfigurer; import org.apereo.cas.webauthn.storage.WebAuthnCredentialRepository; +import org.apereo.cas.webauthn.web.WebAuthnController; import org.ldaptive.ConnectionFactory; import org.opensaml.saml.metadata.resolver.MetadataResolver; import org.pac4j.core.client.Client; @@ -117,6 +121,11 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager; +import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration(proxyBeanMethods = false) public class WAContext { @@ -422,6 +431,42 @@ public U2FDeviceRepository u2fDeviceRepository( return new WAU2FDeviceRepository(casProperties, requestStorage, waRestClient, expirationDate); } + @Bean + @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT) + public ProtocolEndpointWebSecurityConfigurer webAuthnProtocolEndpointConfigurer( + @Qualifier("webAuthnCsrfTokenRepository") + final ObjectProvider webAuthnCsrfTokenRepository) { + + return new ProtocolEndpointWebSecurityConfigurer<>() { + + @Override + @CanIgnoreReturnValue + @SuppressWarnings("UnnecessaryMethodReference") + public ProtocolEndpointWebSecurityConfigurer configure(final HttpSecurity http) + throws Exception { + + http.csrf(customizer -> webAuthnCsrfTokenRepository.ifAvailable(repository -> { + var pattern = new AntPathRequestMatcher(WebAuthnController.BASE_ENDPOINT_WEBAUTHN + "/**"); + var delegate = new XorCsrfTokenRequestAttributeHandler(); + delegate.setSecureRandom(RandomUtils.getNativeInstance()); + customizer.requireCsrfProtectionMatcher(pattern) + .csrfTokenRequestHandler(delegate::handle) + .csrfTokenRepository(repository); + + })); + http.authorizeHttpRequests(customizer -> { + customizer.requestMatchers(new AntPathRequestMatcher(WebAuthnController.BASE_ENDPOINT_WEBAUTHN + + WebAuthnController.WEBAUTHN_ENDPOINT_REGISTER + "/**")) + .access(new WebExpressionAuthorizationManager("hasRole('USER') and isAuthenticated()")); + customizer.requestMatchers(new AntPathRequestMatcher(WebAuthnController.BASE_ENDPOINT_WEBAUTHN + + WebAuthnController.WEBAUTHN_ENDPOINT_AUTHENTICATE + "/**")) + .permitAll(); + }); + return this; + } + }; + } + @Bean public SurrogateAuthenticationService surrogateAuthenticationService(final WARestClient waRestClient) { return new WASurrogateAuthenticationService(waRestClient);