aAPT
dDebian
fFFmpeg
jJava
mMercurial: Usage
oOCaml
pPostgreSQL

Home Code Java

Spring Boot

Logging

Enable jdbc query logging

logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG

Enable cache logging

logging.level.org.springframework.cache=TRACE

HTTPS

Enabling HTTPS with built-in Tomcat

1. Retrieve (e.g. letsencrypt) certificate.
2. Generate pk12 keystore:

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

3. Add SSL configuration to application.properties:

security.require-ssl=true
server.ssl.key-store=/path/to/default.p12
server.ssl.key-store-password=PASSWORD
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=default

4. Restart application.

Enabling HTTPS with Apache HTTP as reverse proxy

Requred additional Apache HTTP modules are proxy, proxy_http and headers.

1. Configure Apache HTTP:

site.conf (complete)
<IfModule mod_ssl.c>
<VirtualHost *:443>
    Include /etc/apache2/ssl/default

    ServerName example.org
 
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    SSLCertificateFile    /etc/apache2/ssl/certs/example.org/cert.pem
    SSLCertificateKeyFile /etc/apache2/ssl/certs/exmaple.org/privkey.pem
    SSLCACertificateFile /etc/apache2/ssl/certs/example.org/fullchain.pem

    ErrorLog ${APACHE_LOG_DIR}/example.org.error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/example.org.access.log combined
 
    ProxyRequests Off
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto https
    RequestHeader set X-Forwarded-Port 443
    ProxyPass / http://127.0.0.1:64444/
    ProxyPassReverse / http://127.0.0.1:64444/
</VirtualHost>
</IfModule>
/etc/apache2/ssl/default (for reference)
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"

BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

2. Configure application:

application.properties:

server.forward-headers-strategy=native

3. Required HttpSecurity config:

...
http.requiresChannel()
    .anyRequest()
    .requiresSecure()

Noteworthy application properties

server.servlet.session.cookie.name

Misc

Example build script

build.gradle
plugins {
    id "org.springframework.boot" version "3.3.0"
    id "io.spring.dependency-management" version "1.1.5"
    id "java"
}

group = "org.example"

repositories {
    mavenCentral()
}

dependencies {
    implementation "org.springframework.boot:spring-boot-starter-web"
    implementation "org.springframework.boot:spring-boot-starter-jdbc"
    implementation "org.springframework.boot:spring-boot-starter-security"
    implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
    implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity6"
    runtimeOnly "org.xerial:sqlite-jdbc:3.45.3.0"
    developmentOnly "org.springframework.boot:spring-boot-devtools"
    testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.3"
    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.3"
}

configurations.implementation {
    exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j"
    exclude group: "org.springframework.boot", module: "spring-boot-starter-json"
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

test {
    useJUnitPlatform()
}

bootJar {
    launchScript()
}

springBoot {
    buildInfo {
        properties {
            additional = [
                revision: buildRev(),
                time: new Date().format("yyyy-MM-dd:HHmmssZ")
            ]
        }
    }
}

def buildRev() {
    final out = new ByteArrayOutputStream()
    exec {
        commandLine "hg", "parents", "--template", "{rev}"
        standardOutput = out
    }
    out.toString()
}

Collections in the application.properties

application.properties

foo.key={'aa', 'b''b', 'cc'}

Value injection:

@Value("#{${foo.key}}") String[] keys

Avoiding redirects to login page on incorrect credentials when basic authentication is used:

1. Check that error page is not protected from anonymous access.
2. Alternatively, it may be avoided from the client-side by marking request as AJAX one by setting appropriate header:

X-Requested-With: XMLHttpRequest