1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.river.tool;
20
21 import java.io.BufferedWriter;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FilePermission;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.PrintWriter;
29 import java.net.MalformedURLException;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.security.AccessController;
34 import java.security.CodeSource;
35 import java.security.GeneralSecurityException;
36 import java.security.KeyStore;
37 import java.security.KeyStoreException;
38 import java.security.Permission;
39 import java.security.Permissions;
40 import java.security.Policy;
41 import java.security.Principal;
42 import java.security.ProtectionDomain;
43 import java.security.cert.Certificate;
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.Map.Entry;
49 import java.util.concurrent.ConcurrentHashMap;
50 import java.util.concurrent.ConcurrentMap;
51 import java.util.concurrent.ConcurrentSkipListSet;
52 import java.util.function.Function;
53 import java.util.logging.Level;
54 import java.util.logging.Logger;
55 import javax.security.auth.PrivateCredentialPermission;
56 import org.apache.river.action.GetBooleanAction;
57 import org.apache.river.api.net.Uri;
58 import org.apache.river.api.security.CombinerSecurityManager;
59 import org.apache.river.api.security.PermissionComparator;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 public class SecurityPolicyWriter extends CombinerSecurityManager{
108
109 private static Logger logger;
110 private static final Object loggerLock = new Object();
111
112
113
114
115 private static Logger getLogger() {
116 synchronized (loggerLock){
117 if (logger != null) return logger;
118 logger =
119 Logger.getLogger("org.apache.river.tool.SecurityPolicyWriter");
120 return logger;
121 }
122 }
123
124 private final ConcurrentMap<ProtectionDomain, Collection<Permission>> domainPermissions;
125 private static KeyStore keyStore = null;
126 private static final Object keyStoreLock = new Object();
127 private final ConcurrentMap<Certificate,String> aliases;
128 private final Cert certFunc;
129
130
131 private SecurityPolicyWriter(
132 ConcurrentMap<ProtectionDomain,Collection<Permission>> map)
133 {
134 super();
135 domainPermissions = map;
136 aliases = new ConcurrentHashMap<Certificate,String>();
137 certFunc = new Cert();
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 }
157
158 public SecurityPolicyWriter() {
159 this(new ConcurrentHashMap<ProtectionDomain,Collection<Permission>>());
160 Runtime.getRuntime().addShutdownHook(shutdownHook());
161 }
162
163 private static File policyFile() throws URISyntaxException{
164 String policy = System.getProperty("java.security.policy");
165
166
167 Uri polLocation = new Uri(policy +".new");
168 URI poliLoc = Uri.uriToURI(polLocation);
169 File policyFile = new File(poliLoc);
170 if (!policyFile.exists()){
171 try {
172 policyFile.createNewFile();
173 } catch (IOException ex) {
174 throw new RuntimeException("Unable to create a policy file: "+ policy +".new", ex);
175 }
176 }
177 return policyFile;
178 }
179
180 private static KeyStore keyStore(){
181 synchronized (keyStoreLock){
182 if (keyStore == null){
183 try {
184 keyStore = initStore();
185 } catch (IOException ex) {
186 getLogger().log(Level.FINE, "Unable to create KeyStore instance", ex);
187 } catch (GeneralSecurityException ex) {
188 getLogger().log(Level.FINE, "Unable to create KeyStore instance", ex);
189 }
190 }
191 return keyStore;
192 }
193 }
194
195
196
197
198 private static KeyStore initStore() throws IOException, GeneralSecurityException {
199 String path, type, passwd;
200 if ((path = System.getProperty("javax.net.ssl.trustStore")) != null) {
201 type = System.getProperty(
202 "javax.net.ssl.trustStoreType", KeyStore.getDefaultType());
203 passwd = System.getProperty("javax.net.ssl.trustStorePassword");
204 } else {
205 path = System.getProperty("java.home") + "/lib/security/cacerts";
206 type = KeyStore.getDefaultType();
207 passwd = null;
208 }
209 KeyStore kstore = KeyStore.getInstance(type);
210 InputStream in;
211 URL url = null;
212 try {
213 url = new Uri(path).toURL();
214 } catch (MalformedURLException e) {
215 getLogger().log(Level.SEVERE, null, e);
216 } catch (URISyntaxException ex) {
217 getLogger().log(Level.SEVERE, null, ex);
218 }
219 if (url != null) {
220 in = url.openStream();
221 } else {
222 in = new FileInputStream(path);
223 }
224 try {
225 kstore.load(in, (passwd != null) ? passwd.toCharArray() : null);
226 } finally {
227 in.close();
228 }
229
230
231
232
233 return kstore;
234 }
235
236 @Override
237 protected boolean checkPermission(ProtectionDomain pd, Permission p){
238 Collection<Permission> perms = domainPermissions.get(pd);
239 if (perms == null) {
240 perms = new ConcurrentSkipListSet<Permission>(new PermissionComparator());
241 Collection<Permission> existed = domainPermissions.putIfAbsent(pd, perms);
242 if (existed != null) perms = existed;
243 }
244 perms.add(p);
245 return true;
246 }
247
248 private Thread shutdownHook(){
249 Thread t = new Thread ( new Runnable(){
250 @Override
251 public void run (){
252 PrintWriter pw = null;
253 boolean onlyAdditional = AccessController.doPrivileged(new GetBooleanAction("org.apache.river.tool.addPerms"));
254 Policy policy = Policy.getPolicy();
255 try {
256 File policyFile = policyFile();
257
258 pw = new PrintWriter(new BufferedWriter(new FileWriter(policyFile, true)));
259 } catch (IOException ex) {
260 getLogger().log(Level.SEVERE, "unable to write to policy file ", ex);
261 return;
262 } catch (URISyntaxException ex) {
263 getLogger().log(Level.SEVERE, "unable to write to policy file ", ex);
264 return;
265 }
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 Iterator<Entry<ProtectionDomain,Collection<Permission>>> it
287 = domainPermissions.entrySet().iterator();
288 while (it.hasNext()){
289 Entry<ProtectionDomain,Collection<Permission>> entry = it.next();
290 ProtectionDomain pd = entry.getKey();
291 Collection<Permission> perms = entry.getValue();
292 if (onlyAdditional){
293 Iterator<Permission> pIt = perms.iterator();
294 while (pIt.hasNext()){
295 Permission p = pIt.next();
296 if (policy.implies(pd, p)) pIt.remove();
297 }
298 }
299 if (perms.isEmpty()) continue;
300 CodeSource cs = null;
301 Principal [] principals = null;
302 try {
303 cs = pd.getCodeSource();
304 principals = pd.getPrincipals();
305 } catch (NullPointerException e){
306
307
308 System.err.println(
309 "ProtectionDomain wasn't safely published: "
310 + pd.toString()
311 );
312 }
313
314 if (cs != null){
315 Certificate [] signers = cs.getCertificates();
316 if (signers != null && signers.length > 0){
317 if (keyStore() != null){
318 for (int i=0, l=signers.length; i<l; i++){
319 aliases.computeIfAbsent(signers[i], certFunc);
320 }
321 }
322 }
323 }
324 if (cs != null || (principals != null && principals.length > 0)){
325 URL codebase = cs.getLocation();
326 pw.print("grant ");
327 if (keyStore != null){
328 Certificate [] signers = cs.getCertificates();
329 if (signers != null && signers.length > 0) {
330 List<String> alia = new ArrayList<String>(signers.length);
331 for (int i=0, l=signers.length; i<l; i++){
332 alia.add(aliases.get(signers[i]));
333 }
334 if (!alia.isEmpty()){
335 pw.print("signedBy \"");
336 for (int i=0, l=alia.size(); i<l; i++){
337 if (i != 0) pw.print(",");
338 pw.print(alia.get(i));
339 }
340 pw.print("\", ");
341 }
342 }
343 }
344 if (codebase != null){
345 pw.print("codebase \"");
346 String codebaseStr = replaceValuesWithProperties(codebase.toString());
347 pw.print(codebaseStr);
348 pw.print("\"");
349 if (principals != null && principals.length >0) pw.print(",\n");
350 }
351 if (principals != null && principals.length > 0){
352 for (int i=0, l=principals.length; i<l; i++){
353 pw.print(" principal ");
354 pw.print(principals[i].getClass().getCanonicalName());
355 pw.print(" \"");
356 pw.print(principals[i].getName());
357 if (i<l-1) pw.print("\",\n");
358 else pw.print("\"\n");
359 }
360 } else {
361 pw.print("\n");
362 }
363 pw.print("{\n");
364
365 Iterator<Permission> permIt = entry.getValue().iterator();
366 Permissions permissions = new Permissions();
367 while (permIt.hasNext()){
368 Permission p = permIt.next();
369 if (permissions.implies(p)) continue;
370 permissions.add(p);
371 pw.print(" permission ");
372 pw.print(p.getClass().getCanonicalName());
373 pw.print(" \"");
374 if (p instanceof PrivateCredentialPermission){
375 PrivateCredentialPermission pcp = (PrivateCredentialPermission) p;
376 String credential = pcp.getCredentialClass();
377 String [][] princpals = pcp.getPrincipals();
378 StringBuilder sb = new StringBuilder();
379 sb.append(credential);
380 sb.append(" ");
381 for (int i=0,l=princpals.length; i<l; i++){
382 String [] pals = princpals [i];
383 for (int j=0,m=pals.length; j<m; j++){
384 sb.append(pals[j]);
385 if (j < m-1) sb.append(" \\\"");
386 else sb.append("\\\"");
387 }
388 if (i < l-1) sb.append(" ");
389 }
390 pw.print(sb.toString());
391 } else {
392
393
394 String name = p.getName();
395 if (p instanceof FilePermission && File.separatorChar == '\\'){
396 name = name.replace("\\", "\\\\");
397 } else {
398 name = name.replace("\\\"", "\\\\\"").replace("\"","\\\"").replace("\r","\\\r");
399 }
400 pw.print(name);
401 }
402 String actions = p.getActions();
403 if (actions != null && !"".equals(actions)){
404 pw.print("\", \"");
405 pw.print(actions);
406 pw.print("\"");
407 } else {
408 pw.print("\"");
409 }
410
411 pw.print(";\n");
412 }
413 pw.print("};\n\n");
414 }
415 }
416 pw.flush();
417 pw.close();
418 }
419 },"SecurityPolicyWriter policy creation thread");
420 if (t.isDaemon()) t.setDaemon(false);
421
422
423
424
425
426
427 t.setContextClassLoader(ClassLoader.getSystemClassLoader());
428 return t;
429 }
430
431 private String replaceValuesWithProperties(String s){
432 return System.getProperty(s,s);
433 }
434
435 private class Cert implements Function<Certificate,String> {
436
437 @Override
438 public String apply(Certificate t) {
439 try {
440 return keyStore().getCertificateAlias(t);
441 } catch (KeyStoreException ex) {
442 getLogger().log(Level.WARNING, "Alias not found in keystore", ex);
443 }
444 return null;
445 }
446
447 }
448 }