I have built a client/server app with JAAS. The login seems to work OK, as logins are successful. It is when trying to grant permissions to specific methods that the AccessController
starts casting AccessControlException
.
java.security.AccessControlException: access denied ("myPackage.CustomPermission" "someMethod")
The permission-class:
public class CustomPermission extends BasicPermission {
public CustomPermission(String name) {
super(name);
}
public CustomPermission(String name, String method) {
super(name, method);
}
}
I have a custom Principal-class as well:
public class CustomPrincipal implements Principal {
private String name;
public CustomPrincipal(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
When logging in, a user provides a username and a password. In the DB the usernames and passwords have a "user level" associated to them. These user levels are used as principal-names, added to the Subject
created when logging in. I add it when handling the commit
-method in the LoginModule
:
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;
}
For the sake of it, this is how I instantiate the login-procedure:
LoginContext lc = new LoginContext("MyLoginModule", new RemoteCallbackHandler(username, password));
lc.login();
new ServerImpl(lc.getSubject());
The Subject
is then used in a "proxy" server implementation to check for permissions, like this (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();
}
});
}
The .policy-file:
grant codeBase "file:./bin/-" Principal myPackage.CustomPrincipal "user" {
permission myPackage.CustomPermission "someMethod";
};
The "user" is of course one of the user levels you could login with.
I've tried to add some extra grants, like:
grant codeBase "file:./bin/-" {
permission javax.security.auth.AuthPermission "createLoginContext.MyLoginModule";
permission javax.security.auth.AuthPermission "doAs";
};
I have a config for the LoginModule as well:
MyLoginModule {
myPackage.MyLoginModule required debug=true;
};
I set the properties before all this, of course: edit: the files are located in the root of the project
System.setProperty("java.security.auth.login.config", "file:./MyConfig.config");
System.setProperty("java.security.policy", "file:./MyPolicy.policy");
The server is run with the -Djava.security.manager
argument. The client does not use any arguments, nor any config- or policy-files.
I've tried to remove the codeBase to see if my path was wrong. If I add permissions java.util.AllPermissions
, then all is fine (but... of course it's not fine, as this is definitely not as intended). What am doing wrong here? I guess it's a combination of the Principal-, Permission, .policiy- and LoginModule-implementation.
EDIT
It is when the AccessController.checkPermissions(...)
is called in the "proxy" server implementation that the exception is thrown.
EDIT 2 I have tried with the following edit of the code:
return AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
@Override
public String run() throws PrivilegedActionException, RemoteException, ServerNotActiveException {
//AccessController.checkPermission(new CustomPermission("someMethod"));
return realServerImplObj.someMethod();
}
});
Note that I've changed Subject.doAs(user, new Privile....
to AccessController.doPrivileged(new Privilege
.
The user
is no longer parsed in the parameter, and we use the static method AccessController.doPrivileged
, rather than the Subject.doAs
.
Another note:
//AccessController.checkPermission(new CustomPer...
has been commented.
But now everyone can invoke any method, as we actually never check for permissions. It is as if the AccessController never is aware of the permissions granted in the .policy-file.
EDIT 3 It seemed to be an issue with the implementation of the Principal that was the issue.
Just for clarification, these are the edits that have been made:
@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);
}
Difference is the return Subject.doAsPrivileged(user, ... , null);
. Note the null at the end as well.
Implemented two methods in the CustomPrincipal
-class, #equals(Object)
and #hashCode()
. See here for a general-purpose example of both methods, and a sample Principal
implementation in general.
Also added (even though it seems to be running without, actually) the following the the .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";
is the newly added entry.
AuthPermission("doAsPrivileged")
to "file:./bin/-" and substitutingSubject.doAs
forSubject.doAsPrivileged(..., null)
.Principal
implement#hashCode()
and#equals(Object)
.Policy
(sun.security.provider.PolicyFile
) which, in the absense ofPrincipal#equals
is unable to verify that the activePrincipal
is "equivalent" to the one in itsgrant
statements. Can you explain what you mean by "more permissions"? What would their expected permission set be? What are they actually being granted?AccessController.checkPermission
stripped. Basically no permission checks were done. ;-) Can you make an answer? I'll upvote + set it as correct answer, as it works now.