mirror of https://github.com/apache/lucene.git
SOLR-8410: Add all read paths to 'read' permission in RuleBasedAuthorizationPlugin
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1720223 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
fc09a4729f
commit
a1951a4469
|
@ -318,6 +318,8 @@ Other Changes
|
||||||
|
|
||||||
* SOLR-8414: AbstractDistribZkTestBase.verifyReplicaStatus could throw NPE (Christine Poerschke)
|
* SOLR-8414: AbstractDistribZkTestBase.verifyReplicaStatus could throw NPE (Christine Poerschke)
|
||||||
|
|
||||||
|
* SOLR-8410: Add all read paths to 'read' permission in RuleBasedAuthorizationPlugin (noble)
|
||||||
|
|
||||||
================== 5.4.0 ==================
|
================== 5.4.0 ==================
|
||||||
|
|
||||||
Consult the LUCENE_CHANGES.txt file for additional, low level, changes in this release
|
Consult the LUCENE_CHANGES.txt file for additional, low level, changes in this release
|
||||||
|
|
|
@ -464,17 +464,17 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config
|
||||||
" update :{" +
|
" update :{" +
|
||||||
" path:'/update/*'}," +
|
" path:'/update/*'}," +
|
||||||
" read :{" +
|
" read :{" +
|
||||||
" path:['/select', '/get']}," +
|
" path:['/select', '/get','/browse','/tvrh','/terms','/clustering','/elevate', '/export','/spell','/clustering']}," +
|
||||||
" config-edit:{" +
|
" config-edit:{" +
|
||||||
" method:POST," +
|
" method:POST," +
|
||||||
" path:'/config/*'}}");
|
" path:'/config/*'}}");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
((Map) well_known_permissions.get("collection-admin-edit")).put(Predicate.class.getName(), getPredicate(true));
|
((Map) well_known_permissions.get("collection-admin-edit")).put(Predicate.class.getName(), getCollectionActionPredicate(true));
|
||||||
((Map) well_known_permissions.get("collection-admin-read")).put(Predicate.class.getName(), getPredicate(false));
|
((Map) well_known_permissions.get("collection-admin-read")).put(Predicate.class.getName(), getCollectionActionPredicate(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Predicate<AuthorizationContext> getPredicate(final boolean isEdit) {
|
private static Predicate<AuthorizationContext> getCollectionActionPredicate(final boolean isEdit) {
|
||||||
return new Predicate<AuthorizationContext>() {
|
return new Predicate<AuthorizationContext>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean test(AuthorizationContext context) {
|
public boolean test(AuthorizationContext context) {
|
||||||
|
|
|
@ -17,11 +17,10 @@ package org.apache.solr.security;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -30,98 +29,137 @@ import org.apache.solr.SolrTestCaseJ4;
|
||||||
import org.apache.solr.common.params.MapSolrParams;
|
import org.apache.solr.common.params.MapSolrParams;
|
||||||
import org.apache.solr.common.params.SolrParams;
|
import org.apache.solr.common.params.SolrParams;
|
||||||
import org.apache.solr.common.util.Utils;
|
import org.apache.solr.common.util.Utils;
|
||||||
|
import org.apache.solr.security.AuthorizationContext.CollectionRequest;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static org.apache.solr.common.util.Utils.makeMap;
|
||||||
|
|
||||||
public class TestRuleBasedAuthorizationPlugin extends SolrTestCaseJ4 {
|
public class TestRuleBasedAuthorizationPlugin extends SolrTestCaseJ4 {
|
||||||
|
String permissions = "{" +
|
||||||
|
" user-role : {" +
|
||||||
|
" steve: [dev,user]," +
|
||||||
|
" tim: [dev,admin]," +
|
||||||
|
" joe: [user]," +
|
||||||
|
" noble:[dev,user]" +
|
||||||
|
" }," +
|
||||||
|
" permissions : [" +
|
||||||
|
" {name:'schema-edit'," +
|
||||||
|
" role:admin}," +
|
||||||
|
" {name:'collection-admin-read'," +
|
||||||
|
" role:null}," +
|
||||||
|
" {name:collection-admin-edit ," +
|
||||||
|
" role:admin}," +
|
||||||
|
" {name:mycoll_update," +
|
||||||
|
" collection:mycoll," +
|
||||||
|
" path:'/update/*'," +
|
||||||
|
" role:[dev,admin]" +
|
||||||
|
" },{name:read , role:dev }]}";
|
||||||
|
|
||||||
|
|
||||||
public void testBasicPermissions() {
|
public void testBasicPermissions() {
|
||||||
int STATUS_OK = 200;
|
int STATUS_OK = 200;
|
||||||
int FORBIDDEN = 403;
|
int FORBIDDEN = 403;
|
||||||
int PROMPT_FOR_CREDENTIALS = 401;
|
int PROMPT_FOR_CREDENTIALS = 401;
|
||||||
|
|
||||||
String jsonRules= "{" +
|
checkRules(makeMap("resource", "/update/json/docs",
|
||||||
" user-role : {" +
|
|
||||||
" steve: [dev,user]," +
|
|
||||||
" tim: [dev,admin]," +
|
|
||||||
" joe: [user]," +
|
|
||||||
" noble:[dev,user]" +
|
|
||||||
" }," +
|
|
||||||
" permissions : [" +
|
|
||||||
" {name:'schema-edit'," +
|
|
||||||
" role:admin}," +
|
|
||||||
" {name:'collection-admin-read'," +
|
|
||||||
" role:null}," +
|
|
||||||
" {name:collection-admin-edit ," +
|
|
||||||
" role:admin}," +
|
|
||||||
" {name:mycoll_update," +
|
|
||||||
" collection:mycoll," +
|
|
||||||
" path:'/update/*'," +
|
|
||||||
" role:[dev,admin]" +
|
|
||||||
" }]}" ;
|
|
||||||
Map initConfig = (Map) Utils.fromJSON(jsonRules.getBytes(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
RuleBasedAuthorizationPlugin plugin= new RuleBasedAuthorizationPlugin();
|
|
||||||
plugin.init(initConfig);
|
|
||||||
|
|
||||||
Map<String, Object> values = Utils.makeMap(
|
|
||||||
"resource", "/update/json/docs",
|
|
||||||
"httpMethod", "POST",
|
"httpMethod", "POST",
|
||||||
"collectionRequests", Collections.singletonList(new AuthorizationContext.CollectionRequest("mycoll")),
|
"userPrincipal", "tim",
|
||||||
"userPrincipal", new BasicUserPrincipal("tim"));
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")) )
|
||||||
|
, STATUS_OK);
|
||||||
|
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/update/json/docs",
|
||||||
|
"httpMethod", "POST",
|
||||||
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")) )
|
||||||
|
, PROMPT_FOR_CREDENTIALS);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/schema",
|
||||||
|
"userPrincipal", "somebody",
|
||||||
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")),
|
||||||
|
"httpMethod", "POST")
|
||||||
|
, FORBIDDEN);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/schema",
|
||||||
|
"userPrincipal", "somebody",
|
||||||
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")),
|
||||||
|
"httpMethod", "GET")
|
||||||
|
, STATUS_OK);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/schema/fields",
|
||||||
|
"userPrincipal", "somebody",
|
||||||
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")),
|
||||||
|
"httpMethod", "GET")
|
||||||
|
, STATUS_OK);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/schema",
|
||||||
|
"userPrincipal", "somebody",
|
||||||
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")),
|
||||||
|
"httpMethod", "POST" )
|
||||||
|
, FORBIDDEN);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/admin/collections",
|
||||||
|
"userPrincipal", "tim",
|
||||||
|
"requestType", AuthorizationContext.RequestType.ADMIN,
|
||||||
|
"collectionRequests", null,
|
||||||
|
"httpMethod", "GET",
|
||||||
|
"params", new MapSolrParams(singletonMap("action", "LIST")))
|
||||||
|
, STATUS_OK);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/admin/collections",
|
||||||
|
"userPrincipal", null,
|
||||||
|
"requestType", AuthorizationContext.RequestType.ADMIN,
|
||||||
|
"collectionRequests", null,
|
||||||
|
"httpMethod", "GET",
|
||||||
|
"params", new MapSolrParams(singletonMap("action", "LIST")))
|
||||||
|
, STATUS_OK);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/admin/collections",
|
||||||
|
"userPrincipal", null,
|
||||||
|
"requestType", AuthorizationContext.RequestType.ADMIN,
|
||||||
|
"collectionRequests", null,
|
||||||
|
"params", new MapSolrParams(singletonMap("action", "CREATE")))
|
||||||
|
, PROMPT_FOR_CREDENTIALS);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/admin/collections",
|
||||||
|
"userPrincipal", null,
|
||||||
|
"requestType", AuthorizationContext.RequestType.ADMIN,
|
||||||
|
"collectionRequests", null,
|
||||||
|
"params", new MapSolrParams(singletonMap("action", "RELOAD")))
|
||||||
|
, PROMPT_FOR_CREDENTIALS);
|
||||||
|
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/admin/collections",
|
||||||
|
"userPrincipal", "somebody",
|
||||||
|
"requestType", AuthorizationContext.RequestType.ADMIN,
|
||||||
|
"collectionRequests", null,
|
||||||
|
"params", new MapSolrParams(singletonMap("action", "CREATE")))
|
||||||
|
, FORBIDDEN);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/admin/collections",
|
||||||
|
"userPrincipal", "tim",
|
||||||
|
"requestType", AuthorizationContext.RequestType.ADMIN,
|
||||||
|
"collectionRequests", null,
|
||||||
|
"params", new MapSolrParams(singletonMap("action", "CREATE")))
|
||||||
|
, STATUS_OK);
|
||||||
|
|
||||||
|
checkRules(makeMap("resource", "/select",
|
||||||
|
"httpMethod", "GET",
|
||||||
|
"collectionRequests", singletonList(new CollectionRequest("mycoll")),
|
||||||
|
"userPrincipal", "joe")
|
||||||
|
, FORBIDDEN);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void checkRules(Map<String, Object> values, int expected) {
|
||||||
|
|
||||||
AuthorizationContext context = new MockAuthorizationContext(values);
|
AuthorizationContext context = new MockAuthorizationContext(values);
|
||||||
|
RuleBasedAuthorizationPlugin plugin = new RuleBasedAuthorizationPlugin();
|
||||||
|
plugin.init((Map) Utils.fromJSONString(permissions));
|
||||||
AuthorizationResponse authResp = plugin.authorize(context);
|
AuthorizationResponse authResp = plugin.authorize(context);
|
||||||
assertEquals(STATUS_OK, authResp.statusCode);
|
assertEquals(expected, authResp.statusCode);
|
||||||
|
|
||||||
values.remove("userPrincipal");
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(PROMPT_FOR_CREDENTIALS,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("userPrincipal", new BasicUserPrincipal("somebody"));
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(FORBIDDEN,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("httpMethod","GET");
|
|
||||||
values.put("resource","/schema");
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(STATUS_OK,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("resource","/schema/fields");
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(STATUS_OK,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("resource","/schema");
|
|
||||||
values.put("httpMethod","POST");
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(FORBIDDEN,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("resource","/admin/collections");
|
|
||||||
values.put("requestType", AuthorizationContext.RequestType.ADMIN);
|
|
||||||
values.put("params", new MapSolrParams(Collections.singletonMap("action", "LIST")));
|
|
||||||
values.put("httpMethod","GET");
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(STATUS_OK,authResp.statusCode);
|
|
||||||
|
|
||||||
values.remove("userPrincipal");
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(STATUS_OK,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("params", new MapSolrParams(Collections.singletonMap("action", "CREATE")));
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(PROMPT_FOR_CREDENTIALS, authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("params", new MapSolrParams(Collections.singletonMap("action", "RELOAD")));
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(PROMPT_FOR_CREDENTIALS, authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("userPrincipal", new BasicUserPrincipal("somebody"));
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(FORBIDDEN,authResp.statusCode);
|
|
||||||
|
|
||||||
values.put("userPrincipal", new BasicUserPrincipal("tim"));
|
|
||||||
authResp = plugin.authorize(context);
|
|
||||||
assertEquals(STATUS_OK,authResp.statusCode);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockAuthorizationContext extends AuthorizationContext {
|
private static class MockAuthorizationContext extends AuthorizationContext {
|
||||||
|
@ -133,12 +171,14 @@ public class TestRuleBasedAuthorizationPlugin extends SolrTestCaseJ4 {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SolrParams getParams() {
|
public SolrParams getParams() {
|
||||||
return (SolrParams) values.get("params");
|
SolrParams params = (SolrParams) values.get("params");
|
||||||
|
return params == null ? new MapSolrParams(new HashMap<String, String>()) : params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Principal getUserPrincipal() {
|
public Principal getUserPrincipal() {
|
||||||
return (Principal) values.get("userPrincipal");
|
Object userPrincipal = values.get("userPrincipal");
|
||||||
|
return userPrincipal == null ? null : new BasicUserPrincipal(String.valueOf(userPrincipal));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue