Search code examples
javarestweb-serviceshttpsrest-security

Rest api in java using https


when I am creating Restservices in java using GET, POST etc then I am requesting them using http protocol. as soon as i use https it gives error.

for eg : http://localhost:8080/demorest/webapi/aliens is working properly.

but when I query same using https

https://localhost:8080/demorest/webapi/aliens

I get error site can not provide secured connection

what modification is required to make them compatible with https.


Solution

  • As you mentioned you are new to APIs here is a detailed answer for you.

    Answer is based on assumption that you are using tomcat server. There is 4 step approach to have application running on https, red below

    1. Get an SSL certificate or Generate a self-signed SSL certificate
    2. Enable HTTPS in application
    3. Redirect HTTP to HTTPS
    4. Distribute the SSL certificate to clients.

    If you dont already have ssl certificate generate yourself using keytool. Keytool is a certificate management utility provided together with the JDK, so if you have the JDK installed, you should already have keytool available.

    Let's open our Terminal prompt and write the following command to create a JKS keystore:

    keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 3650 -storepass password

    To create a PKCS12 keystore, and we should, the command is the following:

    keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650 -storepass password

    Let's have a closer look at the command we just run:

    genkeypair: generates a key pair;
    alias: the alias name for the item we are generating;
    keyalg: the cryptographic algorithm to generate the key pair;
    keysize: the size of the key. We have used 2048 bits, but 4096 would be a better choice for production;
    storetype: the type of keystore;
    keystore: the name of the keystore;
    validity: validity number of days;
    storepass: a password for the keystore.
    

    When running the previous command, we will be asked to input some information, but we are free to skip all of it (just press Return to skip an option). When asked if the information is correct, we should type yes. Finally, we hit return to use the keystore password as key password as well.

    What is your first and last name? 
        [Unknown]:  What is the name of your organizational unit? 
        [Unknown]:  What is the name of your organization? 
        [Unknown]:  What is the name of your City or Locality? 
        [Unknown]:  What is the name of your State or Province? 
        [Unknown]:  What is the two-letter country code for this unit? 
        [Unknown]:  Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct? 
        [no]: yes 
    
    Enter key password for <tomcat> 
        (RETURN if same as keystore password):
    

    Verify the keystore content To check the content of the keystore following the JKS format, we can use keytool again:

    keytool -list -v -keystore keystore.jks

    To test the content of a keystore following the PKCS12 format:

    keytool -list -v -storetype pkcs12 -keystore keystore.p12

    Convert a JKS keystore into PKCS12

    Should we have already a JKS keystore, we have the option to migrate it to PKCS12; keytool has a convenient command for that:

    keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12

    2.) To Enable https in your project

    If you have a application.properties file

    server.port=8443
    
    server.ssl.key-store-type=PKCS12
    server.ssl.key-store=classpath:keystore.p12
    server.ssl.key-store-password=password
    server.ssl.key-alias=tomcat
    
    security.require-ssl=true
    

    If you have application.yml file

    server:
      ssl:
        key-store: classpath:keystore.p12
        key-store-password: password
        key-store-type: pkcs12
        key-alias: tomcat
        key-password: password
      port: 8443
    

    To achieve in application, we need to extend the WebSecurityConfigurerAdapter class, since the security.require-ssl property has been deprecated.

    if you are on older version then you can skip below mentioned code.

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .requiresChannel()
                .anyRequest()
                .requiresSecure();
        }
    }
    

    3.) Redirect http to https

    Now that we have enabled HTTPS in our Spring Boot application and blocked any HTTP request, we want to redirect all traffic to HTTPS.

    Spring allows defining just one network connector in application.properties (or application.yml). Since we have used it for HTTPS, we have to set the HTTP connector programmatically for our Tomcat web server.

    @Configuration
    public class ServerConfig {
    
        @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(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
            connector.setScheme("http");
            connector.setPort(8080);
            connector.setSecure(false);
            connector.setRedirectPort(8443);
            return connector;
        }
    }
    

    4.) Distribute the SSL certificate to clients When using a self-signed SSL certificate, our browser won't trust our application and will warn the user that it's not secure. And that'll be the same with any other client.

    It's possible to make a client trust our application by providing it with our certificate.

    Extract an SSL certificate from a keystore We have stored our certificate inside a keystore, so we need to extract it. Again, keytool supports us very well:

    keytool -export -keystore keystore.jks -alias tomcat -file myCertificate.crt

    Make a browser trust an SSL certificate When using a keystore in the industry-standard PKCS12 format, we should be able to use it directly without extracting the certificate.

    I suggest you check the official guide on how to import a PKCS12 file into your specific client.

    If deploying the application on localhost, we may need to do a further step from our browser: enabling insecure connections with localhost.

    In Chrome, we can write the following URL in the search bar: chrome://flags/#allow-insecure-localhost and activate the relative option.

    Import an SSL certificate inside the JRE keystore To make the JRE trust our certificate, we need to import it inside cacerts: the JRE trust store in charge of holding all certificates that can be trusted.

    First, we need to know the path to our JDK home. A quick way to find it, if we are using Eclipse or STS as our IDE, is by going to Preferences > Java > Installed JREs. If using IntelliJ IDEA, we can access this information by going to Project Structure > SDKs and look at the value of the JDK home path field.

    Then, from our Terminal prompt, let's insert the following command (we might need to run it with administrator privileges by prefixing it with sudo):

    keytool -importcert -file myCertificate.crt -alias tomcat -keystore $JDK_HOME/jre/lib/security/cacerts

    you can refer project on github here