Permalink
Browse files

Ensure private search features are not lost on Digest auth timeout

This is a fix for mantis 766 ( http://mantis.tokeek.de/view.php?id=766 )

Since the upgrade to Digest authentication, access to protected search
features was indeed disabled once the Digest nonce timed out.

After Digest auth timeout the browser no more sent authentication
information and as the search results page is not private, protected
features were simply be hidden without asking browser again for
authentication.

Adding a supplementary parameter when accessing the search results as
authenticated fixes this.
  • Loading branch information...
luccioman committed Sep 29, 2017
1 parent ba60f65 commit 27ab733685930a8c967c3f28197fc34f98123010
@@ -20,6 +20,9 @@
<input type="hidden" name="urlmaskfilter" value=".*" />
<input type="hidden" name="prefermaskfilter" value="" />
<input type="hidden" name="nav" value="all" />
#(authorized)#::
<input type="hidden" name="auth" id="auth" value=""/>
#(/authorized)#
</form>
</div>
<script type="text/javascript">
@@ -61,6 +61,9 @@ <h2 class="yacy">#[promoteSearchPageGreeting]#</h2>
<button id="Enter" name="Enter" class="btn btn-primary" type="submit">Search</button>
</div>
</div>
#(authorized)#::
<input type="hidden" name="auth" id="auth" value=""/>
#(/authorized)#
<input type="hidden" name="verify" value="#[search.verify]#" />
#(searchdomswitches)#::
<div class="yacysearch">
@@ -109,6 +109,9 @@
#(/resortEnabled)#
</div>
</div>
#(authorized)#::
<input type="hidden" name="auth" id="auth" value=""/>
#(/authorized)#
<input type="hidden" name="contentdom" id="contentdom" value="#[contentdom]#" />
<input type="hidden" name="former" value="#[former]#" />
<input type="hidden" name="maximumRecords" value="#[count]#" />
@@ -106,7 +106,7 @@ public static serverObjects respond(
boolean authenticated = sb.adminAuthenticated(header) >= 2;
if ( !authenticated ) {
final UserDB.Entry user = sb.userDB.getUser(header);
final UserDB.Entry user = sb.userDB != null ? sb.userDB.getUser(header) : null;
authenticated = (user != null && user.hasRight(UserDB.AccessRight.EXTENDED_SEARCH_RIGHT));
}
final boolean localhostAccess = header.accessFromLocalhost();
@@ -198,6 +198,18 @@ public static serverObjects respond(
return prop;
}
if (post.containsKey("auth") && !authenticated) {
/*
* Access to authentication protected features is explicitely requested here
* but no authentication is provided : ask now for authentication.
* Wihout this, after timeout of HTTP Digest authentication nonce, browsers no more send authentication information
* and as this page is not private, protected features would simply be hidden without asking browser again for authentication.
* (see mantis 766 : http://mantis.tokeek.de/view.php?id=766) *
*/
prop.authenticationRequired();
return prop;
}
// check for JSONP
if ( post.containsKey("callback") ) {
final String jsonp = post.get("callback") + "([";
@@ -764,7 +776,7 @@ public static serverObjects respond(
RequestHeader.FileType.HTML,
0,
theQuery,
suggestion, true).toString());
suggestion, true, authenticated).toString());
prop.put("didYouMean_suggestions_" + meanCount + "_sep", "|");
meanCount++;
} catch (final ConcurrentModificationException e) {
@@ -842,8 +854,9 @@ public static serverObjects respond(
* eventually including fetched results with higher ranks from the Solr and RWI stacks */
prop.put("resortEnabled", !jsResort && global && !stealthmode && theSearch.resortCacheAllowed.availablePermits() > 0 ? 1 : 0);
prop.put("resortEnabled_url",
QueryParams.navurlBase(RequestHeader.FileType.HTML, theQuery, null, true).append("&startRecord=")
.append(startRecord).append("&resortCachedResults=true").toString());
QueryParams.navurlBase(RequestHeader.FileType.HTML, theQuery, null, true, authenticated)
.append("&startRecord=").append(startRecord).append("&resortCachedResults=true")
.toString());
// generate the search result lines; the content will be produced by another servlet
for ( int i = 0; i < theQuery.itemsPerPage(); i++ ) {
@@ -33,7 +33,7 @@ <h4 class="linktitle">
#(showMetadata)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="solr/select?q=id:%22#[urlhash]#%22&defType=edismax&start=0&rows=1&core=collection1&wt=html" target="_blank">Metadata</a>#(/showMetadata)#
#(showParser)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="ViewFile.html?urlHash=#[urlhash]#&amp;words=#[words]#" target="_blank">Parser</a>#(/showParser)#
#(showCitation)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="api/citation.html?hash=#[urlhash]#&filter=true" target="_blank">Citations</a>#(/showCitation)#
#(showPictures)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="yacysearch.html?contentdom=image&url=#[link]#&query=#[former]#+inurl:#[link]#" target="_blank">Pictures</a>#(/showPictures)#
#(showPictures)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="yacysearch.html?contentdom=image#(authorized)#::&auth#(/authorized)#&url=#[link]#&query=#[former]#+inurl:#[link]#" target="_blank">Pictures</a>#(/showPictures)#
#(showCache)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="CacheResource_p.html?url=#[link]#" target="_blank">Cache</a>#(/showCache)#
#(showProxy)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="proxy.html?url=#[link]#" target="_blank">View via proxy</a>#(/showProxy)#
#(showHostBrowser)#::<span role="separator" aria-orientation="vertical">&nbsp;|&nbsp;</span><a href="HostBrowser.html?path=#[link]#"><img src="env/grafics/minitree.png" width="15" height="8" title="Browse index" alt="Browse index"/></a>#(/showHostBrowser)#
@@ -53,7 +53,9 @@
import net.yacy.crawler.data.Transactions.State;
import net.yacy.crawler.retrieval.Response;
import net.yacy.data.URLLicense;
import net.yacy.data.UserDB;
import net.yacy.document.parser.html.IconEntry;
import net.yacy.http.servlets.TemplateMissingParameterException;
import net.yacy.kelondro.data.meta.URIMetadataNode;
import net.yacy.kelondro.util.Formatter;
import net.yacy.peers.NewsPool;
@@ -89,14 +91,35 @@
//private static boolean col = true;
public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) {
if (post == null) {
throw new TemplateMissingParameterException("The eventID parameter is required");
}
final Switchboard sb = (Switchboard) env;
final serverObjects prop = new serverObjects();
final String eventID = post.get("eventID", "");
final boolean authenticated = sb.verifyAuthentication(header);
final boolean adminAuthenticated = sb.verifyAuthentication(header);
final UserDB.Entry user = sb.userDB != null ? sb.userDB.getUser(header) : null;
final boolean userAuthenticated = (user != null && user.hasRight(UserDB.AccessRight.EXTENDED_SEARCH_RIGHT));
final boolean authenticated = adminAuthenticated || userAuthenticated;
final int item = post.getInt("item", -1);
final RequestHeader.FileType fileType = header.fileType();
if (post.containsKey("auth") && !authenticated) {
/*
* Access to authentication protected features is explicitely requested here
* but no authentication is provided : ask now for authentication.
* Wihout this, after timeout of HTTP Digest authentication nonce, browsers no more send authentication information
* and as this page is not private, protected features would simply be hidden without asking browser again for authentication.
* (see mantis 766 : http://mantis.tokeek.de/view.php?id=766) *
*/
prop.authenticationRequired();
return prop;
}
// default settings for blank item
prop.put("content", "0");
prop.put("rss", "0");
@@ -122,7 +145,9 @@ public static serverObjects respond(final RequestHeader header, final serverObje
prop.put("statistics_localIndexCount", Formatter.number(theSearch.local_rwi_available.get() + theSearch.local_solr_stored.get() - theSearch.local_solr_evicted.get(), true));
prop.put("statistics_remoteIndexCount", Formatter.number(theSearch.remote_rwi_available.get() + theSearch.remote_solr_available.get(), true));
prop.put("statistics_remotePeerCount", Formatter.number(theSearch.remote_rwi_peerCount.get() + theSearch.remote_solr_peerCount.get(), true));
prop.put("statistics_navurlBase", QueryParams.navurlBase(RequestHeader.FileType.HTML, theSearch.query, null, false).toString());
prop.put("statistics_navurlBase",
QueryParams.navurlBase(RequestHeader.FileType.HTML, theSearch.query, null, false, authenticated)
.toString());
prop.put("statistics_localQuery", theSearch.query.isLocal() ? "1" : "0");
prop.put("statistics_feedRunning", Boolean.toString(!theSearch.isFeedingFinished()));
final String target_special_pattern = sb.getConfig(SwitchboardConstants.SEARCH_TARGET_SPECIAL_PATTERN, "");
@@ -143,9 +168,9 @@ public static serverObjects respond(final RequestHeader header, final serverObje
final String resource = theSearch.query.domType.toString();
final String origQ = theSearch.query.getQueryGoal().getQueryString(true);
prop.put("content", 1); // switch on specific content
prop.put("content_authorized", authenticated ? "1" : "0");
prop.put("content_authorized", adminAuthenticated ? "1" : "0");
final String urlhash = ASCII.String(result.hash());
if (authenticated) { // only needed if authorized
if (adminAuthenticated) { // only needed if authorized
addAuthorizedActions(sb, prop, theSearch, resultUrlstring, resource, origQ, urlhash);
}
prop.putHTML("content_title", result.title());
@@ -255,7 +280,8 @@ public static serverObjects respond(final RequestHeader header, final serverObje
} else { // otherwise just use the keyword as additional query word
rawNavQueryModifier = word;
}
prop.put("content_showKeywords_keywords_" + i + "_tagurl", QueryParams.navurl(fileType, 0, theSearch.query, rawNavQueryModifier, naviAvail).toString());
prop.put("content_showKeywords_keywords_" + i + "_tagurl", QueryParams.navurl(fileType, 0,
theSearch.query, rawNavQueryModifier, naviAvail, authenticated).toString());
i++;
}
prop.put("content_showKeywords_keywords", i);
@@ -471,10 +497,10 @@ private static void addAuthorizedActions(final Switchboard sb, final serverObjec
/* Bookmark, delete and recommend action links share the same URL prefix */
StringBuilder linkBuilder = new StringBuilder();
String actionLinkPrefix = linkBuilder.append("yacysearch.html?query=").append(origQ.replace(' ', '+'))
final String actionLinkPrefix = linkBuilder.append("yacysearch.html?query=").append(origQ.replace(' ', '+'))
.append("&Enter=Search&count=").append(theSearch.query.itemsPerPage()).append("&offset=")
.append((theSearch.query.neededResults() - theSearch.query.itemsPerPage())).append("&resource=")
.append(resource).append("&time=3").toString();
.append(resource).append("&time=3").append("auth").toString();
linkBuilder.setLength(0);
String encodedURLString;
@@ -484,7 +510,7 @@ private static void addAuthorizedActions(final Switchboard sb, final serverObjec
ConcurrentLog.warn("YACY_SEARCH_ITEM", "UTF-8 encoding is not supported!");
encodedURLString = crypt.simpleEncode(resultUrlstring);
}
String bookmarkLink = linkBuilder.append(actionLinkPrefix).append("&bookmarkref=").append(urlhash)
final String bookmarkLink = linkBuilder.append(actionLinkPrefix).append("&bookmarkref=").append(urlhash)
.append("&bookmarkurl=").append(encodedURLString).append("&urlmaskfilter=.*")
.toString();
linkBuilder.setLength(0);
@@ -1,5 +1,8 @@
import net.yacy.cora.protocol.RequestHeader;
import net.yacy.data.UserDB;
import net.yacy.http.servlets.TemplateMissingParameterException;
import net.yacy.kelondro.util.Formatter;
import net.yacy.search.Switchboard;
import net.yacy.search.query.QueryParams;
import net.yacy.search.query.SearchEvent;
import net.yacy.search.query.SearchEventCache;
@@ -10,8 +13,17 @@
public class yacysearchlatestinfo {
public static serverObjects respond(@SuppressWarnings("unused") final RequestHeader header, final serverObjects post, @SuppressWarnings("unused") final serverSwitch env) {
if (post == null) {
throw new TemplateMissingParameterException("The eventID parameter is required");
}
final serverObjects prop = new serverObjects();
//Switchboard sb = (Switchboard) env;
Switchboard sb = (Switchboard) env;
final boolean adminAuthenticated = sb.verifyAuthentication(header);
final UserDB.Entry user = sb.userDB != null ? sb.userDB.getUser(header) : null;
final boolean userAuthenticated = (user != null && user.hasRight(UserDB.AccessRight.EXTENDED_SEARCH_RIGHT));
final boolean authenticated = adminAuthenticated || userAuthenticated;
// find search event
final String eventID = post.get("eventID", "");
@@ -44,7 +56,7 @@ public static serverObjects respond(@SuppressWarnings("unused") final RequestHea
prop.put("remoteResourceSize", Formatter.number(theSearch.remote_rwi_stored.get() + theSearch.remote_solr_stored.get(), true));
prop.put("remoteIndexCount", Formatter.number(theSearch.remote_rwi_available.get() + theSearch.remote_solr_available.get(), true));
prop.put("remotePeerCount", Formatter.number(theSearch.remote_rwi_peerCount.get() + theSearch.remote_solr_peerCount.get(), true));
prop.putJSON("navurlBase", QueryParams.navurlBase(RequestHeader.FileType.HTML, theSearch.query, null, false).toString());
prop.putJSON("navurlBase", QueryParams.navurlBase(RequestHeader.FileType.HTML, theSearch.query, null, false, authenticated).toString());
prop.put("feedRunning", Boolean.toString(!theSearch.isFeedingFinished()));
return prop;
Oops, something went wrong.

0 comments on commit 27ab733

Please sign in to comment.