mirror of https://github.com/apache/lucene.git
SOLR-7275: Authorization framework for Solr. It defines an interface and a mechanism to create, load and use an Authorization plugin.
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1679316 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
dcb19cd007
commit
acb40f6225
|
@ -180,6 +180,8 @@ New Features
|
||||||
* SOLR-7522: Facet Module - Implement field/terms faceting over single-valued
|
* SOLR-7522: Facet Module - Implement field/terms faceting over single-valued
|
||||||
numeric fields. (yonik)
|
numeric fields. (yonik)
|
||||||
|
|
||||||
|
* SOLR-7275: Authorization framework for Solr. It defines an interface and a mechanism to create,
|
||||||
|
load, and use an Authorization plugin. (Noble Paul, Ishan Chattopadhyaya, Anshum Gupta)
|
||||||
|
|
||||||
Bug Fixes
|
Bug Fixes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
|
|
||||||
package org.apache.solr.core;
|
package org.apache.solr.core;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.*;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -30,8 +29,9 @@ import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import org.apache.solr.cloud.ZkController;
|
import org.apache.solr.cloud.ZkController;
|
||||||
import org.apache.solr.cloud.ZkSolrResourceLoader;
|
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
import org.apache.solr.common.SolrException.ErrorCode;
|
import org.apache.solr.common.SolrException.ErrorCode;
|
||||||
import org.apache.solr.common.util.ExecutorUtil;
|
import org.apache.solr.common.util.ExecutorUtil;
|
||||||
|
@ -43,6 +43,7 @@ import org.apache.solr.handler.admin.InfoHandler;
|
||||||
import org.apache.solr.handler.component.ShardHandlerFactory;
|
import org.apache.solr.handler.component.ShardHandlerFactory;
|
||||||
import org.apache.solr.logging.LogWatcher;
|
import org.apache.solr.logging.LogWatcher;
|
||||||
import org.apache.solr.request.SolrRequestHandler;
|
import org.apache.solr.request.SolrRequestHandler;
|
||||||
|
import org.apache.solr.security.AuthorizationPlugin;
|
||||||
import org.apache.solr.update.UpdateShardHandler;
|
import org.apache.solr.update.UpdateShardHandler;
|
||||||
import org.apache.solr.util.DefaultSolrThreadFactory;
|
import org.apache.solr.util.DefaultSolrThreadFactory;
|
||||||
import org.apache.solr.util.FileUtils;
|
import org.apache.solr.util.FileUtils;
|
||||||
|
@ -50,8 +51,7 @@ import org.apache.zookeeper.KeeperException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,6 +64,8 @@ public class CoreContainer {
|
||||||
|
|
||||||
final SolrCores solrCores = new SolrCores(this);
|
final SolrCores solrCores = new SolrCores(this);
|
||||||
|
|
||||||
|
protected AuthorizationPlugin authorizationPlugin;
|
||||||
|
|
||||||
public static class CoreLoadFailure {
|
public static class CoreLoadFailure {
|
||||||
|
|
||||||
public final CoreDescriptor cd;
|
public final CoreDescriptor cd;
|
||||||
|
@ -176,6 +178,27 @@ public class CoreContainer {
|
||||||
this.containerProperties = new Properties(properties);
|
this.containerProperties = new Properties(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void intializeAuthorizationPlugin() {
|
||||||
|
//Initialize the Authorization module
|
||||||
|
Map securityProps = getZkController().getZkStateReader().getSecurityProps();
|
||||||
|
if(securityProps != null) {
|
||||||
|
Map authorizationConf = (Map) securityProps.get("authorization");
|
||||||
|
if(authorizationConf == null) return;
|
||||||
|
String klas = (String) authorizationConf.get("class");
|
||||||
|
if(klas == null){
|
||||||
|
throw new SolrException(ErrorCode.SERVER_ERROR, "class is required for authorization plugin");
|
||||||
|
}
|
||||||
|
log.info("Initializing authorization plugin: " + klas);
|
||||||
|
authorizationPlugin = getResourceLoader().newInstance((String) klas,
|
||||||
|
AuthorizationPlugin.class);
|
||||||
|
|
||||||
|
// Read and pass the authorization context to the plugin
|
||||||
|
authorizationPlugin.init(authorizationConf);
|
||||||
|
} else {
|
||||||
|
log.info("Security conf doesn't exist. Skipping setup for authorization module.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method allows subclasses to construct a CoreContainer
|
* This method allows subclasses to construct a CoreContainer
|
||||||
* without any default init behavior.
|
* without any default init behavior.
|
||||||
|
@ -246,6 +269,9 @@ public class CoreContainer {
|
||||||
log.info("Node Name: " + hostName);
|
log.info("Node Name: " + hostName);
|
||||||
|
|
||||||
zkSys.initZooKeeper(this, solrHome, cfg.getCloudConfig());
|
zkSys.initZooKeeper(this, solrHome, cfg.getCloudConfig());
|
||||||
|
if (isZooKeeperAware()) {
|
||||||
|
intializeAuthorizationPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
collectionsHandler = createHandler(cfg.getCollectionsHandlerClass(), CollectionsHandler.class);
|
collectionsHandler = createHandler(cfg.getCollectionsHandlerClass(), CollectionsHandler.class);
|
||||||
containerHandlers.put(COLLECTIONS_HANDLER_PATH, collectionsHandler);
|
containerHandlers.put(COLLECTIONS_HANDLER_PATH, collectionsHandler);
|
||||||
|
@ -396,6 +422,16 @@ public class CoreContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It should be safe to close the authorization plugin at this point.
|
||||||
|
try {
|
||||||
|
if(authorizationPlugin != null) {
|
||||||
|
authorizationPlugin.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Exception while closing authorization plugin.", e);
|
||||||
|
}
|
||||||
|
|
||||||
org.apache.lucene.util.IOUtils.closeWhileHandlingException(loader); // best effort
|
org.apache.lucene.util.IOUtils.closeWhileHandlingException(loader); // best effort
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,7 +484,7 @@ public class CoreContainer {
|
||||||
solrCores.putDynamicDescriptor(name, cd);
|
solrCores.putDynamicDescriptor(name, cd);
|
||||||
}
|
}
|
||||||
|
|
||||||
SolrCore old = null;
|
SolrCore old;
|
||||||
|
|
||||||
if (isShutDown) {
|
if (isShutDown) {
|
||||||
core.close();
|
core.close();
|
||||||
|
@ -640,7 +676,7 @@ public class CoreContainer {
|
||||||
|
|
||||||
coresLocator.swap(this, solrCores.getCoreDescriptor(n0), solrCores.getCoreDescriptor(n1));
|
coresLocator.swap(this, solrCores.getCoreDescriptor(n0), solrCores.getCoreDescriptor(n1));
|
||||||
|
|
||||||
log.info("swapped: "+n0 + " with " + n1);
|
log.info("swapped: " + n0 + " with " + n1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -689,8 +725,7 @@ public class CoreContainer {
|
||||||
// cancel recovery in cloud mode
|
// cancel recovery in cloud mode
|
||||||
core.getSolrCoreState().cancelRecovery();
|
core.getSolrCoreState().cancelRecovery();
|
||||||
}
|
}
|
||||||
String configSetZkPath = core.getResourceLoader() instanceof ZkSolrResourceLoader ? ((ZkSolrResourceLoader)core.getResourceLoader()).getConfigSetZkPath() : null;
|
|
||||||
|
|
||||||
core.unloadOnClose(deleteIndexDir, deleteDataDir, deleteInstanceDir);
|
core.unloadOnClose(deleteIndexDir, deleteDataDir, deleteInstanceDir);
|
||||||
if (close)
|
if (close)
|
||||||
core.close();
|
core.close();
|
||||||
|
@ -705,7 +740,6 @@ public class CoreContainer {
|
||||||
throw new SolrException(ErrorCode.SERVER_ERROR, "Error unregistering core [" + name + "] from cloud state", e);
|
throw new SolrException(ErrorCode.SERVER_ERROR, "Error unregistering core [" + name + "] from cloud state", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rename(String name, String toName) {
|
public void rename(String name, String toName) {
|
||||||
|
@ -885,6 +919,11 @@ public class CoreContainer {
|
||||||
public SolrResourceLoader getResourceLoader() {
|
public SolrResourceLoader getResourceLoader() {
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuthorizationPlugin getAuthorizationPlugin() {
|
||||||
|
return authorizationPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CloserThread extends Thread {
|
class CloserThread extends Thread {
|
||||||
|
|
|
@ -17,6 +17,37 @@
|
||||||
|
|
||||||
package org.apache.solr.core;
|
package org.apache.solr.core;
|
||||||
|
|
||||||
|
import javax.naming.Context;
|
||||||
|
import javax.naming.InitialContext;
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
import javax.naming.NoInitialContextException;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.charset.CharacterCodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.lucene.analysis.util.CharFilterFactory;
|
import org.apache.lucene.analysis.util.CharFilterFactory;
|
||||||
import org.apache.lucene.analysis.util.ResourceLoader;
|
import org.apache.lucene.analysis.util.ResourceLoader;
|
||||||
import org.apache.lucene.analysis.util.ResourceLoaderAware;
|
import org.apache.lucene.analysis.util.ResourceLoaderAware;
|
||||||
|
@ -44,38 +75,6 @@ import org.apache.solr.util.plugin.SolrCoreAware;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.naming.Context;
|
|
||||||
import javax.naming.InitialContext;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.NoInitialContextException;
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.nio.charset.CharacterCodingException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since solr 1.3
|
* @since solr 1.3
|
||||||
*/
|
*/
|
||||||
|
@ -88,7 +87,7 @@ public class SolrResourceLoader implements ResourceLoader,Closeable
|
||||||
static final String[] packages = {
|
static final String[] packages = {
|
||||||
"", "analysis.", "schema.", "handler.", "search.", "update.", "core.", "response.", "request.",
|
"", "analysis.", "schema.", "handler.", "search.", "update.", "core.", "response.", "request.",
|
||||||
"update.processor.", "util.", "spelling.", "handler.component.", "handler.dataimport.",
|
"update.processor.", "util.", "spelling.", "handler.component.", "handler.dataimport.",
|
||||||
"spelling.suggest.", "spelling.suggest.fst.", "rest.schema.analysis."
|
"spelling.suggest.", "spelling.suggest.fst.", "rest.schema.analysis.", "security."
|
||||||
};
|
};
|
||||||
|
|
||||||
protected URLClassLoader classLoader;
|
protected URLClassLoader classLoader;
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.apache.solr.security;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.solr.common.params.SolrParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request context for Solr to be used by Authorization plugin.
|
||||||
|
*/
|
||||||
|
public abstract class AuthorizationContext {
|
||||||
|
|
||||||
|
public static class CollectionRequest {
|
||||||
|
final public String collectionName;
|
||||||
|
|
||||||
|
public CollectionRequest(String collectionName) {
|
||||||
|
this.collectionName = collectionName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract SolrParams getParams() ;
|
||||||
|
|
||||||
|
public abstract Principal getUserPrincipal() ;
|
||||||
|
|
||||||
|
public abstract String getHttpHeader(String header);
|
||||||
|
|
||||||
|
public abstract Enumeration getHeaderNames();
|
||||||
|
|
||||||
|
public abstract List<CollectionRequest> getCollectionRequests() ;
|
||||||
|
|
||||||
|
public abstract RequestType getRequestType();
|
||||||
|
|
||||||
|
public abstract String getResource();
|
||||||
|
|
||||||
|
public enum RequestType {READ, WRITE, ADMIN, UNKNOWN}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.apache.solr.security;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization interface that needs to be implemented to write an authorization
|
||||||
|
* plugin.
|
||||||
|
*/
|
||||||
|
public interface AuthorizationPlugin extends Closeable {
|
||||||
|
AuthorizationResponse authorize(AuthorizationContext context);
|
||||||
|
|
||||||
|
void init(Map<String, Object> initInfo);
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package org.apache.solr.security;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This class currently only stores an int statusCode (HttpStatus) value and a message but can
|
||||||
|
be used to return ACLs and other information from the authorization plugin.
|
||||||
|
*/
|
||||||
|
public class AuthorizationResponse {
|
||||||
|
public final int statusCode;
|
||||||
|
String message;
|
||||||
|
|
||||||
|
public AuthorizationResponse(int httpStatusCode) {
|
||||||
|
this.statusCode = httpStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commonly used classes for Solr security framework.
|
||||||
|
*/
|
||||||
|
package org.apache.solr.security;
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.Principal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -42,6 +43,7 @@ import org.apache.http.HeaderIterator;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpEntityEnclosingRequest;
|
import org.apache.http.HttpEntityEnclosingRequest;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
@ -79,16 +81,26 @@ import org.apache.solr.request.SolrRequestInfo;
|
||||||
import org.apache.solr.response.QueryResponseWriter;
|
import org.apache.solr.response.QueryResponseWriter;
|
||||||
import org.apache.solr.response.QueryResponseWriterUtil;
|
import org.apache.solr.response.QueryResponseWriterUtil;
|
||||||
import org.apache.solr.response.SolrQueryResponse;
|
import org.apache.solr.response.SolrQueryResponse;
|
||||||
|
import org.apache.solr.security.AuthorizationContext;
|
||||||
|
import org.apache.solr.security.AuthorizationContext.CollectionRequest;
|
||||||
|
import org.apache.solr.security.AuthorizationContext.RequestType;
|
||||||
|
import org.apache.solr.security.AuthorizationResponse;
|
||||||
import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
|
import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
|
||||||
import org.apache.solr.servlet.cache.Method;
|
import org.apache.solr.servlet.cache.Method;
|
||||||
import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
|
import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
|
||||||
import org.apache.solr.util.RTimer;
|
import org.apache.solr.util.RTimer;
|
||||||
import org.apache.zookeeper.KeeperException;
|
import org.apache.zookeeper.KeeperException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
|
import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
|
||||||
|
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||||
import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
|
import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
|
||||||
import static org.apache.solr.common.cloud.ZkStateReader.NODE_NAME_PROP;
|
import static org.apache.solr.common.cloud.ZkStateReader.NODE_NAME_PROP;
|
||||||
|
import static org.apache.solr.common.params.CollectionParams.CollectionAction.CREATE;
|
||||||
|
import static org.apache.solr.common.params.CollectionParams.CollectionAction.DELETE;
|
||||||
|
import static org.apache.solr.common.params.CollectionParams.CollectionAction.RELOAD;
|
||||||
import static org.apache.solr.servlet.SolrDispatchFilter.Action;
|
import static org.apache.solr.servlet.SolrDispatchFilter.Action;
|
||||||
import static org.apache.solr.servlet.SolrDispatchFilter.Action.ADMIN;
|
import static org.apache.solr.servlet.SolrDispatchFilter.Action.ADMIN;
|
||||||
import static org.apache.solr.servlet.SolrDispatchFilter.Action.FORWARD;
|
import static org.apache.solr.servlet.SolrDispatchFilter.Action.FORWARD;
|
||||||
|
@ -101,7 +113,9 @@ import static org.apache.solr.servlet.SolrDispatchFilter.Action.RETURN;
|
||||||
/**
|
/**
|
||||||
* This class represents a call made to Solr
|
* This class represents a call made to Solr
|
||||||
**/
|
**/
|
||||||
class HttpSolrCall {
|
public class HttpSolrCall {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(HttpSolrCall.class);
|
||||||
|
|
||||||
private final SolrDispatchFilter solrDispatchFilter;
|
private final SolrDispatchFilter solrDispatchFilter;
|
||||||
private final CoreContainer cores;
|
private final CoreContainer cores;
|
||||||
private final HttpServletRequest req;
|
private final HttpServletRequest req;
|
||||||
|
@ -117,6 +131,19 @@ class HttpSolrCall {
|
||||||
private SolrConfig config;
|
private SolrConfig config;
|
||||||
private Map<String, Integer> invalidStates;
|
private Map<String, Integer> invalidStates;
|
||||||
|
|
||||||
|
public RequestType getRequestType() {
|
||||||
|
return requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestType requestType;
|
||||||
|
|
||||||
|
|
||||||
|
public List<String> getCollectionsList() {
|
||||||
|
return collectionsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> collectionsList;
|
||||||
|
|
||||||
HttpSolrCall(SolrDispatchFilter solrDispatchFilter, CoreContainer cores,
|
HttpSolrCall(SolrDispatchFilter solrDispatchFilter, CoreContainer cores,
|
||||||
HttpServletRequest request, HttpServletResponse response, boolean retry) {
|
HttpServletRequest request, HttpServletResponse response, boolean retry) {
|
||||||
this.solrDispatchFilter = solrDispatchFilter;
|
this.solrDispatchFilter = solrDispatchFilter;
|
||||||
|
@ -124,6 +151,7 @@ class HttpSolrCall {
|
||||||
this.req = request;
|
this.req = request;
|
||||||
this.response = response;
|
this.response = response;
|
||||||
this.retry = retry;
|
this.retry = retry;
|
||||||
|
this.requestType = RequestType.UNKNOWN;
|
||||||
queryParams = SolrRequestParsers.parseQueryString(req.getQueryString());
|
queryParams = SolrRequestParsers.parseQueryString(req.getQueryString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +159,20 @@ class HttpSolrCall {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setContext() throws Exception {
|
|
||||||
|
public HttpServletRequest getReq() {
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolrCore getCore() {
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolrParams getQueryParams() {
|
||||||
|
return queryParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() throws Exception {
|
||||||
//The states of client that is invalid in this request
|
//The states of client that is invalid in this request
|
||||||
Aliases aliases = null;
|
Aliases aliases = null;
|
||||||
String corename = "";
|
String corename = "";
|
||||||
|
@ -158,13 +199,13 @@ class HttpSolrCall {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean usingAliases = false;
|
boolean usingAliases = false;
|
||||||
List<String> collectionsList = null;
|
|
||||||
|
|
||||||
// Check for container handlers
|
// Check for container handlers
|
||||||
handler = cores.getRequestHandler(path);
|
handler = cores.getRequestHandler(path);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
solrReq = SolrRequestParsers.DEFAULT.parse(null, path, req);
|
solrReq = SolrRequestParsers.DEFAULT.parse(null, path, req);
|
||||||
solrReq.getContext().put(CoreContainer.class.getName(), cores);
|
solrReq.getContext().put(CoreContainer.class.getName(), cores);
|
||||||
|
requestType = RequestType.ADMIN;
|
||||||
action = ADMIN;
|
action = ADMIN;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -210,6 +251,9 @@ class HttpSolrCall {
|
||||||
// we found a core, update the path
|
// we found a core, update the path
|
||||||
path = path.substring(idx);
|
path = path.substring(idx);
|
||||||
addMDCValues();
|
addMDCValues();
|
||||||
|
if (collectionsList == null)
|
||||||
|
collectionsList = new ArrayList<>();
|
||||||
|
collectionsList.add(corename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we couldn't find it locally, look on other nodes
|
// if we couldn't find it locally, look on other nodes
|
||||||
|
@ -351,8 +395,28 @@ class HttpSolrCall {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setContext();
|
init();
|
||||||
|
/* Authorize the request if
|
||||||
|
1. Authorization is enabled, and
|
||||||
|
2. The requested resource is not a known static file
|
||||||
|
*/
|
||||||
|
// TODO: There should be a better way to ignore the static files.
|
||||||
|
if (cores.getAuthorizationPlugin() != null &&
|
||||||
|
!(req.getRequestURI().endsWith(".html")
|
||||||
|
|| req.getRequestURI().endsWith(".png")
|
||||||
|
|| req.getRequestURI().endsWith(".ico")
|
||||||
|
|| req.getRequestURI().endsWith(".css")
|
||||||
|
)) {
|
||||||
|
AuthorizationContext context = getAuthCtx();
|
||||||
|
log.info(context.toString());
|
||||||
|
AuthorizationResponse authResponse = cores.getAuthorizationPlugin().authorize(context);
|
||||||
|
if (!(authResponse.statusCode == HttpStatus.SC_ACCEPTED) && !(authResponse.statusCode == HttpStatus.SC_OK)) {
|
||||||
|
sendError(authResponse.statusCode,
|
||||||
|
"Unauthorized request, Response code: " + authResponse.statusCode);
|
||||||
|
return RETURN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HttpServletResponse resp = response;
|
HttpServletResponse resp = response;
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ADMIN:
|
case ADMIN:
|
||||||
|
@ -593,7 +657,7 @@ class HttpSolrCall {
|
||||||
|
|
||||||
private void processAliases(Aliases aliases,
|
private void processAliases(Aliases aliases,
|
||||||
List<String> collectionsList) {
|
List<String> collectionsList) {
|
||||||
String collection = solrReq.getParams().get("collection");
|
String collection = solrReq.getParams().get(COLLECTION_PROP);
|
||||||
if (collection != null) {
|
if (collection != null) {
|
||||||
collectionsList = StrUtils.splitSmart(collection, ",", true);
|
collectionsList = StrUtils.splitSmart(collection, ",", true);
|
||||||
}
|
}
|
||||||
|
@ -621,7 +685,7 @@ class HttpSolrCall {
|
||||||
}
|
}
|
||||||
ModifiableSolrParams params = new ModifiableSolrParams(
|
ModifiableSolrParams params = new ModifiableSolrParams(
|
||||||
solrReq.getParams());
|
solrReq.getParams());
|
||||||
params.set("collection", collectionString.toString());
|
params.set(COLLECTION_PROP, collectionString.toString());
|
||||||
solrReq.setParams(params);
|
solrReq.setParams(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -760,6 +824,10 @@ class HttpSolrCall {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (collectionsList == null)
|
||||||
|
collectionsList = new ArrayList<>();
|
||||||
|
|
||||||
|
collectionsList.add(collectionName);
|
||||||
String coreUrl = getCoreUrl(collectionName, origCorename, clusterState,
|
String coreUrl = getCoreUrl(collectionName, origCorename, clusterState,
|
||||||
slices, byCoreName, true);
|
slices, byCoreName, true);
|
||||||
|
|
||||||
|
@ -807,6 +875,105 @@ class HttpSolrCall {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AuthorizationContext getAuthCtx() {
|
||||||
|
|
||||||
|
String resource = getPath();
|
||||||
|
|
||||||
|
SolrParams params = getQueryParams();
|
||||||
|
final ArrayList<CollectionRequest> collectionRequests = new ArrayList<>();
|
||||||
|
if (getCollectionsList() != null) {
|
||||||
|
for (String collection : getCollectionsList()) {
|
||||||
|
collectionRequests.add(new CollectionRequest(collection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract collection name from the params in case of a Collection Admin request
|
||||||
|
if (getPath().equals("/admin/collections")) {
|
||||||
|
if (CREATE.isEqual(params.get("action"))||
|
||||||
|
RELOAD.isEqual(params.get("action"))||
|
||||||
|
DELETE.isEqual(params.get("action")))
|
||||||
|
collectionRequests.add(new CollectionRequest(params.get("name")));
|
||||||
|
else if (params.get(COLLECTION_PROP) != null)
|
||||||
|
collectionRequests.add(new CollectionRequest(params.get(COLLECTION_PROP)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the case when it's a /select request and collections are specified as a param
|
||||||
|
if(resource.equals("/select") && params.get("collection") != null) {
|
||||||
|
collectionRequests.clear();
|
||||||
|
for(String collection:params.get("collection").split(",")) {
|
||||||
|
collectionRequests.add(new CollectionRequest(collection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the request type if the request is select or update
|
||||||
|
if(requestType == RequestType.UNKNOWN) {
|
||||||
|
if(resource.startsWith("/select"))
|
||||||
|
requestType = RequestType.READ;
|
||||||
|
if(resource.startsWith("/update"))
|
||||||
|
requestType = RequestType.WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no collection explicitly mentioned, let's try and extract it from the core if one exists for
|
||||||
|
// the purpose of processing this request.
|
||||||
|
if (getCore() != null && (getCollectionsList() == null || getCollectionsList().size() == 0)) {
|
||||||
|
collectionRequests.add(new CollectionRequest(getCore().getCoreDescriptor().getCollectionName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getQueryParams().get(COLLECTION_PROP) != null)
|
||||||
|
collectionRequests.add(new CollectionRequest(getQueryParams().get(COLLECTION_PROP)));
|
||||||
|
|
||||||
|
return new AuthorizationContext() {
|
||||||
|
@Override
|
||||||
|
public SolrParams getParams() {
|
||||||
|
return getQueryParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Principal getUserPrincipal() {
|
||||||
|
return getReq().getUserPrincipal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHttpHeader(String s) {
|
||||||
|
return getReq().getHeader(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration getHeaderNames() {
|
||||||
|
return getReq().getHeaderNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CollectionRequest> getCollectionRequests() {
|
||||||
|
return collectionRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestType getRequestType() {
|
||||||
|
return requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResource() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder response = new StringBuilder("userPrincipal: [").append(getUserPrincipal()).append("]")
|
||||||
|
.append(" type: [").append(requestType.toString()).append("], collections: [");
|
||||||
|
for (CollectionRequest collectionRequest : collectionRequests) {
|
||||||
|
response.append(collectionRequest.collectionName).append(", ");
|
||||||
|
}
|
||||||
|
if(collectionRequests.size() > 0)
|
||||||
|
response.delete(response.length() - 1, response.length());
|
||||||
|
|
||||||
|
response.append("], Path: [").append(resource).append("]");
|
||||||
|
return response.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static final String CONNECTION_HEADER = "Connection";
|
static final String CONNECTION_HEADER = "Connection";
|
||||||
static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
|
static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
|
||||||
static final String CONTENT_LENGTH_HEADER = "Content-Length";
|
static final String CONTENT_LENGTH_HEADER = "Content-Length";
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.apache.solr.security;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class MockAuthorizationPlugin implements AuthorizationPlugin{
|
||||||
|
|
||||||
|
private Logger log = LoggerFactory.getLogger(MockAuthorizationPlugin.class);
|
||||||
|
HashSet<String> denyUsers;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthorizationResponse authorize(AuthorizationContext context) {
|
||||||
|
log.info("User request: " + context.getParams().get("uname"));
|
||||||
|
if(denyUsers.contains(context.getParams().get("uname")))
|
||||||
|
return new AuthorizationResponse(403);
|
||||||
|
else
|
||||||
|
return new AuthorizationResponse(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Map<String, Object> initInfo) {
|
||||||
|
denyUsers = new HashSet();
|
||||||
|
denyUsers.add("user1");
|
||||||
|
denyUsers.add("user2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package org.apache.solr.security;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.io.Charsets;
|
||||||
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
|
import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
|
||||||
|
import org.apache.solr.common.cloud.ZkStateReader;
|
||||||
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@LuceneTestCase.Slow
|
||||||
|
public class TestAuthorizationFramework extends AbstractFullDistribZkTestBase {
|
||||||
|
final private Logger log = LoggerFactory.getLogger(TestAuthorizationFramework.class);
|
||||||
|
|
||||||
|
static final int TIMEOUT = 10000;
|
||||||
|
|
||||||
|
public void distribSetUp() throws Exception {
|
||||||
|
super.distribSetUp();
|
||||||
|
try (ZkStateReader zkStateReader = new ZkStateReader(zkServer.getZkAddress(),
|
||||||
|
TIMEOUT, TIMEOUT)) {
|
||||||
|
zkStateReader.getZkClient().create(ZkStateReader.SOLR_SECURITY_CONF_PATH,
|
||||||
|
"{\"authorization\":{\"class\":\"org.apache.solr.security.MockAuthorizationPlugin\"}}".getBytes(Charsets.UTF_8),
|
||||||
|
CreateMode.PERSISTENT, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void authorizationFrameworkTest() throws Exception {
|
||||||
|
waitForThingsToLevelOut(10);
|
||||||
|
log.info("Starting test");
|
||||||
|
ModifiableSolrParams params = new ModifiableSolrParams();
|
||||||
|
params.add("q", "*:*");
|
||||||
|
// This should work fine.
|
||||||
|
cloudClient.query(params);
|
||||||
|
|
||||||
|
// This user is blacklisted in the mock. The request should return a 403.
|
||||||
|
params.add("uname", "user1");
|
||||||
|
try {
|
||||||
|
cloudClient.query(params);
|
||||||
|
fail("This should have failed");
|
||||||
|
} catch (Exception e) {}
|
||||||
|
log.info("Ending test");
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,7 @@ public class ZkStateReader implements Closeable {
|
||||||
public static final String CLUSTER_STATE = "/clusterstate.json";
|
public static final String CLUSTER_STATE = "/clusterstate.json";
|
||||||
public static final String CLUSTER_PROPS = "/clusterprops.json";
|
public static final String CLUSTER_PROPS = "/clusterprops.json";
|
||||||
public static final String REJOIN_AT_HEAD_PROP = "rejoinAtHead";
|
public static final String REJOIN_AT_HEAD_PROP = "rejoinAtHead";
|
||||||
|
public static final String SOLR_SECURITY_CONF_PATH = "/security.json";
|
||||||
|
|
||||||
public static final String REPLICATION_FACTOR = "replicationFactor";
|
public static final String REPLICATION_FACTOR = "replicationFactor";
|
||||||
public static final String MAX_SHARDS_PER_NODE = "maxShardsPerNode";
|
public static final String MAX_SHARDS_PER_NODE = "maxShardsPerNode";
|
||||||
|
@ -830,6 +831,23 @@ public class ZkStateReader implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of /security.json from ZooKeeper as a Map
|
||||||
|
* If the files doesn't exist, it returns null.
|
||||||
|
*/
|
||||||
|
public Map getSecurityProps() {
|
||||||
|
try {
|
||||||
|
if(getZkClient().exists(SOLR_SECURITY_CONF_PATH, true)) {
|
||||||
|
return (Map) ZkStateReader.fromJSON(getZkClient()
|
||||||
|
.getData(ZkStateReader.SOLR_SECURITY_CONF_PATH, null, new Stat(), true)) ;
|
||||||
|
}
|
||||||
|
} catch (KeeperException | InterruptedException e) {
|
||||||
|
throw new SolrException(ErrorCode.SERVER_ERROR,"Error reading security properties",e) ;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the baseURL corresponding to a given node's nodeName --
|
* Returns the baseURL corresponding to a given node's nodeName --
|
||||||
* NOTE: does not (currently) imply that the nodeName (or resulting
|
* NOTE: does not (currently) imply that the nodeName (or resulting
|
||||||
|
|
Loading…
Reference in New Issue