使用 JAAS 调用方法时的 AccessControlException



我用JAAS构建了一个客户端/服务器应用程序。登录似乎工作正常,因为登录成功。当尝试向特定方法授予权限时,AccessController开始转换AccessControlException

java.security.AccessControlException: access denied ("myPackage.CustomPermission" "someMethod")

权限类:

public class CustomPermission extends BasicPermission {
public CustomPermission(String name) {
super(name);
}
public CustomPermission(String name, String method) {
super(name, method);
}
}

我也有一个自定义的主体类:

public class CustomPrincipal implements Principal {
private String name;
public CustomPrincipal(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}

登录时,用户提供用户名和密码。在数据库中,用户名和密码具有与之关联的"用户级别"。这些用户级别用作主体名称,添加到登录时创建的Subject中。我在处理LoginModule中的commit方法时添加它:

public boolean commit() throws LoginException {
if(status == ConfigValues.NOT || subject == null)
return false;
principal = new CustomPrincipal(userlvl);
if(subject.getPrincipals().add(principal)) {
username = null;
password = null;
status = ConfigValues.COMMIT;
return true;
}
return false;
}

为此,这就是我实例化登录过程的方式:

LoginContext lc = new LoginContext("MyLoginModule", new RemoteCallbackHandler(username, password));
lc.login();
new ServerImpl(lc.getSubject());

然后,Subject在"代理"服务器实现中用于检查权限,如下所示(user = lc.getSubject):

public String someMethod() throws RemoteException, PrivilegedActionException {
return Subject.doAs(user, new PrivilegedExceptionAction<String>() {
@Override
public String run() throws PrivilegedActionException, RemoteException, ServerNotActiveException {
AccessController.checkPermission(new CustomPermission("someMethod"));
return realServerImplObj.someMethod();
}
});
}

.policy-file:

grant codeBase "file:./bin/-" Principal myPackage.CustomPrincipal "user" {
permission myPackage.CustomPermission "someMethod";
};

"用户"当然是您可以登录的用户级别之一。

我试图添加一些额外的赠款,例如:

grant codeBase "file:./bin/-" {
permission javax.security.auth.AuthPermission "createLoginContext.MyLoginModule";
permission javax.security.auth.AuthPermission "doAs";
};

我也有一个登录模块的配置:

MyLoginModule {
myPackage.MyLoginModule required debug=true;
};

当然,我在这一切之前设置了属性:编辑:文件位于项目的根目录中

System.setProperty("java.security.auth.login.config", "file:./MyConfig.config");
System.setProperty("java.security.policy", "file:./MyPolicy.policy");

服务器使用-Djava.security.manager参数运行。客户端不使用任何参数,也不使用任何配置或策略文件。

我试图删除代码库以查看我的路径是否错误。如果我添加permissions java.util.AllPermissions,那么一切都很好(但是...当然这并不好,因为这绝对不是预期的)。这里做错了什么?我想它是Principal-,Permission,.policiy和LoginModule实现的组合。

编辑当在"代理"服务器实现中调用AccessController.checkPermissions(...)时,将引发异常。

编辑2我尝试了以下代码编辑:

return AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
@Override
public String run() throws PrivilegedActionException, RemoteException, ServerNotActiveException {
//AccessController.checkPermission(new CustomPermission("someMethod"));
return realServerImplObj.someMethod();
}
});

