238 * @see java.security.Security security properties |
216 * @see java.security.Security security properties |
239 */ |
217 */ |
240 @Deprecated |
218 @Deprecated |
241 public class PolicyFile extends javax.security.auth.Policy { |
219 public class PolicyFile extends javax.security.auth.Policy { |
242 |
220 |
243 static final java.util.ResourceBundle rb = |
221 private final sun.security.provider.AuthPolicyFile apf; |
244 java.security.AccessController.doPrivileged |
|
245 (new java.security.PrivilegedAction<java.util.ResourceBundle>() { |
|
246 public java.util.ResourceBundle run() { |
|
247 return (java.util.ResourceBundle.getBundle |
|
248 ("sun.security.util.AuthResources")); |
|
249 } |
|
250 }); |
|
251 // needs to be package private |
|
252 |
|
253 private static final sun.security.util.Debug debug = |
|
254 sun.security.util.Debug.getInstance("policy", "\t[Auth Policy]"); |
|
255 |
|
256 private static final String AUTH_POLICY = "java.security.auth.policy"; |
|
257 private static final String SECURITY_MANAGER = "java.security.manager"; |
|
258 private static final String AUTH_POLICY_URL = "auth.policy.url."; |
|
259 |
|
260 private Vector<PolicyEntry> policyEntries; |
|
261 private Hashtable<Object, Object> aliasMapping; |
|
262 |
|
263 private boolean initialized = false; |
|
264 |
|
265 private boolean expandProperties = true; |
|
266 private boolean ignoreIdentityScope = true; |
|
267 |
|
268 // for use with the reflection API |
|
269 |
|
270 private static final Class[] PARAMS = { String.class, String.class}; |
|
271 |
222 |
272 /** |
223 /** |
273 * Initializes the Policy object and reads the default policy |
224 * Initializes the Policy object and reads the default policy |
274 * configuration file(s) into the Policy object. |
225 * configuration file(s) into the Policy object. |
275 */ |
226 */ |
276 public PolicyFile() { |
227 public PolicyFile() { |
277 // initialize Policy if either the AUTH_POLICY or |
228 apf = new sun.security.provider.AuthPolicyFile(); |
278 // SECURITY_MANAGER properties are set |
|
279 String prop = System.getProperty(AUTH_POLICY); |
|
280 |
|
281 if (prop == null) { |
|
282 prop = System.getProperty(SECURITY_MANAGER); |
|
283 } |
|
284 if (prop != null) |
|
285 init(); |
|
286 } |
|
287 |
|
288 private synchronized void init() { |
|
289 |
|
290 if (initialized) |
|
291 return; |
|
292 |
|
293 policyEntries = new Vector<PolicyEntry>(); |
|
294 aliasMapping = new Hashtable<Object, Object>(11); |
|
295 |
|
296 initPolicyFile(); |
|
297 initialized = true; |
|
298 } |
229 } |
299 |
230 |
300 /** |
231 /** |
301 * Refreshes the policy object by re-reading all the policy files. |
232 * Refreshes the policy object by re-reading all the policy files. |
302 * |
233 * |
303 * <p> |
234 * <p> |
304 * |
235 * |
305 * @exception SecurityException if the caller doesn't have permission |
236 * @exception SecurityException if the caller doesn't have permission |
306 * to refresh the <code>Policy</code>. |
237 * to refresh the <code>Policy</code>. |
307 */ |
238 */ |
308 public synchronized void refresh() |
239 @Override |
309 { |
240 public void refresh() { |
310 |
241 apf.refresh(); |
311 java.lang.SecurityManager sm = System.getSecurityManager(); |
|
312 if (sm != null) { |
|
313 sm.checkPermission(new javax.security.auth.AuthPermission |
|
314 ("refreshPolicy")); |
|
315 } |
|
316 |
|
317 // XXX |
|
318 // |
|
319 // 1) if code instantiates PolicyFile directly, then it will need |
|
320 // all the permissions required for the PolicyFile initialization |
|
321 // 2) if code calls Policy.getPolicy, then it simply needs |
|
322 // AuthPermission(getPolicy), and the javax.security.auth.Policy |
|
323 // implementation instantiates PolicyFile in a doPrivileged block |
|
324 // 3) if after instantiating a Policy (either via #1 or #2), |
|
325 // code calls refresh, it simply needs |
|
326 // AuthPermission(refreshPolicy). then PolicyFile wraps |
|
327 // the refresh in a doPrivileged block. |
|
328 initialized = false; |
|
329 java.security.AccessController.doPrivileged |
|
330 (new java.security.PrivilegedAction<Void>() { |
|
331 public Void run() { |
|
332 init(); |
|
333 return null; |
|
334 } |
|
335 }); |
|
336 } |
|
337 |
|
338 private KeyStore initKeyStore(URL policyUrl, String keyStoreName, |
|
339 String keyStoreType) { |
|
340 if (keyStoreName != null) { |
|
341 try { |
|
342 /* |
|
343 * location of keystore is specified as absolute URL in policy |
|
344 * file, or is relative to URL of policy file |
|
345 */ |
|
346 URL keyStoreUrl = null; |
|
347 try { |
|
348 keyStoreUrl = new URL(keyStoreName); |
|
349 // absolute URL |
|
350 } catch (java.net.MalformedURLException e) { |
|
351 // relative URL |
|
352 keyStoreUrl = new URL(policyUrl, keyStoreName); |
|
353 } |
|
354 |
|
355 if (debug != null) { |
|
356 debug.println("reading keystore"+keyStoreUrl); |
|
357 } |
|
358 |
|
359 InputStream inStream = |
|
360 new BufferedInputStream(getInputStream(keyStoreUrl)); |
|
361 |
|
362 KeyStore ks; |
|
363 if (keyStoreType != null) |
|
364 ks = KeyStore.getInstance(keyStoreType); |
|
365 else |
|
366 ks = KeyStore.getInstance(KeyStore.getDefaultType()); |
|
367 ks.load(inStream, null); |
|
368 inStream.close(); |
|
369 return ks; |
|
370 } catch (Exception e) { |
|
371 // ignore, treat it like we have no keystore |
|
372 if (debug != null) { |
|
373 e.printStackTrace(); |
|
374 } |
|
375 return null; |
|
376 } |
|
377 } |
|
378 return null; |
|
379 } |
|
380 |
|
381 private void initPolicyFile() { |
|
382 |
|
383 String prop = Security.getProperty("policy.expandProperties"); |
|
384 |
|
385 if (prop != null) expandProperties = prop.equalsIgnoreCase("true"); |
|
386 |
|
387 String iscp = Security.getProperty("policy.ignoreIdentityScope"); |
|
388 |
|
389 if (iscp != null) ignoreIdentityScope = iscp.equalsIgnoreCase("true"); |
|
390 |
|
391 String allowSys = Security.getProperty("policy.allowSystemProperty"); |
|
392 |
|
393 if ((allowSys!=null) && allowSys.equalsIgnoreCase("true")) { |
|
394 |
|
395 String extra_policy = System.getProperty(AUTH_POLICY); |
|
396 if (extra_policy != null) { |
|
397 boolean overrideAll = false; |
|
398 if (extra_policy.startsWith("=")) { |
|
399 overrideAll = true; |
|
400 extra_policy = extra_policy.substring(1); |
|
401 } |
|
402 try { |
|
403 extra_policy = PropertyExpander.expand(extra_policy); |
|
404 URL policyURL; |
|
405 File policyFile = new File(extra_policy); |
|
406 if (policyFile.exists()) { |
|
407 policyURL = |
|
408 new URL("file:" + policyFile.getCanonicalPath()); |
|
409 } else { |
|
410 policyURL = new URL(extra_policy); |
|
411 } |
|
412 if (debug != null) |
|
413 debug.println("reading "+policyURL); |
|
414 init(policyURL); |
|
415 } catch (Exception e) { |
|
416 // ignore. |
|
417 if (debug != null) { |
|
418 debug.println("caught exception: "+e); |
|
419 } |
|
420 |
|
421 } |
|
422 if (overrideAll) { |
|
423 if (debug != null) { |
|
424 debug.println("overriding other policies!"); |
|
425 } |
|
426 return; |
|
427 } |
|
428 } |
|
429 } |
|
430 |
|
431 int n = 1; |
|
432 boolean loaded_one = false; |
|
433 String policy_url; |
|
434 |
|
435 while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) { |
|
436 try { |
|
437 policy_url = PropertyExpander.expand(policy_url).replace |
|
438 (File.separatorChar, '/'); |
|
439 if (debug != null) |
|
440 debug.println("reading "+policy_url); |
|
441 init(new URL(policy_url)); |
|
442 loaded_one = true; |
|
443 } catch (Exception e) { |
|
444 if (debug != null) { |
|
445 debug.println("error reading policy "+e); |
|
446 e.printStackTrace(); |
|
447 } |
|
448 // ignore that policy |
|
449 } |
|
450 n++; |
|
451 } |
|
452 |
|
453 if (loaded_one == false) { |
|
454 // do not load a static policy |
|
455 } |
|
456 } |
|
457 |
|
458 /** |
|
459 * Checks public key. If it is marked as trusted in |
|
460 * the identity database, add it to the policy |
|
461 * with the AllPermission. |
|
462 */ |
|
463 private boolean checkForTrustedIdentity(final Certificate cert) { |
|
464 // XXX JAAS has no way to access the SUN package. |
|
465 // we'll add this back in when JAAS goes into core. |
|
466 return false; |
|
467 } |
|
468 |
|
469 /** |
|
470 * Reads a policy configuration into the Policy object using a |
|
471 * Reader object. |
|
472 * |
|
473 * @param policyFile the policy Reader object. |
|
474 */ |
|
475 private void init(URL policy) { |
|
476 sun.security.provider.PolicyParser pp = |
|
477 new sun.security.provider.PolicyParser(expandProperties); |
|
478 try { |
|
479 InputStreamReader isr |
|
480 = new InputStreamReader(getInputStream(policy)); |
|
481 pp.read(isr); |
|
482 isr.close(); |
|
483 KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(), |
|
484 pp.getKeyStoreType()); |
|
485 Enumeration<GrantEntry> enum_ = pp.grantElements(); |
|
486 while (enum_.hasMoreElements()) { |
|
487 GrantEntry ge = enum_.nextElement(); |
|
488 addGrantEntry(ge, keyStore); |
|
489 } |
|
490 } catch (sun.security.provider.PolicyParser.ParsingException pe) { |
|
491 System.err.println(AUTH_POLICY + |
|
492 rb.getString(".error.parsing.") + policy); |
|
493 System.err.println(AUTH_POLICY + |
|
494 rb.getString("COLON") + |
|
495 pe.getMessage()); |
|
496 if (debug != null) |
|
497 pe.printStackTrace(); |
|
498 |
|
499 } catch (Exception e) { |
|
500 if (debug != null) { |
|
501 debug.println("error parsing "+policy); |
|
502 debug.println(e.toString()); |
|
503 e.printStackTrace(); |
|
504 } |
|
505 } |
|
506 } |
|
507 |
|
508 /* |
|
509 * Fast path reading from file urls in order to avoid calling |
|
510 * FileURLConnection.connect() which can be quite slow the first time |
|
511 * it is called. We really should clean up FileURLConnection so that |
|
512 * this is not a problem but in the meantime this fix helps reduce |
|
513 * start up time noticeably for the new launcher. -- DAC |
|
514 */ |
|
515 private InputStream getInputStream(URL url) throws IOException { |
|
516 if ("file".equals(url.getProtocol())) { |
|
517 String path = url.getFile().replace('/', File.separatorChar); |
|
518 return new FileInputStream(path); |
|
519 } else { |
|
520 return url.openStream(); |
|
521 } |
|
522 } |
|
523 |
|
524 /** |
|
525 * Given a PermissionEntry, create a codeSource. |
|
526 * |
|
527 * @return null if signedBy alias is not recognized |
|
528 */ |
|
529 CodeSource getCodeSource(GrantEntry ge, KeyStore keyStore) |
|
530 throws java.net.MalformedURLException |
|
531 { |
|
532 Certificate[] certs = null; |
|
533 if (ge.signedBy != null) { |
|
534 certs = getCertificates(keyStore, ge.signedBy); |
|
535 if (certs == null) { |
|
536 // we don't have a key for this alias, |
|
537 // just return |
|
538 if (debug != null) { |
|
539 debug.println(" no certs for alias " + |
|
540 ge.signedBy + ", ignoring."); |
|
541 } |
|
542 return null; |
|
543 } |
|
544 } |
|
545 |
|
546 URL location; |
|
547 |
|
548 if (ge.codeBase != null) |
|
549 location = new URL(ge.codeBase); |
|
550 else |
|
551 location = null; |
|
552 |
|
553 if (ge.principals == null || ge.principals.size() == 0) { |
|
554 return (canonicalizeCodebase |
|
555 (new CodeSource(location, certs), |
|
556 false)); |
|
557 } else { |
|
558 return (canonicalizeCodebase |
|
559 (new SubjectCodeSource(null, ge.principals, location, certs), |
|
560 false)); |
|
561 } |
|
562 } |
|
563 |
|
564 /** |
|
565 * Add one policy entry to the vector. |
|
566 */ |
|
567 private void addGrantEntry(GrantEntry ge, KeyStore keyStore) { |
|
568 |
|
569 if (debug != null) { |
|
570 debug.println("Adding policy entry: "); |
|
571 debug.println(" signedBy " + ge.signedBy); |
|
572 debug.println(" codeBase " + ge.codeBase); |
|
573 if (ge.principals != null && ge.principals.size() > 0) { |
|
574 ListIterator<PrincipalEntry> li = ge.principals.listIterator(); |
|
575 while (li.hasNext()) { |
|
576 PrincipalEntry pppe = li.next(); |
|
577 debug.println(" " + pppe.getPrincipalClass() + |
|
578 " " + pppe.getPrincipalName()); |
|
579 } |
|
580 } |
|
581 debug.println(); |
|
582 } |
|
583 |
|
584 try { |
|
585 CodeSource codesource = getCodeSource(ge, keyStore); |
|
586 // skip if signedBy alias was unknown... |
|
587 if (codesource == null) return; |
|
588 |
|
589 PolicyEntry entry = new PolicyEntry(codesource); |
|
590 Enumeration<PermissionEntry> enum_ = ge.permissionElements(); |
|
591 while (enum_.hasMoreElements()) { |
|
592 PermissionEntry pe = enum_.nextElement(); |
|
593 try { |
|
594 // XXX special case PrivateCredentialPermission-SELF |
|
595 Permission perm; |
|
596 if (pe.permission.equals |
|
597 ("javax.security.auth.PrivateCredentialPermission") && |
|
598 pe.name.endsWith(" self")) { |
|
599 perm = getInstance(pe.permission, |
|
600 pe.name + " \"self\"", |
|
601 pe.action); |
|
602 } else { |
|
603 perm = getInstance(pe.permission, |
|
604 pe.name, |
|
605 pe.action); |
|
606 } |
|
607 entry.add(perm); |
|
608 if (debug != null) { |
|
609 debug.println(" "+perm); |
|
610 } |
|
611 } catch (ClassNotFoundException cnfe) { |
|
612 Certificate certs[]; |
|
613 if (pe.signedBy != null) |
|
614 certs = getCertificates(keyStore, pe.signedBy); |
|
615 else |
|
616 certs = null; |
|
617 |
|
618 // only add if we had no signer or we had a |
|
619 // a signer and found the keys for it. |
|
620 if (certs != null || pe.signedBy == null) { |
|
621 Permission perm = new UnresolvedPermission( |
|
622 pe.permission, |
|
623 pe.name, |
|
624 pe.action, |
|
625 certs); |
|
626 entry.add(perm); |
|
627 if (debug != null) { |
|
628 debug.println(" "+perm); |
|
629 } |
|
630 } |
|
631 } catch (java.lang.reflect.InvocationTargetException ite) { |
|
632 System.err.println |
|
633 (AUTH_POLICY + |
|
634 rb.getString(".error.adding.Permission.") + |
|
635 pe.permission + |
|
636 rb.getString("SPACE") + |
|
637 ite.getTargetException()); |
|
638 } catch (Exception e) { |
|
639 System.err.println |
|
640 (AUTH_POLICY + |
|
641 rb.getString(".error.adding.Permission.") + |
|
642 pe.permission + |
|
643 rb.getString("SPACE") + |
|
644 e); |
|
645 } |
|
646 } |
|
647 policyEntries.addElement(entry); |
|
648 } catch (Exception e) { |
|
649 System.err.println |
|
650 (AUTH_POLICY + |
|
651 rb.getString(".error.adding.Entry.") + |
|
652 ge + |
|
653 rb.getString("SPACE") + |
|
654 e); |
|
655 } |
|
656 |
|
657 if (debug != null) |
|
658 debug.println(); |
|
659 } |
|
660 |
|
661 /** |
|
662 * Returns a new Permission object of the given Type. The Permission is |
|
663 * created by getting the |
|
664 * Class object using the <code>Class.forName</code> method, and using |
|
665 * the reflection API to invoke the (String name, String actions) |
|
666 * constructor on the |
|
667 * object. |
|
668 * |
|
669 * @param type the type of Permission being created. |
|
670 * @param name the name of the Permission being created. |
|
671 * @param actions the actions of the Permission being created. |
|
672 * |
|
673 * @exception ClassNotFoundException if the particular Permission |
|
674 * class could not be found. |
|
675 * |
|
676 * @exception IllegalAccessException if the class or initializer is |
|
677 * not accessible. |
|
678 * |
|
679 * @exception InstantiationException if getInstance tries to |
|
680 * instantiate an abstract class or an interface, or if the |
|
681 * instantiation fails for some other reason. |
|
682 * |
|
683 * @exception NoSuchMethodException if the (String, String) constructor |
|
684 * is not found. |
|
685 * |
|
686 * @exception InvocationTargetException if the underlying Permission |
|
687 * constructor throws an exception. |
|
688 * |
|
689 */ |
|
690 |
|
691 private static final Permission getInstance(String type, |
|
692 String name, |
|
693 String actions) |
|
694 throws ClassNotFoundException, |
|
695 InstantiationException, |
|
696 IllegalAccessException, |
|
697 NoSuchMethodException, |
|
698 InvocationTargetException |
|
699 { |
|
700 //XXX we might want to keep a hash of created factories... |
|
701 Class<?> pc = Class.forName(type); |
|
702 Constructor<?> c = pc.getConstructor(PARAMS); |
|
703 return (Permission) c.newInstance(new Object[] { name, actions }); |
|
704 } |
|
705 |
|
706 /** |
|
707 * Fetch all certs associated with this alias. |
|
708 */ |
|
709 Certificate[] getCertificates( |
|
710 KeyStore keyStore, String aliases) { |
|
711 |
|
712 Vector<Certificate> vcerts = null; |
|
713 |
|
714 StringTokenizer st = new StringTokenizer(aliases, ","); |
|
715 int n = 0; |
|
716 |
|
717 while (st.hasMoreTokens()) { |
|
718 String alias = st.nextToken().trim(); |
|
719 n++; |
|
720 Certificate cert = null; |
|
721 //See if this alias's cert has already been cached |
|
722 cert = (Certificate) aliasMapping.get(alias); |
|
723 if (cert == null && keyStore != null) { |
|
724 |
|
725 try { |
|
726 cert = keyStore.getCertificate(alias); |
|
727 } catch (KeyStoreException kse) { |
|
728 // never happens, because keystore has already been loaded |
|
729 // when we call this |
|
730 } |
|
731 if (cert != null) { |
|
732 aliasMapping.put(alias, cert); |
|
733 aliasMapping.put(cert, alias); |
|
734 } |
|
735 } |
|
736 |
|
737 if (cert != null) { |
|
738 if (vcerts == null) |
|
739 vcerts = new Vector<Certificate>(); |
|
740 vcerts.addElement(cert); |
|
741 } |
|
742 } |
|
743 |
|
744 // make sure n == vcerts.size, since we are doing a logical *and* |
|
745 if (vcerts != null && n == vcerts.size()) { |
|
746 Certificate[] certs = new Certificate[vcerts.size()]; |
|
747 vcerts.copyInto(certs); |
|
748 return certs; |
|
749 } else { |
|
750 return null; |
|
751 } |
|
752 } |
|
753 |
|
754 /** |
|
755 * Enumerate all the entries in the global policy object. |
|
756 * This method is used by policy admin tools. The tools |
|
757 * should use the Enumeration methods on the returned object |
|
758 * to fetch the elements sequentially. |
|
759 */ |
|
760 private final synchronized Enumeration<PolicyEntry> elements(){ |
|
761 return policyEntries.elements(); |
|
762 } |
242 } |
763 |
243 |
764 /** |
244 /** |
765 * Examines this <code>Policy</code> and returns the Permissions granted |
245 * Examines this <code>Policy</code> and returns the Permissions granted |
766 * to the specified <code>Subject</code> and <code>CodeSource</code>. |
246 * to the specified <code>Subject</code> and <code>CodeSource</code>. |
814 * are returned. |
294 * are returned. |
815 * |
295 * |
816 * @return the Permissions granted to the provided <code>Subject</code> |
296 * @return the Permissions granted to the provided <code>Subject</code> |
817 * <code>CodeSource</code>. |
297 * <code>CodeSource</code>. |
818 */ |
298 */ |
|
299 @Override |
819 public PermissionCollection getPermissions(final Subject subject, |
300 public PermissionCollection getPermissions(final Subject subject, |
820 final CodeSource codesource) { |
301 final CodeSource codesource) { |
821 |
302 return apf.getPermissions(subject, codesource); |
822 // XXX when JAAS goes into the JDK core, |
|
823 // we can remove this method and simply |
|
824 // rely on the getPermissions variant that takes a codesource, |
|
825 // which no one can use at this point in time. |
|
826 // at that time, we can also make SubjectCodeSource a public |
|
827 // class. |
|
828 |
|
829 // XXX |
|
830 // |
|
831 // 1) if code instantiates PolicyFile directly, then it will need |
|
832 // all the permissions required for the PolicyFile initialization |
|
833 // 2) if code calls Policy.getPolicy, then it simply needs |
|
834 // AuthPermission(getPolicy), and the javax.security.auth.Policy |
|
835 // implementation instantiates PolicyFile in a doPrivileged block |
|
836 // 3) if after instantiating a Policy (either via #1 or #2), |
|
837 // code calls getPermissions, PolicyFile wraps the call |
|
838 // in a doPrivileged block. |
|
839 return java.security.AccessController.doPrivileged |
|
840 (new java.security.PrivilegedAction<PermissionCollection>() { |
|
841 public PermissionCollection run() { |
|
842 SubjectCodeSource scs = new SubjectCodeSource |
|
843 (subject, |
|
844 null, |
|
845 codesource == null ? null : codesource.getLocation(), |
|
846 codesource == null ? null : codesource.getCertificates()); |
|
847 if (initialized) |
|
848 return getPermissions(new Permissions(), scs); |
|
849 else |
|
850 return new PolicyPermissions(PolicyFile.this, scs); |
|
851 } |
|
852 }); |
|
853 } |
|
854 |
|
855 /** |
|
856 * Examines the global policy for the specified CodeSource, and |
|
857 * creates a PermissionCollection object with |
|
858 * the set of permissions for that principal's protection domain. |
|
859 * |
|
860 * @param CodeSource the codesource associated with the caller. |
|
861 * This encapsulates the original location of the code (where the code |
|
862 * came from) and the public key(s) of its signer. |
|
863 * |
|
864 * @return the set of permissions according to the policy. |
|
865 */ |
|
866 PermissionCollection getPermissions(CodeSource codesource) { |
|
867 |
|
868 if (initialized) |
|
869 return getPermissions(new Permissions(), codesource); |
|
870 else |
|
871 return new PolicyPermissions(this, codesource); |
|
872 } |
|
873 |
|
874 /** |
|
875 * Examines the global policy for the specified CodeSource, and |
|
876 * creates a PermissionCollection object with |
|
877 * the set of permissions for that principal's protection domain. |
|
878 * |
|
879 * @param permissions the permissions to populate |
|
880 * @param codesource the codesource associated with the caller. |
|
881 * This encapsulates the original location of the code (where the code |
|
882 * came from) and the public key(s) of its signer. |
|
883 * |
|
884 * @return the set of permissions according to the policy. |
|
885 */ |
|
886 Permissions getPermissions(final Permissions perms, |
|
887 final CodeSource cs) |
|
888 { |
|
889 if (!initialized) { |
|
890 init(); |
|
891 } |
|
892 |
|
893 final CodeSource codesource[] = {null}; |
|
894 |
|
895 codesource[0] = canonicalizeCodebase(cs, true); |
|
896 |
|
897 if (debug != null) { |
|
898 debug.println("evaluate("+codesource[0]+")\n"); |
|
899 } |
|
900 |
|
901 // needs to be in a begin/endPrivileged block because |
|
902 // codesource.implies calls URL.equals which does an |
|
903 // InetAddress lookup |
|
904 |
|
905 for (int i = 0; i < policyEntries.size(); i++) { |
|
906 |
|
907 PolicyEntry entry = policyEntries.elementAt(i); |
|
908 |
|
909 if (debug != null) { |
|
910 debug.println("PolicyFile CodeSource implies: " + |
|
911 entry.codesource.toString() + "\n\n" + |
|
912 "\t" + codesource[0].toString() + "\n\n"); |
|
913 } |
|
914 |
|
915 if (entry.codesource.implies(codesource[0])) { |
|
916 for (int j = 0; j < entry.permissions.size(); j++) { |
|
917 Permission p = entry.permissions.elementAt(j); |
|
918 if (debug != null) { |
|
919 debug.println(" granting " + p); |
|
920 } |
|
921 if (!addSelfPermissions(p, entry.codesource, |
|
922 codesource[0], perms)) { |
|
923 // we could check for duplicates |
|
924 // before adding new permissions, |
|
925 // but the SubjectDomainCombiner |
|
926 // already checks for duplicates later |
|
927 perms.add(p); |
|
928 } |
|
929 } |
|
930 } |
|
931 } |
|
932 |
|
933 // now see if any of the keys are trusted ids. |
|
934 |
|
935 if (!ignoreIdentityScope) { |
|
936 Certificate certs[] = codesource[0].getCertificates(); |
|
937 if (certs != null) { |
|
938 for (int k=0; k < certs.length; k++) { |
|
939 if ((aliasMapping.get(certs[k]) == null) && |
|
940 checkForTrustedIdentity(certs[k])) { |
|
941 // checkForTrustedIdentity added it |
|
942 // to the policy for us. next time |
|
943 // around we'll find it. This time |
|
944 // around we need to add it. |
|
945 perms.add(new java.security.AllPermission()); |
|
946 } |
|
947 } |
|
948 } |
|
949 } |
|
950 return perms; |
|
951 } |
|
952 |
|
953 /** |
|
954 * Returns true if 'Self' permissions were added to the provided |
|
955 * 'perms', and false otherwise. |
|
956 * |
|
957 * <p> |
|
958 * |
|
959 * @param p check to see if this Permission is a "SELF" |
|
960 * PrivateCredentialPermission. <p> |
|
961 * |
|
962 * @param entryCs the codesource for the Policy entry. |
|
963 * |
|
964 * @param accCs the codesource for from the current AccessControlContext. |
|
965 * |
|
966 * @param perms the PermissionCollection where the individual |
|
967 * PrivateCredentialPermissions will be added. |
|
968 */ |
|
969 private boolean addSelfPermissions(final Permission p, |
|
970 CodeSource entryCs, |
|
971 CodeSource accCs, |
|
972 Permissions perms) { |
|
973 |
|
974 if (!(p instanceof PrivateCredentialPermission)) |
|
975 return false; |
|
976 |
|
977 if (!(entryCs instanceof SubjectCodeSource)) |
|
978 return false; |
|
979 |
|
980 |
|
981 PrivateCredentialPermission pcp = (PrivateCredentialPermission)p; |
|
982 SubjectCodeSource scs = (SubjectCodeSource)entryCs; |
|
983 |
|
984 // see if it is a SELF permission |
|
985 String[][] pPrincipals = pcp.getPrincipals(); |
|
986 if (pPrincipals.length <= 0 || |
|
987 !pPrincipals[0][0].equalsIgnoreCase("self") || |
|
988 !pPrincipals[0][1].equalsIgnoreCase("self")) { |
|
989 |
|
990 // regular PrivateCredentialPermission |
|
991 return false; |
|
992 } else { |
|
993 |
|
994 // granted a SELF permission - create a |
|
995 // PrivateCredentialPermission for each |
|
996 // of the Policy entry's CodeSource Principals |
|
997 |
|
998 if (scs.getPrincipals() == null) { |
|
999 // XXX SubjectCodeSource has no Subject??? |
|
1000 return true; |
|
1001 } |
|
1002 |
|
1003 ListIterator<PrincipalEntry> pli = |
|
1004 scs.getPrincipals().listIterator(); |
|
1005 while (pli.hasNext()) { |
|
1006 |
|
1007 PrincipalEntry principal = pli.next(); |
|
1008 |
|
1009 // XXX |
|
1010 // if the Policy entry's Principal does not contain a |
|
1011 // WILDCARD for the Principal name, then a |
|
1012 // new PrivateCredentialPermission is created |
|
1013 // for the Principal listed in the Policy entry. |
|
1014 // if the Policy entry's Principal contains a WILDCARD |
|
1015 // for the Principal name, then a new |
|
1016 // PrivateCredentialPermission is created |
|
1017 // for each Principal associated with the Subject |
|
1018 // in the current ACC. |
|
1019 |
|
1020 String[][] principalInfo = getPrincipalInfo |
|
1021 (principal, accCs); |
|
1022 |
|
1023 for (int i = 0; i < principalInfo.length; i++) { |
|
1024 |
|
1025 // here's the new PrivateCredentialPermission |
|
1026 |
|
1027 PrivateCredentialPermission newPcp = |
|
1028 new PrivateCredentialPermission |
|
1029 (pcp.getCredentialClass() + |
|
1030 " " + |
|
1031 principalInfo[i][0] + |
|
1032 " " + |
|
1033 "\"" + principalInfo[i][1] + "\"", |
|
1034 "read"); |
|
1035 |
|
1036 if (debug != null) { |
|
1037 debug.println("adding SELF permission: " + |
|
1038 newPcp.toString()); |
|
1039 } |
|
1040 |
|
1041 perms.add(newPcp); |
|
1042 } |
|
1043 } |
|
1044 } |
|
1045 return true; |
|
1046 } |
|
1047 |
|
1048 /** |
|
1049 * return the principal class/name pair in the 2D array. |
|
1050 * array[x][y]: x corresponds to the array length. |
|
1051 * if (y == 0), it's the principal class. |
|
1052 * if (y == 1), it's the principal name. |
|
1053 */ |
|
1054 private String[][] getPrincipalInfo |
|
1055 (PrincipalEntry principal, final CodeSource accCs) { |
|
1056 |
|
1057 // there are 3 possibilities: |
|
1058 // 1) the entry's Principal class and name are not wildcarded |
|
1059 // 2) the entry's Principal name is wildcarded only |
|
1060 // 3) the entry's Principal class and name are wildcarded |
|
1061 |
|
1062 if (!principal.getPrincipalClass().equals |
|
1063 (PrincipalEntry.WILDCARD_CLASS) && |
|
1064 !principal.getPrincipalName().equals |
|
1065 (PrincipalEntry.WILDCARD_NAME)) { |
|
1066 |
|
1067 // build a PrivateCredentialPermission for the principal |
|
1068 // from the Policy entry |
|
1069 String[][] info = new String[1][2]; |
|
1070 info[0][0] = principal.getPrincipalClass(); |
|
1071 info[0][1] = principal.getPrincipalName(); |
|
1072 return info; |
|
1073 |
|
1074 } else if (!principal.getPrincipalClass().equals |
|
1075 (PrincipalEntry.WILDCARD_CLASS) && |
|
1076 principal.getPrincipalName().equals |
|
1077 (PrincipalEntry.WILDCARD_NAME)) { |
|
1078 |
|
1079 // build a PrivateCredentialPermission for all |
|
1080 // the Subject's principals that are instances of principalClass |
|
1081 |
|
1082 // the accCs is guaranteed to be a SubjectCodeSource |
|
1083 // because the earlier CodeSource.implies succeeded |
|
1084 SubjectCodeSource scs = (SubjectCodeSource)accCs; |
|
1085 |
|
1086 Set<? extends Principal> principalSet = null; |
|
1087 try { |
|
1088 // principal.principalClass should extend Principal |
|
1089 // If it doesn't, we should stop here with a ClassCastException. |
|
1090 @SuppressWarnings("unchecked") |
|
1091 Class<? extends Principal> pClass = (Class<? extends Principal>) |
|
1092 Class.forName(principal.getPrincipalClass(), false, |
|
1093 ClassLoader.getSystemClassLoader()); |
|
1094 principalSet = scs.getSubject().getPrincipals(pClass); |
|
1095 } catch (Exception e) { |
|
1096 if (debug != null) { |
|
1097 debug.println("problem finding Principal Class " + |
|
1098 "when expanding SELF permission: " + |
|
1099 e.toString()); |
|
1100 } |
|
1101 } |
|
1102 |
|
1103 if (principalSet == null) { |
|
1104 // error |
|
1105 return new String[0][0]; |
|
1106 } |
|
1107 |
|
1108 String[][] info = new String[principalSet.size()][2]; |
|
1109 |
|
1110 int i = 0; |
|
1111 for (Principal p : principalSet) { |
|
1112 info[i][0] = p.getClass().getName(); |
|
1113 info[i][1] = p.getName(); |
|
1114 i++; |
|
1115 } |
|
1116 return info; |
|
1117 |
|
1118 } else { |
|
1119 |
|
1120 // build a PrivateCredentialPermission for every |
|
1121 // one of the current Subject's principals |
|
1122 |
|
1123 // the accCs is guaranteed to be a SubjectCodeSource |
|
1124 // because the earlier CodeSource.implies succeeded |
|
1125 SubjectCodeSource scs = (SubjectCodeSource)accCs; |
|
1126 Set<Principal> principalSet = scs.getSubject().getPrincipals(); |
|
1127 |
|
1128 String[][] info = new String[principalSet.size()][2]; |
|
1129 java.util.Iterator<Principal> pIterator = principalSet.iterator(); |
|
1130 |
|
1131 int i = 0; |
|
1132 while (pIterator.hasNext()) { |
|
1133 Principal p = pIterator.next(); |
|
1134 info[i][0] = p.getClass().getName(); |
|
1135 info[i][1] = p.getName(); |
|
1136 i++; |
|
1137 } |
|
1138 return info; |
|
1139 } |
|
1140 } |
|
1141 |
|
1142 /* |
|
1143 * Returns the signer certificates from the list of certificates associated |
|
1144 * with the given code source. |
|
1145 * |
|
1146 * The signer certificates are those certificates that were used to verify |
|
1147 * signed code originating from the codesource location. |
|
1148 * |
|
1149 * This method assumes that in the given code source, each signer |
|
1150 * certificate is followed by its supporting certificate chain |
|
1151 * (which may be empty), and that the signer certificate and its |
|
1152 * supporting certificate chain are ordered bottom-to-top (i.e., with the |
|
1153 * signer certificate first and the (root) certificate authority last). |
|
1154 */ |
|
1155 Certificate[] getSignerCertificates(CodeSource cs) { |
|
1156 Certificate[] certs = null; |
|
1157 if ((certs = cs.getCertificates()) == null) |
|
1158 return null; |
|
1159 for (int i=0; i<certs.length; i++) { |
|
1160 if (!(certs[i] instanceof X509Certificate)) |
|
1161 return cs.getCertificates(); |
|
1162 } |
|
1163 |
|
1164 // Do we have to do anything? |
|
1165 int i = 0; |
|
1166 int count = 0; |
|
1167 while (i < certs.length) { |
|
1168 count++; |
|
1169 while (((i+1) < certs.length) |
|
1170 && ((X509Certificate)certs[i]).getIssuerDN().equals( |
|
1171 ((X509Certificate)certs[i+1]).getSubjectDN())) { |
|
1172 i++; |
|
1173 } |
|
1174 i++; |
|
1175 } |
|
1176 if (count == certs.length) |
|
1177 // Done |
|
1178 return certs; |
|
1179 |
|
1180 ArrayList<Certificate> userCertList = new ArrayList<>(); |
|
1181 i = 0; |
|
1182 while (i < certs.length) { |
|
1183 userCertList.add(certs[i]); |
|
1184 while (((i+1) < certs.length) |
|
1185 && ((X509Certificate)certs[i]).getIssuerDN().equals( |
|
1186 ((X509Certificate)certs[i+1]).getSubjectDN())) { |
|
1187 i++; |
|
1188 } |
|
1189 i++; |
|
1190 } |
|
1191 Certificate[] userCerts = new Certificate[userCertList.size()]; |
|
1192 userCertList.toArray(userCerts); |
|
1193 return userCerts; |
|
1194 } |
|
1195 |
|
1196 private CodeSource canonicalizeCodebase(CodeSource cs, |
|
1197 boolean extractSignerCerts) { |
|
1198 CodeSource canonCs = cs; |
|
1199 if (cs.getLocation() != null && |
|
1200 cs.getLocation().getProtocol().equalsIgnoreCase("file")) { |
|
1201 try { |
|
1202 String path = cs.getLocation().getFile().replace |
|
1203 ('/', |
|
1204 File.separatorChar); |
|
1205 URL csUrl = null; |
|
1206 if (path.endsWith("*")) { |
|
1207 // remove trailing '*' because it causes canonicalization |
|
1208 // to fail on win32 |
|
1209 path = path.substring(0, path.length()-1); |
|
1210 boolean appendFileSep = false; |
|
1211 if (path.endsWith(File.separator)) |
|
1212 appendFileSep = true; |
|
1213 if (path.equals("")) { |
|
1214 path = System.getProperty("user.dir"); |
|
1215 } |
|
1216 File f = new File(path); |
|
1217 path = f.getCanonicalPath(); |
|
1218 StringBuffer sb = new StringBuffer(path); |
|
1219 // reappend '*' to canonicalized filename (note that |
|
1220 // canonicalization may have removed trailing file |
|
1221 // separator, so we have to check for that, too) |
|
1222 if (!path.endsWith(File.separator) && |
|
1223 (appendFileSep || f.isDirectory())) |
|
1224 sb.append(File.separatorChar); |
|
1225 sb.append('*'); |
|
1226 path = sb.toString(); |
|
1227 } else { |
|
1228 path = new File(path).getCanonicalPath(); |
|
1229 } |
|
1230 csUrl = new File(path).toURL(); |
|
1231 |
|
1232 if (cs instanceof SubjectCodeSource) { |
|
1233 SubjectCodeSource scs = (SubjectCodeSource)cs; |
|
1234 if (extractSignerCerts) { |
|
1235 canonCs = new SubjectCodeSource |
|
1236 (scs.getSubject(), |
|
1237 scs.getPrincipals(), |
|
1238 csUrl, |
|
1239 getSignerCertificates(scs)); |
|
1240 } else { |
|
1241 canonCs = new SubjectCodeSource |
|
1242 (scs.getSubject(), |
|
1243 scs.getPrincipals(), |
|
1244 csUrl, |
|
1245 scs.getCertificates()); |
|
1246 } |
|
1247 } else { |
|
1248 if (extractSignerCerts) { |
|
1249 canonCs = new CodeSource(csUrl, |
|
1250 getSignerCertificates(cs)); |
|
1251 } else { |
|
1252 canonCs = new CodeSource(csUrl, |
|
1253 cs.getCertificates()); |
|
1254 } |
|
1255 } |
|
1256 } catch (IOException ioe) { |
|
1257 // leave codesource as it is, unless we have to extract its |
|
1258 // signer certificates |
|
1259 if (extractSignerCerts) { |
|
1260 if (!(cs instanceof SubjectCodeSource)) { |
|
1261 canonCs = new CodeSource(cs.getLocation(), |
|
1262 getSignerCertificates(cs)); |
|
1263 } else { |
|
1264 SubjectCodeSource scs = (SubjectCodeSource)cs; |
|
1265 canonCs = new SubjectCodeSource(scs.getSubject(), |
|
1266 scs.getPrincipals(), |
|
1267 scs.getLocation(), |
|
1268 getSignerCertificates(scs)); |
|
1269 } |
|
1270 } |
|
1271 } |
|
1272 } else { |
|
1273 if (extractSignerCerts) { |
|
1274 if (!(cs instanceof SubjectCodeSource)) { |
|
1275 canonCs = new CodeSource(cs.getLocation(), |
|
1276 getSignerCertificates(cs)); |
|
1277 } else { |
|
1278 SubjectCodeSource scs = (SubjectCodeSource)cs; |
|
1279 canonCs = new SubjectCodeSource(scs.getSubject(), |
|
1280 scs.getPrincipals(), |
|
1281 scs.getLocation(), |
|
1282 getSignerCertificates(scs)); |
|
1283 } |
|
1284 } |
|
1285 } |
|
1286 return canonCs; |
|
1287 } |
|
1288 |
|
1289 /** |
|
1290 * Each entry in the policy configuration file is represented by a |
|
1291 * PolicyEntry object. <p> |
|
1292 * |
|
1293 * A PolicyEntry is a (CodeSource,Permission) pair. The |
|
1294 * CodeSource contains the (URL, PublicKey) that together identify |
|
1295 * where the Java bytecodes come from and who (if anyone) signed |
|
1296 * them. The URL could refer to localhost. The URL could also be |
|
1297 * null, meaning that this policy entry is given to all comers, as |
|
1298 * long as they match the signer field. The signer could be null, |
|
1299 * meaning the code is not signed. <p> |
|
1300 * |
|
1301 * The Permission contains the (Type, Name, Action) triplet. <p> |
|
1302 * |
|
1303 * For now, the Policy object retrieves the public key from the |
|
1304 * X.509 certificate on disk that corresponds to the signedBy |
|
1305 * alias specified in the Policy config file. For reasons of |
|
1306 * efficiency, the Policy object keeps a hashtable of certs already |
|
1307 * read in. This could be replaced by a secure internal key |
|
1308 * store. |
|
1309 * |
|
1310 * <p> |
|
1311 * For example, the entry |
|
1312 * <pre> |
|
1313 * permission java.io.File "/tmp", "read,write", |
|
1314 * signedBy "Duke"; |
|
1315 * </pre> |
|
1316 * is represented internally |
|
1317 * <pre> |
|
1318 * |
|
1319 * FilePermission f = new FilePermission("/tmp", "read,write"); |
|
1320 * PublicKey p = publickeys.get("Duke"); |
|
1321 * URL u = InetAddress.getLocalHost(); |
|
1322 * CodeBase c = new CodeBase( p, u ); |
|
1323 * pe = new PolicyEntry(f, c); |
|
1324 * </pre> |
|
1325 * |
|
1326 * @author Marianne Mueller |
|
1327 * @author Roland Schemers |
|
1328 * @see java.security.CodeSource |
|
1329 * @see java.security.Policy |
|
1330 * @see java.security.Permissions |
|
1331 * @see java.security.ProtectionDomain |
|
1332 */ |
|
1333 |
|
1334 private static class PolicyEntry { |
|
1335 |
|
1336 CodeSource codesource; |
|
1337 Vector<Permission> permissions; |
|
1338 |
|
1339 /** |
|
1340 * Given a Permission and a CodeSource, create a policy entry. |
|
1341 * |
|
1342 * XXX Decide if/how to add validity fields and "purpose" fields to |
|
1343 * XXX policy entries |
|
1344 * |
|
1345 * @param cs the CodeSource, which encapsulates the URL and the public |
|
1346 * key |
|
1347 * attributes from the policy config file. Validity checks are |
|
1348 * performed on the public key before PolicyEntry is called. |
|
1349 * |
|
1350 */ |
|
1351 PolicyEntry(CodeSource cs) |
|
1352 { |
|
1353 this.codesource = cs; |
|
1354 this.permissions = new Vector<Permission>(); |
|
1355 } |
|
1356 |
|
1357 /** |
|
1358 * add a Permission object to this entry. |
|
1359 */ |
|
1360 void add(Permission p) { |
|
1361 permissions.addElement(p); |
|
1362 } |
|
1363 |
|
1364 /** |
|
1365 * Return the CodeSource for this policy entry |
|
1366 */ |
|
1367 CodeSource getCodeSource() { |
|
1368 return this.codesource; |
|
1369 } |
|
1370 |
|
1371 public String toString(){ |
|
1372 StringBuffer sb = new StringBuffer(); |
|
1373 sb.append(rb.getString("LPARAM")); |
|
1374 sb.append(getCodeSource()); |
|
1375 sb.append("\n"); |
|
1376 for (int j = 0; j < permissions.size(); j++) { |
|
1377 Permission p = permissions.elementAt(j); |
|
1378 sb.append(rb.getString("SPACE")); |
|
1379 sb.append(rb.getString("SPACE")); |
|
1380 sb.append(p); |
|
1381 sb.append(rb.getString("NEWLINE")); |
|
1382 } |
|
1383 sb.append(rb.getString("RPARAM")); |
|
1384 sb.append(rb.getString("NEWLINE")); |
|
1385 return sb.toString(); |
|
1386 } |
|
1387 |
|
1388 } |
303 } |
1389 } |
304 } |
1390 |
|
1391 @SuppressWarnings("deprecation") |
|
1392 class PolicyPermissions extends PermissionCollection { |
|
1393 |
|
1394 private static final long serialVersionUID = -1954188373270545523L; |
|
1395 |
|
1396 private CodeSource codesource; |
|
1397 private Permissions perms; |
|
1398 private PolicyFile policy; |
|
1399 private boolean notInit; // have we pulled in the policy permissions yet? |
|
1400 private Vector<Permission> additionalPerms; |
|
1401 |
|
1402 PolicyPermissions(PolicyFile policy, |
|
1403 CodeSource codesource) |
|
1404 { |
|
1405 this.codesource = codesource; |
|
1406 this.policy = policy; |
|
1407 this.perms = null; |
|
1408 this.notInit = true; |
|
1409 this.additionalPerms = null; |
|
1410 } |
|
1411 |
|
1412 public void add(Permission permission) { |
|
1413 if (isReadOnly()) |
|
1414 throw new SecurityException |
|
1415 (PolicyFile.rb.getString |
|
1416 ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection")); |
|
1417 |
|
1418 if (perms == null) { |
|
1419 if (additionalPerms == null) |
|
1420 additionalPerms = new Vector<Permission>(); |
|
1421 additionalPerms.add(permission); |
|
1422 } else { |
|
1423 perms.add(permission); |
|
1424 } |
|
1425 } |
|
1426 |
|
1427 private synchronized void init() { |
|
1428 if (notInit) { |
|
1429 if (perms == null) |
|
1430 perms = new Permissions(); |
|
1431 |
|
1432 if (additionalPerms != null) { |
|
1433 Enumeration<Permission> e = additionalPerms.elements(); |
|
1434 while (e.hasMoreElements()) { |
|
1435 perms.add(e.nextElement()); |
|
1436 } |
|
1437 additionalPerms = null; |
|
1438 } |
|
1439 policy.getPermissions(perms,codesource); |
|
1440 notInit=false; |
|
1441 } |
|
1442 } |
|
1443 |
|
1444 public boolean implies(Permission permission) { |
|
1445 if (notInit) |
|
1446 init(); |
|
1447 return perms.implies(permission); |
|
1448 } |
|
1449 |
|
1450 public Enumeration<Permission> elements() { |
|
1451 if (notInit) |
|
1452 init(); |
|
1453 return perms.elements(); |
|
1454 } |
|
1455 |
|
1456 public String toString() { |
|
1457 if (notInit) |
|
1458 init(); |
|
1459 return perms.toString(); |
|
1460 } |
|
1461 } |
|