Apache HttpClient 5.1 bypass SSL Verification - apache-httpclient-4.x

I have configured CloseableHttpAsyncClient as mentioned below
public CloseableHttpAsyncClient closeableHttpAsyncClient(){
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
final PoolingAsyncClientConnectionManager connManager = new PoolingAsyncClientConnectionManager();
connManager.setMaxTotal(10);
clientBuilder.setConnectionManager(connManager);
clientBuilder.setRedirectStrategy(DefaultRedirectStrategy.INSTANCE);
CloseableHttpAsyncClient closeableHttpAsyncClient = clientBuilder.build();
return closeableHttpAsyncClient;
}
I want to bypass SSL verification. I have tried to check different configurations but didn't find the solution for the same.

One can set up a custom TLS context and use it with the default TLS strategy as described here:
https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
In this particular example the connection manager has been configured to trust all certificates with the CN equal to httpbin.org in addition to standard CAs. One can choose a different stratefgy or trust all certificates indiscriminately, though the latter is STONGLY discouraged.
final SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new TrustStrategy() {
#Override
public boolean isTrusted(
final X509Certificate[] chain,
final String authType) throws CertificateException {
// Trust all certs with CN equal `httpbin.org`
final X509Certificate cert = chain[0];
return "CN=httpbin.org".equalsIgnoreCase(cert.getSubjectDN().getName());
}
})
.build();
final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
.setSslContext(sslcontext)
.build();
final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
.setTlsStrategy(tlsStrategy)
.build();

Related

How do you override the Hystrix configuration for OpenFeign?

How do you override the Hystrix default configuration for OpenFeign? Most of the documentation out there is for SpringBoot + OpenFeign, which has its own Spring-specific configuration override system.
Ideally it would be possible to configure the Hystrix core size for the client and configure and timeouts on a per endpoint basis.
Hystrix OpenFeign has a setterFactory() method on the builder that allows you to pass in a SetterFactory lambda function that is executed when setting up each target endpoint:
final SetterFactory hystrixConfigurationFactory = (target, method) -> {
final String groupKey = target.name();
final String commandKey = method.getAnnotation(RequestLine.class).value();
// Configure default thread pool properties
final HystrixThreadPoolProperties.Setter hystrixThreadPoolProperties = HystrixThreadPoolProperties.Setter()
.withCoreSize(50)
.withMaximumSize(200)
.withAllowMaximumSizeToDivergeFromCoreSize(true);
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
.andThreadPoolPropertiesDefaults(hystrixThreadPoolProperties);;
};
final MyTargetClient myTargetClient = HystrixFeign.builder()
.setterFactory(hystrixConfigurationFactory)
.client(new OkHttpClient())
.encoder(new JacksonEncoder(objectMapper))
.decoder(new JacksonDecoder(objectMapper))
.target(new Target.HardCodedTarget<>(MyTargetClient.class, "customclientname", baseUrl))
The above example uses boilerplate from the OpenFeign documentation to properly name Hystrix keys based on the target endpoint function. It then goes further by also configuring the default thread pool property core size and maximum core size as a default for all of the target functions.
However, since this factory is called for each target endpoint, we can actually override the Hystrix configuration on a per endpoint basis. A use good case for this is Hystrix timeouts: sometimes there are endpoints that take longer than others and we need to account for that.
The easiest way would be to first create an annotation and place it on the target endpoints that need to be overridden:
/**
* Override Hystrix configuration for Feign targets.
*/
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface HystrixOverride {
int DEFAULT_EXECUTION_TIMEOUT = 2_000;
/**
* Execution timeout in milliseconds.
*/
int executionTimeout() default DEFAULT_EXECUTION_TIMEOUT;
}
interface MyTargetClient {
#HystrixOverride(executionTimeout = 10_000)
#RequestLine("GET /rest/{storeCode}/V1/products")
Products searchProducts(#Param("storeCode") String storeCode, #QueryMap Map<String, Object> queryMap);
#RequestLine("GET /rest/{storeCode}/V1/products/{sku}")
Product getProduct(#Param("storeCode") String storeCode, #Param("sku") String sku);
}
In the above example, the search API might take a little longer to load so we have an override for that.
Just putting the override annotation on the target endpoint function is not enough though. We need to go back to our factory and update it to use the data in the annotations:
final SetterFactory hystrixConfigurationFactory = (target, method) -> {
final String groupKey = target.name();
final String commandKey = method.getAnnotation(RequestLine.class).value();
// Configure per-function Hystrix configuration by referencing annotations
final HystrixCommandProperties.Setter hystrixCommandProperties = HystrixCommandProperties.Setter();
final HystrixOverride hystrixOverride = method.getAnnotation(HystrixOverride.class);
final int executionTimeout = (hystrixOverride == null)
? HystrixOverride.DEFAULT_EXECUTION_TIMEOUT
: hystrixOverride.executionTimeout();
hystrixCommandProperties.withExecutionTimeoutInMilliseconds(executionTimeout);
// Configure default thread pool properties
final HystrixThreadPoolProperties.Setter hystrixThreadPoolProperties = HystrixThreadPoolProperties.Setter()
.withCoreSize(50)
.withMaximumSize(200)
.withAllowMaximumSizeToDivergeFromCoreSize(true);
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
.andCommandPropertiesDefaults(hystrixCommandProperties)
.andThreadPoolPropertiesDefaults(hystrixThreadPoolProperties);;
};
The above checks that an override annotation exists and then uses the data in that annotation to configure the execution timeout for that target endpoint. If the override is not present, the default for the HystrixOverride endpoint will be used instead. The resulting hystrixCommandProperties variable is then plugged in to the overall HystrixCommand.Setter at the end.

"Invalid JSON Number" Spring Data Mongo 2.0.2

** FIXED **
All I had to do is add an apostrophe before and after each argument index,
i.e, change:
#Query(value = "{'type': 'Application','name': ?0,'organizationId': ?1}", fields = "{_id:1}")
To:
#Query(value = "{'type': 'Application','name': '?0','organizationId': '?1'}", fields = "{_id:1}")
===================
I recently upgraded my MongoDB and my Spring-Data-MongoDB Driver.
I used to access my MongoDB through mongoRepository using this code:
#Query(value = "{'type': 'Application','name': ?0,'organizationId': ?1}", fields = "{_id:1}")
Policies findPolicyByNameAndOrganizationId(String name, String organizationId);
Where Policies is the object I want to consume.
After performing an update to Spring, I get the following Error now when accessing the method above:
org.bson.json.JsonParseException: Invalid JSON number
I fear this is because I use Spring's MongoCoverter (in the case of this specific object only) to map documents to object.
Here's is my Reader Converter:
public class ApplicationPolicyReadConverotor implements Converter<Document, ApplicationPolicy > {
private MongoConverter mongoConverter;
public ApplicationPolicyReadConverotor(MongoConverter mongoConverter) {
this.mongoConverter = mongoConverter;
}
//#Override
public ApplicationPolicy convert(Document source) {
ApplicationPolicyEntity entity = mongoConverter.read(ApplicationPolicyEntity.class, source);
ApplicationPolicy policy = new ApplicationPolicy();
addFields(policy, entity);
addPackages(policy, entity);
return policy;
}
And here's is my Writer Converter:
public class ApplicationPolicyWriteConvertor implements Converter<ApplicationPolicy, Document>{
private MongoConverter mongoConverter;
public ApplicationPolicyWriteConvertor(MongoConverter mongoConverter) {
this.mongoConverter = mongoConverter;
}
#Override
public Document convert(ApplicationPolicy source) {
System.out.println("mashuWrite");
ApplicationPolicyEntity target = new ApplicationPolicyEntity();
copyFields(source, target);
copyPackages(source, target);
Document Doc = new Document();
mongoConverter.write(target, Doc);
return Doc;
}
I checked Spring reference (2.0.2) regarding MongoConverter and how it works and at this stage I think I'm doing it correctly.
Other object who do not use mapping/conversions suffer no problems.
Same did this Object (ApplicationPolicy) untill I upgraded my mongo and my spring driver.
My mongodb is 3.4.10 and Spring data mongo driver is 2.0.2.
Here's the code that initializes the MappingMongoCoverter Object:
(Adds my custom Converters).
SimpleMongoDbFactory simpleMongoDbFactory = new SimpleMongoDbFactory(client, dbName);
DefaultDbRefResolver defaultDbRefResolver = new DefaultDbRefResolver(simpleMongoDbFactory);
MongoMappingContext mongoMappingContext = new MongoMappingContext();
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(defaultDbRefResolver,
mongoMappingContext);
mappingMongoConverter.setMapKeyDotReplacement("_dot_");
// Adding custom read and write converters for permission policy.
mappingMongoConverter.setCustomConversions(new MongoCustomConversions(Arrays.asList(
new ApplicationPolicyWriteConvertor(mappingMongoConverter), new ApplicationPolicyReadConverotor(
mappingMongoConverter))));
mappingMongoConverter.afterPropertiesSet();
final MongoTemplate template = new MongoTemplate(simpleMongoDbFactory, mappingMongoConverter);
return template;
I know for sure that ReaderConverter WORKS legit (at least in some cases) since other aspects of the software use the custom ReaderConverter I've written and it works as expected.
Also when using debug mode (Intellij) I do not reach to the conversion code block when invoking the following:
#Query(value = "{'type': 'Application','name': ?0,'organizationId': ?1}", fields = "{_id:1}")
Policies findPolicyByNameAndOrganizationId(String name, String organizationId);
So basically I'm kinda clueless. I have a sense my converter Implementation is messy but couldn't fix it..

JSON Web Signature (Ninbus-JOSE-JWT)

I want to do a project with JSON Web Signature (JWS) and i want to send the public key of the certificate used for the signature so that the message can be validated once received with this public key. I am using the Ninbus JOS JWT library. I can sign the JSON object and I can see the public key, but i can not validate it correctly.
This is the code:
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(_signatureKey_); // PrivateKey
com.nimbusds.jose.util.Base64 b64 = new com.nimbusds.jose.util.Base64(_x509certificate.toString()); // X509Certificate
ArrayList<com.nimbusds.jose.util.Base64> certificados = new ArrayList<com.nimbusds.jose.util.Base64>();
certificados.add(b64);
RSAPublicKey _rsaPublicKey = (RSAPublicKey)_x509certificate.getPublicKey(); // Get the public key of the X509Certificate
RSAKey jwk = new com.nimbusds.jose.jwk.RSAKey.Builder( new Base64URL( _rsaPublicKey.getModulus().toString()), new Base64URL( _rsaPublicKey.getPublicExponent().toString()))
.x509CertChain(certificados)
.build();
JWSHeader _jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256).
x509CertChain(certificados).
jwk(jwk).
build();
// Prepare JWS object with simple string as payload
JWSObject jwsObject = new JWSObject(_jwsHeader, new Payload(_jsonObject));
// Compute the RSA signature
jwsObject.sign(signer);
// Validation OK : This validation works
JWSVerifier verifier = new RSASSAVerifier(_rsaPublicKey);
boolean signatureValid = jwsObject.verify(verifier); // ---> True, OK
// Now I want to validate the JWSObject getting the public key from the same JWSObject. This validation Fails
JWK _jwk = jwsObject.getHeader().getJWK();
RSAKey _rsakey = (RSAKey)_jwk;
RSAPublicKey _rsaPublicKey2 = _rsakey.toRSAPublicKey();
JWSVerifier verifier2 = new RSASSAVerifier(_rsakey.toRSAPublicKey());
boolean verificado2 = jwsObject.verify(verifier2); // False!
// Another option, this fails too
RSAKey __rsaKey2 = new com.nimbusds.jose.jwk.RSAKey.Builder( _rsakey.toRSAPublicKey() ).x509CertChain(_jwk.getX509CertChain()).build();
JWSVerifier verifier3 = new RSASSAVerifier(__rsaKey2);
boolean verificado3 = jwsObject.verify(verifier3); // False!
The _rsaPublicKey is: "Sun RSA public key, 2048 bits", but when i get it from the JWK (_rsaPublicKey2), I get "Sun RSA public key, 3696 bits" and i don't know why.
Thanks!
On the recipient side, do you validate the X.509 certificate issuer, subject and chain before trusting the key? Signature validation must not be attempted before the recipient is certain that it can trust the certificate included in the JWS.
Another note: Do not include the public JWK in the JWS header. This should only be used for ephemeral public keys in ECDH (a different alg used for JWE). Passing the certificate chain in the JWS header is sufficient, but you must validate it / find out if the certificate can be trusted, before using its public key.
The library will not validate / find out if the certificate can be trusted for you!
If the second signature validation fails, then probably the key used to sign the JWS and the one that came with the X.509 certificate are not the same (as suggested by the different reported lengths - 2048 bits vs. 3696 bits).

HttpClient 4.3 set source port

I am using HttpClient 4.3. I would like to set source port (or local port) for each request. I didn't see any method on HttpClient or HttpGet class. On the Server side, we have written security code (kind of whitelist IP with port number) to check incoming request ip and port number (this is all within intranet with static ips).
RequestConfig requestConfig = RequestConfig.custom()
.setLocalAddress(InetAddress.getByAddress(new byte[] {127, 0, 0, 1}))
.build();
HttpGet httpGet = new HttpGet("/");
httpGet.setConfig(requestConfig);
Correction:
Explicit setting of local ports is not supported by HttpClien 4.x

JavaMail SMTPSendFailedException

I am writing a bulk email program using the JavaMail api. I have a Microsoft Exhange server which I am trying to send the emails in to. When I run my program I get the following error:
**com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:1862)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1100)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at SendEmail.postMail(SendEmail.java:100)
at EmailGenerator.main(EmailGenerator.java:52)**
The part of my code trying to send the message is as follows:
Properties props = new Properties();
props.put("mail.smtp.host", email_server);
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", true);
class EmailAuthenticator extends Authenticator {
String user;
String pw;
EmailAuthenticator (String FROM, String PASSWORD)
{
super();
this.user = FROM;
this.pw = PASSWORD;
}
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user, pw);
}
}
Session session = Session.getInstance(props, new EmailAuthenticator(USER, PASSWORD));
session.setDebug(debug);
System.out.println("Session created");
.. CREATED MESSAGE HERE...
Transport transport = session.getTransport("smtp");
transport.connect(exchange_server,user,password);
transport.send(msg);
transport.close();
I wonder am I missing some configuration on the Exchange server side, or is an issue with my code?
OK I figured out where I was going wrong here and am posting up the answer incase anybody else can get some value out of it. I had the following line of code:
props.put("mail.smtp.auth", true);
This was telling my application that it needed to authenticate to the SMTP server, when in fact it didnt. This was causing my application from logging into the SMTP server and sending the email and thus producing the error message. Setting this property to false or not having this line of code fixed the issue for me. This line of code is only necessary for SMTP servers that require you to login, which my Exchange server didnt.