We are calling external system webservice from Salesforce. the webservice exposed are internet We have created stub from the WSDL. It is a SOAP based call. But while calling the service, We are getting error 'java.security.cert.CertificateException: No subject alternative names present'.
[SalesForce] java.security.cert.CertificateException: No subject alternative names present
Related Solutions
This is sort of a Java problem, rather than an entirely Salesforce-specific problem, so depending on how you search for the answer, it could take you a while to get to why it failed, and what the actual solution is.
Basically: The Java used by Salesforce/Apex for SSL handshaking requires that the server certificate has a SAN (Subject Alternative Name) that matches the CN (Common Name) when the CN is an IP Address. This isn't an issue when the CN is a Hostname.
As such, as you can't use any of the (not particularly nice anyway) java workarounds for this issue; the solution to this involves generating a new server certificate with extra info on it. If you control the web service you're calling out to, that should be reasonably easy - otherwise you will need to get in touch with whoever administers the server and its certs and ask them to do this, as this is a definite blocker with no known workarounds in Salesforce (unless anyone else wants to chime in with one!).
Either way, someone will need to pay for a new Public CA signed server certificate to replace the old one. Depending on your Public CA, you will need to make sure you are buying a cert type that allows SANs, and be aware there may be extra charges per SAN added, depending on your provider.
To include the required SAN using Java 7's keytool
, use the flag -ext san=ip:0.0.0.0
- filling in the appropriate IP address here, that matches the CN IP address, instead of 0.0.0.0.
To include the required SAN using openssl
, include the following in your openssl.conf
file used for generation
[req]
req_extensions = v3_req
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = 0.0.0.0
Again, filling in the appropriate IP address that matches your CN, instead of 0.0.0.0
The Java flavoured Q&A can be found at https://stackoverflow.com/questions/8443081/
Salesforce Convention in WSDL for Required Elements. It has been Salesforce's convention when exposing its own Web Services and those built via Apex to expose each child element of a given XML structure, be that derived from an Object or an Apex class, without consideration for it being required (typically denoted in XML Schema via minOccurs="1", the default if not specified) or optional.
Salesforce use of minOccurs in XML Schema and why?. Salesforce explicitly outputs minOccurs="0" for every child element, regardless if it maps to a required field on an Object for example. Meaning that web service clients cannot enforce client side the need for required information, which is a shame, as this would be a good client side optimisation and make your web service API's more self describing. However the reasoning i imagine behind this, is to allow records to be updated and/or created with only specific fields to be specified. Thus if they made the XML Schema enforce required fields they would not be able to support this convention, which can be quite useful.
<xsd:complexType name="Test__c">
<xsd:complexContent>
<xsd:extension base="tns:sObject">
<xsd:sequence>
<xsd:element name="A_Number__c" minOccurs="0" type="xsd:double" nillable="true"/>
Implementing required field validation without Apex code. If your using any of the Salesforce standard API's (Enterprise, Partner or REST) eventually the platform will enforce the 'required' field attribute on the field definition giving you an error, all be it only after the database operation has been attempted. Likewise if you write an Apex Web Service and it receives an SObject structure, it is only after you have attempted to perform DML (Database Manipulation Language) will an exception occur. In all but, Lookup Field types, you can configure this on a field. If you need something more custom before the database is hit, you will need to implement this yourself in your Apex code.
Best Answer
There are a few things that could be wrong here.
1) If you're using HTTPS for the Endpoint URL, the other system must have a CA signed SSL certificate
2) Make sure you've added the endpoint URL in the Remote Site Settings in salesforce
3) If you're using Salesforce CA signed certificate, make sure you specify the cert name in your class (example) and you upload the cert file on the other server.