i'm trying for the first time to set up an own web site from front to end.
My problem is: I cannot connect to my server to http://mysite.de nor to https://mysite.de.
Goal: Enable the user to reach my server via HTTPS at all. All three input strings should lead to a https connection: my-site.de, http://my-site.de and https://my-site.de.
What have I done already?
I made a spring boot web application and rented a Strato VPS (Cent OS 8, but I also tried it on Ubuntu 18.04).
Used the Digicert CSR maker, the command it gave me was
keytool -genkey -alias pvpfeedback -keyalg RSA -keysize 2048 -keystore pvpfeedback_de.jks -dname "CN=pvpfeedback.de,OU=PvPFeedback, O=PvPFeedback, L=PvPFeedback, ST=PvPFeedback, C=DE" && keytool -certreq -alias pvpfeedback -file pvpfeedback_de.csr -keystore pvpfeedback_de.jks
I uploaded the csr to Strato (for a free SSL certificate from them)
Strato in return lets me download a .crt, a root .crt and an intermediate .crt file. I added the normal .crt and the root .crt to my .jks keystore
keytool -import -alias pvpfeedback -file root_pvpfeedback.de.crt -keystore pvpfeedback_de.jks
keytool -trustcacerts -importcert -alias pvpfeedback -file cert_pvpfeedback.de.crt -keystore pvpfeedback_de.jks
I placed all my stuff to etc/pki/ca-trust/source/anchors and update-ca-trust extract
I'm running my program with java -jar -Djdk.tls.client.protocols=TLSv1.2 pvpfeedback-0.0.1-SNAPSHOT.jar
Some additional stuff:
I set up an Apache to verify that my site is registered, and indeed the default apache landing page was shown.
Chrome give back a connection timeout error on http://my-site.de and https://my-site.de:
Website not reachable
This is my very first post on this site, if I did something wrong please tell me.
When I start the spring boot app on the server, this is the feedback:
2021-02-20 18:00:09.341 INFO 19868 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8443 (https) 8080 (http) with context path ''
2021-02-20 18:00:09.360 INFO 19868 --- [ main] c.e.pvpfeedback.PvpfeedbackApplication : Started PvpfeedbackApplication in 6.042 seconds (JVM running for 7.72)
2021-02-20 18:00:09.559 INFO 19868 --- [ scheduling-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:7, serverValue:75478}] to pvpfeedbackcluster-shard-00-02.xjveo.mongodb.net:27017
My Spring Boot Https configuration:
#EnableWebSecurity
public class HTTPSSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.requiresChannel()
.anyRequest()
.requiresSecure();
}
}
#Configuration
public class HttpToHttpsServerConfig {
#Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(getHttpConnector());
return tomcat;
}
private Connector getHttpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}
server.address=<ServerIP>
server.port=8443
server.ssl.key-alias=pvpfeedback
server.ssl.key-store-password=<Password>
server.ssl.key-store=classpath:pvpfeedback_de.jks
server.ssl.key-store-provider=SUN
server.ssl.key-store-type=JKS
I managed to make it work.
I had to forward some ports in the firewall.
The following code snippet did the trick for me:
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT
Related
I'm using a docker-compose file to start a keycloak container in https. In order to do that, I've added these services to my compose:
keycloak-db:
image: postgres
volumes:
- keycloak-db-pgdata:/var/lib/postgresql/data
- ./docker/keycloak-db/init.sql:/docker-entrypoint-initdb.d/init.sql
env_file:
- docker/keycloak-db/keycloak-db.env
ports:
- 10005:5432
keycloak:
image: jboss/keycloak
env_file:
- docker/keycloak/keycloak.env
volumes:
- ./docker/keycloak/https/:/etc/x509/https
ports:
- 10006:8443
volumes:
keycloak-db-pgdata:
driver: local
This is the content of keycloak.env and keycloak-db.env:
keycloak.env
KEYCLOAK_USER=admin
KEYCLOAK_PASSWORD=admin
KEYCLOAK_LOGLEVEL=INFO
DB_VENDOR=POSTGRES
DB_ADDR=keycloak-db
DB_DATABASE=keycloak
DB_USER=keycloak-admin
DB_PASSWORD=password
KEYCLOAK_FRONTEND_URL=https://localhost:10006/auth
keycloak-db.env
POSTGRES_DB=keycloak
POSTGRES_USER=keycloak-admin
POSTGRES_PASSWORD=password
The file init.sql is simply a dump file to restore the database in case of necessity.
The /docker/keycloak/https folder contains two files that I've generated to start keycloak instance in https. These files are:
A self-signed certificate: tls.crt
A private key: tls.key
I used the "keytool" and "openssl" commands from the command prompt to create these files, as follow:
keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950
keytool -importkeystore -srckeystore keycloak.jks -destkeystore keycloak.p12 -deststoretype PKCS12
openssl pkcs12 -in keycloak.p12 -nokeys -out tls.crt
openssl pkcs12 -in keycloak.p12 -nocerts -nodes -out tls.key
keytool -import -trustcacerts -keystore trust.keystore -storepass password -alias localhost -file tls.crt
The keycloak instance runs correctly in https.
The problem is a spring boot application which wants to communicate with it.
This application is managed with maven and uses the keycloak-spring-boot-starter dependency to secure its endpoints with spring security:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>16.1.1</version>
</dependency>
This is the configuration bean:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled = true)
#Profile("!test")
public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/tests").hasAnyRole("USER")
.anyRequest()
.authenticated();
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
and this is the content of application.properties file:
logging.level.root=INFO
server.port=8080
keycloak.realm=${The name of realm in keycloak}
keycloak.auth-server-url=https://localhost:10006/auth
keycloak.ssl-required=external
keycloak.resource=${The name of client in keycloak}
keycloak.credentials.secret=${The client secret in keycloak}
keycloak.use-resource-role-mappings=true
keycloak.bearer-only=true
#this is the file I've previously generated using keytool (I also tried to use keycloak.jks here #but I obtained the same error)
keycloak.truststore=classpath:trust.keystore
keycloak.truststore-password=password
keycloak.confidential-port=10006
When I try to call /tests endpoint by postman (with a valid token), I obtain a 500 internal server error with this stacktrace:
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) ~[na:na]
at java.base/sun.security.validator.Validator.validate(Validator.java:264) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:630) ~[na:na]
... 84 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:na]
at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:na]
at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434) ~[na:na]
... 90 common frames omitted
Can anyone help me?
Thank you
I have a web-app running with SSL only (no http allowed) on port 8080:
server:
ssl:
key-store-type: PKCS12
key-store: file:${SERVER_KEYSTORE_PATH}
key-store-password: ${SERVER_CERT_PASSWORD}
port: 8080
When I launch the app, I see in the logs:
2020-03-17 17:32:29.836 INFO 90960 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (https)
One of my endpoints (the root one, actually) is protected by Spring Security, OAuth2:
#Override
protected void configure(HttpSecurity http) throws Exception {
String baseURI = redirectURI.substring(redirectURI.lastIndexOf("/"));
http.csrf().disable()
.authorizeRequests()
.antMatchers("/").authenticated()
.antMatchers("/**").permitAll()
.and()
.oauth2Login()
.defaultSuccessUrl("/")
.redirectionEndpoint().baseUri(baseURI);
}
The problem is that when I go to https://localhost:8080 - it redirects me to https://localhost:8443/oauth2/authorization/oauth So, for some reason the port 8080 is overriden with 8443.
As far as I understood from similar questions, this is happening because Tomcat is trying to redirect the user to the SSL-enabled endpoint (https) from the plain endpoint (http). But my endpoint is already SSL-enabled, so I don't really understand why is it happening. If I go to any other endpoint, it works with https and 8080 port - so only protected endpoint is problematic.
I tried to customize TomcatServletWebServerFactory with ConnectorCustomizers and set there redirect port to 8080, but it didn't help.
Any ideas on how to disable this useless redirect?
As per https://github.com/spring-projects/spring-security/issues/8140#issuecomment-600980028 :
#Override
protected void configure(HttpSecurity http) throws Exception {
PortMapperImpl portMapper = new PortMapperImpl();
portMapper.setPortMappings(Collections.singletonMap("8080","8080"));
PortResolverImpl portResolver = new PortResolverImpl();
portResolver.setPortMapper(portMapper);
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(
"/login");
entryPoint.setPortMapper(portMapper);
entryPoint.setPortResolver(portResolver);
http
.exceptionHandling()
.authenticationEntryPoint(entryPoint)
.and()
//...
;
}
Is possible to config Spring Booot application to have some url with non-secure (non-https) ex: /actuator/info, /actuator/prometheous While All other enpoint forced to be secure?
Enable SSL like this:
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=xxxx
I was try to set:
management.server.port=8762
management.server.ssl.enabled=false
and
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().antMatchers("/actuator").requiresInsecure();
http.requiresChannel().anyRequest().requiresSecure();
// accept only IP in range to access metric
http.csrf().disable().authorizeRequests().antMatchers("/actuator/**")
.access("hasIpAddress('" + ipRangeMain + "') or hasIpAddress('" + ipRangeSecond + "')");
}
But it's still not working
When I try to access /actuator/info, it show error:
Bad Request
This combination of host and port requires TLS.
"/actuator/info" endpoint need to accessed by Load Balancer and "/actuator/prometheous" to Monitoring, But now it not work.
In case anybody stumbles over this as well. I solved it using 2 Ports like #user3611168 suggested:
applycation.yml:
server:
port: 10000
ssl:
key-store-type: ...
key-store: ...
key-store-password: ...
key-alias: ...
management:
server:
port: 8080
ssl:
enabled: false
Port 10000 with SSL. Port for Prometheus 8080 without SSL
I am trying to integrate my Sprint Boot applications with Keycloak, starting with secure swagger page.
keytool helped me to generate a selfsigned keystore
keytool -genkey -alias abcdef -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
I use the above to setup ssl for the app
server:
port: "15700"
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: password
key-alias: abcdef
keyStoreType: PKCS12
Without keycloak, the https for swagger works as expected.
I started keycloak from their docker image as below, export http and https
services:
keycloak:
image: jboss/keycloak
environment:
DB_VENDOR: POSTGRES
DB_ADDR: my.ip.address
DB_PORT: 5432
DB_DATABASE: keycloak
DB_USER: username
DB_PASSWORD: password
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: password
ports:
- 8443:8443
- 8080:8080
I ask user to login first when they want to access the swagger docs, so I configure keycloak as below:
keycloak:
auth-server-url: "https://192.168.1.15:8443/auth"
realm: "DemoRealm"
public-client: true
resource: demo-app
security-constraints[0]:
authRoles[0]: "user"
securityCollections[0]:
name: "Demo App"
patterns[0]: "/swagger-ui.html"
Now, not logged in user will be direct to keycloak login page, it works perfect. But after the successful login, when redirect back to the app's swagger page, I go the following error:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
If I configure the keycloak auth uri to http
keycloak:
auth-server-url: "http://192.168.1.15:8080/auth"
realm: "DemoRealm"
public-client: true
resource: demo-app
security-constraints[0]:
authRoles[0]: "user"
securityCollections[0]:
name: "Demo App"
patterns[0]: "/swagger-ui.html"
everything works perfectly.
Is this a configuration issue for keycloak or for the spring boot app? Any required steps I missed?
You can try to set up your Rest Template bean:
Add dependency:
implementation 'org.apache.httpcomponents:httpclient:4.5'
Provide RestTemplate bean:
#Bean
private RestTemplate restTemplate() {
SSLContext sslContext = buildSslContext();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
private SSLContext buildSslContext() {
try {
char[] keyStorePassword = sslProperties.getKeyStorePassword();
return new SSLContextBuilder()
.loadKeyMaterial(
KeyStore.getInstance(new File(sslProperties.getKeyStore()), keyStorePassword),
keyStorePassword
).build();
} catch (Exception ex) {
throw new IllegalStateException("Unable to instantiate SSL context", ex);
} finally {
sslProperties.setKeyStorePassword(null);
sslProperties.setTrustStorePassword(null);
}
}
Provide required SSL properties in your application.properties or application.yaml file:
server:
ssl:
enabled: true
key-store: /path/to/key.keystore
key-store-password: password
key-alias: alias
trust-store: /path/to/truststore
trust-store-password: password
Alternatively, you can use my spring boot starter
I want to configure my Spring #MVC stub application's Spring RestTemplate with SSL for communicate to REST base https application, that deployed on Tomcat server (Spring 3, Tomcat 7). I have done up to now my works by refer this link. Now I have not any idea how to use these generated certificates with Spring RestTemplate, Can anyone have some idea please help me. Thanks. Up to now things I have done,
//Spring Security xml Configurations
<http>
<intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
<http-basic/></http>
//Configurations for enable SSL with Tomcat
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="C:\Users\Channa\.keystore" keystorePass="changeit"
clientAuth="false" sslProtocol="TLS"/>
For generating Keys, certificates etc,
//Generate client and server keys:
F:\jdk1.6.0_23\bin>keytool -genkey -keystore keystore_client -alias clientKey -dname "CN=localhost, OU=Dev, O=MyBusiness, L=Colombo, S=Westen, C=SL"
F:\jdk1.6.0_23\bin>keytool -genkey -keystore keystore_server -alias serverKey -dname "CN=localhost, OU=Dev, O=MyBusiness, L=Colombo, S=Westen, C=SL"
//Generate client and server certificates:
F:\jdk1.6.0_23\bin>keytool -export -alias clientKey -rfc -keystore keystore_client > client.cert
F:\jdk1.6.0_23\bin>keytool -export -alias serverKey -rfc -keystore keystore_server > server.cert
//Import certificates to corresponding truststores:
F:\jdk1.6.0_23\bin>keytool -import -alias clientCert -file client.cert -keystore truststore_server
F:\jdk1.6.0_23\bin>keytool -import -alias serverCert -file server.cert -keystore truststore_client
//Spring RestTemplate configurations
<!--Http client-->
<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
<constructor-arg ref="httpClientParams"/>
<property name="state" ref="httpState"/>
</bean>
<!--Http state-->
<bean id="httpState" class="com.org.imc.test.stub.http.CustomHttpState">
<property name="credentials" ref="usernamePasswordCredentials"/>
</bean>
<!--User name password credentials-->
<bean id="usernamePasswordCredentials" class="org.apache.commons.httpclient.UsernamePasswordCredentials"/>
<!--Http client-->
<bean id="httpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
</bean>
<!--RestTemplate-->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="httpClientFactory"/>
</bean>
//Https URL going to access
ResponseEntity<User> rECreateUser = restTemplate.postForEntity("https://127.0.0.1:8443/skeleton-1.0/login", user, User.class);
//Exception currently I got:
org.springframework.web.client.ResourceAccessException: I/O error: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
This is because SSL certificate of the service you are calling is not signed by a trusted certificate authority. The workaround is to import the certificate into the certificate trust store (cacerts) of your JRE.
download the cert by opening the URL in a browser, click the lock
icon in the browser's address bar.
Once you have a .cer file execute the below command
keytool -import -keystore jdk1.8.0_77/jre/lib/security/cacerts -file ~/test.cer -alias test
Variant for Spring Boot:
Add dependency:
implementation 'org.apache.httpcomponents:httpclient:4.5'
Provide RestTemplate bean:
#Bean
private RestTemplate restTemplate() {
SSLContext sslContext = buildSslContext();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
private SSLContext buildSslContext() {
try {
char[] keyStorePassword = sslProperties.getKeyStorePassword();
return new SSLContextBuilder()
.loadKeyMaterial(
KeyStore.getInstance(new File(sslProperties.getKeyStore()), keyStorePassword),
keyStorePassword
).build();
} catch (Exception ex) {
throw new IllegalStateException("Unable to instantiate SSL context", ex);
} finally {
sslProperties.setKeyStorePassword(null);
sslProperties.setTrustStorePassword(null);
}
}
Provide required SSL properties in your application.properties or application.yaml file:
server:
ssl:
enabled: true
key-store: /path/to/key.keystore
key-store-password: password
key-alias: alias
trust-store: /path/to/truststore
trust-store-password: password
That's it. Now you can see your Tomcat is starting on 8080 (or another port) (https).
Alternatively, you can use my spring boot starter
You can configure the RestTemplate with the HttpComponentsClientHttpRequestFactory from Apache HttpComponents HttpClient, which definitely supports SSL.
ref: Does REST (RestTemplate) in Spring Library support HTTPS protocol?
You can set a couple of system properties to select the truststore used in clients
System.setProperty("javax.net.ssl.trustStorePassword", "mypassword");
System.setProperty("javax.net.ssl.keyStoreType", "jks");
System.setProperty("javax.net.ssl.trustStore", "truststore_client");