diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml index 7b3120c..14becab 100644 --- a/.github/workflows/maven-build.yml +++ b/.github/workflows/maven-build.yml @@ -7,19 +7,19 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: zulu - java-version: 11 + java-version: 17 - name: Cache Maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 - key: ${{ runner.os }}-m2-v11-${{ secrets.CACHE_VERSION }}-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2-v11-${{ secrets.CACHE_VERSION }} + key: ${{ runner.os }}-m2-v17-${{ secrets.CACHE_VERSION }}-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2-v17-${{ secrets.CACHE_VERSION }} - name: Build run: mvn --batch-mode compile diff --git a/README.md b/README.md index 55049e7..5ab2297 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Web eID only works over a HTTPS connection with a trusted HTTPS certificate. You can either setup a reverse HTTPS proxy during development or, alternatively, configure HTTPS support directly in the bundled web server. HTTPS configuration is described in more detail in section _[HTTPS support](#https-support)_ below. -You can use, for example, [_ngrok_](https://ngrok.com/) to get a reverse HTTPS proxy. Download _ngrok_ and run it in a terminal window by providing the protocol and Spring Boot application port arguments as follows: +You can use, for example, [_ngrok_](https://ngrok.com/) or [_localtunnel_](https://theboroer.github.io/localtunnel-www/) to get a reverse HTTPS proxy. Download _ngrok_ and run it in a terminal window by providing the protocol and Spring Boot application port arguments as follows: ngrok http 8080 @@ -35,7 +35,7 @@ web-eid-auth-token: ### 3. Configure the trusted certificate authority certificates -The algorithm, which performs the validation of the Web eID authentication token, needs to know which intermediate certificate authorities (CA) are trusted to issue the eID authentication certificates. CA certificates are loaded either from `.cer` files in the profile-specific subdirectory of the [`certs`resource directory](src/main/resources/certs) or the [truststore file](src/main/resources/certs/prod/trusted_certificates.jks). By default, Estonian eID test CA certificates are included in the `dev` profile and production CA certificates in the `prod` profile. +The algorithm, which performs the validation of the Web eID authentication token, needs to know which intermediate certificate authorities (CA) are trusted to issue the eID authentication certificates. CA certificates are loaded either from `.cer` files in the profile-specific subdirectory of the [`certs` resource directory](src/main/resources/certs) or the [truststore file](src/main/resources/certs/prod/trusted_certificates.jks). By default, Estonian eID test CA certificates are included in the `dev` profile and production CA certificates in the `prod` profile. In case you need to provide your own CA certificates, either add the `.cer` files to the `src/main/resources/certs/{dev,prod}` profile-specific directory or add the certificates to the truststore file. @@ -49,7 +49,7 @@ You can specify the profile as a command-line argument to the Maven wrapper comm ### 5. Run the application -Spring Boot web applications can be run from the command-line. You need to have the Java Development Kit 8 installed for building the application package and running the application. +Spring Boot web applications can be run from the command-line. You need to have the Java Development Kit 17 installed for building the application package and running the application. Build and run the application with the following command in a terminal window: diff --git a/pom.xml b/pom.xml index 3568a9c..e35b076 100644 --- a/pom.xml +++ b/pom.xml @@ -5,22 +5,22 @@ org.springframework.boot spring-boot-starter-parent - 2.7.15 + 3.2.4 - org.webeid.example + eu.webeid.example web-eid-springboot-example 3.0.0-SNAPSHOT web-eid-springboot-example - Example Spring Boot project that demonstrates how to use Web eID for authentication and digital + Example Spring Boot application that demonstrates how to use Web eID for authentication and digital signing - 11 - 2.22.1 - 3.0.0 - 5.2.0 + 17 + 3.2.5 + 3.0.1 + 5.3.0 1.44 @@ -31,20 +31,12 @@ org.springframework.boot - spring-boot-starter-validation + spring-boot-starter-security org.springframework.boot spring-boot-starter-thymeleaf - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.security - spring-security-config - org.digidoc4j @@ -57,22 +49,10 @@ ${webeid.version} - - org.springframework.boot - spring-boot-devtools - true - - org.springframework.boot spring-boot-starter-test test - - - org.junit.vintage - junit-vintage-engine - - org.springframework.security diff --git a/src/main/java/eu/webeid/example/config/ApplicationConfiguration.java b/src/main/java/eu/webeid/example/config/ApplicationConfiguration.java index 9fba315..d93c942 100644 --- a/src/main/java/eu/webeid/example/config/ApplicationConfiguration.java +++ b/src/main/java/eu/webeid/example/config/ApplicationConfiguration.java @@ -24,12 +24,14 @@ import eu.webeid.example.security.AuthTokenDTOAuthenticationProvider; import eu.webeid.example.security.WebEidAjaxLoginProcessingFilter; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +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.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; @@ -37,40 +39,21 @@ @Configuration @EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) -public class ApplicationConfiguration extends WebSecurityConfigurerAdapter implements WebMvcConfigurer { - final AuthTokenDTOAuthenticationProvider authTokenDTOAuthenticationProvider; - - public ApplicationConfiguration(AuthTokenDTOAuthenticationProvider authTokenDTOAuthenticationProvider) { - this.authTokenDTOAuthenticationProvider = authTokenDTOAuthenticationProvider; - } - - @Override - protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) { - authenticationManagerBuilder.authenticationProvider(authTokenDTOAuthenticationProvider); +@EnableMethodSecurity(securedEnabled = true) +public class ApplicationConfiguration implements WebMvcConfigurer { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http, AuthTokenDTOAuthenticationProvider authTokenDTOAuthenticationProvider, AuthenticationConfiguration authConfig) throws Exception { + return http + .authenticationProvider(authTokenDTOAuthenticationProvider) + .addFilterBefore(new WebEidAjaxLoginProcessingFilter("/auth/login", authConfig.getAuthenticationManager()), + UsernamePasswordAuthenticationFilter.class) + .logout(logout -> logout.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())) + .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)) + .build(); } @Override - protected void configure(HttpSecurity http) throws Exception { - // @formatter:off - http - .addFilterBefore( - new WebEidAjaxLoginProcessingFilter("/auth/login", authenticationManager()), - UsernamePasswordAuthenticationFilter.class) - .authorizeRequests() - .antMatchers("/auth/challenge", "/auth/login", "/") - .permitAll() - .antMatchers("/welcome") - .authenticated() - .and() - .logout() - .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler()) - .and() - .headers() - .frameOptions().sameOrigin(); - // @formatter:on - } - public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/welcome").setViewName("welcome"); diff --git a/src/main/java/eu/webeid/example/config/SessionBackedChallengeNonceStore.java b/src/main/java/eu/webeid/example/config/SessionBackedChallengeNonceStore.java index c94a324..cb4654d 100644 --- a/src/main/java/eu/webeid/example/config/SessionBackedChallengeNonceStore.java +++ b/src/main/java/eu/webeid/example/config/SessionBackedChallengeNonceStore.java @@ -26,7 +26,7 @@ import eu.webeid.security.challenge.ChallengeNonce; import eu.webeid.security.challenge.ChallengeNonceStore; -import javax.servlet.http.HttpSession; +import jakarta.servlet.http.HttpSession; public class SessionBackedChallengeNonceStore implements ChallengeNonceStore { diff --git a/src/main/java/eu/webeid/example/config/ValidationConfiguration.java b/src/main/java/eu/webeid/example/config/ValidationConfiguration.java index 83f0f47..dbe21ee 100644 --- a/src/main/java/eu/webeid/example/config/ValidationConfiguration.java +++ b/src/main/java/eu/webeid/example/config/ValidationConfiguration.java @@ -37,7 +37,7 @@ import eu.webeid.security.validator.AuthTokenValidator; import eu.webeid.security.validator.AuthTokenValidatorBuilder; -import javax.servlet.http.HttpSession; +import jakarta.servlet.http.HttpSession; import java.io.IOException; import java.io.InputStream; import java.net.URI; diff --git a/src/main/java/eu/webeid/example/security/AuthTokenDTOAuthenticationProvider.java b/src/main/java/eu/webeid/example/security/AuthTokenDTOAuthenticationProvider.java index 03e535f..9965ff3 100644 --- a/src/main/java/eu/webeid/example/security/AuthTokenDTOAuthenticationProvider.java +++ b/src/main/java/eu/webeid/example/security/AuthTokenDTOAuthenticationProvider.java @@ -23,9 +23,12 @@ package eu.webeid.example.security; import eu.webeid.example.security.dto.AuthTokenDTO; +import eu.webeid.security.authtoken.WebEidAuthToken; +import eu.webeid.security.challenge.ChallengeNonceStore; +import eu.webeid.security.exceptions.AuthTokenException; +import eu.webeid.security.validator.AuthTokenValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; @@ -34,15 +37,9 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.stereotype.Component; -import eu.webeid.security.authtoken.WebEidAuthToken; -import eu.webeid.security.challenge.ChallengeNonceStore; -import eu.webeid.security.exceptions.AuthTokenException; -import eu.webeid.security.validator.AuthTokenValidator; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -56,10 +53,13 @@ public class AuthTokenDTOAuthenticationProvider implements AuthenticationProvide private static final Logger LOG = LoggerFactory.getLogger(AuthTokenDTOAuthenticationProvider.class); - @Autowired - private AuthTokenValidator tokenValidator; - @Autowired - private ChallengeNonceStore challengeNonceStore; + private final AuthTokenValidator tokenValidator; + private final ChallengeNonceStore challengeNonceStore; + + public AuthTokenDTOAuthenticationProvider(AuthTokenValidator tokenValidator, ChallengeNonceStore challengeNonceStore) { + this.tokenValidator = tokenValidator; + this.challengeNonceStore = challengeNonceStore; + } @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { diff --git a/src/main/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilter.java b/src/main/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilter.java index ac43205..cc47f86 100644 --- a/src/main/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilter.java +++ b/src/main/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilter.java @@ -23,13 +23,14 @@ package eu.webeid.example.security; import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import com.fasterxml.jackson.databind.ObjectReader; import eu.webeid.example.security.ajax.AjaxAuthenticationFailureHandler; import eu.webeid.example.security.ajax.AjaxAuthenticationSuccessHandler; import eu.webeid.example.security.dto.AuthTokenDTO; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpMethod; @@ -37,27 +38,35 @@ import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; +import org.springframework.security.web.context.SecurityContextRepository; + +import java.io.IOException; public class WebEidAjaxLoginProcessingFilter extends AbstractAuthenticationProcessingFilter { private static final Logger LOG = LoggerFactory.getLogger(WebEidAjaxLoginProcessingFilter.class); + private final ObjectReader OBJECT_READER = new ObjectMapper().readerFor(AuthTokenDTO.class); + private final SecurityContextRepository securityContextRepository; public WebEidAjaxLoginProcessingFilter( - String defaultFilterProcessesUrl, - AuthenticationManager authenticationManager + String defaultFilterProcessesUrl, + AuthenticationManager authenticationManager ) { super(defaultFilterProcessesUrl); this.setAuthenticationManager(authenticationManager); this.setAuthenticationSuccessHandler(new AjaxAuthenticationSuccessHandler()); this.setAuthenticationFailureHandler(new AjaxAuthenticationFailureHandler()); setSessionAuthenticationStrategy(new SessionFixationProtectionStrategy()); + this.securityContextRepository = new HttpSessionSecurityContextRepository(); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) - throws AuthenticationException, IOException { + throws AuthenticationException, IOException { if (!HttpMethod.POST.name().equals(request.getMethod())) { LOG.warn("HttpMethod not supported: {}", request.getMethod()); throw new AuthenticationServiceException("HttpMethod not supported: " + request.getMethod()); @@ -69,11 +78,16 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ } LOG.info("attemptAuthentication(): Reading request body"); - final ObjectMapper objectMapper = new ObjectMapper(); - final AuthTokenDTO authTokenDTO = objectMapper.readValue(request.getReader(), AuthTokenDTO.class); + final AuthTokenDTO authTokenDTO = OBJECT_READER.readValue(request.getReader()); LOG.info("attemptAuthentication(): Creating token"); final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(null, authTokenDTO); LOG.info("attemptAuthentication(): Calling authentication manager"); return getAuthenticationManager().authenticate(token); } + + @Override + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { + super.successfulAuthentication(request, response, chain, authResult); + securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response); + } } diff --git a/src/main/java/eu/webeid/example/security/WebEidAuthentication.java b/src/main/java/eu/webeid/example/security/WebEidAuthentication.java index 4a67020..59ab2a7 100644 --- a/src/main/java/eu/webeid/example/security/WebEidAuthentication.java +++ b/src/main/java/eu/webeid/example/security/WebEidAuthentication.java @@ -61,4 +61,15 @@ private static String getPrincipalNameFromCertificate(X509Certificate userCertif } } + @Override + public boolean equals(Object o) { + if (!super.equals(o)) return false; + WebEidAuthentication that = (WebEidAuthentication) o; + return Objects.equals(idCode, that.idCode); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), idCode); + } } diff --git a/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationFailureHandler.java b/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationFailureHandler.java index 8580bca..647698f 100644 --- a/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationFailureHandler.java +++ b/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationFailureHandler.java @@ -27,9 +27,9 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import java.io.IOException; public class AjaxAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { diff --git a/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationSuccessHandler.java b/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationSuccessHandler.java index 19d0410..b545422 100644 --- a/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationSuccessHandler.java +++ b/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationSuccessHandler.java @@ -25,19 +25,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.fasterxml.jackson.databind.ObjectWriter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.stereotype.Component; +import java.io.IOException; + /** * Write custom response on having user successfully authenticated. *

@@ -50,11 +48,11 @@ public class AjaxAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc @Override public void onAuthenticationSuccess( - HttpServletRequest request, - HttpServletResponse response, - Authentication authentication + HttpServletRequest request, + HttpServletResponse response, + Authentication authentication ) - throws IOException { + throws IOException { LOG.info("onAuthenticationSuccess(): {}", authentication); response.setStatus(HttpServletResponse.SC_OK); @@ -64,23 +62,19 @@ public void onAuthenticationSuccess( } public static class AuthSuccessDTO { - private final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectWriter OBJECT_WRITER = new ObjectMapper().writerFor(AuthSuccessDTO.class); @JsonProperty("sub") private String sub; @JsonProperty("auth") - private List auth; + private String auth; public static String asJson(Authentication authentication) throws JsonProcessingException { final AuthSuccessDTO dto = new AuthSuccessDTO(); dto.sub = authentication.getName(); - dto.auth = convertAuthorities(authentication.getAuthorities()); - return dto.objectMapper.writeValueAsString(dto); - } - - private static List convertAuthorities(Collection authorities) { - return authorities.stream().map(GrantedAuthority::toString).collect(Collectors.toList()); + dto.auth = authentication.getAuthorities().toString(); + return OBJECT_WRITER.writeValueAsString(dto); } } } diff --git a/src/main/java/eu/webeid/example/service/SigningService.java b/src/main/java/eu/webeid/example/service/SigningService.java index a7d71b4..e96af33 100644 --- a/src/main/java/eu/webeid/example/service/SigningService.java +++ b/src/main/java/eu/webeid/example/service/SigningService.java @@ -29,6 +29,8 @@ import eu.webeid.example.service.dto.FileDTO; import eu.webeid.example.service.dto.SignatureDTO; import eu.webeid.security.certificate.CertificateData; +import jakarta.servlet.http.HttpSession; +import jakarta.xml.bind.DatatypeConverter; import org.apache.commons.io.FilenameUtils; import org.digidoc4j.Configuration; import org.digidoc4j.Container; @@ -44,10 +46,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.core.io.ByteArrayResource; +import org.springframework.security.access.annotation.Secured; import org.springframework.stereotype.Service; -import javax.servlet.http.HttpSession; -import javax.xml.bind.DatatypeConverter; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchAlgorithmException; @@ -55,7 +56,10 @@ import java.security.cert.X509Certificate; import java.util.Objects; +import static eu.webeid.example.security.AuthTokenDTOAuthenticationProvider.ROLE_USER; + @Service +@Secured(ROLE_USER) public class SigningService { private static final String SESSION_ATTR_FILE = "file-to-sign"; @@ -64,7 +68,7 @@ public class SigningService { private static final Logger LOG = LoggerFactory.getLogger(SigningService.class); private final Configuration signingConfiguration; - ObjectFactory httpSessionFactory; + private final ObjectFactory httpSessionFactory; public SigningService(ObjectFactory httpSessionFactory, YAMLConfig yamlConfig) { this.httpSessionFactory = httpSessionFactory; diff --git a/src/main/java/eu/webeid/example/service/dto/FileDTO.java b/src/main/java/eu/webeid/example/service/dto/FileDTO.java index dca653b..3a65edc 100644 --- a/src/main/java/eu/webeid/example/service/dto/FileDTO.java +++ b/src/main/java/eu/webeid/example/service/dto/FileDTO.java @@ -27,12 +27,13 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.io.Serializable; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Objects; -public class FileDTO { +public class FileDTO implements Serializable { private static final String EXAMPLE_FILENAME = "example-for-signing.txt"; private final String name; diff --git a/src/main/java/eu/webeid/example/web/IndexController.java b/src/main/java/eu/webeid/example/web/IndexController.java new file mode 100644 index 0000000..e464a50 --- /dev/null +++ b/src/main/java/eu/webeid/example/web/IndexController.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020-2024 Estonian Information System Authority + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package eu.webeid.example.web; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class IndexController { + @GetMapping("/") + public String welcome(Model model, HttpServletRequest request) { + model.addAttribute("serverName", request.getServerName()); + return "index"; + } +} diff --git a/src/main/java/eu/webeid/example/web/WelcomeController.java b/src/main/java/eu/webeid/example/web/WelcomeController.java index deb7ab8..0db6fc7 100644 --- a/src/main/java/eu/webeid/example/web/WelcomeController.java +++ b/src/main/java/eu/webeid/example/web/WelcomeController.java @@ -24,23 +24,24 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.access.annotation.Secured; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; -import javax.validation.constraints.NotNull; import java.security.Principal; +import java.util.Objects; import static eu.webeid.example.security.AuthTokenDTOAuthenticationProvider.ROLE_USER; @Controller +@Secured(ROLE_USER) public class WelcomeController { private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class); - @PreAuthorize("hasAuthority('" + ROLE_USER + "')") @GetMapping("welcome") - public String welcome(Model model, @NotNull Principal principal) { + public String welcome(Model model, Principal principal) { + Objects.requireNonNull(principal); LOG.info("Showing welcome page, logged in as principal={}", principal.getName()); model.addAttribute("principalName", principal.getName()); return "welcome"; diff --git a/src/main/java/eu/webeid/example/web/rest/ChallengeController.java b/src/main/java/eu/webeid/example/web/rest/ChallengeController.java index 9640fe6..ecc3ee4 100644 --- a/src/main/java/eu/webeid/example/web/rest/ChallengeController.java +++ b/src/main/java/eu/webeid/example/web/rest/ChallengeController.java @@ -23,10 +23,10 @@ package eu.webeid.example.web.rest; import eu.webeid.example.service.dto.ChallengeDTO; +import eu.webeid.security.challenge.ChallengeNonceGenerator; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import eu.webeid.security.challenge.ChallengeNonceGenerator; @RestController @RequestMapping("auth") diff --git a/src/main/java/eu/webeid/example/web/rest/SigningController.java b/src/main/java/eu/webeid/example/web/rest/SigningController.java index 14ecfae..4f935be 100644 --- a/src/main/java/eu/webeid/example/web/rest/SigningController.java +++ b/src/main/java/eu/webeid/example/web/rest/SigningController.java @@ -32,14 +32,22 @@ import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import static eu.webeid.example.security.AuthTokenDTOAuthenticationProvider.ROLE_USER; + @RestController @RequestMapping("sign") +@Secured(ROLE_USER) public class SigningController { private final SigningService signingService; diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml index 709d314..3868f35 100644 --- a/src/main/resources/application-prod.yaml +++ b/src/main/resources/application-prod.yaml @@ -3,3 +3,6 @@ web-eid-auth-token: use-digidoc4j-prod-configuration: true local-origin: "https://web-eid.eu" truststore-password: "changeit" +spring: + thymeleaf: + cache: true diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 6a86740..5836d2e 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -57,7 +57,7 @@

Usage

  • on Ubuntu Linux, for Firefox and Chrome, download and execute the
    download-install-web-eid.sh script from the console with
    - wget -O - https:///scripts/download-install-web-eid.sh + wget -O - https:///scripts/download-install-web-eid.sh | bash
    Note: as of the 2.5 version, Web eID supports Firefox installed via Snap.
  • diff --git a/src/test/java/eu/webeid/example/WebApplicationTest.java b/src/test/java/eu/webeid/example/WebApplicationTest.java index 4d95f43..e28e8fa 100644 --- a/src/test/java/eu/webeid/example/WebApplicationTest.java +++ b/src/test/java/eu/webeid/example/WebApplicationTest.java @@ -59,7 +59,7 @@ public class WebApplicationTest { private WebApplicationContext context; @Autowired - private javax.servlet.Filter[] springSecurityFilterChain; + private jakarta.servlet.Filter[] springSecurityFilterChain; private static DefaultMockMvcBuilder mvcBuilder; @@ -110,7 +110,7 @@ public void validateOcspResponse(XadesSignature xadesSignature) { MvcResult result = HttpHelper.login(mvcBuilder, session, ObjectMother.mockAuthToken()); session = (MockHttpSession) result.getRequest().getSession(); MockHttpServletResponse response = result.getResponse(); - assertEquals("{\"sub\":\"JAAK-KRISTJAN JÕEORG\",\"auth\":[\"ROLE_USER\"]}", response.getContentAsString()); + assertEquals("{\"sub\":\"JAAK-KRISTJAN JÕEORG\",\"auth\":\"[ROLE_USER]\"}", response.getContentAsString()); /* Example how to test file upload. response = HttpHelper.upload(mvcBuilder, session, mockMultipartFile()); diff --git a/src/test/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilterTest.java b/src/test/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilterTest.java index 0640a4d..cb95073 100644 --- a/src/test/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilterTest.java +++ b/src/test/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilterTest.java @@ -1,11 +1,11 @@ package eu.webeid.example.security; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.Test; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.StringReader; diff --git a/src/test/java/eu/webeid/example/testutil/ObjectMother.java b/src/test/java/eu/webeid/example/testutil/ObjectMother.java index ad048fd..f6103d5 100644 --- a/src/test/java/eu/webeid/example/testutil/ObjectMother.java +++ b/src/test/java/eu/webeid/example/testutil/ObjectMother.java @@ -33,7 +33,7 @@ import eu.webeid.example.service.dto.CertificateDTO; import eu.webeid.example.service.dto.SignatureDTO; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import java.io.FileInputStream; import java.security.GeneralSecurityException; import java.security.KeyStore;