From b5e4a0dc28966479e0f2d5c0d69f2f38f734fee1 Mon Sep 17 00:00:00 2001
From: Leonardo Vannucci <leonardo.vannucci@grupposistematica.it>
Date: Thu, 09 Aug 2018 17:35:28 +0200
Subject: [PATCH] Implementazione recaptcha
---
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/RestTemplateConfig.java | 32 ++
dg1cloud-core/src/main/java/it/digione/dg1cloud/service/Utils.java | 60 ++++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponse.java | 103 ++++++++
dg1cloud-core/src/main/java/it/digione/dg1cloud/config/dg1cloud.properties | 7
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaController.java | 44 +++
dg1cloud-core/pom.xml | 30 ++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ValidReCaptcha.java | 25 ++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaService.java | 46 +++
dg1cloud-core/src/main/resources/templates/downloadFileCaptcha.html | 48 ++++
dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadFileController.java | 70 +----
dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadPageController.java | 38 +++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/CaptchaSettings.java | 46 +++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaConstraintValidator.java | 28 ++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaForm.java | 41 +++
dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponseFilter.java | 75 ++++++
15 files changed, 634 insertions(+), 59 deletions(-)
diff --git a/dg1cloud-core/pom.xml b/dg1cloud-core/pom.xml
index 1fcf8c8..d97e3cd 100644
--- a/dg1cloud-core/pom.xml
+++ b/dg1cloud-core/pom.xml
@@ -53,6 +53,22 @@
</dependency>
<dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-thymeleaf</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-configuration-processor</artifactId>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
@@ -77,7 +93,19 @@
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
- </dependency>
+ </dependency>
+
+ <!-- bootstrap and jquery -->
+ <dependency>
+ <groupId>org.webjars</groupId>
+ <artifactId>bootstrap</artifactId>
+ <version>3.3.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.webjars</groupId>
+ <artifactId>jquery</artifactId>
+ <version>3.2.1</version>
+ </dependency>
</dependencies>
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/config/dg1cloud.properties b/dg1cloud-core/src/main/java/it/digione/dg1cloud/config/dg1cloud.properties
index f74bf52..79d523e 100644
--- a/dg1cloud-core/src/main/java/it/digione/dg1cloud/config/dg1cloud.properties
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/config/dg1cloud.properties
@@ -13,4 +13,9 @@
server.servlet.context-path=/dg1cloud
-external.server.address.base.url=http://vannux.grupposistematica.it:8080/dg1cloud
\ No newline at end of file
+external.server.address.base.url=http://vannux.grupposistematica.it:8080/dg1cloud
+
+google.recaptcha.enabled=false
+google.recaptcha.url=https://www.google.com/recaptcha/api/siteverify
+google.recaptcha.key=6LfCHmkUAAAAAFa1KmVtPFecItBriBHx1qmKHcVS
+google.recaptcha.secret=6LfCHmkUAAAAAKXdXWO36daHnItKQwkEvXOpX6YY
\ No newline at end of file
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadFileController.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadFileController.java
index 4962f61..be67cd2 100644
--- a/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadFileController.java
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadFileController.java
@@ -1,82 +1,40 @@
package it.digione.dg1cloud.controller;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import javax.servlet.ServletContext;
-
-import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
-import it.digione.dg1cloud.model.RegDocument;
-import it.digione.dg1cloud.repository.RegDocumentRepository;
-import it.digione.dg1cloud.service.CloudService;
+import it.digione.dg1cloud.recaptcha.CaptchaSettings;
+import it.digione.dg1cloud.service.Utils;
@Controller
public class DownloadFileController {
- private static final Logger logger = LoggerFactory.getLogger(CloudService.class);
+ private static final Logger logger = LoggerFactory.getLogger(DownloadFileController.class);
- @Autowired private ServletContext servletContext;
- @Autowired private RegDocumentRepository regDocumentRepository;
+ @Autowired private Utils utils;
+ @Autowired CaptchaSettings captchaSettings;
@RequestMapping("/downloadFile")
public ResponseEntity<InputStreamResource> downloadFile(@RequestParam String fileName,
- @RequestParam long id,
- @RequestParam(value = "secretKey", required = false) String secretKey) throws IOException {
+ @RequestParam long id,
+ @RequestParam(value = "secretKey", required = false) String secretKey) throws IOException {
- logger.debug("Avvio download file {} con id {}, fileName, id");
-
- MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
- try {
- mediaType = MediaType.parseMediaType(servletContext.getMimeType(fileName));
- } catch (Exception e) {
- logger.warn("Errore nello stabilire il mime type del file. VerrĂ usato " + mediaType.toString(), e);
+ if ( captchaSettings.isEnabled() == true ) {
+ String error = "Download diretto non ammesso. Usare la pagina di download tramite reCaptcha";
+ logger.error(error);
+ throw new RuntimeException("Download diretto non ammesso. Usare la pagina di download tramite reCaptcha");
}
- RegDocument regDocument = regDocumentRepository.getOne(id);
-
- if (regDocument.getFileName().equalsIgnoreCase(fileName) == false ) {
- logger.error("Il nome del file richiesto non corrisponde con quello referenziato dall'id");
- throw new RuntimeException("Il nome del file richiesto non corrisponde con quello referenziato dall'id");
- }
-
- if ( regDocument.getSecretKey() != null ) {
- logger.debug("E' stata specificata una secretKey. Avvio le verifiche.");
- if ( Strings.isEmpty(secretKey) == true ) {
- logger.error("Non e' stata inviata la secretKey");
- throw new RuntimeException("Per scaricare il file occorre specificare la secretKey");
- } else {
- logger.debug("Controllo corrispondenza della secretKey");
- if (secretKey.equals(regDocument.getSecretKey()) == false ) {
- logger.error("La secretKey inviata non corrisponde a quella impostata in fase di richiesta salvataggio del file");
- throw new RuntimeException("La secretKey inviata non corrisponde a quella impostata in fase di richiesta salvataggio del file");
- } else {
- logger.debug("SecretKey verificata correttamente");
- }
- }
- }
-
- File file = new File(regDocument.getFilePath());
- FileInputStream fis = new FileInputStream(file);
- InputStreamResource isr = new InputStreamResource(fis);
- return ResponseEntity.ok()
- // Content-Disposition
- .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
- // Content-Type
- .contentType(mediaType)
- // Contet-Length
- .contentLength(file.length()) //
- .body(isr);
+ return utils.getDownloadResponseEntity(fileName, id, secretKey);
}
+
+
}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadPageController.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadPageController.java
new file mode 100644
index 0000000..8ce7a97
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/controller/DownloadPageController.java
@@ -0,0 +1,38 @@
+package it.digione.dg1cloud.controller;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.ModelAndView;
+
+import it.digione.dg1cloud.recaptcha.CaptchaSettings;
+import it.digione.dg1cloud.recaptcha.DownloadFileCaptchaForm;
+
+@Controller
+public class DownloadPageController {
+
+ private static final Logger logger = LoggerFactory.getLogger(DownloadPageController.class);
+
+ @RequestMapping("/downloadPage")
+ public ModelAndView downloadPage(@RequestParam String fileName, @RequestParam long id,
+ @RequestParam(value = "secretKey", required = false) String secretKey) throws IOException {
+
+ logger.debug("Preparazione pagina download file {} con id {}", fileName, id);
+
+ DownloadFileCaptchaForm downloadParams = new DownloadFileCaptchaForm();
+
+ downloadParams.setFileName(fileName);
+ downloadParams.setId(id);
+ downloadParams.setSecretKey(secretKey);
+
+ ModelAndView modelAndView = new ModelAndView("downloadFileCaptcha");
+ modelAndView.addObject("downloadFileCaptchaForm", downloadParams);
+
+ return modelAndView;
+ }
+}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/CaptchaSettings.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/CaptchaSettings.java
new file mode 100644
index 0000000..f52a4f8
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/CaptchaSettings.java
@@ -0,0 +1,46 @@
+package it.digione.dg1cloud.recaptcha;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "google.recaptcha")
+public class CaptchaSettings {
+
+ private boolean enabled;
+ private String url;
+ private String key;
+ private String secret;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ public void setSecret(String secret) {
+ this.secret = secret;
+ }
+}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaController.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaController.java
new file mode 100644
index 0000000..1a6c79f
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaController.java
@@ -0,0 +1,44 @@
+package it.digione.dg1cloud.recaptcha;
+
+import java.io.FileNotFoundException;
+
+import javax.validation.Valid;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import it.digione.dg1cloud.service.Utils;
+
+@Controller
+@RequestMapping("/downloadFileCaptcha")
+public class DownloadFileCaptchaController {
+
+ @Autowired private Utils utils;
+
+ @ModelAttribute("downloadFileCaptchaForm")
+ public DownloadFileCaptchaForm downloadFileCaptchaForm() {
+ return new DownloadFileCaptchaForm();
+ }
+
+ @PostMapping
+ public Object handleDownloadFileCaptcha(@ModelAttribute("downloadFileCaptchaForm") @Valid DownloadFileCaptchaForm form,
+ BindingResult result) throws FileNotFoundException{
+
+ ModelAndView modelAndView;
+ if (result.hasErrors()){
+ modelAndView = new ModelAndView("downloadFileCaptcha");
+ modelAndView.addObject(result);
+ modelAndView.addObject("downloadFileCaptchaForm", form);
+
+ return modelAndView;
+ } else {
+ return utils.getDownloadResponseEntity(form.getFileName(), form.getId(), form.getSecretKey());
+ }
+
+ }
+}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaForm.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaForm.java
new file mode 100644
index 0000000..d743d43
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/DownloadFileCaptchaForm.java
@@ -0,0 +1,41 @@
+package it.digione.dg1cloud.recaptcha;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+public class DownloadFileCaptchaForm {
+
+ @NotNull
+ private Long id;
+ private String fileName;
+ private String secretKey;
+ @NotEmpty
+ @ValidReCaptcha
+ private String reCaptchaResponse;
+
+ public Long getId() {
+ return id;
+ }
+ public void setId(Long id) {
+ this.id = id;
+ }
+ public String getFileName() {
+ return fileName;
+ }
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+ public String getSecretKey() {
+ return secretKey;
+ }
+ public void setSecretKey(String secretKey) {
+ this.secretKey = secretKey;
+ }
+ public String getReCaptchaResponse() {
+ return reCaptchaResponse;
+ }
+ public void setReCaptchaResponse(String reCaptchaResponse) {
+ this.reCaptchaResponse = reCaptchaResponse;
+ }
+
+}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaConstraintValidator.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaConstraintValidator.java
new file mode 100644
index 0000000..1833ffc
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaConstraintValidator.java
@@ -0,0 +1,28 @@
+package it.digione.dg1cloud.recaptcha;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class ReCaptchaConstraintValidator implements ConstraintValidator<ValidReCaptcha, String> {
+
+ @Autowired
+ private ReCaptchaService reCaptchaService;
+
+ @Override
+ public void initialize(ValidReCaptcha constraintAnnotation) {
+
+ }
+
+ @Override
+ public boolean isValid(String reCaptchaResponse, ConstraintValidatorContext context) {
+
+ if (reCaptchaResponse == null || reCaptchaResponse.isEmpty()){
+ return true;
+ }
+
+ return reCaptchaService.validate(reCaptchaResponse);
+ }
+
+}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponse.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponse.java
new file mode 100644
index 0000000..ddef69f
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponse.java
@@ -0,0 +1,103 @@
+package it.digione.dg1cloud.recaptcha;
+
+import com.fasterxml.jackson.annotation.*;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonPropertyOrder({
+ "success",
+ "challenge_ts",
+ "hostname",
+ "error-codes"
+})
+public class ReCaptchaResponse {
+
+ @JsonProperty("success")
+ private boolean success;
+
+ @JsonProperty("challenge_ts")
+ private Date challengeTs;
+
+ @JsonProperty("hostname")
+ private String hostname;
+
+ @JsonProperty("error-codes")
+ private ErrorCode[] errorCodes;
+
+ @JsonIgnore
+ public boolean hasClientError() {
+ ErrorCode[] errors = getErrorCodes();
+ if(errors == null) {
+ return false;
+ }
+ for(ErrorCode error : errors) {
+ switch(error) {
+ case InvalidResponse:
+ case MissingResponse:
+ return true;
+ case InvalidSecret:
+ break;
+ case MissingSecret:
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ static enum ErrorCode {
+ MissingSecret, InvalidSecret,
+ MissingResponse, InvalidResponse;
+
+ private static Map<String, ErrorCode> errorsMap = new HashMap<>(4);
+
+ static {
+ errorsMap.put("missing-input-secret", MissingSecret);
+ errorsMap.put("invalid-input-secret", InvalidSecret);
+ errorsMap.put("missing-input-response", MissingResponse);
+ errorsMap.put("invalid-input-response", InvalidResponse);
+ }
+
+ @JsonCreator
+ public static ErrorCode forValue(String value) {
+ return errorsMap.get(value.toLowerCase());
+ }
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public Date getChallengeTs() {
+ return challengeTs;
+ }
+
+ public void setChallengeTs(Date challengeTs) {
+ this.challengeTs = challengeTs;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public ErrorCode[] getErrorCodes() {
+ return errorCodes;
+ }
+
+ public void setErrorCodes(ErrorCode[] errorCodes) {
+ this.errorCodes = errorCodes;
+ }
+}
\ No newline at end of file
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponseFilter.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponseFilter.java
new file mode 100644
index 0000000..727acee
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaResponseFilter.java
@@ -0,0 +1,75 @@
+package it.digione.dg1cloud.recaptcha;
+
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class ReCaptchaResponseFilter implements Filter {
+
+ private static final String RE_CAPTCHA_ALIAS = "reCaptchaResponse";
+ private static final String RE_CAPTCHA_RESPONSE = "g-recaptcha-response";
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest,
+ ServletResponse servletResponse,
+ FilterChain chain) throws IOException, ServletException {
+
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+ if (request.getParameter(RE_CAPTCHA_RESPONSE) != null) {
+ ReCaptchaHttpServletRequest reCaptchaRequest = new ReCaptchaHttpServletRequest(request);
+ chain.doFilter(reCaptchaRequest, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ private static class ReCaptchaHttpServletRequest extends HttpServletRequestWrapper {
+
+ final Map<String, String[]> params;
+
+ ReCaptchaHttpServletRequest(HttpServletRequest request) {
+ super(request);
+ params = new HashMap<>(request.getParameterMap());
+ params.put(RE_CAPTCHA_ALIAS, request.getParameterValues(RE_CAPTCHA_RESPONSE));
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return params.containsKey(name) ? params.get(name)[0] : null;
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ return params;
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ return Collections.enumeration(params.keySet());
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return params.get(name);
+ }
+ }
+}
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaService.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaService.java
new file mode 100644
index 0000000..aee72ee
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ReCaptchaService.java
@@ -0,0 +1,46 @@
+package it.digione.dg1cloud.recaptcha;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestOperations;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.URI;
+
+@Service
+public class ReCaptchaService {
+
+ private static final Logger log = LoggerFactory.getLogger(ReCaptchaService.class);
+
+ @Autowired
+ private RestOperations restTemplate;
+
+ @Autowired
+ private CaptchaSettings captchaSettings;
+
+ @Autowired
+ private HttpServletRequest request;
+
+ public boolean validate(String reCaptchaResponse){
+ URI verifyUri = URI.create(String.format(
+ captchaSettings.getUrl() + "?secret=%s&response=%s&remoteip=%s",
+ captchaSettings.getSecret(),
+ reCaptchaResponse,
+ request.getRemoteAddr()
+ ));
+
+ try {
+ ReCaptchaResponse response = restTemplate.getForObject(verifyUri, ReCaptchaResponse.class);
+ return response.isSuccess();
+ } catch (Exception ignored){
+ log.error("", ignored);
+ // ignore when google services are not available
+ // maybe add some sort of logging or trigger that'll alert the administrator
+ }
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/RestTemplateConfig.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/RestTemplateConfig.java
new file mode 100644
index 0000000..69c4173
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/RestTemplateConfig.java
@@ -0,0 +1,32 @@
+package it.digione.dg1cloud.recaptcha;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+
+ @Bean
+ public RestTemplate restTemplate(ClientHttpRequestFactory httpRequestFactory) {
+ RestTemplate template = new RestTemplate(httpRequestFactory);
+ template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
+ return template;
+ }
+
+ @Bean
+ public ClientHttpRequestFactory httpRequestFactory(HttpClient httpClient) {
+ return new HttpComponentsClientHttpRequestFactory(httpClient);
+ }
+
+ @Bean
+ public HttpClient httpClient() {
+ return HttpClientBuilder.create().build();
+ }
+
+}
\ No newline at end of file
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ValidReCaptcha.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ValidReCaptcha.java
new file mode 100644
index 0000000..ba8f107
--- /dev/null
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/recaptcha/ValidReCaptcha.java
@@ -0,0 +1,25 @@
+package it.digione.dg1cloud.recaptcha;
+
+import javax.validation.Payload;
+import javax.validation.Constraint;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Documented
+@Constraint(validatedBy = ReCaptchaConstraintValidator.class)
+@Target({ TYPE, FIELD, ANNOTATION_TYPE })
+@Retention(RUNTIME)
+public @interface ValidReCaptcha {
+
+ String message() default "Invalid ReCaptcha";
+
+ Class<?>[] groups() default {};
+
+ Class<? extends Payload>[] payload() default {};
+
+}
\ No newline at end of file
diff --git a/dg1cloud-core/src/main/java/it/digione/dg1cloud/service/Utils.java b/dg1cloud-core/src/main/java/it/digione/dg1cloud/service/Utils.java
index 815499b..4c54b5d 100644
--- a/dg1cloud-core/src/main/java/it/digione/dg1cloud/service/Utils.java
+++ b/dg1cloud-core/src/main/java/it/digione/dg1cloud/service/Utils.java
@@ -1,33 +1,44 @@
package it.digione.dg1cloud.service;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
+
+import javax.servlet.ServletContext;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import it.digione.dg1cloud.config.AppConfig;
import it.digione.dg1cloud.model.RegDocument;
+import it.digione.dg1cloud.repository.RegDocumentRepository;
@Service("utils")
public class Utils {
@Autowired private AppConfig appConfig;
+ @Autowired private RegDocumentRepository regDocumentRepository;
+ @Autowired private ServletContext servletContext;
private static final Logger logger = LoggerFactory.getLogger(CloudService.class);
public URL generateUrl(RegDocument regDocument) throws MalformedURLException {
logger.debug("Genero l'url per il record file {} con id {}", regDocument.getFileName(), regDocument.getDocumentId());
UriBuilder uriBuilder = UriComponentsBuilder.fromUriString(appConfig.getExternalBaseUrl());
- uriBuilder.path("/downloadFile");
+ uriBuilder.path("/downloadPage");
uriBuilder.queryParam("fileName", regDocument.getFileName());
uriBuilder.queryParam("id", regDocument.getDocumentId());
if ( Strings.isEmpty(regDocument.getSecretKey()) == false ) {
@@ -53,4 +64,51 @@
logger.debug("La directory {} non e' vuota", directory.getAbsolutePath());
}
}
+
+ public ResponseEntity<InputStreamResource> getDownloadResponseEntity(String fileName, long id, String secretKey)
+ throws FileNotFoundException {
+ logger.debug("Avvio download file {} con id {}", fileName, id);
+
+ MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
+ try {
+ mediaType = MediaType.parseMediaType(servletContext.getMimeType(fileName));
+ } catch (Exception e) {
+ logger.warn("Errore nello stabilire il mime type del file. VerrĂ usato " + mediaType.toString(), e);
+ }
+
+ RegDocument regDocument = regDocumentRepository.getOne(id);
+
+ if (regDocument.getFileName().equalsIgnoreCase(fileName) == false ) {
+ logger.error("Il nome del file richiesto non corrisponde con quello referenziato dall'id");
+ throw new RuntimeException("Il nome del file richiesto non corrisponde con quello referenziato dall'id");
+ }
+
+ if ( regDocument.getSecretKey() != null ) {
+ logger.debug("E' stata specificata una secretKey. Avvio le verifiche.");
+ if ( Strings.isEmpty(secretKey) == true ) {
+ logger.error("Non e' stata inviata la secretKey");
+ throw new RuntimeException("Per scaricare il file occorre specificare la secretKey");
+ } else {
+ logger.debug("Controllo corrispondenza della secretKey");
+ if (secretKey.equals(regDocument.getSecretKey()) == false ) {
+ logger.error("La secretKey inviata non corrisponde a quella impostata in fase di richiesta salvataggio del file");
+ throw new RuntimeException("La secretKey inviata non corrisponde a quella impostata in fase di richiesta salvataggio del file");
+ } else {
+ logger.debug("SecretKey verificata correttamente");
+ }
+ }
+ }
+
+ File file = new File(regDocument.getFilePath());
+ FileInputStream fis = new FileInputStream(file);
+ InputStreamResource isr = new InputStreamResource(fis);
+ return ResponseEntity.ok()
+ // Content-Disposition
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
+ // Content-Type
+ .contentType(mediaType)
+ // Contet-Length
+ .contentLength(file.length()) //
+ .body(isr);
+ }
}
diff --git a/dg1cloud-core/src/main/resources/templates/downloadFileCaptcha.html b/dg1cloud-core/src/main/resources/templates/downloadFileCaptcha.html
new file mode 100644
index 0000000..79218f2
--- /dev/null
+++ b/dg1cloud-core/src/main/resources/templates/downloadFileCaptcha.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+ <head>
+ <meta charset="utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+ <link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}"/>
+ <link rel="stylesheet" type="text/css" th:href="@{/css/main.css}"/>
+
+ <title>Link download file</title>
+ <script src='https://www.google.com/recaptcha/api.js'></script>
+ </head>
+ <body>
+ <div class="container">
+ <div class="row">
+ <div class="col-md-4 col-md-offset-4">
+ <div class="panel panel-default">
+ <div class="panel-body">
+ <div class="text-center">
+ <h3><i class="glyphicon glyphicon-lock" style="font-size:2em;"></i></h3>
+ <h2 class="text-center" th:text="*{downloadFileCaptchaForm.fileName}"></h2>
+ <div class="panel-body">
+ <form action="#" th:action="@{/downloadFileCaptcha}" th:object="${downloadFileCaptchaForm}" method="post">
+ <input type="hidden" th:field="*{id}" />
+ <input type="hidden" th:field="*{fileName}" />
+ <input type="hidden" th:field="*{secretKey}" />
+ <div class="form-group">
+ <div class="g-recaptcha" th:attr="data-sitekey=${@captchaSettings.getKey()}"></div>
+ <p class="error-message"
+ th:each="error: ${#fields.errors('reCaptchaResponse')}"
+ th:text="${error}">Errore validazione reCaptcha</p>
+ </div>
+ <div class="form-group">
+ <button name="downloadFile" type="submit" th:text="'Scarica il file ' + *{fileName} "></button>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script type="text/javascript" th:src="@{/webjars/jquery/3.2.1/jquery.min.js/}"></script>
+ <script type="text/javascript" th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script>
+ </body>
+</html>
\ No newline at end of file
--
Gitblit v1.6.2