Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Client side certificate and custom list of trusted certificates #92

Closed
wants to merge 4 commits into from

Conversation

Hakky54
Copy link

@Hakky54 Hakky54 commented Jul 19, 2020

This pull request is regarding the implementation of the issue number #91

This feature will enable loading the client certificate into the http client which could be used when the server requires client authentication based on certificates. The client will also have the ability to trust specific certificates by loading a list of trusted certificates.

This PR is for now a WIP as the jvm part is finished but the node part is still pending

@Hakky54
Copy link
Author

Hakky54 commented Jul 19, 2020

@hmil I did an attempt for the initial version of the implementation. The jvm version is mostly done, but I am not quite sure how to implement node version. I think I need the following fields within the RequestOptions:

pfx: js.UndefOr[String] = js.undefined,
passphrase: js.UndefOr[String] = js.undefined,
ca: js.UndefOr[String] = js.undefined

I am also not quite sure if the type String is correct here and I am also not sure how to correctly load a file into this field as I am not sure if it should be a String. Node has the following documentation at their page for loading a pfx or pem file:

onst https = require('https');
const fs = require('fs');

const options = {
  pfx: fs.readFileSync('test/fixtures/test_cert.pfx'),
  passphrase: 'sample'
};

I can fetch the path of the pfx with from the sslconfig within the backendConfig of the request. But I am not quite sure how to properly load it. What do you think?

@@ -6,6 +6,7 @@ import java.nio.ByteBuffer
import fr.hmil.roshttp.exceptions._
import fr.hmil.roshttp.response.{HttpResponse, HttpResponseFactory, HttpResponseHeader}
import fr.hmil.roshttp.util.HeaderMap
import javax.net.ssl.HttpsURLConnection
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking, how portable is this?
I'm not 100% aware of the limitations of the javax package.

Copy link
Author

@Hakky54 Hakky54 Jul 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean exactly by portable?

trustManagers = createTrustManagers(sslConfig.trustStorePaths.get)
}

sslContext.init(keyManagers, trustManagers, new SecureRandom())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc says the last argument can be left empty, in which case the default implementation is used. Why not leave it empty?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware that by passing null it would use the default implementation. I will refactor it

val keyStore = KeyStore.getInstance(KEYSTORE_TYPE)
val keyStoreInputStream = Files.newInputStream(Paths.get(keyStorePath))

Objects.requireNonNull(keyStoreInputStream)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for newInputStream doesn't specify that this can be null. So I guess this means it cannot be null?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes indeed, very sharp! I just tested it and if the file cannot be found it will throw a NoSuchFileException
I thought it was similar to getClass.getClassLoader.getResourceAsStream() which will return a null when it cant find the file. I will drop the null check

val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
keyManagerFactory.init(keyStore, keyStorePassphrase)

closeSafely(keyStoreInputStream)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for non-nullable

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will also refactor this one

@hmil
Copy link
Owner

hmil commented Jul 20, 2020

I can fetch the path of the pfx with from the sslconfig within the backendConfig of the request

Just use fs.readFileSync. It's the easiest to get started.

I am realizing now that this solution re-creates the whole SSL config from disk for each request. It can be quite wasteful and can even become a performance bottleneck if someone uses the lib to make many requests. A better solution would be to pre-configure a client with the SSL config and then use that client to make requests.

But this is a long shot. All in all implementing proper support for SSL might take more than just one PR.

I would advise that you focus only on what you need for your specific use case. If you do not need Node.js, then in the JS backend just throw an exception when an ssl config is specified. We'll add to the limitations that SSL is only supported on the JVM. If you feel like adding it or if someone else needs this feature, then support for Node.js can be added in a following PR.

@Hakky54
Copy link
Author

Hakky54 commented Jul 20, 2020

I am realizing now that this solution re-creates the whole SSL config from disk for each request. It can be quite wasteful and can even become a performance bottleneck if someone uses the lib to make many requests. A better solution would be to pre-configure a client with the SSL config and then use that client to make requests.

Yes the best way would actually create the sslcontext once, reuse it multiple times for every new request. But I wasn't quite sure what would be a good implementation for that as every new request within the current implementation "recreates" the HttpConnection and executes a request with the given parameters.

But this is a long shot. All in all implementing proper support for SSL might take more than just one PR.

I would advise that you focus only on what you need for your specific use case. If you do not need Node.js, then in the JS backend just throw an exception when an ssl config is specified. We'll add to the limitations that SSL is only supported on the JVM. If you feel like adding it or if someone else needs this feature, then support for Node.js can be added in a following PR.

I actually don't feel very comfortable applying changes to the Node.js part as I have no experience yet with it. So I would gladly pass it to someone else who wants to implement it if you are also ok with it.

@hmil
Copy link
Owner

hmil commented Aug 11, 2020

Hey, sorry I don't have any time at all to maintain this package right now. Feel free to publish your own version to bintray.

I refer to #58 to focus discussions around finding a package maintainer or a serious fork.

@Hakky54
Copy link
Author

Hakky54 commented Aug 15, 2020

Ah too bad to hear that, but I can understand that

@Hakky54 Hakky54 closed this Dec 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants