WebDeveloperHints

Notas sobre desarrollo, programación, marketing digital y tecnología

Ver en GitHub

Spring Boot

Jackson local date time deserialize

Si se recibe el error Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate' se debe a que no se esta serializado el contenido de los parámetros.

Ejemplo para aceptar parámetros de tipo fecha serializados:

@RestController
public class Controller {
    @GetMapping("/")
    public void get(
        @RequestParam
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        LocalDate date,
        @RequestParam
        @DateTimeFormat(pattern = "kk:mm:ss")
        LocalTime time,
        @RequestParam
        @DateTimeFormat(pattern = "yyyy-MM-dd kk:mm:ss")
        LocalDateTime dateTime) {}
}

Si se esta usando un objeto como parámetro y se recibe el siguiente error Failed to instantiate [com.example.demo.DateType]: No default constructor found se debe a que hay que especificar la forma de serializar las propiedades.

Ejemplo para deserealizar parámetros envueltos en un objeto:

public class DateType {
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
    @DateTimeFormat(pattern = "kk:mm:ss")
    private LocalTime time;
    @DateTimeFormat(pattern = "yyyy-MM-dd kk:mm:ss")
    private LocalDateTime dateTime;

    public LocalDate getDate() {
        return date;
    }

    public void setDate(LocalDate date) {
        this.date = date;
    }

    public LocalTime getTime() {
        return time;
    }

    public void setTime(LocalTime time) {
        this.time = time;
    }

    public LocalDateTime getDateTime() {
        return dateTime;
    }

    public void setDateTime(LocalDateTime dateTime) {
        this.dateTime = dateTime;
    }

    public DateType(LocalDate date, LocalTime time, LocalDateTime dateTime) {
        this.date = date;
        this.time = time;
        this.dateTime = dateTime;
    }

    public DateType() {}
}

@RestController
public class Controller {
    @PostMapping("/")
    public void post(@RequestBody DateType dateType) {}
}

Deseralización personalizada

@Configuration
public class JacksonConfig {
    @Bean
    public Module jsonMapperJava8DateTimeModule() {
        SimpleModule module = new SimpleModule();

        module.addDeserializer(LocalDate.class, new JsonDeserializer<LocalDate>() {
            @Override
            public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                return LocalDate.parse(jsonParser.getValueAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            }
        });

        module.addDeserializer(LocalTime.class, new JsonDeserializer<LocalTime>() {
            @Override
            public LocalTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                return LocalTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ofPattern("kk:mm:ss"));
            }
        });

        module.addDeserializer(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
            @Override
            public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                return LocalDateTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd kk:mm:ss"));
            }
        });

        return module;
    }
}

public class DateType {
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonFormat(pattern = "yyyy/MM/dd kk:mm:ss")
    private LocalDateTime dateTime;

    public LocalDateTime getDateTime() {
        return dateTime;
    }

    public void setDateTime(LocalDateTime dateTime) {
        this.dateTime = dateTime;
    }
}

Spring security

//Seguridad básica
http.authorizeRequests().anyRequest().authenticated()
        .and().httpBasic();

//Desactivar cache
http.requestCache().disable()

//Desactivar headers
http.headers().disable()

//Deny frame options
http.headers().frameOptions().disable()
http.headers().frameOptions().sameOrigin()

//content-security-policy
http.headers().contentSecurityPolicy("script-src: self")
http.headers().contentSecurityPolicy("script-src: http://{domain}...")

//Referrer policy
http.headers().referrerPolicy().policy(ReferrerPolicy.ORIGIN)

Https spring boot

Generar un certificado con la validación expresada en días

keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -vadility 400
server:
  port: 8443
  ssl:
    key-store-password: password
    key-store: classpath:keystore.p12
    key-store-type: PKCS12
    key-alias: tomcat

logging:
  level:
    root: WARN
    com.memorynotfound: DEBUG
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG

ACME Automated Certificate Management Environment protocol

Requerimientos

Instalar certbot

git clone https://github.com/certbot/certbot
./certbot-auto certonly -a standalone -d {domain.com}

Convertir con OpenSSL

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name tomcat -CAfile chain.pem -caname root

Verificar la seguridad de un hsts

Configurar CSRF en SPA

Hasta las aplicaciones SPA necesitan una protección CSRF para evitar problemas de seguridad.

http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()

withHttpOnlyFalse()

El navegador debe permite la ejecución de javascript originada desde el mismo origen de la cookie.

Encriptar llaves privadas

encrypt input="password" password={password_encryption}
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
server:
  key-store-password: ENC({encrypted_data})

jasypt:
  encryptor:
    password: { password_encryption } - ${JASYPT_ENCRYPTOR_PASSWORD:}
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
    algorithm: PBEWithMD5AndTripleDES

Secret Management

Referencias: