Skip to content

Commit 51f2c68

Browse files
authored
DTNT-528: added tests for snapshot API (openfin#40)
* DTNT-528: added tests for snapshot API * DTNT-528: review from Anthony * DTNT-528 updated signer.java * DTNT-528: update tests for snapshot API
1 parent f4b0aa2 commit 51f2c68

3 files changed

Lines changed: 222 additions & 2 deletions

File tree

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,98 @@
1-
package com.openfin.desktop.demo;public class Signer {
1+
package com.openfin.desktop.demo;
2+
3+
import java.io.InputStream;
4+
import java.security.CodeSigner;
5+
import java.security.cert.Certificate;
6+
import java.security.cert.X509Certificate;
7+
import java.util.Enumeration;
8+
import java.util.HashSet;
9+
import java.util.Map;
10+
import java.util.Set;
11+
import java.util.jar.Attributes;
12+
import java.util.jar.JarEntry;
13+
import java.util.jar.JarFile;
14+
import java.util.jar.Manifest;
15+
16+
public class Signer {
17+
private final String filename;
18+
19+
public Signer(String filename) {
20+
this.filename = filename;
21+
}
22+
23+
public void verify() throws Exception {
24+
JarFile jar = new JarFile(this.filename, true);
25+
26+
Enumeration<JarEntry> entries = jar.entries();
27+
while (entries.hasMoreElements()) {
28+
JarEntry entry = entries.nextElement();
29+
byte[] buffer = new byte[8192];
30+
InputStream is = jar.getInputStream(entry);
31+
while ((is.read(buffer, 0, buffer.length)) != -1) {
32+
// We just read. This will throw a SecurityException
33+
// if a signature/digest check fails.
34+
}
35+
is.close();
36+
}
37+
38+
if (!checkSign(jar)) {
39+
throw new SecurityException("not signed");
40+
}
41+
42+
}
43+
44+
private boolean checkSign(JarFile jar) throws Exception {
45+
InputStream jis = jar.getInputStream(jar.getEntry("META-INF/MANIFEST.MF"));
46+
Manifest man = new Manifest(jis);
47+
jis.close();
48+
49+
HashSet<String> signed = new HashSet<>();
50+
for(Map.Entry<String, Attributes> entry: man.getEntries().entrySet()) {
51+
for(Object attrkey: entry.getValue().keySet()) {
52+
if (attrkey instanceof Attributes.Name && attrkey.toString().contains("-Digest")) {
53+
signed.add(entry.getKey());
54+
}
55+
}
56+
}
57+
System.out.printf("Number of Digest from manifest %d \n", signed.size());
58+
59+
Set<String> entries = new HashSet<>();
60+
for(Enumeration<JarEntry> entry = jar.entries(); entry.hasMoreElements(); ) {
61+
JarEntry je = entry.nextElement();
62+
String fileName = je.getName().toUpperCase();
63+
if (!je.isDirectory()
64+
&& !fileName.endsWith(".MF")
65+
&& !fileName.endsWith(".SF")
66+
&& !fileName.endsWith(".DSA")
67+
&& !fileName.endsWith(".EC")
68+
&& !fileName.endsWith(".RSA")
69+
) {
70+
CodeSigner[] signers = je.getCodeSigners();
71+
if (signers != null && signers.length == 1) {
72+
CodeSigner signer = signers[0];
73+
if (signer.getSignerCertPath().getCertificates().size() != 4) {
74+
throw new SecurityException(String.format("invalid cert chain %s", je.getName()));
75+
}
76+
X509Certificate cert = (X509Certificate) signer.getSignerCertPath().getCertificates().get(0);
77+
if (!cert.getSubjectDN().toString().contains("OpenFin Inc.")) {
78+
throw new SecurityException(String.format("invalid signed %s", je.getName()));
79+
}
80+
entries.add(je.getName());
81+
} else {
82+
throw new SecurityException(String.format("missing cert %s", je.getName()));
83+
}
84+
}
85+
}
86+
System.out.printf("Number of signed entries %d \n", entries.size());
87+
88+
Set<String> unsigned = new HashSet<>(entries);
89+
unsigned.removeAll(signed);
90+
return unsigned.size() == 0;
91+
}
92+
93+
public static void main(String[] args) throws Exception {
94+
Signer signer = new Signer(args[0]);
95+
signer.verify();
96+
}
97+
298
}

src/test/java/com/openfin/desktop/AllTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
*/
1111

1212
@RunWith(Suite.class)
13-
@Suite.SuiteClasses({ ApplicationTest.class, OpenFinRuntimeTest.class, WindowTest.class, SystemTest.class, InterApplicationBusTest.class, ChannelTest.class, RuntimeConfigTest.class})
13+
@Suite.SuiteClasses({ ApplicationTest.class, OpenFinRuntimeTest.class, WindowTest.class, SystemTest.class, InterApplicationBusTest.class, ChannelTest.class, RuntimeConfigTest.class, SnapshotTest.class})
1414
public class AllTests {
1515
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package com.openfin.desktop;
2+
3+
import com.openfin.desktop.snapshot.SnapshotSource;
4+
import com.openfin.desktop.snapshot.SnapshotSourceProvider;
5+
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx;
6+
import org.json.JSONArray;
7+
import org.json.JSONObject;
8+
import org.junit.AfterClass;
9+
import org.junit.BeforeClass;
10+
import org.junit.Ignore;
11+
import org.junit.Test;
12+
import org.slf4j.Logger;
13+
import org.slf4j.LoggerFactory;
14+
15+
import java.util.concurrent.CountDownLatch;
16+
import java.util.concurrent.TimeUnit;
17+
18+
import static org.junit.Assert.assertEquals;
19+
import static org.junit.Assert.fail;
20+
21+
public class SnapshotTest implements SnapshotSourceProvider {
22+
23+
private static Logger logger = LoggerFactory.getLogger(SnapshotTest.class.getName());
24+
25+
private static final String DESKTOP_UUID = SnapshotTest.class.getName();
26+
private static DesktopConnection desktopConnection;
27+
private static OpenFinRuntime runtime;
28+
private static final JSONObject SNAPSHOT_CONTENT = new JSONObject("{width: 123}");
29+
30+
private JSONObject randomSnapshot;
31+
32+
@BeforeClass
33+
public static void setup() throws Exception {
34+
logger.debug("starting");
35+
desktopConnection = TestUtils.setupConnection(DESKTOP_UUID);
36+
if (desktopConnection != null) {
37+
runtime = new OpenFinRuntime(desktopConnection);
38+
}
39+
}
40+
41+
@AfterClass
42+
public static void teardown() throws Exception {
43+
TestUtils.teardownDesktopConnection(desktopConnection);
44+
}
45+
46+
@Test
47+
public void initProviderThenCreateClient() throws Exception {
48+
CountDownLatch latch = new CountDownLatch(2);
49+
final String appUuid = "initProviderThenCreateClient";
50+
desktopConnection.getSnapshotSource().initSnapshotSourceProviderAsync(appUuid, this).thenAccept(provider -> {
51+
logger.debug("Snapshot provider created");
52+
latch.countDown();
53+
});
54+
desktopConnection.getSnapshotSource().createSnapshotSourceClientAsync(appUuid).thenAccept(client -> {
55+
logger.debug("Snapshot client created");
56+
latch.countDown();
57+
});
58+
59+
latch.await(5, TimeUnit.SECONDS);
60+
61+
assertEquals("initProviderThenCreateClient timeout", latch.getCount(), 0);
62+
}
63+
64+
@Test
65+
public void initProviderThenCreateClientThenGetSnapshot() throws Exception {
66+
CountDownLatch latch = new CountDownLatch(2);
67+
final String appUuid = "initProviderThenCreateClientThenGetSnapshot";
68+
desktopConnection.getSnapshotSource().initSnapshotSourceProviderAsync(appUuid, this).thenAccept(provider -> {
69+
logger.debug("Snapshot provider created");
70+
latch.countDown();
71+
});
72+
73+
desktopConnection.getSnapshotSource().createSnapshotSourceClientAsync(appUuid).thenAccept(client -> {
74+
client.getSnapshotAsync().thenAccept(snapshot -> {
75+
if (SNAPSHOT_CONTENT.toString().equals(snapshot.toString())) {
76+
latch.countDown();
77+
}
78+
});
79+
});
80+
81+
latch.await(5, TimeUnit.SECONDS);
82+
83+
assertEquals("initProviderThenCreateClientThenGetSnapshot timeout", latch.getCount(), 0);
84+
}
85+
86+
@Test
87+
public void initProviderThenCreateClientThenApplySnapshot() throws Exception {
88+
CountDownLatch latch = new CountDownLatch(2);
89+
final JSONObject random = new JSONObject(String.format("{value: %f}", Math.random()));
90+
final String appUuid = "initProviderThenCreateClientThenApplySnapshot";
91+
desktopConnection.getSnapshotSource().initSnapshotSourceProviderAsync(appUuid, this).thenAccept(provider -> {
92+
latch.countDown();
93+
});
94+
95+
desktopConnection.getSnapshotSource().createSnapshotSourceClientAsync(appUuid).thenAccept(client -> {
96+
client.applySnapshotAsync(random).thenAccept(ack -> {
97+
client.getSnapshotAsync().thenAccept(snapshot -> {
98+
if (random.toString().equals(snapshot.toString())) {
99+
latch.countDown();
100+
}
101+
});
102+
103+
});
104+
});
105+
106+
latch.await(5, TimeUnit.SECONDS);
107+
108+
assertEquals("initProviderThenCreateClientThenGetSnapshot timeout", latch.getCount(), 0);
109+
}
110+
111+
@Override
112+
public JSONObject getSnapshot() {
113+
if (this.randomSnapshot != null) {
114+
return this.randomSnapshot;
115+
} else {
116+
return SNAPSHOT_CONTENT;
117+
}
118+
}
119+
120+
@Override
121+
public void applySnapshot(JSONObject snapshot) {
122+
this.randomSnapshot = snapshot;
123+
}
124+
}

0 commit comments

Comments
 (0)