Skip to content

Conversation

@kpayson64
Copy link
Contributor

Per request of the VTK team, we want to bake in the needed SSL workaround for AppEngine standard.

Copy link
Contributor

@carl-mastrangelo carl-mastrangelo left a comment

Choose a reason for hiding this comment

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

Tests?

@kpayson64
Copy link
Contributor Author

If I do some hacky stuff to make IS_RESTRICTED_APPENGINE=true for a unit test, it still seems the JDK used for unit tests doesn't support the SHA1PRNG.

io.grpc.okhttp.OkHttpChannelBuilderTest > restrictedAppEngineSocketFactory FAILED
    java.lang.RuntimeException: TLS Provider failure
        at io.grpc.okhttp.OkHttpChannelBuilder.createSocketFactory(OkHttpChannelBuilder.java:284)
        at io.grpc.okhttp.OkHttpChannelBuilderTest.restrictedAppEngineSocketFactory(OkHttpChannelBuilderTest.java:140)

        Caused by:
        java.security.NoSuchAlgorithmException: no such algorithm: SHA1PRNG for provider SunJSSE
            at sun.security.jca.GetInstance.getService(GetInstance.java:101)
            at sun.security.jca.GetInstance.getInstance(GetInstance.java:218)
            at java.security.SecureRandom.getInstance(SecureRandom.java:383)
            at io.grpc.okhttp.OkHttpChannelBuilder.createSocketFactory(OkHttpChannelBuilder.java:276)
            ... 1 more

This code path gets exercised in an AppEngine end to end test.

@kpayson64
Copy link
Contributor Author

@carl-mastrangelo
After thinking this over, I don't think adding a unit tests for this with mocked providers adds much value.

If anything, it adds a false sense of security. I wouldn't feel comfortable making any changes to this logic without testing it in AppEngine. This code path gets exercised as part of an AppEngine end to end test, and I think that is the better method of testing.

@kpayson64 kpayson64 changed the base branch from master to v1.2.x March 8, 2017 18:06
try {
if (sslSocketFactory == null) {
SSLContext sslContext = SSLContext.getInstance("Default", Platform.get().getProvider());
SSLContext sslContext = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

The assignment of null is not necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

SSLContext sslContext = SSLContext.getInstance("Default", Platform.get().getProvider());
SSLContext sslContext = null;
if (GrpcUtil.IS_RESTRICTED_APPENGINE) {
// The following auth code circumvents the following AccessControlException:
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is good, but it doesn't really explain why or how. Where is that exception thrown from? Why does this block of code change that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added some details to the comment, but the root of the stack trace looks like this:

Caused by: java.security.AccessControlException: access denied ("java.util.PropertyPermission" "javax.net.ssl.keyStore" "read")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:484)
	at java.security.AccessController.checkPermission(AccessController.java:698)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1298)
	at java.lang.System.getProperty(System.java:708)
	at org.conscrypt.DefaultSSLContextImpl.getKeyManagers(DefaultSSLContextImpl.java:66)
	at org.conscrypt.OpenSSLContextImpl.<init>(OpenSSLContextImpl.java:81)
	at org.conscrypt.DefaultSSLContextImpl.<init>(DefaultSSLContextImpl.java:57)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
	at java.security.Provider$Service.newInstance(Provider.java:1253)
	... 56 more

// access denied ("java.util.PropertyPermission" "javax.net.ssl.keyStore" "read")
sslContext = SSLContext.getInstance("TLS", Platform.get().getProvider());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

what is null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As it turns out, this KeyStore logic was not needed.

keyStore.load(null, null);
KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

here too, what does null mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This logic was extraneous and removed.

keyManagerFactory.init(keyStore, null);
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why aren't you using the keyStore you made above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The key store was not being used.

sslContext.init(
null,
trustManagerFactory.getTrustManagers(),
SecureRandom.getInstance("SHA1PRNG", Platform.get().getProvider()));
Copy link
Contributor

Choose a reason for hiding this comment

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

What is special about SHA1PRNG?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a comment.

return sslSocketFactory;
} catch (GeneralSecurityException gse) {
throw new RuntimeException("TLS Provider failure", gse);
} catch (IOException e) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What throws this exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The key store init was throwing it, but it has now been removed.

@carl-mastrangelo
Copy link
Contributor

@kpayson64 We can't really accept untested code. You may not feel comfortable making changes to this code, but you may not be the person making changes, or know the context. Adding unit tests proves that code is not accidentally broken, but also documents how it should work.

Look at it from gRPC Java team's point of view. This code has no tests so we don't know if changes we make to it will break. It isn't clear why it is doing things differently. It reduces our test coverage. It will have a really long time between breakages and finding it, since the commits will take 1 -2 weeks to be brought in. Lastly, we have no way to actually run these. It is unreasonable to expect a custom test environment to be brought up to try these out. Not all contributors may know how to do it, or even be able.

This code is not maintainable.

@louiscryan
Copy link
Contributor

It seems sufficient to test that this code does not interfere with non-Appengine code paths. It's the responsibility of AppEngine folks to make sure that this works in their environment. The same would be true for other special environment detection that some other PaaS might want to do.

The alternative is to find some way to inject behavior, possibly by AppEngine doing their own channel provider but that has proven painful in the past with other platforms

Copy link
Contributor

@carl-mastrangelo carl-mastrangelo left a comment

Choose a reason for hiding this comment

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

@kpayson64 kpayson64 merged commit b753231 into grpc:v1.2.x Mar 14, 2017
carl-mastrangelo added a commit to carl-mastrangelo/grpc-java that referenced this pull request Mar 15, 2017
carl-mastrangelo added a commit that referenced this pull request Mar 15, 2017
@lock lock bot locked as resolved and limited conversation to collaborators Jan 20, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants