mirror of https://github.com/apache/lucene.git
SOLR-13649 change the default behavior of the basic authentication plugin. (#805)
SOLR-13649: Property 'blockUnknown' of BasicAuthPlugin and JWTAuthPlugin now defaults to 'true'. This change is backward incompatible. To achieve the previous default behavior, explicitly set 'blockUnknown':'false' in security.json
This commit is contained in:
parent
a8d5bd34bf
commit
b37d92bfee
|
@ -57,6 +57,10 @@ Upgrade Notes
|
|||
|
||||
* SOLR-13596: Deprecated GroupingSpecification methods are removed. (Munendra S N)
|
||||
|
||||
* SOLR-13649: Property 'blockUnknown' of BasicAuthPlugin and JWTAuthPlugin now defaults to 'true'. This change is backward
|
||||
incompatible. To achieve the previous default behavior, explicitly set 'blockUnknown':'false' in security.json
|
||||
(marcussorealheis, janhoy, shalin)
|
||||
|
||||
* SOLR-11266: default Content-Type override for JSONResponseWriter from _default configSet is removed. Example has been
|
||||
provided in sample_techproducts_configs to override content-type. (Ishan Chattopadhyaya, Munendra S N, Gus Heck)
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class BasicAuthPlugin extends AuthenticationPlugin implements ConfigEdita
|
|||
private AuthenticationProvider authenticationProvider;
|
||||
private final static ThreadLocal<Header> authHeader = new ThreadLocal<>();
|
||||
private static final String X_REQUESTED_WITH_HEADER = "X-Requested-With";
|
||||
private boolean blockUnknown = false;
|
||||
private boolean blockUnknown = true;
|
||||
private boolean forwardCredentials = false;
|
||||
|
||||
public boolean authenticate(String username, String pwd) {
|
||||
|
|
|
@ -40,6 +40,8 @@ import org.slf4j.LoggerFactory;
|
|||
import static org.apache.solr.handler.admin.SecurityConfHandler.getMapValue;
|
||||
|
||||
public class Sha256AuthenticationProvider implements ConfigEditablePlugin, BasicAuthPlugin.AuthenticationProvider {
|
||||
|
||||
static String CANNOT_DELETE_LAST_USER_ERROR = "You cannot delete the last user. At least one user must be configured at all times.";
|
||||
private Map<String, String> credentials;
|
||||
private String realm;
|
||||
private Map<String, String> promptHeader;
|
||||
|
@ -73,9 +75,8 @@ public class Sha256AuthenticationProvider implements ConfigEditablePlugin, Basi
|
|||
promptHeader = Collections.unmodifiableMap(Collections.singletonMap("WWW-Authenticate", "Basic realm=\"" + realm + "\""));
|
||||
credentials = new LinkedHashMap<>();
|
||||
Map<String,String> users = (Map<String,String>) pluginConfig.get("credentials");
|
||||
if (users == null) {
|
||||
log.debug("No users configured yet");
|
||||
return;
|
||||
if (users == null || users.isEmpty()) {
|
||||
throw new IllegalStateException("No users configured yet. At least one user must be configured in security.json");
|
||||
}
|
||||
for (Map.Entry<String, String> e : users.entrySet()) {
|
||||
String v = e.getValue();
|
||||
|
@ -142,7 +143,15 @@ public class Sha256AuthenticationProvider implements ConfigEditablePlugin, Basi
|
|||
cmd.addError("No such user(s) " +names );
|
||||
return null;
|
||||
}
|
||||
for (String name : names) map.remove(name);
|
||||
for (String name : names) {
|
||||
if (map.containsKey(name)) {
|
||||
if (map.size() == 1){
|
||||
cmd.addError(CANNOT_DELETE_LAST_USER_ERROR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
map.remove(name);
|
||||
}
|
||||
return latestConf;
|
||||
}
|
||||
if ("set-user".equals(cmd.name) ) {
|
||||
|
|
|
@ -4414,7 +4414,7 @@ public class SolrCLI implements CLIO {
|
|||
password = new String(console.readPassword("Enter password: "));
|
||||
}
|
||||
|
||||
boolean blockUnknown = Boolean.valueOf(cli.getOptionValue("blockUnknown", "false"));
|
||||
boolean blockUnknown = Boolean.valueOf(cli.getOptionValue("blockUnknown", "true"));
|
||||
|
||||
String securityJson = "{" +
|
||||
"\n \"authentication\":{" +
|
||||
|
|
|
@ -383,6 +383,7 @@ public class TestConfigSetsAPI extends SolrTestCaseJ4 {
|
|||
String securityJson = "{\n" +
|
||||
" 'authentication':{\n" +
|
||||
" 'class':'solr.BasicAuthPlugin',\n" +
|
||||
" 'blockUnknown': false,\n" +
|
||||
" 'credentials':{'solr':'orwp2Ghgj39lmnrZOTm7Qtre1VqHFDfwAEzr0ApbN3Y= Ju5osoAqOX8iafhWpPP01E5P+sg8tK8tHON7rCYZRRw='}},\n" +
|
||||
" 'authorization':{\n" +
|
||||
" 'class':'solr.RuleBasedAuthorizationPlugin',\n" +
|
||||
|
|
|
@ -24,13 +24,13 @@ import java.util.Map;
|
|||
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
import org.apache.solr.common.util.CommandOperation;
|
||||
import org.apache.solr.common.util.ContentStreamBase;
|
||||
import org.apache.solr.common.util.Utils;
|
||||
import org.apache.solr.request.LocalSolrQueryRequest;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.security.BasicAuthPlugin;
|
||||
import org.apache.solr.security.RuleBasedAuthorizationPlugin;
|
||||
import org.apache.solr.common.util.CommandOperation;
|
||||
|
||||
import static org.apache.solr.common.util.Utils.makeMap;
|
||||
import static org.apache.solr.handler.admin.SecurityConfHandler.SecurityConfig;
|
||||
|
@ -55,10 +55,9 @@ public class SecurityConfHandlerTest extends SolrTestCaseJ4 {
|
|||
basicAuth.init((Map<String, Object>) securityCfg.getData().get("authentication"));
|
||||
assertTrue(basicAuth.authenticate("tom", "TomIsUberCool"));
|
||||
|
||||
|
||||
command = "{\n" +
|
||||
"'set-user': {'harry':'HarryIsCool'},\n" +
|
||||
"'delete-user': ['tom','harry']\n" +
|
||||
"'delete-user': ['tom']\n" +
|
||||
"}";
|
||||
o = new ContentStreamBase.ByteArrayStream(command.getBytes(StandardCharsets.UTF_8), "");
|
||||
req.setContentStreams(Collections.singletonList(o));
|
||||
|
@ -67,7 +66,7 @@ public class SecurityConfHandlerTest extends SolrTestCaseJ4 {
|
|||
assertEquals(3, securityCfg.getVersion());
|
||||
Map result = (Map) securityCfg.getData().get("authentication");
|
||||
result = (Map) result.get("credentials");
|
||||
assertTrue(result.isEmpty());
|
||||
assertEquals(1,result.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,7 +193,7 @@ public class SecurityConfHandlerTest extends SolrTestCaseJ4 {
|
|||
sp.getData().put("authorization", makeMap("class", "solr."+RuleBasedAuthorizationPlugin.class.getSimpleName()));
|
||||
m.put("/security.json", sp);
|
||||
|
||||
basicAuthPlugin.init(new HashMap<>());
|
||||
basicAuthPlugin.init(Collections.singletonMap("credentials", Collections.singletonMap("ignore", "me")));
|
||||
|
||||
rulesBasedAuthorizationPlugin.init(new HashMap<>());
|
||||
}
|
||||
|
|
|
@ -356,7 +356,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
|
|||
// before returning...
|
||||
final Set<Map.Entry<String,Object>> initialPlugins
|
||||
= getAuthPluginsInUseForCluster(url).entrySet();
|
||||
|
||||
|
||||
HttpPost httpPost;
|
||||
HttpResponse r;
|
||||
httpPost = new HttpPost(url);
|
||||
|
@ -394,6 +394,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
|
|||
//this could be generated everytime. But , then we will not know if there is any regression
|
||||
protected static final String STD_CONF = "{\n" +
|
||||
" 'authentication':{\n" +
|
||||
" 'blockUnknown':'false',\n" +
|
||||
" 'class':'solr.BasicAuthPlugin',\n" +
|
||||
" 'credentials':{'solr':'orwp2Ghgj39lmnrZOTm7Qtre1VqHFDfwAEzr0ApbN3Y= Ju5osoAqOX8iafhWpPP01E5P+sg8tK8tHON7rCYZRRw='}},\n" +
|
||||
" 'authorization':{\n" +
|
||||
|
|
|
@ -17,23 +17,25 @@
|
|||
package org.apache.solr.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.common.util.CommandOperation;
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
public class TestSha256AuthenticationProvider extends SolrTestCaseJ4 {
|
||||
public void testAuthenticate(){
|
||||
Sha256AuthenticationProvider zkAuthenticationProvider = new Sha256AuthenticationProvider();
|
||||
zkAuthenticationProvider.init(Collections.emptyMap());
|
||||
zkAuthenticationProvider.init(createConfigMap("ignore", "me"));
|
||||
|
||||
String pwd = "My#$Password";
|
||||
String user = "noble";
|
||||
Map latestConf = new LinkedHashMap<>();
|
||||
String pwd = "Friendly";
|
||||
String user = "marcus";
|
||||
Map latestConf = createConfigMap(user, pwd);
|
||||
Map<String, Object> params = singletonMap(user, pwd);
|
||||
Map<String, Object> result = zkAuthenticationProvider.edit(latestConf,
|
||||
Collections.singletonList(new CommandOperation("set-user",params )));
|
||||
|
@ -48,9 +50,9 @@ public class TestSha256AuthenticationProvider extends SolrTestCaseJ4 {
|
|||
|
||||
public void testBasicAuthCommands() throws IOException {
|
||||
try (BasicAuthPlugin basicAuthPlugin = new BasicAuthPlugin()) {
|
||||
basicAuthPlugin.init(Collections.emptyMap());
|
||||
basicAuthPlugin.init(createConfigMap("ignore", "me"));
|
||||
|
||||
Map latestConf = new LinkedHashMap<>();
|
||||
Map latestConf = createConfigMap("solr", "SolrRocks");
|
||||
|
||||
CommandOperation blockUnknown = new CommandOperation("set-property", singletonMap("blockUnknown", true));
|
||||
basicAuthPlugin.edit(latestConf, Collections.singletonList(blockUnknown));
|
||||
|
@ -64,4 +66,46 @@ public class TestSha256AuthenticationProvider extends SolrTestCaseJ4 {
|
|||
assertFalse(basicAuthPlugin.getBlockUnknown());
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasicAuthWithCredentials() throws IOException {
|
||||
try (BasicAuthPlugin basicAuthPlugin = new BasicAuthPlugin()) {
|
||||
Map<String, Object> config = createConfigMap("solr", "IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c=");
|
||||
basicAuthPlugin.init(config);
|
||||
assertTrue(basicAuthPlugin.authenticate("solr", "SolrRocks"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testBasicAuthUserNotFound() throws IOException {
|
||||
try (BasicAuthPlugin basicAuthPlugin = new BasicAuthPlugin()) {
|
||||
Map<String, Object> config = createConfigMap(null, null);
|
||||
basicAuthPlugin.init(config);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasicAuthDeleteFinalUser() throws IOException {
|
||||
try (BasicAuthPlugin basicAuthPlugin = new BasicAuthPlugin()) {
|
||||
Map<String, Object> config = createConfigMap("solr", "IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c=");
|
||||
basicAuthPlugin.init(config);
|
||||
assertTrue(basicAuthPlugin.authenticate("solr", "SolrRocks"));
|
||||
|
||||
CommandOperation deleteUser = new CommandOperation("delete-user", "solr");
|
||||
assertFalse(deleteUser.hasError());
|
||||
basicAuthPlugin.edit(config, Arrays.asList(deleteUser));
|
||||
assertTrue(deleteUser.hasError());
|
||||
assertTrue(deleteUser.getErrors().contains(Sha256AuthenticationProvider.CANNOT_DELETE_LAST_USER_ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> createConfigMap(String user, String pw) {
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
Map<String, String> credentials = new HashMap<>();
|
||||
if (user != null) {
|
||||
credentials.put(user, pw);
|
||||
}
|
||||
config.put("credentials", credentials);
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ There are several things defined in this file:
|
|||
|
||||
Save your settings to a file called `security.json` locally. If you are using Solr in standalone mode, you should put this file in `$SOLR_HOME`.
|
||||
|
||||
If `blockUnknown` does not appear in the `security.json` file, it will default to `false`. This has the effect of not requiring authentication at all. In some cases, you may want this; for example, if you want to have `security.json` in place but aren't ready to enable authentication. However, you will want to ensure that this parameter is set to `true` in order for authentication to be truly enabled in your system.
|
||||
If `blockUnknown` does not appear in the `security.json` file, it will default to `true`. This has the effect of requiring authentication for HTTP access to Solr. In some cases, you may not want authentication after enabling the plugin; for example, if you want to have `security.json` in place but aren't ready to enable authentication. However, you will want to ensure that `blockUnknown` is set to `true` or omitted entirely in order for authentication to be enforced for all requests to your system.
|
||||
|
||||
If `realm` is not defined, it will default to `solr`.
|
||||
|
||||
|
|
|
@ -28,12 +28,13 @@ The simplest possible `security.json` for registering the plugin without configu
|
|||
----
|
||||
{
|
||||
"authentication": {
|
||||
"class":"solr.JWTAuthPlugin"
|
||||
"class":"solr.JWTAuthPlugin",
|
||||
"blockUnknown":"false"
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The plugin will NOT block anonymous traffic in this mode, since the default for `blockUnknown` is false. It is then possible to start configuring the plugin using REST API calls, which is described below.
|
||||
The plugin will by default require a valid JWT token for all traffic. If the `blockUnknown` property is set to false as in the above example, it is possible to start configuring the plugin using REST API calls, which is further described below.
|
||||
|
||||
== Configuration Parameters
|
||||
|
||||
|
@ -41,7 +42,7 @@ The plugin will NOT block anonymous traffic in this mode, since the default for
|
|||
[%header,format=csv,separator=;]
|
||||
|===
|
||||
Key ; Description ; Default
|
||||
blockUnknown ; Set to `true` in order to block requests from users without a token ; `false`
|
||||
blockUnknown ; Set to `false` to if you need to perform configuration through REST API or if you use an Authorization Plugin and only want certain paths protected. By default all requests will require a token ; `true`
|
||||
wellKnownUrl ; URL to an https://openid.net/specs/openid-connect-discovery-1_0.html[OpenID Connect Discovery] endpoint ; (no default)
|
||||
clientId ; Client identifier for use with OpenID Connect ; (no default value) Required to authenticate with Admin UI
|
||||
realm ; Name of the authentication realm to echo back in HTTP 401 responses. Will also be displayed in Admin UI login page ; 'solr-jwt'
|
||||
|
@ -70,7 +71,6 @@ To start enforcing authentication for all users, requiring a valid JWT in the `A
|
|||
{
|
||||
"authentication": {
|
||||
"class": "solr.JWTAuthPlugin",
|
||||
"blockUnknown": true,
|
||||
"jwkUrl": "https://my.key.server/jwk.json"
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,6 @@ The next example shows configuring using https://openid.net/specs/openid-connect
|
|||
{
|
||||
"authentication": {
|
||||
"class": "solr.JWTAuthPlugin",
|
||||
"blockUnknown": true,
|
||||
"wellKnownUrl": "https://idp.example.com/.well-known/openid-configuration",
|
||||
"clientId": "xyz",
|
||||
"redirectUri": "https://my.solr.server:8983/solr/"
|
||||
|
@ -123,7 +122,7 @@ Let's look at a more complex configuration, this time with a static embedded JWK
|
|||
Let's comment on this config:
|
||||
|
||||
<1> Plugin class
|
||||
<2> Make sure to block anyone without a valid token
|
||||
<2> Make sure to block anyone without a valid token (this is also the default)
|
||||
<3> Here we pass the JWK inline instead of referring to a URL with `jwkUrl`
|
||||
<4> Set the client id registered with Identity Provider
|
||||
<5> The issuer claim must match "https://example.com/idp"
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
= Major Changes in Solr 9
|
||||
:page-tocclass: right
|
||||
// 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.
|
||||
|
||||
Solr 9.0 is a major new release of Solr.
|
||||
|
||||
This page highlights the biggest changes, including new features you may want to be aware of, and changes in default behavior and deprecated features that have been removed.
|
||||
|
||||
== Solr 9 Upgrade Planning
|
||||
|
||||
Before staring an upgrade to Solr 9, please take the time to review all information about changes from the version you are currently on up to Solr 9.
|
||||
|
||||
You should also consider all changes that have been made to Solr in any version you have not upgraded to already. For example, if you are currently using Solr 8.1, you should review changes made in all subsequent 8.x releases in addition to changes for 9.0.
|
||||
|
||||
A thorough review of the list in Major Changes in Earlier 8.x Versions as well as the {solr-javadocs}/changes/Changes.html[CHANGES.txt] in your Solr instance will help you plan your migration to Solr 9.
|
||||
|
||||
=== Upgrade Prerequisites in Solr 9
|
||||
|
||||
=== Rolling Upgrades with Solr 9
|
||||
|
||||
=== Reindexing After Upgrades in Solr 9
|
||||
|
||||
== New Features & Enhancements in Solr 9
|
||||
|
||||
== Configuration and Default Parameter Changes in Solr 9
|
||||
|
||||
=== Schema Changes in 9
|
||||
|
||||
=== Authentication & Security Changes in Solr 9
|
||||
|
||||
* BasicAuthPlugin property 'blockUnknown' now defaults to 'true'. This change is backward incompatible. If you need the pre-9.0 default behavior, you need to explicitly set 'blockUnknown':'false' in security.json.
|
|
@ -559,7 +559,7 @@ If prompt is preferred, pass *true* as a parameter to request the script to prom
|
|||
Either `-credentials` or `-prompt` *must* be specified.
|
||||
|
||||
`-blockUnknown`::
|
||||
When *true*, blocks all unauthenticated users from accessing Solr. This defaults to *false*, which means unauthenticated users will still be able to access Solr.
|
||||
When *true*, blocks all unauthenticated users from accessing Solr. When *false*,unauthenticated users will still be able to access Solr, but only for operations not explicitly requiring a user role in the Authorization plugin configuration.
|
||||
|
||||
`-updateIncludeFileOnly`::
|
||||
When *true*, only the settings in `bin/solr.in.sh` or `bin\solr.in.cmd` will be updated, and `security.json` will not be created.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
= Solr Upgrade Notes
|
||||
:page-children: major-changes-in-solr-8, major-changes-in-solr-7, major-changes-from-solr-5-to-solr-6
|
||||
:page-children: major-changes-in-solr-9, major-changes-in-solr-8, major-changes-in-solr-7, major-changes-from-solr-5-to-solr-6
|
||||
:page-toclevels: 3
|
||||
:page-tocclass: right
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
|
|
Loading…
Reference in New Issue