Skip to content

Greengrass DiscoveryClient does not work if a SecurityManager is installed #320

Closed
@nicolatimeus

Description

@nicolatimeus

Describe the bug

If a SecurityManager is installed, Greengrass Core Device discovery performed using DiscoveryClient will fail even with a permissive policy.

Expected Behavior

Greengrass Discovery completes successfully even if a security manager is installed.

Current Behavior

Greengrass Core Device discovery performed using DiscoveryClient fails with exception [1]

[1]

Exception thrown: java.util.concurrent.ExecutionException: com.google.gson.JsonIOException: Failed making field 'software.amazon.awssdk.iot.discovery.model.DiscoverResponse#GGGroups' accessible; either change its visibility or write a custom TypeAdapter for its declaring type
java.util.concurrent.ExecutionException: com.google.gson.JsonIOException: Failed making field 'software.amazon.awssdk.iot.discovery.model.DiscoverResponse#GGGroups' accessible; either change its visibility or write a custom TypeAdapter for its declaring type
	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908)
	at greengrass.BasicDiscovery.getClientFromDiscovery(BasicDiscovery.java:157)
	at greengrass.BasicDiscovery.main(BasicDiscovery.java:114)
Caused by: com.google.gson.JsonIOException: Failed making field 'software.amazon.awssdk.iot.discovery.model.DiscoverResponse#GGGroups' accessible; either change its visibility or write a custom TypeAdapter for its declaring type
	at com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:22)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:158)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:101)
	at com.google.gson.Gson.getAdapter(Gson.java:501)
	at com.google.gson.Gson.fromJson(Gson.java:990)
	at com.google.gson.Gson.fromJson(Gson.java:929)
	at software.amazon.awssdk.iot.discovery.DiscoveryClient.lambda$discover$0(DiscoveryClient.java:97)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1596)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)
Caused by: java.security.AccessControlException: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
	at java.security.AccessController.checkPermission(AccessController.java:886)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:128)
	at com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:19)
	... 12 more

Reproduction Steps

Build a standalone JAR file that executes https://github.com/aws/aws-iot-device-sdk-java-v2/blob/main/samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java as main class. This can obtained for example by adding the snippet [1] to the build -> plugins section of https://github.com/aws/aws-iot-device-sdk-java-v2/blob/main/samples/Greengrass/pom.xml.

Run the produced jar file with the following command:

java -Djava.security.manager -Djava.security.policy=security.policy -jar ./Greengrass-1.0-SNAPSHOT-jar-with-dependencies.jar ${DISCOVERY_SAMPLE_ARGS}

where DISCOVERY_SAMPLE_ARGS is as described in https://docs.aws.amazon.com/greengrass/v2/developerguide/test-client-device-communications.html#test-client-device-communications-java and security.policy contains the following maximally permissive policy:

grant { 
      permission java.security.AllPermission;
};

The command should fail logging the reported exception if the-Djava.security.manager -Djava.security.policy=security.policy arguments are provided and succeed if they are removed.

[1]

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <archive>
            <manifest>
                <mainClass>greengrass.BasicDiscovery</mainClass>
            </manifest>
        </archive>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
</plugin>

Possible Solution

The issue is likely caused by the fact that

return GSON.fromJson(new StringReader(responseString), DiscoverResponse.class);

is executed through CompletableFuture.supplyAsync() using the Fork Join Pool common pool.

Quoting from ForkJoinPool Javadoc, If a SecurityManager is present and no factory is specified, then the default pool uses a factory supplying threads that have no Permissions enabled..

Additional Information/Context

No response

SDK version used

main branch cloned from 1a2e1b5

Environment details (OS name and version, etc.)

Raspberry PI OS, openjdk version "1.8.0_312" OpenJDK Runtime Environment (build 1.8.0_312-8u312-b07-1+rpi1-b07) OpenJDK Client VM (build 25.312-b07, mixed mode)

Metadata

Metadata

Assignees

Labels

bugThis issue is a bug.p2This is a standard priority issuepending-releaseThis issue will be fixed by an approved PR that hasn't been released yet.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions