package me.test.jaas.platform;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.PolicySpi;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.PropertyPermission;
import java.util.StringTokenizer;
/**
* 自定义的安全策略实现。可以参考并修改之后从数据库中加载权限。
* @author zhangliangliang
*
*/
public class SecurityPolicySpi extends PolicySpi {
private List<ProtectionDomain> cache = null;
public SecurityPolicySpi(Policy.Parameters params) throws IOException {
cache = new ArrayList<ProtectionDomain>();
CodeSource cs = null;
PermissionCollection pc = null;
ProtectionDomain pd = null;
URL url = null;
// 先初始化默认安全策略
initDefault();
// 在自定义安全测略:
// ----平台代码拥有所有权限
url = new File("./deploy/platform.jar").getCanonicalFile().toURI()
.toURL();
cs = new CodeSource(url, (Certificate[]) null);
pc = new Permissions();
pc.add(SecurityConstants.ALL_PERMISSION);
pd = new ProtectionDomain(cs, pc);
cache.add(pd);
// ----TaskA 可以对系统属性"java.version"进行读写操作
url = new File("./deploy/provider_a.jar").getCanonicalFile().toURI()
.toURL();
cs = new CodeSource(url, (Certificate[]) null);
pc = new Permissions();
pc.add(new PropertyPermission("java.version", "read,write"));
pd = new ProtectionDomain(cs, pc);
cache.add(pd);
// ----TaskB 按照默认设定,对系统属性"java.version"仅能够进行读操作
}
/**
* 解析系统属性 "java.ext.dirs",获取其中每个目录的绝对URL。
*/
public static String[] parseExtDirs() throws IOException {
final String extDir = "java.ext.dirs";
String s = System.getProperty(extDir);
List<String> dirs = new ArrayList<String>();
if (s != null) {
StringTokenizer st = new StringTokenizer(s, File.pathSeparator);
int count = st.countTokens();
for (int i = 0; i < count; i++) {
String nextToken = st.nextToken();
if (nextToken == null || nextToken.matches("^\\s*$")) {
continue;
}
File file = new File(nextToken);
String dir = null;
try {
dir = file.getCanonicalFile().toURI().toURL().toString();
} catch (MalformedURLException e) {
e.printStackTrace();
}
dir += dir.endsWith("/") ? "*" : "/*";
dirs.add(dir);
}
}
return dirs.toArray(new String[0]);
}
/**
* 等同于 ${java.ext.dirs}/java.policy 中的设定。
*
* @throws IOException
*/
public void initDefault() throws IOException {
PermissionCollection pc = null;
CodeSource cs = null;
ProtectionDomain pd = null;
// Standard extensions get all permissions by default
String[] extDirs = parseExtDirs();
for (String dir : extDirs) {
cs = new CodeSource(new URL(dir), (Certificate[]) null);
pc = new Permissions();
pc.add(SecurityConstants.ALL_PERMISSION);
pd = new ProtectionDomain(cs, pc);
cache.add(pd);
}
// default permissions granted to all domains
// 参考: http://javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/security/provider/PolicyFile.java.html
cs = new CodeSource(null, (Certificate[]) null);
pc = new Permissions();
pc.add(SecurityConstants.STOP_THREAD_PERMISSION); // NOTICE
pc.add(SecurityConstants.LOCAL_LISTEN_PERMISSION);
pc.add(new PropertyPermission("java.version",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vendor",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vendor.url",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.class.version",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("os.name",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("os.version",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("os.arch",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("file.separator",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("path.separator",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("line.separator",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.specification.version",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.specification.vendor",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.specification.name",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vm.specification.version",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vm.specification.vendor",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vm.specification.name",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vm.version",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vm.vendor",
SecurityConstants.PROPERTY_READ_ACTION));
pc.add(new PropertyPermission("java.vm.name",
SecurityConstants.PROPERTY_READ_ACTION));
pd = new ProtectionDomain(cs, pc);
cache.add(pd);
}
@Override
protected boolean engineImplies(final ProtectionDomain domain,
Permission permission) {
PermissionCollection pc = engineGetPermissions(domain);
return pc.implies(permission);
}
@Override
protected PermissionCollection engineGetPermissions(CodeSource codesource) {
Permissions permissions = new Permissions();
for (int i = 0; i < cache.size(); i++) {
ProtectionDomain pd = cache.get(i);
CodeSource cs = pd.getCodeSource();
if (cs != null && cs.implies(codesource)) {
Enumeration<Permission> e = pd.getPermissions().elements();
while (e.hasMoreElements()) {
Permission p = e.nextElement();
permissions.add(p);
}
}
}
if (permissions.elements().hasMoreElements()) {
return permissions;
}
return super.engineGetPermissions(codesource);
}
@Override
protected PermissionCollection engineGetPermissions(ProtectionDomain domain) {
return engineGetPermissions(domain.getCodeSource());
}
@Override
protected void engineRefresh() {
// TODO 重新查询数据库,以获取最新的安全策略配置。
super.engineRefresh();
}
}