I'm working on elasticsearch plugin and currently I cannot hack security policy mechanism.
According to documentation we should avoid disabling security manager, but what if I'm using some jars in my plugin that should have some privileges?
Currently I created such plugin-security.policy file:
grant {
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
permission java.lang.RuntimePermission "getClassLoader";
}
I need this to work with properties file and with Unsafe byte arrays. Customer will have a code source, so for customer development is transparent.
Still I cannot launch my plugin without disabling security manager. What am I doing wrong?
Are you running the code within a specific block as explained here?
// ES permission you should check before doPrivileged() blocks
import org.elasticsearch.SpecialPermission;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// unprivileged code such as scripts do not have SpecialPermission
sm.checkPermission(new SpecialPermission());
}
AccessController.doPrivileged(
// sensitive operation
);
Thank you for your answer. I've tried this but I'm not sure that I uderstood this correctly.
The sesentive operation in my case is calling Disruptor ds = new Disruptor(..) which under the hood call Unsafe initialization. I tired to call it as 'priviledged' , but it failed
AccessController.doPrivileged(
Disruptor ds = new Disruptor(..);
);
And make sure that plugin-security.policy is available in your plugins/myplugin directory.
To make sure that it's picked up by elasticsearch, write a malformed policy file and make sure it breaks.
Genius! I spent to much time today digging into this problem and smth went wrong. I saw this code and I even tried it, but it didn't work before, then you wrote it here and voilà it works!
I am creating a custom realm plugin for shield and I have used a Jersey client to do a REST call, I am facing the Security Managers Access denied issue.
[2017-02-07 10:56:05,642][INFO ][gateway ] [Techno] recovered [1] indices into cluster_state
[2017-02-07 10:56:06,348][INFO ][cluster.routing.allocation] [Techno] Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[.kibana][0]] ...]).
[2017-02-07 10:56:09,870][DEBUG][shield.authc ] [Techno] authentication of request failed for principal [john], uri [/]
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getClassLoader")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.ClassLoader.checkClassLoaderPermission(ClassLoader.java:1528)
at java.lang.Thread.getContextClassLoader(Thread.java:1440)
at com.sun.jersey.spi.service.ServiceFinder.find(ServiceFinder.java:498)
at com.sun.jersey.api.client.Client.init(Client.java:213)
at com.sun.jersey.api.client.Client.access$000(Client.java:118)
at com.sun.jersey.api.client.Client$1.f(Client.java:191)
at com.sun.jersey.api.client.Client$1.f(Client.java:187)
at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)
at com.sun.jersey.api.client.Client.<init>(Client.java:187)
at com.sun.jersey.api.client.Client.<init>(Client.java:159)
at com.sun.jersey.api.client.Client.create(Client.java:669)
at org.elasticsearch.example.realm.CustomRealm$1.run(CustomRealm.java:224)
at org.elasticsearch.example.realm.CustomRealm$1.run(CustomRealm.java:222)
at java.security.AccessController.doPrivileged(Native Method)
at org.elasticsearch.example.realm.CustomRealm.authenticate(CustomRealm.java:222)
at org.elasticsearch.example.realm.CustomRealm.authenticate(CustomRealm.java:61)
at org.elasticsearch.shield.authc.InternalAuthenticationService.authenticate(InternalAuthenticationService.java:363)
at org.elasticsearch.shield.authc.InternalAuthenticationService.authenticate(InternalAuthenticationService.java:109)
Following is my code.
if (userPwJwt != null) {
if (userPwJwt.length() < 30) {
byte[] encoded = Base64.encodeBase64((actualUser+":"+userPwJwt).getBytes(StandardCharsets.UTF_8));
encodedUserPw = "Basic " + new String(encoded,StandardCharsets.UTF_8);
} else {
encodedUserPw = "Bearer " + userPwJwt;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// unprivileged code such as scripts do not have SpecialPermission
sm.checkPermission(new SpecialPermission());
}
Client client = AccessController.doPrivileged(new PrivilegedAction<Client>() {
public Client run() {
return Client.create();
}});
try {
// initiating a client rest request
WebResource webResource = client.resource(restURL);
// sending the request and capturing the response
ClientResponse response = webResource.accept("text/plain").header("Authorization", encodedUserPw)
.get(ClientResponse.class);
// check if response code is correct else we return null
if (response.getStatus() == 200) {
jwtToken = response.getEntity(String.class);
if (!jwtToken.equals(null) && !jwtToken.isEmpty()) {
JWT jwt = JWT.decode(jwtToken);
Map<String, Claim> claims = jwt.getClaims();
// mapping the extracted jwt to username & roles
Claim claimName = claims.get("name");
resUserName = claimName.asString();
Claim claimRoles = claims.get("roles");
resUserRoles = claimRoles.asString().split(",");
if (resUserName != null && resUserRoles != null) {
return new User(resUserName, resUserRoles);
} else {
logger.debug("Recieved null value from JWT as User:Roles ",
resUserName + ":" + resUserRoles);
}
}
}
Is my AccessController method correct? I have changed the security.policy file to allow grant for get class loader.
grant {
// needed to set custom SSL factory for the CLI migrate tool
permission java.lang.RuntimePermission "setFactory";
// Allow RuntimePermission getClassLoader
permission java.lang.RuntimePermission "getClassLoader";
permission java.lang.RuntimePermission "accessDeclaredMembers";
};
~
I modified the AccessController to the following, even then i get the same issue:
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// unprivileged code such as scripts do not have SpecialPermission
sm.checkPermission(new SpecialPermission());
logger.info("Have access", "test");
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
Client client = Client.create();
WebResource webResource = client.resource(restURL);
ClientResponse response = webResource.accept("text/plain").header("Authorization", encodedUserPw)
.get(ClientResponse.class);
if (response.getStatus() == 200) {
ttoken = response.getEntity(String.class);
}
return null;
}
});
Can you please share how you got over this as I have used your code above and could successfully install the plugin and restart ES, however I get the security error below when I try to invoke my plugin's REST end point.
"type": "class_not_found_exception",
"reason": "Provider org.glassfish.jersey.client.JerseyClientBuilder could not be instantiated: java.security.AccessControlException: access denied (\"java.lang.RuntimePermission\" \"getClassLoader\")",
"caused_by": {
"type": "access_control_exception",
"reason": "access denied (\"java.lang.RuntimePermission\" \"getClassLoader\")"
}```
Apache, Apache Lucene, Apache Hadoop, Hadoop, HDFS and the yellow elephant
logo are trademarks of the
Apache Software Foundation
in the United States and/or other countries.