Git + Linux: (gnome-ssh-askpass:24871): Gtk-WARNING **: cannot open display:

PROBLEM

When running git clone on Linux, the following error appears:-

-bash-4.1$ git clone http://user@tfs:8080/tfs/my-institution/my-domain/_git/my-project
Initialized empty Git repository in /people/my-group/user/my-project/.git/

(gnome-ssh-askpass:24871): Gtk-WARNING **: cannot open display:

SOLUTION

To fix this, run the following command to disable gnome-ssh-askpass:-

-bash-4.1$ unset SSH_ASKPASS

Now, git clone will work just fine:-

-bash-4.1$ git clone http://user@tfs:8080/tfs/my-institution/my-domain/_git/my-project
Initialized empty Git repository in /people/my-group/user/my-project/.git/
Password:
remote:
remote:                    fTfs
remote:                  fSSSSSSSs
remote:                fSSSSSSSSSS
remote: TSSf         fSSSSSSSSSSSS
remote: SSSSSF     fSSSSSSST SSSSS
remote: SSfSSSSSsfSSSSSSSt   SSSSS
remote: SS  tSSSSSSSSSs      SSSSS
remote: SS   fSSSSSSST       SSSSS
remote: SS fSSSSSFSSSSSSf    SSSSS
remote: SSSSSST    FSSSSSSFt SSSSS
remote: SSSSt        FSSSSSSSSSSSS
remote:                FSSSSSSSSSS
remote:                  FSSSSSSs
remote:                    FSFs    (TM)
remote:
remote:  Microsoft (R) Visual Studio (R) Team Foundation Server
remote:
Receiving objects: 100% (504/504), 1.05 MiB, done.
Resolving deltas: 100% (138/138), done.

To prevent this from happening again, add unset SSH_ASKPASS command to .bashrc file.

Spring Security SAML: Replacing SHA-1 with SHA-256 on Signature and Digest Algorithms

PROBLEM

By default, Spring Security SAML’s SAMLBootstrap uses SHA1withRSA for signature algorithm and SHA-1 for digest algorithm.

@Configuration
@EnableWebSecurity
public abstract class AppSAMLConfig extends WebSecurityConfigurerAdapter {
	...

    @Bean
    public static SAMLBootstrap SAMLBootstrap() {
        return new SAMLBootstrap();
    }
	
	...
}

For example, the above configuration will generate the following SAML request payload when using HTTP-POST binding:-

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest
    AssertionConsumerServiceURL="https://server/app/saml/SSO"
    Destination="https://adfs-server/adfs/ls/" ForceAuthn="true"
    ID="a3bj4e05i70f6946gi85299i51i02a" IsPassive="false"
    IssueInstant="2016-02-23T15:10:26.414Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://server/app/saml/metadata</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#a3bj4e05i70f6946gi85299i51i02a">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>u25hV7rk8hIpXYLJQs0aZjkueP0=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>YDR9ybi...</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIICxz...</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml2p:RequestedAuthnContext Comparison="exact">
        <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
    </saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>

Unfortunately, SHA-1 is now deemed insecure due to “Freestart Collision” attack.

Further, most modern browsers have ceased to trust SHA-1 code signing certificates starting January 2016 and will eventually stop accepting these certificates by January 2017.

SOLUTION

To fix this, we could replace SHA-1 with stronger secure hash algorithm, such as SHA-256.

To do so, create a class that extends SAMLBootstrap that uses SHA256withRSA for signature algorithm and SHA-256 for digest algorithm.

public final class CustomSAMLBootstrap extends SAMLBootstrap {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        super.postProcessBeanFactory(beanFactory);
        BasicSecurityConfiguration config = (BasicSecurityConfiguration) Configuration.getGlobalSecurityConfiguration();
        config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
        config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
    }
}

Then, return CustomSAMLBootstrap instead of SAMLBootstrap

@Configuration
@EnableWebSecurity
public abstract class AppSAMLConfig extends WebSecurityConfigurerAdapter {
	...

    @Bean
    public static SAMLBootstrap SAMLBootstrap() {
        return new CustomSAMLBootstrap();
    }
	
	...
}

Now, the generated SAML request payload using HTTP-POST binding looks like this:-

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest
    AssertionConsumerServiceURL="https://server/app/saml/SSO"
    Destination="https://adfs-server/adfs/ls/" ForceAuthn="true"
    ID="a2e7f98agfaec7d253714fjdbcf8a83" IsPassive="false"
    IssueInstant="2016-02-23T15:18:43.452Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://server/app/saml/metadata</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <ds:Reference URI="#a2e7f98agfaec7d253714fjdbcf8a83">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <ds:DigestValue>w4qHFsBxFGifzemEJCYcuGOt+oZJ9N2DQM+Q2aEqJFI=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>YDR9ybi...</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIICxz...</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml2p:RequestedAuthnContext Comparison="exact">
        <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
    </saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>

Spring Security SAML: Handling IdP’s Public Certificate When Loading Metadata Over HTTPS

PROBLEM

By default, when loading IdP’s metadata over HTTPS (ex: https://adfs-server/federationmetadata/2007-06/federationmetadata.xml), Spring Security SAML will perform the trust verification configured in JDK.

However, there are times we do not have direct access to JDK home directory especially if the web apps are hosted on someone else’s JEE or PaaS servers.

SOLUTION

To fix this, the IdP’s public certificate can be imported into the app’s keystore instead of JDK’s keystore.

keytool -importcert -file adfs-server.cer -keystore app-keystore.jks -alias "adfs-server"

Then, configure Spring Security SAML to use TLSProtocolConfigurer, which will use all public certificates stored in the app’s keystore as trust anchors for PKIX validation.

@Configuration
@EnableWebSecurity
public abstract class SecuritySAMLConfig extends WebSecurityConfigurerAdapter {

    ...
	
	// in this case, `app-keystore.jks` contains the app's public/private keys and 
	// the imported IdP's public certificate
    @Bean
    public KeyManager keyManager() {
        DefaultResourceLoader loader = new DefaultResourceLoader();
        Resource storeFile = loader.getResource("classpath:app-keystore.jks");
        Map<String, String> passwords = new HashMap<>();
        passwords.put("app_alias", "app_password");
        return new JKSKeyManager(storeFile, "app_password", passwords, "app_alias");
    }

    @Bean
    public TLSProtocolConfigurer tlsProtocolConfigurer() {
        return new TLSProtocolConfigurer();
    }

    @Bean
    public ProtocolSocketFactory protocolSocketFactory(KeyManager keyManager) {
        return new TLSProtocolSocketFactory(keyManager, null, "default");
    }

    @Bean
    public Protocol protocol(ProtocolSocketFactory protocolSocketFactory) {
        return new Protocol("https", protocolSocketFactory, 443);
    }

    @Bean
    public MethodInvokingFactoryBean socketFactoryInitialization(Protocol protocol) {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setTargetClass(Protocol.class);
        methodInvokingFactoryBean.setTargetMethod("registerProtocol");
        Object[] args = {"https", protocol};
        methodInvokingFactoryBean.setArguments(args);
        return methodInvokingFactoryBean;
    }

    ...
}

Doing so makes the app more portable so that it can be deployed into any JEE or PaaS servers without any problem.

Java + SAML: Illegal Key Size

PROBLEM

When attempting to decrypt the SAML response from IdP, the following exception occurs:-

org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size
Original Exception was java.security.InvalidKeyException: Illegal key size
	at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1822)
	at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:596)
	at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
	at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
	at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
	at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
	at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
	at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
	at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)

SOLUTION

