From b98f8627ac3c4c677c3ff224d3d8299032f993e1 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:40:51 +0000 Subject: [PATCH] Csrf fix and ssoAutoLogin for enterprise users (#2653) This pull request includes several changes to the `SecurityConfiguration` and other related classes to enhance security and configuration management. The most important changes involve adding new beans, modifying logging levels, and updating dependency injections. Enhancements to security configuration: * [`src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java`](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4L3-L36): Added new dependencies and beans for `GrantedAuthoritiesMapper`, `RelyingPartyRegistrationRepository`, and `OpenSaml4AuthenticationRequestResolver`. Removed unused imports and simplified the class by removing the `@Lazy` annotation from `UserService`. [[1]](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4L3-L36) [[2]](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4L46-L63) [[3]](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4L75-R52) [[4]](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4R66-L98) [[5]](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4L109-R85) [[6]](diffhunk://#diff-49df1b16b72e9fcaa7d0c58f46c94ffda0033f5f5e3ddab90a88e2f9022b66f4R96-R98) Logging improvements: * [`src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java`](diffhunk://#diff-742f789731a32cb5aa20f7067ef18049002eec2a4909ef6f240d2a26bdcb53c4L97-R97): Changed the logging level from `info` to `debug` for the license validation response body to reduce log verbosity in production. Configuration updates: * [`src/main/java/stirling/software/SPDF/EE/EEAppConfig.java`](diffhunk://#diff-d842c2a4cf43f37ab5edcd644b19a51d614cb0e39963789e1c7e9fb28ddc1de8R30-R34): Added a new bean `ssoAutoLogin` to manage single sign-on auto-login configuration in the enterprise edition. These changes collectively enhance the security configuration and logging management of the application. Please provide a summary of the changes, including relevant motivation and context. Closes #(issue_number) ## Checklist - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have performed a self-review of my own code - [ ] I have attached images of the change if it is UI based - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) - [ ] My changes generate no new warnings - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) --- .../software/SPDF/EE/EEAppConfig.java | 5 + .../SPDF/EE/KeygenLicenseVerifier.java | 2 +- .../security/SecurityConfiguration.java | 329 +----------------- .../security/database/DatabaseConfig.java | 4 +- .../security/oauth2/OAuth2Configuration.java | 213 ++++++++++++ .../security/saml2/SAML2Configuration.java | 136 ++++++++ .../api/security/RedactController.java | 44 ++- .../SPDF/model/ApplicationProperties.java | 1 + .../api/security/ManualRedactPdfRequest.java | 1 + .../model/api/security/RedactionArea.java | 3 + .../StringToArrayListPropertyEditor.java | 4 +- src/main/resources/settings.yml.template | 5 +- src/main/resources/templates/account.html | 54 +-- src/main/resources/templates/login.html | 124 ++++--- test.sh | 10 +- 15 files changed, 532 insertions(+), 403 deletions(-) create mode 100644 src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml2/SAML2Configuration.java diff --git a/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java b/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java index 1d73cd93e..4648c033e 100644 --- a/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java +++ b/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java @@ -27,4 +27,9 @@ public class EEAppConfig { public boolean runningEnterpriseEdition() { return licenseKeyChecker.getEnterpriseEnabledResult(); } + + @Bean(name = "SSOAutoLogin") + public boolean ssoAutoLogin() { + return applicationProperties.getEnterpriseEdition().isSsoAutoLogin(); + } } diff --git a/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java b/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java index e9b14ac44..c75c98e9f 100644 --- a/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java +++ b/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java @@ -94,7 +94,7 @@ public class KeygenLicenseVerifier { .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - log.info(" validateLicenseResponse body: " + response.body()); + log.debug(" validateLicenseResponse body: " + response.body()); JsonNode jsonResponse = objectMapper.readTree(response.body()); if (response.statusCode() == 200) { diff --git a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java index 94422283c..7fbc44369 100644 --- a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java @@ -1,39 +1,24 @@ package stirling.software.SPDF.config.security; -import java.security.cert.X509Certificate; import java.util.*; -import org.opensaml.saml.saml2.core.AuthnRequest; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Lazy; -import org.springframework.core.io.Resource; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 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.http.SessionCreationPolicy; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ClientRegistrations; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; -import org.springframework.security.saml2.core.Saml2X509Credential; -import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType; import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider; -import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; -import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @@ -43,24 +28,16 @@ import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService; -import stirling.software.SPDF.config.security.saml2.CertificateUtils; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationFailureHandler; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationSuccessHandler; import stirling.software.SPDF.config.security.saml2.CustomSaml2ResponseAuthenticationConverter; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.model.ApplicationProperties; -import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; -import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client; -import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2; import stirling.software.SPDF.model.User; -import stirling.software.SPDF.model.provider.GithubProvider; -import stirling.software.SPDF.model.provider.GoogleProvider; -import stirling.software.SPDF.model.provider.KeycloakProvider; import stirling.software.SPDF.repository.JPATokenRepositoryImpl; import stirling.software.SPDF.repository.PersistentLoginRepository; @@ -72,7 +49,7 @@ import stirling.software.SPDF.repository.PersistentLoginRepository; public class SecurityConfiguration { private final CustomUserDetailsService userDetailsService; - @Lazy private final UserService userService; + private final UserService userService; @Qualifier("loginEnabled") private final boolean loginEnabledValue; @@ -86,16 +63,10 @@ public class SecurityConfiguration { private final FirstLoginFilter firstLoginFilter; private final SessionPersistentRegistry sessionRegistry; private final PersistentLoginRepository persistentLoginRepository; + private final GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper; + private final RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations; + private final OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver; - // // Only Dev test - // @Bean - // public WebSecurityCustomizer webSecurityCustomizer() { - // return (web) -> - // web.ignoring() - // .requestMatchers( - // "/css/**", "/images/**", "/js/**", "/**.svg", - // "/pdfjs-legacy/**"); - // } public SecurityConfiguration( PersistentLoginRepository persistentLoginRepository, CustomUserDetailsService userDetailsService, @@ -106,7 +77,12 @@ public class SecurityConfiguration { UserAuthenticationFilter userAuthenticationFilter, LoginAttemptService loginAttemptService, FirstLoginFilter firstLoginFilter, - SessionPersistentRegistry sessionRegistry) { + SessionPersistentRegistry sessionRegistry, + @Autowired(required = false) GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper, + @Autowired(required = false) + RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations, + @Autowired(required = false) + OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver) { this.userDetailsService = userDetailsService; this.userService = userService; this.loginEnabledValue = loginEnabledValue; @@ -117,6 +93,9 @@ public class SecurityConfiguration { this.firstLoginFilter = firstLoginFilter; this.sessionRegistry = sessionRegistry; this.persistentLoginRepository = persistentLoginRepository; + this.oAuth2userAuthoritiesMapper = oAuth2userAuthoritiesMapper; + this.saml2RelyingPartyRegistrations = saml2RelyingPartyRegistrations; + this.saml2AuthenticationRequestResolver = saml2AuthenticationRequestResolver; } @Bean @@ -274,7 +253,7 @@ public class SecurityConfiguration { userService, loginAttemptService)) .userAuthoritiesMapper( - userAuthoritiesMapper())) + oAuth2userAuthoritiesMapper)) .permitAll()); } // Handle SAML @@ -291,7 +270,7 @@ public class SecurityConfiguration { try { saml2.loginPage("/saml2") .relyingPartyRegistrationRepository( - relyingPartyRegistrations()) + saml2RelyingPartyRegistrations) .authenticationManager( new ProviderManager(authenticationProvider)) .successHandler( @@ -302,8 +281,7 @@ public class SecurityConfiguration { .failureHandler( new CustomSaml2AuthenticationFailureHandler()) .authenticationRequestResolver( - authenticationRequestResolver( - relyingPartyRegistrations())); + saml2AuthenticationRequestResolver); } catch (Exception e) { log.error("Error configuring SAML2 login", e); throw new RuntimeException(e); @@ -311,244 +289,11 @@ public class SecurityConfiguration { }); } } else { - // if (!applicationProperties.getSecurity().getCsrfDisabled()) { - // CookieCsrfTokenRepository cookieRepo = - // CookieCsrfTokenRepository.withHttpOnlyFalse(); - // CsrfTokenRequestAttributeHandler requestHandler = - // new CsrfTokenRequestAttributeHandler(); - // requestHandler.setCsrfRequestAttributeName(null); - // http.csrf( - // csrf -> - // csrf.csrfTokenRepository(cookieRepo) - // .csrfTokenRequestHandler(requestHandler)); - // } http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll()); } return http.build(); } - @Bean - @ConditionalOnProperty( - value = "security.oauth2.enabled", - havingValue = "true", - matchIfMissing = false) - public ClientRegistrationRepository clientRegistrationRepository() { - List registrations = new ArrayList<>(); - githubClientRegistration().ifPresent(registrations::add); - oidcClientRegistration().ifPresent(registrations::add); - googleClientRegistration().ifPresent(registrations::add); - keycloakClientRegistration().ifPresent(registrations::add); - if (registrations.isEmpty()) { - log.error("At least one OAuth2 provider must be configured"); - System.exit(1); - } - return new InMemoryClientRegistrationRepository(registrations); - } - - private Optional googleClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null || !oauth.getEnabled()) { - return Optional.empty(); - } - Client client = oauth.getClient(); - if (client == null) { - return Optional.empty(); - } - GoogleProvider google = client.getGoogle(); - return google != null && google.isSettingsValid() - ? Optional.of( - ClientRegistration.withRegistrationId(google.getName()) - .clientId(google.getClientId()) - .clientSecret(google.getClientSecret()) - .scope(google.getScopes()) - .authorizationUri(google.getAuthorizationuri()) - .tokenUri(google.getTokenuri()) - .userInfoUri(google.getUserinfouri()) - .userNameAttributeName(google.getUseAsUsername()) - .clientName(google.getClientName()) - .redirectUri("{baseUrl}/login/oauth2/code/" + google.getName()) - .authorizationGrantType( - org.springframework.security.oauth2.core - .AuthorizationGrantType.AUTHORIZATION_CODE) - .build()) - : Optional.empty(); - } - - private Optional keycloakClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null || !oauth.getEnabled()) { - return Optional.empty(); - } - Client client = oauth.getClient(); - if (client == null) { - return Optional.empty(); - } - KeycloakProvider keycloak = client.getKeycloak(); - return keycloak != null && keycloak.isSettingsValid() - ? Optional.of( - ClientRegistrations.fromIssuerLocation(keycloak.getIssuer()) - .registrationId(keycloak.getName()) - .clientId(keycloak.getClientId()) - .clientSecret(keycloak.getClientSecret()) - .scope(keycloak.getScopes()) - .userNameAttributeName(keycloak.getUseAsUsername()) - .clientName(keycloak.getClientName()) - .build()) - : Optional.empty(); - } - - private Optional githubClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null || !oauth.getEnabled()) { - return Optional.empty(); - } - Client client = oauth.getClient(); - if (client == null) { - return Optional.empty(); - } - GithubProvider github = client.getGithub(); - return github != null && github.isSettingsValid() - ? Optional.of( - ClientRegistration.withRegistrationId(github.getName()) - .clientId(github.getClientId()) - .clientSecret(github.getClientSecret()) - .scope(github.getScopes()) - .authorizationUri(github.getAuthorizationuri()) - .tokenUri(github.getTokenuri()) - .userInfoUri(github.getUserinfouri()) - .userNameAttributeName(github.getUseAsUsername()) - .clientName(github.getClientName()) - .redirectUri("{baseUrl}/login/oauth2/code/" + github.getName()) - .authorizationGrantType( - org.springframework.security.oauth2.core - .AuthorizationGrantType.AUTHORIZATION_CODE) - .build()) - : Optional.empty(); - } - - private Optional oidcClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null - || oauth.getIssuer() == null - || oauth.getIssuer().isEmpty() - || oauth.getClientId() == null - || oauth.getClientId().isEmpty() - || oauth.getClientSecret() == null - || oauth.getClientSecret().isEmpty() - || oauth.getScopes() == null - || oauth.getScopes().isEmpty() - || oauth.getUseAsUsername() == null - || oauth.getUseAsUsername().isEmpty()) { - return Optional.empty(); - } - return Optional.of( - ClientRegistrations.fromIssuerLocation(oauth.getIssuer()) - .registrationId("oidc") - .clientId(oauth.getClientId()) - .clientSecret(oauth.getClientSecret()) - .scope(oauth.getScopes()) - .userNameAttributeName(oauth.getUseAsUsername()) - .clientName("OIDC") - .build()); - } - - @Bean - @ConditionalOnProperty( - name = "security.saml2.enabled", - havingValue = "true", - matchIfMissing = false) - public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception { - SAML2 samlConf = applicationProperties.getSecurity().getSaml2(); - X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert()); - Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert); - Resource privateKeyResource = samlConf.getPrivateKey(); - Resource certificateResource = samlConf.getSpCert(); - Saml2X509Credential signingCredential = - new Saml2X509Credential( - CertificateUtils.readPrivateKey(privateKeyResource), - CertificateUtils.readCertificate(certificateResource), - Saml2X509CredentialType.SIGNING); - RelyingPartyRegistration rp = - RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId()) - .signingX509Credentials(c -> c.add(signingCredential)) - .assertingPartyMetadata( - metadata -> - metadata.entityId(samlConf.getIdpIssuer()) - .singleSignOnServiceLocation( - samlConf.getIdpSingleLoginUrl()) - .verificationX509Credentials( - c -> c.add(verificationCredential)) - .singleSignOnServiceBinding( - Saml2MessageBinding.POST) - .wantAuthnRequestsSigned(true)) - .build(); - return new InMemoryRelyingPartyRegistrationRepository(rp); - } - - @Bean - @ConditionalOnProperty( - name = "security.saml2.enabled", - havingValue = "true", - matchIfMissing = false) - public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver( - RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) { - OpenSaml4AuthenticationRequestResolver resolver = - new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository); - resolver.setAuthnRequestCustomizer( - customizer -> { - log.debug("Customizing SAML Authentication request"); - AuthnRequest authnRequest = customizer.getAuthnRequest(); - log.debug("AuthnRequest ID: {}", authnRequest.getID()); - if (authnRequest.getID() == null) { - authnRequest.setID("ARQ" + UUID.randomUUID().toString()); - } - log.debug("AuthnRequest new ID after set: {}", authnRequest.getID()); - log.debug("AuthnRequest IssueInstant: {}", authnRequest.getIssueInstant()); - log.debug( - "AuthnRequest Issuer: {}", - authnRequest.getIssuer() != null - ? authnRequest.getIssuer().getValue() - : "null"); - HttpServletRequest request = customizer.getRequest(); - // Log HTTP request details - log.debug("HTTP Request Method: {}", request.getMethod()); - log.debug("Request URI: {}", request.getRequestURI()); - log.debug("Request URL: {}", request.getRequestURL().toString()); - log.debug("Query String: {}", request.getQueryString()); - log.debug("Remote Address: {}", request.getRemoteAddr()); - // Log headers - Collections.list(request.getHeaderNames()) - .forEach( - headerName -> { - log.debug( - "Header - {}: {}", - headerName, - request.getHeader(headerName)); - }); - // Log SAML specific parameters - log.debug("SAML Request Parameters:"); - log.debug("SAMLRequest: {}", request.getParameter("SAMLRequest")); - log.debug("RelayState: {}", request.getParameter("RelayState")); - // Log session debugrmation if exists - if (request.getSession(false) != null) { - log.debug("Session ID: {}", request.getSession().getId()); - } - // Log any assertions consumer service details if present - if (authnRequest.getAssertionConsumerServiceURL() != null) { - log.debug( - "AssertionConsumerServiceURL: {}", - authnRequest.getAssertionConsumerServiceURL()); - } - // Log NameID policy if present - if (authnRequest.getNameIDPolicy() != null) { - log.debug( - "NameIDPolicy Format: {}", - authnRequest.getNameIDPolicy().getFormat()); - } - }); - return resolver; - } - public DaoAuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailsService); @@ -556,46 +301,6 @@ public class SecurityConfiguration { return provider; } - /* - This following function is to grant Authorities to the OAUTH2 user from the values stored in the database. - This is required for the internal; 'hasRole()' function to give out the correct role. - */ - @Bean - @ConditionalOnProperty( - value = "security.oauth2.enabled", - havingValue = "true", - matchIfMissing = false) - GrantedAuthoritiesMapper userAuthoritiesMapper() { - return (authorities) -> { - Set mappedAuthorities = new HashSet<>(); - authorities.forEach( - authority -> { - // Add existing OAUTH2 Authorities - mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority())); - // Add Authorities from database for existing user, if user is present. - if (authority instanceof OAuth2UserAuthority oauth2Auth) { - String useAsUsername = - applicationProperties - .getSecurity() - .getOauth2() - .getUseAsUsername(); - Optional userOpt = - userService.findByUsernameIgnoreCase( - (String) oauth2Auth.getAttributes().get(useAsUsername)); - if (userOpt.isPresent()) { - User user = userOpt.get(); - if (user != null) { - mappedAuthorities.add( - new SimpleGrantedAuthority( - userService.findRole(user).getAuthority())); - } - } - } - }); - return mappedAuthorities; - }; - } - @Bean public IPRateLimitingFilter rateLimitingFilter() { // Example limit TODO add config level diff --git a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java index 66ab1881e..124aee5cb 100644 --- a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java +++ b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java @@ -27,7 +27,9 @@ public class DatabaseConfig { private final ApplicationProperties applicationProperties; private final boolean runningEE; - public DatabaseConfig(ApplicationProperties applicationProperties, @Qualifier("runningEE") boolean runningEE) { + public DatabaseConfig( + ApplicationProperties applicationProperties, + @Qualifier("runningEE") boolean runningEE) { this.applicationProperties = applicationProperties; this.runningEE = runningEE; } diff --git a/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java b/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java new file mode 100644 index 000000000..b7571796c --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java @@ -0,0 +1,213 @@ +package stirling.software.SPDF.config.security.oauth2; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ClientRegistrations; +import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; +import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.security.UserService; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; +import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client; +import stirling.software.SPDF.model.User; +import stirling.software.SPDF.model.provider.GithubProvider; +import stirling.software.SPDF.model.provider.GoogleProvider; +import stirling.software.SPDF.model.provider.KeycloakProvider; + +@Configuration +@Slf4j +@ConditionalOnProperty( + value = "security.oauth2.enabled", + havingValue = "true", + matchIfMissing = false) +public class OAuth2Configuration { + + private final ApplicationProperties applicationProperties; + @Lazy private final UserService userService; + + public OAuth2Configuration( + ApplicationProperties applicationProperties, @Lazy UserService userService) { + this.userService = userService; + this.applicationProperties = applicationProperties; + } + + @Bean + @ConditionalOnProperty( + value = "security.oauth2.enabled", + havingValue = "true", + matchIfMissing = false) + public ClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>(); + githubClientRegistration().ifPresent(registrations::add); + oidcClientRegistration().ifPresent(registrations::add); + googleClientRegistration().ifPresent(registrations::add); + keycloakClientRegistration().ifPresent(registrations::add); + if (registrations.isEmpty()) { + log.error("At least one OAuth2 provider must be configured"); + System.exit(1); + } + return new InMemoryClientRegistrationRepository(registrations); + } + + private Optional googleClientRegistration() { + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); + if (oauth == null || !oauth.getEnabled()) { + return Optional.empty(); + } + Client client = oauth.getClient(); + if (client == null) { + return Optional.empty(); + } + GoogleProvider google = client.getGoogle(); + return google != null && google.isSettingsValid() + ? Optional.of( + ClientRegistration.withRegistrationId(google.getName()) + .clientId(google.getClientId()) + .clientSecret(google.getClientSecret()) + .scope(google.getScopes()) + .authorizationUri(google.getAuthorizationuri()) + .tokenUri(google.getTokenuri()) + .userInfoUri(google.getUserinfouri()) + .userNameAttributeName(google.getUseAsUsername()) + .clientName(google.getClientName()) + .redirectUri("{baseUrl}/login/oauth2/code/" + google.getName()) + .authorizationGrantType( + org.springframework.security.oauth2.core + .AuthorizationGrantType.AUTHORIZATION_CODE) + .build()) + : Optional.empty(); + } + + private Optional keycloakClientRegistration() { + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); + if (oauth == null || !oauth.getEnabled()) { + return Optional.empty(); + } + Client client = oauth.getClient(); + if (client == null) { + return Optional.empty(); + } + KeycloakProvider keycloak = client.getKeycloak(); + return keycloak != null && keycloak.isSettingsValid() + ? Optional.of( + ClientRegistrations.fromIssuerLocation(keycloak.getIssuer()) + .registrationId(keycloak.getName()) + .clientId(keycloak.getClientId()) + .clientSecret(keycloak.getClientSecret()) + .scope(keycloak.getScopes()) + .userNameAttributeName(keycloak.getUseAsUsername()) + .clientName(keycloak.getClientName()) + .build()) + : Optional.empty(); + } + + private Optional githubClientRegistration() { + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); + if (oauth == null || !oauth.getEnabled()) { + return Optional.empty(); + } + Client client = oauth.getClient(); + if (client == null) { + return Optional.empty(); + } + GithubProvider github = client.getGithub(); + return github != null && github.isSettingsValid() + ? Optional.of( + ClientRegistration.withRegistrationId(github.getName()) + .clientId(github.getClientId()) + .clientSecret(github.getClientSecret()) + .scope(github.getScopes()) + .authorizationUri(github.getAuthorizationuri()) + .tokenUri(github.getTokenuri()) + .userInfoUri(github.getUserinfouri()) + .userNameAttributeName(github.getUseAsUsername()) + .clientName(github.getClientName()) + .redirectUri("{baseUrl}/login/oauth2/code/" + github.getName()) + .authorizationGrantType( + org.springframework.security.oauth2.core + .AuthorizationGrantType.AUTHORIZATION_CODE) + .build()) + : Optional.empty(); + } + + private Optional oidcClientRegistration() { + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); + if (oauth == null + || oauth.getIssuer() == null + || oauth.getIssuer().isEmpty() + || oauth.getClientId() == null + || oauth.getClientId().isEmpty() + || oauth.getClientSecret() == null + || oauth.getClientSecret().isEmpty() + || oauth.getScopes() == null + || oauth.getScopes().isEmpty() + || oauth.getUseAsUsername() == null + || oauth.getUseAsUsername().isEmpty()) { + return Optional.empty(); + } + return Optional.of( + ClientRegistrations.fromIssuerLocation(oauth.getIssuer()) + .registrationId("oidc") + .clientId(oauth.getClientId()) + .clientSecret(oauth.getClientSecret()) + .scope(oauth.getScopes()) + .userNameAttributeName(oauth.getUseAsUsername()) + .clientName("OIDC") + .build()); + } + + /* + This following function is to grant Authorities to the OAUTH2 user from the values stored in the database. + This is required for the internal; 'hasRole()' function to give out the correct role. + */ + @Bean + @ConditionalOnProperty( + value = "security.oauth2.enabled", + havingValue = "true", + matchIfMissing = false) + GrantedAuthoritiesMapper userAuthoritiesMapper() { + return (authorities) -> { + Set mappedAuthorities = new HashSet<>(); + authorities.forEach( + authority -> { + // Add existing OAUTH2 Authorities + mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority())); + // Add Authorities from database for existing user, if user is present. + if (authority instanceof OAuth2UserAuthority oauth2Auth) { + String useAsUsername = + applicationProperties + .getSecurity() + .getOauth2() + .getUseAsUsername(); + Optional userOpt = + userService.findByUsernameIgnoreCase( + (String) oauth2Auth.getAttributes().get(useAsUsername)); + if (userOpt.isPresent()) { + User user = userOpt.get(); + if (user != null) { + mappedAuthorities.add( + new SimpleGrantedAuthority( + userService.findRole(user).getAuthority())); + } + } + } + }); + return mappedAuthorities; + }; + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml2/SAML2Configuration.java b/src/main/java/stirling/software/SPDF/config/security/saml2/SAML2Configuration.java new file mode 100644 index 000000000..0e4b83d11 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml2/SAML2Configuration.java @@ -0,0 +1,136 @@ +package stirling.software.SPDF.config.security.saml2; + +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.UUID; + +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.security.saml2.core.Saml2X509Credential; +import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType; +import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; +import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; +import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2; + +@Configuration +@Slf4j +@ConditionalOnProperty( + value = "security.saml2.enabled", + havingValue = "true", + matchIfMissing = false) +public class SAML2Configuration { + + private final ApplicationProperties applicationProperties; + + public SAML2Configuration(ApplicationProperties applicationProperties) { + + this.applicationProperties = applicationProperties; + } + + @Bean + @ConditionalOnProperty( + name = "security.saml2.enabled", + havingValue = "true", + matchIfMissing = false) + public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception { + SAML2 samlConf = applicationProperties.getSecurity().getSaml2(); + X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert()); + Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert); + Resource privateKeyResource = samlConf.getPrivateKey(); + Resource certificateResource = samlConf.getSpCert(); + Saml2X509Credential signingCredential = + new Saml2X509Credential( + CertificateUtils.readPrivateKey(privateKeyResource), + CertificateUtils.readCertificate(certificateResource), + Saml2X509CredentialType.SIGNING); + RelyingPartyRegistration rp = + RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId()) + .signingX509Credentials(c -> c.add(signingCredential)) + .assertingPartyMetadata( + metadata -> + metadata.entityId(samlConf.getIdpIssuer()) + .singleSignOnServiceLocation( + samlConf.getIdpSingleLoginUrl()) + .verificationX509Credentials( + c -> c.add(verificationCredential)) + .singleSignOnServiceBinding( + Saml2MessageBinding.POST) + .wantAuthnRequestsSigned(true)) + .build(); + return new InMemoryRelyingPartyRegistrationRepository(rp); + } + + @Bean + @ConditionalOnProperty( + name = "security.saml2.enabled", + havingValue = "true", + matchIfMissing = false) + public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver( + RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) { + OpenSaml4AuthenticationRequestResolver resolver = + new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository); + resolver.setAuthnRequestCustomizer( + customizer -> { + log.debug("Customizing SAML Authentication request"); + AuthnRequest authnRequest = customizer.getAuthnRequest(); + log.debug("AuthnRequest ID: {}", authnRequest.getID()); + if (authnRequest.getID() == null) { + authnRequest.setID("ARQ" + UUID.randomUUID().toString()); + } + log.debug("AuthnRequest new ID after set: {}", authnRequest.getID()); + log.debug("AuthnRequest IssueInstant: {}", authnRequest.getIssueInstant()); + log.debug( + "AuthnRequest Issuer: {}", + authnRequest.getIssuer() != null + ? authnRequest.getIssuer().getValue() + : "null"); + HttpServletRequest request = customizer.getRequest(); + // Log HTTP request details + log.debug("HTTP Request Method: {}", request.getMethod()); + log.debug("Request URI: {}", request.getRequestURI()); + log.debug("Request URL: {}", request.getRequestURL().toString()); + log.debug("Query String: {}", request.getQueryString()); + log.debug("Remote Address: {}", request.getRemoteAddr()); + // Log headers + Collections.list(request.getHeaderNames()) + .forEach( + headerName -> { + log.debug( + "Header - {}: {}", + headerName, + request.getHeader(headerName)); + }); + // Log SAML specific parameters + log.debug("SAML Request Parameters:"); + log.debug("SAMLRequest: {}", request.getParameter("SAMLRequest")); + log.debug("RelayState: {}", request.getParameter("RelayState")); + // Log session debugrmation if exists + if (request.getSession(false) != null) { + log.debug("Session ID: {}", request.getSession().getId()); + } + // Log any assertions consumer service details if present + if (authnRequest.getAssertionConsumerServiceURL() != null) { + log.debug( + "AssertionConsumerServiceURL: {}", + authnRequest.getAssertionConsumerServiceURL()); + } + // Log NameID policy if present + if (authnRequest.getNameIDPolicy() != null) { + log.debug( + "NameIDPolicy Format: {}", + authnRequest.getNameIDPolicy().getFormat()); + } + }); + return resolver; + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java index d123e2ef8..19d54b0b7 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java @@ -26,7 +26,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; - import stirling.software.SPDF.model.PDFText; import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest; import stirling.software.SPDF.model.api.security.RedactPdfRequest; @@ -53,12 +52,17 @@ public class RedactController { @InitBinder public void initBinder(WebDataBinder binder) { - binder.registerCustomEditor(List.class, "redactions", new StringToArrayListPropertyEditor()); + binder.registerCustomEditor( + List.class, "redactions", new StringToArrayListPropertyEditor()); } @PostMapping(value = "/redact", consumes = "multipart/form-data") - @Operation(summary = "Redacts areas and pages in a PDF document", description = "This operation takes an input PDF file with a list of areas, page number(s)/range(s)/function(s) to redact. Input:PDF, Output:PDF, Type:SISO") - public ResponseEntity redactPDF(@ModelAttribute ManualRedactPdfRequest request) throws IOException { + @Operation( + summary = "Redacts areas and pages in a PDF document", + description = + "This operation takes an input PDF file with a list of areas, page number(s)/range(s)/function(s) to redact. Input:PDF, Output:PDF, Type:SISO") + public ResponseEntity redactPDF(@ModelAttribute ManualRedactPdfRequest request) + throws IOException { MultipartFile file = request.getFileInput(); List redactionAreas = request.getRedactions(); @@ -86,18 +90,22 @@ public class RedactController { + "_redacted.pdf"); } - private void redactAreas(List redactionAreas, PDDocument document, PDPageTree allPages) + private void redactAreas( + List redactionAreas, PDDocument document, PDPageTree allPages) throws IOException { Color redactColor = null; for (RedactionArea redactionArea : redactionAreas) { - if (redactionArea.getPage() == null || redactionArea.getPage() <= 0 - || redactionArea.getHeight() == null || redactionArea.getHeight() <= 0.0D - || redactionArea.getWidth() == null || redactionArea.getWidth() <= 0.0D) - continue; + if (redactionArea.getPage() == null + || redactionArea.getPage() <= 0 + || redactionArea.getHeight() == null + || redactionArea.getHeight() <= 0.0D + || redactionArea.getWidth() == null + || redactionArea.getWidth() <= 0.0D) continue; PDPage page = allPages.get(redactionArea.getPage() - 1); - PDPageContentStream contentStream = new PDPageContentStream( - document, page, PDPageContentStream.AppendMode.APPEND, true, true); + PDPageContentStream contentStream = + new PDPageContentStream( + document, page, PDPageContentStream.AppendMode.APPEND, true, true); redactColor = decodeOrDefault(redactionArea.getColor(), Color.BLACK); contentStream.setNonStrokingColor(redactColor); @@ -114,15 +122,17 @@ public class RedactController { } } - private void redactPages(ManualRedactPdfRequest request, PDDocument document, PDPageTree allPages) + private void redactPages( + ManualRedactPdfRequest request, PDDocument document, PDPageTree allPages) throws IOException { Color redactColor = decodeOrDefault(request.getPageRedactionColor(), Color.BLACK); List pageNumbers = getPageNumbers(request, allPages.getCount()); for (Integer pageNumber : pageNumbers) { PDPage page = allPages.get(pageNumber); - PDPageContentStream contentStream = new PDPageContentStream( - document, page, PDPageContentStream.AppendMode.APPEND, true, true); + PDPageContentStream contentStream = + new PDPageContentStream( + document, page, PDPageContentStream.AppendMode.APPEND, true, true); contentStream.setNonStrokingColor(redactColor); PDRectangle box = page.getBBox(); @@ -146,8 +156,10 @@ public class RedactController { private List getPageNumbers(ManualRedactPdfRequest request, int pagesCount) { String pageNumbersInput = request.getPageNumbers(); - String[] parsedPageNumbers = pageNumbersInput != null ? pageNumbersInput.split(",") : new String[0]; - List pageNumbers = GeneralUtils.parsePageList(parsedPageNumbers, pagesCount, false); + String[] parsedPageNumbers = + pageNumbersInput != null ? pageNumbersInput.split(",") : new String[0]; + List pageNumbers = + GeneralUtils.parsePageList(parsedPageNumbers, pagesCount, false); Collections.sort(pageNumbers); return pageNumbers; } diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java index 1df2208f8..a10c945a8 100644 --- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java +++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java @@ -366,6 +366,7 @@ public class ApplicationProperties { private boolean enabled; @ToString.Exclude private String key; private int maxUsers; + private boolean ssoAutoLogin; private CustomMetadata customMetadata = new CustomMetadata(); @Data diff --git a/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java b/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java index cb98499e0..0bd2d41d7 100644 --- a/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java +++ b/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java @@ -3,6 +3,7 @@ package stirling.software.SPDF.model.api.security; import java.util.List; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; import stirling.software.SPDF.model.api.PDFWithPageNums; diff --git a/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java b/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java index 5157d415d..a8d2a61ad 100644 --- a/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java +++ b/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java @@ -1,17 +1,20 @@ package stirling.software.SPDF.model.api.security; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; @Data public class RedactionArea { @Schema(description = "The left edge point of the area to be redacted.") private Double x; + @Schema(description = "The top edge point of the area to be redacted.") private Double y; @Schema(description = "The height of the area to be redacted.") private Double height; + @Schema(description = "The width of the area to be redacted.") private Double width; diff --git a/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java b/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java index cbcb61721..d4ec7acc4 100644 --- a/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java +++ b/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java @@ -24,8 +24,8 @@ public class StringToArrayListPropertyEditor extends PropertyEditorSupport { } try { objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); - TypeReference> typeRef = new TypeReference>() { - }; + TypeReference> typeRef = + new TypeReference>() {}; List list = objectMapper.readValue(text, typeRef); setValue(list); } catch (Exception e) { diff --git a/src/main/resources/settings.yml.template b/src/main/resources/settings.yml.template index 1b7ef5030..6ab2a8c72 100644 --- a/src/main/resources/settings.yml.template +++ b/src/main/resources/settings.yml.template @@ -63,6 +63,7 @@ security: enterpriseEdition: enabled: false # set to 'true' to enable enterprise edition key: 00000000-0000-0000-0000-000000000000 + SSOAutoLogin: false # Enable to auto login to first provided SSO CustomMetadata: autoUpdateMetadata: false # set to 'true' to automatically update metadata with below values author: username # supports text such as 'John Doe' or types such as username to autopopulate with user's username @@ -86,8 +87,8 @@ system: tessdataDir: /usr/share/tessdata # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored. enableAnalytics: 'true' # set to 'true' to enable analytics, set to 'false' to disable analytics; for enterprise users, this is set to true datasource: - enableCustomDatabase: false # set this property to 'true' if you would like to use your own custom database configuration - customDatabaseUrl: jdbc:postgresql://localhost:5432/postgres # set the url for your own custom database connection. If provided, the type, hostName, port and name are not necessary and will not be used + enableCustomDatabase: false # Enterprise users ONLY, set this property to 'true' if you would like to use your own custom database configuration + customDatabaseUrl: '' # eg jdbc:postgresql://localhost:5432/postgres, set the url for your own custom database connection. If provided, the type, hostName, port and name are not necessary and will not be used username: postgres # set the database username password: postgres # set the database password type: postgresql # the type of the database to set (e.g. 'h2', 'postgresql') diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index 1e61db9d7..c26b93d0c 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -267,7 +267,7 @@ diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index e4a5e3dda..cee20450b 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -11,48 +11,88 @@
-
favicon diff --git a/test.sh b/test.sh index d789c6be7..820d80822 100644 --- a/test.sh +++ b/test.sh @@ -73,15 +73,15 @@ main() { # Building Docker images - # docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile . - # docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite . + # docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile . + docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite . # Test each configuration - #run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" - #docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" down + run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" + docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" down - # run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml" + #run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml" #docker-compose -f "./exampleYmlFiles/docker-compose-latest.yml" down export DOCKER_ENABLE_SECURITY=true