1 package org.pojomatic;
2
3 import static org.testng.Assert.*;
4
5 import java.io.FilePermission;
6 import java.lang.invoke.MethodHandles;
7 import java.lang.reflect.ReflectPermission;
8 import java.net.SocketPermission;
9 import java.security.AccessControlException;
10 import java.security.Permission;
11 import java.security.Policy;
12 import java.security.ProtectionDomain;
13 import java.security.SecurityPermission;
14 import java.util.HashSet;
15 import java.util.Set;
16
17 import org.pojomatic.annotations.Property;
18 import org.pojomatic.annotations.PropertyFormat;
19 import org.pojomatic.formatter.DefaultEnhancedPropertyFormatter;
20 import org.pojomatic.internal.PojomatorFactoryTest;
21 import org.testng.annotations.Test;
22
23 import com.google.common.collect.ImmutableSet;
24
25 public class SecurityTest {
26 private SecurityManager originalSecurityManager;
27 private Policy originalPolicy;
28
29 private Set<Permission> requestedPermissions = new HashSet<>();
30
31 private void setPolicy() {
32 originalSecurityManager = System.getSecurityManager();
33 originalPolicy = Policy.getPolicy();
34 final ProtectionDomain testProtectionDomain = PojomatorFactoryTest.class.getProtectionDomain();
35 final ProtectionDomain mainProtectionDomain = Pojomatic.class.getProtectionDomain();
36 Policy.setPolicy(new Policy() {
37
38 @Override
39 public boolean implies(ProtectionDomain domain, Permission permission) {
40 if (domain == mainProtectionDomain) {
41 requestedPermissions.add(permission);
42 return true;
43 }
44 if (permission instanceof SecurityPermission && "setPolicy".equals(permission.getName())) {
45 return true;
46 }
47 if (permission instanceof RuntimePermission && "setSecurityManager".equals(permission.getName())) {
48 return true;
49 }
50 if (testProtectionDomain.equals(domain)) {
51 return false;
52 }
53 return true;
54 }
55 });
56
57 System.setSecurityManager(new SecurityManager());
58 }
59
60 private void restorePolicy() {
61 System.setSecurityManager(originalSecurityManager);
62 Policy.setPolicy(originalPolicy);
63 }
64
65 private static class Inaccessible{}
66
67 private static class SimplePojo {
68 @Property
69 int x = 0;
70
71 @Property
72 int getY() { return 0; }
73
74 @Property
75 Inaccessible z;
76 }
77
78 @Test
79 public void testSecurityModel() {
80 requestedPermissions.clear();
81 SimplePojo pojo = new SimplePojo();
82 String toString = null;
83 boolean equals;
84 int hashCode;
85 try {
86 setPolicy();
87 equals = Pojomatic.pojomator(SimplePojo.class).doEquals(new SimplePojo(), new SimplePojo());
88 hashCode = Pojomatic.pojomator(SimplePojo.class).doHashCode(new SimplePojo());
89 toString = Pojomatic.pojomator(SimplePojo.class).doToString(pojo);
90 }
91 finally {
92 restorePolicy();
93 }
94 assertEquals(toString, "SimplePojo{x: {0}, z: {null}, y: {0}}");
95 assertTrue(equals);
96 assertEquals(hashCode, 31*31*31);
97
98 String testClassPath = SimplePojo.class.getProtectionDomain().getCodeSource().getLocation().getPath();
99 String simplePojoPath = SimplePojo.class.getName().replace('.', '/') + ".class";
100
101 assertEquals(
102 requestedPermissions,
103 ImmutableSet.of(
104 new FilePermission(testClassPath + simplePojoPath, "read"),
105 new RuntimePermission(haveLookupDefineClass() ? "defineClass" : "accessDeclaredMembers"),
106 new ReflectPermission("suppressAccessChecks")));
107 }
108
109 public static class AttackingConstructorFormatter extends DefaultEnhancedPropertyFormatter {
110 {
111 System.getSecurityManager().checkListen(80);
112 }
113 }
114
115 private static class AttackingConstructorFormattedPojo {
116 @Property
117 @PropertyFormat(SecurityTest.AttackingConstructorFormatter.class)
118 int x = 0;
119 }
120
121
122
123
124
125 @Test
126 public void testPropertyFormatterConstructorSecurity() {
127 try {
128 setPolicy();
129 Pojomatic.pojomator(AttackingConstructorFormattedPojo.class);
130 fail("Exception expected");
131 }
132 catch (AccessControlException e) {
133 assertTrue(e.getPermission() instanceof SocketPermission);
134 }
135 finally {
136 restorePolicy();
137 }
138 }
139
140 public static class AttackingStaticInitializerFormatter extends DefaultEnhancedPropertyFormatter {
141 static {
142 System.getSecurityManager().checkListen(80);
143 }
144 }
145
146 private static class AttackingStaticInitializerFormattedPojo {
147 @Property
148 @PropertyFormat(SecurityTest.AttackingStaticInitializerFormatter.class)
149 int x = 0;
150 }
151
152
153
154
155 @Test
156 public void testPropertyFormatterStaticInitializerSecurity() {
157 try {
158 setPolicy();
159 Pojomatic.pojomator(AttackingStaticInitializerFormattedPojo.class);
160 fail("Exception expected");
161 }
162 catch (ExceptionInInitializerError e) {
163 assertEquals(e.getCause().getClass(), AccessControlException.class);
164 assertTrue(((AccessControlException) e.getCause()).getPermission() instanceof SocketPermission);
165 }
166 finally {
167 restorePolicy();
168 }
169 }
170
171 private static boolean haveLookupDefineClass() {
172 try {
173 MethodHandles.Lookup.class.getMethod("defineClass", new Class<?>[] { byte[].class });
174 return true;
175 }
176 catch (Throwable t) {
177 return false;
178 }
179 }
180 }