When inspecting the SAML response payload below, the data is encrypted with AES-256:-

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response
        Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
        Destination="https://server/my-app/saml/SSO"
        ID="_370d6ba5-177c-494b-9147-2eafd9ecb6c9"
        InResponseTo="a5c5dja1i5fgb2bf2e66f6g9g5398gj"
        IssueInstant="2016-02-18T15:28:43.473Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://adfs-server/adfs/services/trust</Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <EncryptedAssertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
                    <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    </e:EncryptionMethod>
                    <KeyInfo>
                        <ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                            <ds:X509IssuerSerial>
                                <ds:X509IssuerName>CN=server</ds:X509IssuerName>
                                <ds:X509SerialNumber>1822784706</ds:X509SerialNumber>
                            </ds:X509IssuerSerial>
                        </ds:X509Data>
                    </KeyInfo>
                    <e:CipherData>
                        <e:CipherValue>isG83fVk50fJRIcg...</e:CipherValue>
                    </e:CipherData>
                </e:EncryptedKey>
            </KeyInfo>
            <xenc:CipherData>
                <xenc:CipherValue>+b2o6HNxaxsse7rkB...</xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </EncryptedAssertion>
</samlp:Response>

By default, Java’s keysize is limited to 128-bit key due to US export laws and a few countries’ import laws.

To fix this…

  • Determine the Java version.
  • Download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files – Java 7 or Java 8.
  • Inflate the zip file.
  • Copy local_policy.jar and US_export_policy.jar to [JAVA_HOME]/jre/lib/security.

Spring Security SAML: Configuring Binding for Sending SAML Messages to IdP

PROBLEM

Depending on each institution’s Identity Provider (IdP) configuration, the Service Provider (Sp) may need to configure the correct binding for sending SAML messages to IdP.

SOLUTION

Using Spring Security SAML, the binding configuration is highlighted below:-

@Configuration
@EnableWebSecurity
public abstract class SecuritySAMLConfig extends WebSecurityConfigurerAdapter {
    
	...
	
    @Bean
    public WebSSOProfileOptions webSSOProfileOptions() {
        WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions();
        webSSOProfileOptions.setIncludeScoping(false);
        webSSOProfileOptions.setBinding(...);
    }
	
    @Bean
    public SAMLEntryPoint samlEntryPoint(WebSSOProfileOptions webSSOProfileOptions) {
        SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint();
        samlEntryPoint.setDefaultProfileOptions(webSSOProfileOptions);
        return samlEntryPoint;
    }

	...
}

HTTP-POST Binding

Configuration:-

webSSOProfileOptions.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);

Using HTTP-POST binding, the SAML message to IdP will contain the signature information:-

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response
        Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
        Destination="https://server/my-app/saml/SSO"
        ID="_370d6ba5-177c-494b-9147-2eafd9ecb6c9"
        InResponseTo="a5c5dja1i5fgb2bf2e66f6g9g5398gj"
        IssueInstant="2016-02-18T15:28:43.473Z"
        Version="2.0"
        xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://adfs-server/adfs/services/trust</Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <EncryptedAssertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
                    <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    </e:EncryptionMethod>
                    <KeyInfo>
                        <ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                            <ds:X509IssuerSerial>
                                <ds:X509IssuerName>CN=server</ds:X509IssuerName>
                                <ds:X509SerialNumber>1822784706</ds:X509SerialNumber>
                            </ds:X509IssuerSerial>
                        </ds:X509Data>
                    </KeyInfo>
                    <e:CipherData>
                        <e:CipherValue>isG83fVk50fJRI...</e:CipherValue>
                    </e:CipherData>
                </e:EncryptedKey>
            </KeyInfo>
            <xenc:CipherData>
                <xenc:CipherValue>+b2o6HNxaxsse7rkB...</xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </EncryptedAssertion>
</samlp:Response>

HTTP-Redirect Binding

Configuration:-

webSSOProfileOptions.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);

Using SAML2_REDIRECT_BINDING_URI binding, the signature will be removed before the message is delivered. The signature is then performed on the serialized request and sent as a GET parameter.

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
                     AssertionConsumerServiceURL="https://server/my-app/saml/SSO"
                     Destination="https://adfs-server/adfs/ls/"
                     ForceAuthn="false"
                     ID="a4719398gd37jgg464505g70i40a49"
                     IsPassive="false"
                     IssueInstant="2016-02-18T15:24:59.036Z"
                     ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                     Version="2.0">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://server/my-app/saml/metadata</saml2:Issuer>
</saml2p:AuthnRequest>

There are no Limits…

Bruce had me up to three miles a day, really at a good pace. We’d run the three miles in twenty-one or twenty-two minutes. Just under eight minutes a mile [Note: when running on his own in 1968, Lee would get his time down to six-and-a-half minutes per mile].