请注意,我已将Subject.doAs(user, new Privile....更改为AccessController.doPrivileged(new Privilege。 参数中不再解析user,我们使用静态方法AccessController.doPrivileged,而不是Subject.doAs。 另一个注意事项://AccessController.checkPermission(new CustomPer...已被评论。

但是现在每个人都可以调用任何方法,因为我们实际上从不检查权限。就好像访问控制器永远不会知道 .policy-file 中授予的权限。

编辑 3问题似乎是校长的实施问题。

为了澄清起见,这些是已进行的编辑:

@Override
public String someMethod() throws PrivilegedActionException {
return Subject.doAsPrivileged(user, new PrivilegedExceptionAction<String>() {
@Override
public String run() throws PrivilegedActionException, RemoteException, ServerNotActiveException {
AccessController.checkPermission(new CustomPermission("someMethod"));
return realServerImplObj.someMethod();
}
}, null);
}

区别在于return Subject.doAsPrivileged(user, ... , null);.还要注意末尾的空值。

CustomPrincipal类中实现了两个方法,#equals(Object)#hashCode()。有关这两种方法的通用示例以及一般Principal实现的示例,请参阅此处。

还添加了(即使它似乎实际上没有运行)以下 .policy-file

grant codeBase "file:./bin/-" {
permission javax.security.auth.AuthPermission "createLoginContext.MyLoginModule";
permission javax.security.auth.AuthPermission "doAs";
permission javax.security.auth.AuthPermission "doAsPrivileged";
};

permission javax.security.auth.AuthPermission "doAsPrivileged";是新添加的条目。

Subject#doAsvsSubject#doAsPrivileged

AccessController采用的默认授权算法基于Permission交集:如果一个AccessControlContext的所有ProtectionDomain,可能与一个SubjectPrincipals组合,静态和/或根据有效的Policy,正在检查Permission,评估成功;否则,评估失败。

Subject#doAs在您的情况下不起作用,因为您的Permissiongrant到您的ProtectionDomainPrincipal的组合,而不是域本身。具体而言,在AccessController#checkPermission(customPermission)调用时,有效AccessControlContext包括以下相关(就Permission评估而言)框架:

Frame # | ProtectionDomain          | Permissions
--------+---------------------------+---------------------------------------------
2      | "file:./bin/"             | { CustomPermission("someMethod"),
| + CustomPrincipal("user") |   permissions statically assigned by default
|                           |   by the ClassLoader }
--------+---------------------------+---------------------------------------------
1      | "file:./bin/"             | { AuthPermission(
|                           |   "createLoginContext.MyLoginModule"),
|                           |   AuthPermission("doAs"), default as above }
--------+---------------------------+---------------------------------------------

这些帧权限的交集当然不包括所需的CustomPermission

另一方面,当给定一个null AccessControlContext时,Subject#doAsPrivileged可以解决问题,因为它将有效上下文的堆栈"修剪"到其最顶层的框架,即调用doAsPrivileged的框架。实际发生的是,null(空白)上下文被AccessController视为权限评估产生AllPermission的上下文;换句话说:

AllPermission权限2= {CustomPermission("someMethod"), 默认的 } ,

这是(除了看似无关的静态分配Permnission的最小集合)所需的结果。

当然,在不希望这种潜在的任意权限提升的情况下,可以将自定义上下文传递给doAsPrivileged,其封装域的权限表示您愿意授予的最大权限集(例如某些Subject),而不是null

为什么Principal实现被迫覆盖equalshashCode

以下堆栈跟踪代码段说明了原因:

at java.lang.Thread.dumpStack(Thread.java:1329)
at com.foo.bar.PrincipalImpl.equals(PrincipalImpl.java:53)
at javax.security.auth.Subject$SecureSet.contains(Subject.java:1201)
at java.util.Collections$SynchronizedCollection.contains(Collections.java:2021)
at java.security.Principal.implies(Principal.java:92)
at sun.security.provider.PolicyFile.addPermissions(PolicyFile.java:1374)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1228)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1191)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1132)
at sun.security.provider.PolicyFile.implies(PolicyFile.java:1086)
at java.security.ProtectionDomain.implies(ProtectionDomain.java:281)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:450)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
...

延伸阅读:

  • 默认策略实现和策略文件语法
  • Java SE 的安全编码准则 - §9 - 访问控制
  • 安全故障排除

相关内容

  • 没有找到相关文章

最新更新