From ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- .../org/kde/kjas/server/KJASSecurityManager.java | 243 +++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 khtml/java/org/kde/kjas/server/KJASSecurityManager.java (limited to 'khtml/java/org/kde/kjas/server/KJASSecurityManager.java') diff --git a/khtml/java/org/kde/kjas/server/KJASSecurityManager.java b/khtml/java/org/kde/kjas/server/KJASSecurityManager.java new file mode 100644 index 000000000..0525bba0c --- /dev/null +++ b/khtml/java/org/kde/kjas/server/KJASSecurityManager.java @@ -0,0 +1,243 @@ +package org.kde.kjas.server; + +import java.security.*; +import java.security.cert.*; +import java.net.*; +import java.util.*; + + +public class KJASSecurityManager extends SecurityManager +{ + static Hashtable confirmRequests = new Hashtable(); + static int confirmId = 0; + Hashtable grantedPermissions = new Hashtable(); + HashSet grantAllPermissions = new HashSet(); + HashSet rejectAllPermissions = new HashSet(); + + private static final char [] base64table = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + static String encode64( byte [] data) + { + StringBuffer buf = new StringBuffer( 4*((data.length + 2)/3) ); + int i = 0, b1, b2, b3; + while (i < data.length - 2) { + b1 = data[i++]; + b2 = data[i++]; + b3 = data[i++]; + buf.append( base64table[(b1 >>> 2) & 0x3F] ); + buf.append( base64table[((b1 << 4) & 0x30) | ((b2 >>> 4) & 0xF)] ); + buf.append( base64table[((b2 << 2) & 0x3C) | ((b3 >>> 6) & 0x03)] ); + buf.append( base64table[b3 & 0x3F] ); + } + if ( i < data.length ) { + b1 = data[i++]; + buf.append( base64table[(b1 >>> 2) & 0x3F] ); + if ( i < data.length ) { + b2 = data[i++]; + buf.append( base64table[((b1 << 4) & 0x30) | ((b2 >>> 4) & 0xF)] ); + buf.append( base64table[(b2 << 2) & 0x3C] ); + } else { + buf.append( base64table[(b1 << 4) & 0x30] ); + buf.append( "=" ); + } + buf.append( '=' ); + } + return buf.toString(); + } + public KJASSecurityManager() + { + } + /** + * checks for an applets permission to access certain resources + * currently, only a check for SocketPermission is done, that the + * applet cannot connect to any other but the host, where it comes from. + * Anything else seems to be handled automagically + */ + public void checkPermission(Permission perm) throws SecurityException, NullPointerException { + // ClassLoader cl = Thread.currentThread().getContextClassLoader(); + try { + super.checkPermission(perm); + } catch (SecurityException se) { + // Don't annoy users with these + if (/*perm instanceof java.lang.RuntimePermission || */ + perm instanceof java.awt.AWTPermission) + throw se; + + // Collect certificates + HashSet signers = new HashSet(); + Class [] cls = getClassContext(); + for (int i = 1; i < cls.length; i++) { + Object[] objs = cls[i].getSigners(); + if (objs != null && objs.length > 0) { + for (int j = 0; j < objs.length; j++) + if (objs[j] instanceof X509Certificate) + signers.add( ((X509Certificate) objs[j]) ); + } + } + Main.debug("Certificates " + signers.size() + " for " + perm); + + // Check granted/denied permission + if ( grantAllPermissions.contains(signers) ) + return; + if ( rejectAllPermissions.contains(signers) ) + throw se; + Permissions permissions = (Permissions) grantedPermissions.get(signers); + if (permissions != null && permissions.implies(perm)) + return; + + // Ok, ask user what to do + String [] certs = new String[signers.size()]; + int certsnr = 0; + for (Iterator i = signers.iterator(); i.hasNext(); ) { + try { + certs[certsnr] = encode64( ((X509Certificate) i.next()).getEncoded() ); + certsnr++; + } catch (CertificateEncodingException cee) {} + } + if (certsnr == 0) + throw se; + String id = "" + confirmId++; + confirmRequests.put(id, Thread.currentThread()); + Main.protocol.sendSecurityConfirm(certs, certsnr, perm.toString(), id); + boolean granted = false; + try { + Thread.sleep(300000); + } catch (InterruptedException ie) { + if (((String) confirmRequests.get(id)).equals("yes")) { + granted = true; + permissions = (Permissions) grantedPermissions.get(signers); + if (permissions == null) { + permissions = new Permissions(); + grantedPermissions.put(signers, permissions); + } + permissions.add(perm); + } else if (((String) confirmRequests.get(id)).equals("grant")) { + grantAllPermissions.add( signers ); + granted = true; + } else if (((String) confirmRequests.get(id)).equals("reject")) { + rejectAllPermissions.add( signers ); + } // else "no", "nossl" or "invalid" + } finally { + confirmRequests.remove(id); + } + if (!granted) { + Main.debug("Permission denied" + perm); + throw se; + } + } + } + + // keytool -genkey -keystore mystore -alias myalias + // keytool -export -keystore mystore -alias myalias -file mycert + // keytool -printcert -file mycert + // keytool -import -keystore myotherstore -alias myalias -file mycert + // jarsigner -keystore mystore myjar.jar myalias + // jarsigner -verify -keystore myotherstore myjar.jar + // + // policy file (use policytool and check java.security): + // keystore "file:myotherstore", "JKS" + // grant signedBy "myalias" + // { + // permission java.io.FilePermission "<>", "read" + // } + // + // java code: + // KeyStore store = KeyStore.getInstance("JKS", "SUN"); + public void disabled___checkPermission(Permission perm) throws SecurityException, NullPointerException + { + // does not seem to work as expected, Problems with proxy - and it seems that the default + // implementation already does all that well, what I wanted to do here. + // It is likely that this method will hence disappear soon again. + Object context = getSecurityContext(); + Thread thread = Thread.currentThread(); + if (perm instanceof SocketPermission) { + // check if this is a connection back to the originating host + // if not, fall through and call super.checkPermission + // this gives normally access denied + Main.debug("*** checkPermission " + perm + " in context=" + context + " Thread=" + thread); + // use the context class loader to determine if this is one + // of our applets + ClassLoader contextClassLoader = thread.getContextClassLoader(); + Main.debug("* ClassLoader=" + contextClassLoader); + try { + // try to cast ... + KJASAppletClassLoader loader = (KJASAppletClassLoader)contextClassLoader; + // ok. cast succeeded. Now get the codebase of the loader + // because it contains the host name + URL codebase = loader.getCodeBase(); + URL docbase = loader.getDocBase(); + Main.debug("* Class Loader docbase=" + docbase + " codebase=" + codebase); + String hostname = perm.getName(); + // extract the hostname from the permission name + // which is something like "some.host.domain:XX" + // with XX as the port number + int colonIdx = hostname.indexOf(':'); + if (colonIdx > 0) { + // strip of the port + hostname = hostname.substring(0, colonIdx); + } + // Main.info("Checking " + hostname + "<->" + codebase.getHost()); + + if (hostsAreEqual(hostname, codebase.getHost())) { + // ok, host matches + String actions = perm.getActions(); + // just check if listen is specified which we do not want + // to allow + if (actions != null && actions.indexOf("listen") >= 0) { + Main.debug("* Listen is not allowed."); + } else { + // ok, just return and throw _no_ exception + Main.debug("* Hostname equals. Permission granted."); + return; + } + } else { + Main.info("Host mismatch: " + perm + " != " + codebase.getHost()); + } + } catch (ClassCastException e) { + Main.debug("* ClassLoader is not a KJASAppletClassLoader"); + } + Main.debug("* Fall through to super.checkPermission()"); + } + super.checkPermission(perm); + } + + private static final boolean hostsAreEqual(String host1, String host2) { + if (host1 == null || host2 == null) { + return false; + } + if (host1.length() == 0 || host2.length() == 0) { + return false; + } + if (host1.equalsIgnoreCase(host2)) { + return true; + } + + if ( Main.proxyHost != null && Main.proxyPort != 0) { + // if we use a proxy, we certainly cannot use DNS + return false; + } + + InetAddress inet1=null, inet2=null; + try { + inet1 = InetAddress.getByName(host1); + } catch (UnknownHostException e) { + Main.kjas_err("Unknown host:" + host1, e); + return false; + } + try { + inet2 = InetAddress.getByName(host2); + } catch (UnknownHostException e) { + Main.kjas_err("Unknown host:" + host2, e); + return false; + } + if (inet1.equals(inet2)) { + return true; + } + return false; + } +} -- cgit v1.2.1