So this morning he said to me “We’re going to go five.”

I said, “Bruce, I can’t go five. I’m a helluva lot older than you are, and I can’t do five.”

He said, “When we get to three, we’ll shift gears and it’s only two more and you’ll do it.”

I said “Okay, hell, I’ll go for it.”

So we get to three, we go into the fourth mile and I’m okay for three or four minutes, and then I really begin to give out.

I’m tired, my heart’s pounding, I can’t go any more and so I say to him, “Bruce if I run any more,” — and we’re still running — “if I run any more I’m liable to have a heart attack and die.” He said, “Then die.” It made me so mad that I went the full five miles.

Afterward I went to the shower and then I wanted to talk to him about it. I said, you know, “Why did you say that?” He said, “Because you might as well be dead. Seriously, if you always put limits on what you can do, physical or anything else, it’ll spread over into the rest of your life. It’ll spread into your work, into your morality, into your entire being. There are no limits. There are plateaus, but you must not stay there, you must go beyond them. If it kills you, it kills you. A man must constantly exceed his level.

– The Art of Expressing the Human Body by Bruce Lee and John Little

Java + HTTPS: Unable to Find Valid Certification Path to Requested Target

PROBLEM

When invoking a HTTPS URL from Java, for example…

final RestTemplate restTemplate = new RestTemplate();
restTemplate.execute("https://www.google.com/some-api", HttpMethod.GET, null, ...);

…the following exception is thrown…

org.springframework.web.client.ResourceAccessException: I/O error on GET 
request for "https://www.google.com":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
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:607)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)

SOLUTION 1: Disable SSL Validation – NOT RECOMMENDED

One way is to simply disable the SSL validation by configuring SSLContext to trust all X.509 certificates before invoking the intended HTTPS URL.

@Configuration
class MyAppConfig {
    @Bean
    public Boolean disableSSLValidation() throws Exception {
        final SSLContext sslContext = SSLContext.getInstance("TLS");

        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }}, null);

        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

        return true;
    }
}

Unless you are writing test cases or implementing non-production code, this approach is highly discouraged because it doesn’t prevent the man-in-the-middle attacks.

SOLUTION 2: Import Certificate into Java Keystore – RECOMMENDED

The reason we see this exception is because the certificate used by the HTTPS URL doesn’t exist in the Java Keystore. Hence, the SSL validation fails.

To fix this, we can download the website’s certificate using a browser to be added into Java Keystore.

Access the website (in this example, I use https://www.google.com) and click on the pad lock.

Find the button that allows you to view and export the certificate as a PEM file. In this example, I named that file google.cer.

The content of the downloaded PEM file should look like this:-

-----BEGIN CERTIFICATE-----
MIIEgDCCA2igAwIBAgIITq9JKLrGf5EwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
eoV23mHmV6/0mOwocVYt/Th96WNGGmhANkFW//HCphRWnhaOqIG6yFRQ/jxArTvZ
QJEGI5AiYHzQn7LdUM8mH1o3ifR+lX+QiAwyeU9oegdlRslI2KMoPOuOFj329NFx
Bw+XVQXMsRJITPg8pnegPmLCOjpz8y7pBxbxGnfaI66I8X4dArsaXX4r5mkfhk2e
mm7fxQ8qUaW9mKoW0XvwGxU0AwKI8OopuXHoD97vr2GSK0QNZ19A96mtTWnQ2cu2
i9qjGw==
-----END CERTIFICATE-----

Go to the Terminal.

If you have multiple versions of java, make sure you choose the correct version first:-

export JAVA_HOME="`/usr/libexec/java_home -v '1.7*'`"

Import the certificate into Java Keystore:-

sudo keytool -import -trustcacerts -file /path/to/google.cer -alias google -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

Now, you should be able to invoke the HTTPS URL without any exception.

If for some reason you need to remove the imported certificate from Java Keystore, you can refer to that certificate using the alias and run this command:-

sudo keytool -delete -alias google -keystore $JAVA_HOME/jre/lib/security/cacerts