[ https://issues.apache.org/jira/browse/SOLR-4470?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13593830#comment-13593830 ]
Per Steffensen commented on SOLR-4470: -------------------------------------- About SOLR-4470_branch_4x_r1452629.patch * Fits on top of branch_4x revision 1452629 * Fairly big patch but most of it is to provide credentials across all requests issued by BaseDistributedSearchTest tests or to just to forward decisions on credentials down the call-flow on server-side. Notes on the major changes in non-test code ** AuthCredentials: New class encapsulating the concept of credentials. Supports "http basic" only for now, but using this object across code wherever credentials are needed, the framework will be in place for supporting other kinds of credentials in the future ** InterSolrNodeAuthCredentialsFactory: Separation of concern with respect to "getting credentials for inter-solr-node requests". The implementation of the factory can be replaced to "change strategy", but this is only used in tests (for now) ** InterSolrNodeAuthCredentialsFactory.AuthCredentialsSource: A level of abstraction to be used server-side whenever you have to decide on "how to get credentials for sub-requests" - possible decisions are "use credentials from super-request" or "use internal credentials" but NOT "use no credentials". Any server-side code should be able to provide credentials in requests, because you never know if the solr-cluster has been set up with protection on the URL you are about to hit. Therefore there are basically only the two choices listed above. The credentials (internal or on super-request) might be empty/null in concrete cases if no internal credentials has been specified or of no credentials was provided in the super-request, but you as a programmer never know, so you have to decide on "how to get credentials for sub-requests" for your server-side case. Idea is to "use credentials from super-request" whenever such exists, so that a request from "the outside" can never trigger a sub-request that the outside user was not allowed to do directly by himself. Whenever there is no "super-request" use "internal credentials". There are gray-area-cases like e.g. the Observer that asynchronously issues requests to CoreAdmin API when the Collection API has been called "from the outside" - to be true to the idea, in this case, we ought to actually use the credentials provided in the original request to Collection API, but that would require writing those credentials into the ZK-queue, and I wouldn't include that now, so in this case we use internal credentials. Server-side methods should typically not take AuthCredentials-parameters, because that will not encourage/remind developers to decide on the strategy when they use the method in the future - use AuthCredentialsSource instead. ** SolrRequest: Has been modified so that it can hold credentials to be used, and info on whether or not to provide them preemptively ** SolrQueryRequest: Has been modified to hold the credentials used in the request received ** SolrRequestParsers: Has been modified to extract the credentials from the request and add it to SolrQueryRequest ** HttpClientUtil: Has been changed to allow for specifying credentials and/or ClientConnectionManager when creating a HttpClient. Credentials to be used across all requests issued by this HttpClient. ClientConnectionManager to be able to share connection-manager across HttpClients - see reason below ** HttpShardHandler(Factory): It is used many places (and thats good) where sub-request are issued, places doing "use internal credentials" but also places "use credentials from super-request" (SolrCmdDistributor) and therefore HttpShardHandler(Factory) has been modified to support both. ** LBHttpSolrServer: Changed to allow for specific HttpClient for each request, so that even the loadbalancer in HttpShardHandler can use different HttpClients for different requests. It should have been done this way from the beginning - it is strange to use the defaultHttpClient for loadbalancing request through a HttpShardHandler which has been created with a specific HttpClient to use. ** Shared ClientConnectionManager instead of HttpClient: Several classes that used to have a HttpClient used for all requests (PeerSync, SyncStrategy and UpdateShardHandler), now have only a shared ClientConnetionManager. This in order to be able to specify different credentials (on HttpClient level) for different requests issued through those components. Actually it is not absolute necessary for PeerSync because it always uses "internal credentials", but it is done anyway in order to allow HttpShardHandlerFactory to insist on getting a decision on "how to get credentials for sub-requests" even when you "bring you own client" - shardhandlers ALWAYS need to have a strategy for providing credentials, because it is always used for inter-solr-node request. I believe it is ok to replace a shared HttpClient with a shared ClientConnectionManager in those cases, because the main reason for sharing a HttpClient must be to share its connection-manager. ** RegExpAuthorizationFilter: In order to be able to implement the most "common" kind of authorization (see descriptions below) in tests, RegExpAuthorizationFilter has been added for handling authorization. I have placed it in non-test code, even though it is only used in tests. This is due to the fact that it could very well be used by others in a real solr-setup - e.g. we will use it in my project. Will write a little bit about it on http://wiki.apache.org/solr/SolrSecurity. ** HttpSolrServer: Has been modified to be able to provide credentials (from HttpClient or from request) - both preemptively and non-preemptively. Support for non-preemptive POST requests required a little twist also. * Regarding how to use the solution ** You can specify credentials once and for all to be used in every request issued by a specific HttpClient. E.g. to do it for the HttpClient behind a CloudSolrServer {code} HttpClientUtil.setAuthCredentials(cloudSolrServer.getLbServer().getHttpClient(), AuthCredentials.createBasicAuthCredentials(<username>, <password>)); {code} ** You can also specify credentials on a pre-request basis (will override credentials on the HttpClient for this particular request). Just do the following to your SolrRequest before using it {code} solrRequest.setAuthCredentials(AuthCredentials.createBasicAuthCredentials(<username>, <password>)); {code} ** Preemptive authentication supported (and is default) ** Non-preeemptive authentication also supported on a per-request basis. Just do the following to your SolrRequest before using it {code} solrRequest.setPreemptiveAuthentication(false); {code} Have made changes to HttpSolrServer so that non-preemptive POST request will also work. ConcurrentSolrServer enforces preemptive authentication. * SolrServer helper-methods (add, commit, optimize, rollback, deleteByQuery, deleteById, ping, query and queryAndStreamResponse) have been change so that they in "the most advanced" variant support credentials as a parameter. I could have made a credentials variant for all existing variants of "the same operation", but that would make us end up with double the helper-methods. This meant that I had to call this version in cases where a non/few-parameters version of the helper-method uses to be called in all test inheriting from BaseDistributedSearchTestCase, because I have decided to run with "common security" on all resources/urls in those tests. I really believe this is a good decision for two reasons ** It helped me a lot for find particular/hidden places in the solr-server code where inter-solr-node requests where issued, so that I am now pretty sure we deal with credentials in all inter-solr-node requests. ** There is a great chance that future additions to the code where inter-solr-node requests are triggered, will have a test inheriting from BaseDistributedSearchTestCase, a test which will therefore run with "common" security set up, and therefore it is likely that such a test will make the developer discover that he needs to deal with credentials for the inter-solr-requests. Its my best attempt to try to ensure that this feature is not broken in the future. * Introduced close on PeerSync and called it wherever needed. I needed it some time in my development work. Not sure if it is needed anymore for this particular issue, but why not get it done. * Regarding test ** Idea is to run with "common security" in all "distributed" tests (all tests inheriting from BaseDistributedSearchTest) and therefore I needed to go add credentials here and there in all the sub-classes, in cases where they do not use the helper-methods (del, commit, add, etc) in BaseDistributedSearchTest itself. Support for running with "common" security has been added to JettySolrRunner and the feature is "turned on" for all test based on BaseDistributedSearchTest ** In this "common security" the web-container handles authentication (required for everything), but authorization is handled by RegExpAuthorizationFilter, in order to achieve what I consider the most "common" kind of authorization - namely authorization based on "operations allowed" instead of "collections allowed". In this "common security" setup used in BaseDistributedSearchTest tests, we have an all/internal/admin-user which is authorized to do anything, and search- plus update-users allowed to do only searches and updates respectively. ** Collection handling helper-methods (createCollection, checkCollectionExpectations, checkForCollection, checkCollectionIsNotCreated and checkForMissingCollection) and getCommonCloudSolrServer moved from BasicDistributedZkTest to AbstractFullDistribZkTestBase, because I also wanted to use them in new SecurityDistributedTest * Additional ** There is more to say about "security" on a "users-guide" level - will add to http://wiki.apache.org/solr/SolrSecurity. There is also something to be say on a "developers-guide" level. Do we have a developers guide somewhere on Wiki? ** Regarding running the test-suite: If not already granted in your policy file you need to grant "permission javax.security.auth.AuthPermission "*";" in general or at least for the JettySolrRunner (or the anonymous MappedLoginService in JettySolrRunner). This permission is needed in order to be able to set up the LoginModule in JettySolrRunner (test-only) ** Havnt run "ant precommit" but I would if I where to commit myself. Guess it will fail due to the fact that I probably do not live up to the (very bad IMHO) coding-style Please do not hesitate go ask questions about why I changed particular things the way I did and why it is needed. Or just ask questions in general. But please consider getting the patch in soon while its hot - its good stuff. > Support for basic http auth in internal solr requests > ----------------------------------------------------- > > Key: SOLR-4470 > URL: https://issues.apache.org/jira/browse/SOLR-4470 > Project: Solr > Issue Type: Bug > Components: clients - java, multicore, replication (java), SolrCloud > Affects Versions: 4.0 > Reporter: Per Steffensen > Labels: authentication, solrclient, solrcloud > Fix For: 4.2 > > > We want to protect any HTTP-resource (url). We want to require credentials no > matter what kind of HTTP-request you make to a Solr-node. > It can faily easy be acheived as described on > http://wiki.apache.org/solr/SolrSecurity. This problem is that Solr-nodes > also make "internal" request to other Solr-nodes, and for it to work > credentials need to be provided here also. > Ideally we would like to "forward" credentials from a particular request to > all the "internal" sub-requests it triggers. E.g. for search and update > request. > But there are also "internal" requests > * that only indirectly/asynchronously triggered from "outside" requests (e.g. > shard creation/deletion/etc based on calls to the "Collection API") > * that do not in any way have relation to an "outside" "super"-request (e.g. > replica synching stuff) > We would like to aim at a solution where "original" credentials are > "forwarded" when a request directly/synchronously trigger a subrequest, and > fallback to a configured "internal credentials" for the > asynchronous/non-rooted requests. > In our solution we would aim at only supporting basic http auth, but we would > like to make a "framework" around it, so that not to much refactoring is > needed if you later want to make support for other kinds of auth (e.g. digest) > We will work at a solution but create this JIRA issue early in order to get > input/comments from the community as early as possible. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@lucene.apache.org For additional commands, e-mail: dev-h...@lucene.apache.org