lucene-solr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <>
Subject [Solr Wiki] Update of "SolrSecurity" by Per Steffensen
Date Wed, 06 Mar 2013 15:04:59 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Solr Wiki" for change notification.

The "SolrSecurity" page has been changed by Per Steffensen:

  /!\ NOTE: Solr provides access to request handlers through a general purpose /select?qt=request_handler_name
URL.  Prior to [[Solr1.4]] (via SOLR-1233), request handlers named with a leading forward-slash
like /select?qt=/request_handler_name could not be used, but had to be requested using /request_handler_name.
 [[Solr1.4]] removed the forward-slash restriction and allows /select to work with any request
handler name.  Externally blocking access to /select is recommended in environments where
only path-based access to request handlers is warranted.
- When using patch based authentication, you will most likely want to configure your HTTP
client code to use [[|Preemptive
+ When using patch based authentication, you will most likely want to configure your HTTP
client code to use [[|Preemptive
Authentication]]. With [[|SOLR-4470]] preemptive
authentication will be used by default, but it can be turned off on a per-request basis by
doing the following to your SolrRequest before using it
+ {{{
+ solrRequest.setPreemptiveAuthentication(false);
+ }}}
+ With [[|SOLR-4470]] preemptive authentication
works for POST requests - it did not before.
+ === Common servlet container example ===
+ Add this inside <web-app ..> in WEB-INF/web.xml inside solr.war (or for Jetty to /example/etc/webdefault.xml
+ {{{
+   <security-constraint>
+     <web-resource-collection>
+       <web-resource-name>Solr authenticated application</web-resource-name>
+       <url-pattern>/core1/*</url-pattern>
+     </web-resource-collection>
+     <auth-constraint>
+       <role-name>core1-role</role-name>
+     </auth-constraint>
+   </security-constraint>
+   <login-config>
+     <auth-method>BASIC</auth-method>
+     <realm-name>Test Realm</realm-name>
+   </login-config>
+ }}}
+ This is standardized for all servlet containers and will set up security with the following
+ * Authentication: You have to authenticate to access any path starting with "/core1/". Other
paths can be accessed without authenticating. Authentication will have to be performed against
a "realm" called "Test Realm". The "realm" will verify credentials
+ * Authorization: The configuration above also states that you will actually have to be part
of the "role" "core1-role" in order to be authorized for "/core1/" paths. The "realm" will
also, in case credentials where verified successfully, provide a set of "roles" that the authenticated
user is part of.
+ Unfortunately it has not been standardized how to actually set up a "realm" in a servlet
container, so its different from servlet container to servlet container.
- === Jetty example ===
+ === Jetty realm example ===
- For the most basic authentication, edit jetty.xml, webdefault.xml and add to
+ Edit jetty.xml
  In Jetty 6 Add / uncomment this section in /example/etc/jetty.xml
@@ -93, +123 @@

- Add this inside <web-app ..> to /example/etc/webdefault.xml
+ /example/etc/
+ {{{
+ guest: guest, core1-role
+ }}}
+ === Security for inter-solr-node requests ===
+ Without [[|SOLR-4470]], in a cluster/cloud/distributed
installation with several solr-nodes communicating internally, in practice you would not be
able to add security constraint on most paths, because inter-solr-node communication (potentially)
involves requests to most paths, and solr-nodes where not able to provide credentials in those
internal solr-to-solr requests. [[|SOLR-4470]]
introduces this ability. Basically there are two strategies for credentials to be used in
solr-to-solr requests
+ * 1) Just forward credentials from the "super"-request which caused the inter-solr-node
+ * 2) Use "internal credentials" provided to the solr-node by the administrator at startup
+ Using 1) is the most correct way, because it prevent request from "the outside" to indirectly
trigger successful inter-solr-node sub-requests that the user sending the "outside request"
is not allowed to perform directly himself. Therefore 1) should be used whenever feasible.
But there are cases where inter-solr-node requests are not a direct reaction to requests coming
from "the outside" - e.g. requests around shard-synchronization. In such cases 2) will have
to be used - you have no other credentials to use, and you certainly (potentially) want to
be able to protect e.g. shard-synchronization paths. There are also border-cases like e.g.
when a request from "the outside" triggers inter-solr-node requests to be issued asynchronously
- e.g. when a request from "the outside" to the Collections API makes the Overseer send inter-solr-node
request to the CoreAdmin API. In such case 1) ought to be used, but that would require to
persist the credentials from the original request and reuse them when sub-request to CoreAdmin
API is eventually performed. The current implementation in [[|SOLR-4470]]
just uses 2) in such cases.
+ With [[|SOLR-4470]] only "basic http authentication"
is supported, even though the code has been prepared for also supporting other kinds of authentication.
+ To provide 2) to the solr-node at startup you have to add a few VM-params
+ {{{
+ java -jar ... -DinternalAuthCredentialsBasicAuthUsername=<username> -DinternalAuthCredentialsBasicAuthPassword=<password>
... start.jar
+ }}}
+ === Providing credentials in requests ===
+ Basically "basic http authentication" requires you to add a header on the following form
to your request
+ {{{
+ Authorization:Basic <base64 encoding of "<username>:<password>">
+ }}}
+ Fortunately misc tools help you do this
+ ==== SolrJ ====
+ Before [[|SOLR-4470]] SolrJ only supports
setting up credentials on SolrServer/HttpClient level - credentials being used for all requests
issued through this SolrServer/HttpClient. Basically you need to get hold of the HttpClient
used and set it up. E.g. for a CloudSolrServer instance
+ {{{
+ HttpClientUtil.setBasicAuth(cloudSolrServer.getLbServer().getHttpClient(), <username>,
+ }}}
+ With [[|SOLR-4470]] this has changed a little,
because a class AuthCredentials encapsulating the abstract concept of credentials was introduced
+ {{{
+ HttpClientUtil.setAuthCredentials(cloudSolrServer.getLbServer().getHttpClient(), AuthCredentials.createBasicAuthCredentials(<username>,
+ }}}
+ With [[|SOLR-4470]] you are also able to
provide credentials on request level, so that you can use different credentials in different
requests issued through one and the same SolrServer/HttpClient. Just set the credentials on
the SolrRequest before using it (it will override credentials on SolrServer/HttpClient level
if set)
+ {{{
+ solrRequest.setAuthCredentials(AuthCredentials.createBasicAuthCredentials(<username>,
+ }}}
+ ==== curl and base64 on linux ====
+ Believe something like this will work
+ {{{
+ BASE64_CREDENTIALS=$(echo -n "<username>:<password>" | base64)
+ curl -i --header "Authorization:Basic ${BASE64_CREDENTIALS}" <url>
+ }}}
+ ==== javascript (using jquery and jquery-base64) ====
+ This shows how to base64 encode the "<username>:<password>" with jquery and
jquery-base64. How to easily include the credentials in actual requests issued by jquery is
+ {{{
+ <html>                                                                  
+     <head>                                                            
+         <script type="text/javascript" src=""></script>
+         <script type="text/javascript" src=""></script>
+         <script type="text/javascript">
+             $(document).ready(function() {
+                 alert( $.base64.encode( "<username>:<password>" ) );
+             });
+         </script>
+     </head>
+     <body>
+         Javascript base64 encoding test
+     </body>
+ </html>
+ }}}
+ You might want to download jquery-x.y.z.js and jquery.base64.js to be provided by your own
web-application, instead of depending on them always being available from
and :-)
+ === Security in Solr on per-operation basis ===
+ Due to limitations on "url-pattern"'s in web.xml and the structure of URLs in Solr, it is
hard to set up path based authentication on per-type-of-operation basis
+ * url-pattern limitations: Wildcards are only allowed "in the end" (e.g. "/core1/*") or
as "extension patterns" (e.g. "*.jsp" - the . is required)
+ * Solr URL-structure: Solr URLs are structured as <core-or-collection-name>/<operation>
(e.g. /core1/update)
+ Those facts makes it easy to set up path based authentication on per-collection/core basis.
E.g. url-pattern "/core1/*" matchs all operations on core1. On the other hand, it makes it
hard to set up path based authentication on operation basis. Lets say you want a url-pattern
matching "updates" but across all cores/collections, you cannot just use url-pattern "/solr/*/update",
"*/update" or "*update" - its not allowed in url-patterns. Different servlet containers provide
different solutions to this problem, but [[|SOLR-4470]]
also provides a solution as part of solr itself.
+ The solution is provided in
This is a normal filter that can be used to handle the authorization part of security, still
leaving authentication to the servlet container (web.xml).
+ So lets set up web.xml to make the servlet container handle authentication only (basically
letting every authenticated user access any path)
        <web-resource-name>Solr authenticated application</web-resource-name>
-       <url-pattern>/core1/*</url-pattern>
+       <url-pattern>/*</url-pattern>
-       <role-name>core1-role</role-name>
+       <role-name>*</role-name>
@@ -110, +224 @@

      <realm-name>Test Realm</realm-name>
+ In practice you probably want to replace the "<role-name>*</role-name>" line
with several lines on the form "<role-name>some_concrete_role</role-name>" - one
for each actual role your realm will ever "talk about". This is because some servlet containers
(including jetty v8) do not work properly with *.
- /example/etc/
+ Now lets set up RegExpAuthorizationFilter to do the authorization. Insert this filter '''AS
THE FIRST''' filter in the WEB-INF/web.xml inside solr.war.
- guest: guest, core1-role
+ <filter>
+   <filter-name>RegExpAuthorizationFilter</filter-name>
+   <filter-class>org.apache.solr.servlet.RegExpAuthorizationFilter</filter-class>
+   <init-param>
+     <param-name>search-constraint</param-name>
+     <param-value>1|update-role,admin-role|^.*/update$</param-value>
+   </init-param>
+   <init-param>
+     <param-name>admin-constraint</param-name>
+     <param-value>2|admin-role|^.*$</param-value>
+   </init-param>
+ </filter>
+ <filter-mapping>
+   <filter-name>RegExpAuthorizationFilter</filter-name>
+   <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ The RegExpAuthorizationFilter verifies authorization by matching paths against patterns
- but support regular expression patterns. The patterns and corresponding "allowed roles"
are provided to RegExpAuthorizationFilter using init-params. You provide an init-param for
every "rule" you want to set up. Each init-param has to have a value on the from "<order>|<comma-separated-roles>|<path-regular-expression>"
+ * ''order'' is the order of this "rule" relative to the other "rules". Unfortunately it
is not enough just to make sure the "rules" are ordered correctly in the web.xml, because
the init-params might not be provided to the filter in that order
+ * ''comma-separated-roles'' is a comma separated list of "roles" allowed to access paths
matching ''path-regular-expressoin'' of the same "rule"
+ * ''path-regular-expression'' is a regular expression (as understood by java.util.regex.Pattern)
matched against the path of a particular request hitting the filter. RegExpAuthorizationFilter
iterates "rules" in the given order, matches the request-path against its ''path-regular-expression''.
If no match continues to next "rule", if match the next "rule" is never considered. Of no
"rules" match the request is allowed to proceed - it passed authorization so to speak. In
case of a match the authenticated user will be matched against the roles in ''comma-separated-roles''
and only allowed access in case he is in one of the roles mentioned. In case he is not the
filter will return a response with status-code 403 "Unauthorized".
  === Resin example ===

View raw message