use of org.opensolaris.opengrok.web.Statistics in project OpenGrok by OpenGrok.
the class AuthorizationFramework method checkAll.
/**
* Checks if the request should have an access to a resource. This method is
* thread safe with respect to the concurrent reload of plugins.
*
* <p>
* Internally performed with a predicate. Using cache in request
* attributes.</p>
*
* <h3>Order of plugin invocation</h3>
*
* <p>
* The order of plugin invocation is given by the stack and appropriate
* actions are taken when traversing the stack with set of keywords,
* such as:</p>
*
* <h4>required</h4>
* Failure of such a plugin will ultimately lead to the authorization
* framework returning failure but only after the remaining plugins have
* been invoked.
*
* <h4>requisite</h4>
* Like required, however, in the case that such a plugin returns a failure,
* control is directly returned to the application. The return value is that
* associated with the first required or requisite plugin to fail.
*
* <h4>sufficient</h4>
* If such a plugin succeeds and no prior required plugin has failed the
* authorization framework returns success to the application immediately
* without calling any further plugins in the stack. A failure of a
* sufficient plugin is ignored and processing of the plugin list continues
* unaffected.
*
* <p>
* Loaded plugins which do not occur in the configuration are appended to
* the list with "required" keyword. As of the nature of the class discovery
* this means that the order of invocation of these plugins is rather
* random.</p>
*
* <p>
* Plugins in the configuration which have not been loaded are skipped.</p>
*
* @param request request object
* @param cache cache
* @param name name
* @param predicate predicate
* @return true if yes
*
* @see RuntimeEnvironment#getPluginStack()
*/
@SuppressWarnings("unchecked")
private boolean checkAll(HttpServletRequest request, String cache, Nameable entity, AuthorizationEntity.PluginDecisionPredicate pluginPredicate, AuthorizationEntity.PluginSkippingPredicate skippingPredicate) {
if (stack == null) {
return true;
}
Statistics stats = RuntimeEnvironment.getInstance().getStatistics();
Boolean val;
Map<String, Boolean> m = (Map<String, Boolean>) request.getAttribute(cache);
if (m == null) {
m = new TreeMap<>();
} else if ((val = m.get(entity.getName())) != null) {
// cache hit
stats.addRequest("authorization_cache_hits");
return val;
}
stats.addRequest("authorization_cache_misses");
long time = 0;
boolean overallDecision = false;
lock.readLock().lock();
try {
// Make sure there is a HTTP session that corresponds to current plugin version.
HttpSession session;
if (((session = request.getSession(false)) != null) && isSessionInvalid(session)) {
session.invalidate();
stats.addRequest("authorization_sessions_invalidated");
}
request.getSession().setAttribute(SESSION_VERSION, getPluginVersion());
time = System.currentTimeMillis();
overallDecision = performCheck(entity, pluginPredicate, skippingPredicate);
} finally {
lock.readLock().unlock();
}
if (time > 0) {
time = System.currentTimeMillis() - time;
stats.addRequestTime("authorization", time);
stats.addRequestTime(String.format("authorization_%s", overallDecision ? "positive" : "negative"), time);
stats.addRequestTime(String.format("authorization_%s_of_%s", overallDecision ? "positive" : "negative", entity.getName()), time);
stats.addRequestTime(String.format("authorization_of_%s", entity.getName()), time);
}
m.put(entity.getName(), overallDecision);
request.setAttribute(cache, m);
return overallDecision;
}
use of org.opensolaris.opengrok.web.Statistics in project OpenGrok by OpenGrok.
the class AuthorizationStack method processStack.
/**
* Process the stack.
*
* @param entity the given entity
* @param pluginPredicate predicate returning true or false for the given
* entity which determines if the authorization for such entity is
* successful or failed for particular request and plugin
* @param skippingPredicate predicate returning true if this authorization
* entity should be omitted from the authorization process
* @return true if entity is allowed; false otherwise
*/
protected boolean processStack(Nameable entity, PluginDecisionPredicate pluginPredicate, PluginSkippingPredicate skippingPredicate) {
Statistics stats = RuntimeEnvironment.getInstance().getStatistics();
long time = System.currentTimeMillis();
boolean overallDecision = true;
for (AuthorizationEntity authEntity : getStack()) {
if (skippingPredicate.shouldSkip(authEntity)) {
LOGGER.log(Level.FINEST, "AuthEntity \"{0}\" [{1}] skipping testing of name \"{2}\"", new Object[] { authEntity.getName(), authEntity.getFlag(), entity.getName() });
continue;
}
// run the plugin's test method
try {
LOGGER.log(Level.FINEST, "AuthEntity \"{0}\" [{1}] testing a name \"{2}\"", new Object[] { authEntity.getName(), authEntity.getFlag(), entity.getName() });
boolean pluginDecision = authEntity.isAllowed(entity, pluginPredicate, skippingPredicate);
LOGGER.log(Level.FINEST, "AuthEntity \"{0}\" [{1}] testing a name \"{2}\" => {3}", new Object[] { authEntity.getName(), authEntity.getFlag(), entity.getName(), pluginDecision ? "true" : "false" });
if (!pluginDecision && authEntity.isRequired()) {
// required sets a failure but still invokes all other plugins
overallDecision = false;
continue;
} else if (!pluginDecision && authEntity.isRequisite()) {
// requisite sets a failure and immediately returns the failure
overallDecision = false;
break;
} else if (overallDecision && pluginDecision && authEntity.isSufficient()) {
// sufficient immediately returns the success
overallDecision = true;
break;
}
} catch (Throwable ex) {
LOGGER.log(Level.WARNING, String.format("AuthEntity \"%s\" has failed the testing of \"%s\" with an exception.", authEntity.getName(), entity.getName()), ex);
LOGGER.log(Level.FINEST, "AuthEntity \"{0}\" [{1}] testing a name \"{2}\" => {3}", new Object[] { authEntity.getName(), authEntity.getFlag(), entity.getName(), "false (failed)" });
// set the return value to false for this faulty plugin
if (!authEntity.isSufficient()) {
overallDecision = false;
}
// requisite plugin may immediately return the failure
if (authEntity.isRequisite()) {
break;
}
}
}
time = System.currentTimeMillis() - time;
stats.addRequestTime(String.format("authorization_in_stack_%s_%s", getName(), overallDecision ? "positive" : "negative"), time);
stats.addRequestTime(String.format("authorization_in_stack_%s_%s_of_%s", getName(), overallDecision ? "positive" : "negative", entity.getName()), time);
stats.addRequestTime(String.format("authorization_in_stack_%s_of_%s", getName(), entity.getName()), time);
return overallDecision;
}
use of org.opensolaris.opengrok.web.Statistics in project OpenGrok by OpenGrok.
the class AuthorizationFrameworkReloadTest method testReloadCycle.
/**
* Sort of a stress test - call isAllowed() and reload() in parallel.
* This might uncover any snags with locking within AuthorizationFramework.
*/
@Test
public void testReloadCycle() {
Statistics stats = RuntimeEnvironment.getInstance().getStatistics();
Long reloads;
String projectName = "project" + Math.random();
// Create authorization stack for single project.
AuthorizationStack stack = new AuthorizationStack(AuthControlFlag.REQUIRED, "stack for project " + projectName);
assertNotNull(stack);
stack.add(new AuthorizationPlugin(AuthControlFlag.REQUIRED, "opengrok.auth.plugin.FalsePlugin"));
stack.setForProjects(projectName);
AuthorizationFramework framework = new AuthorizationFramework(pluginDirectory.getPath(), stack);
// to avoid noise when loading classes of other tests
framework.setLoadClasses(false);
framework.reload();
// Perform simple sanity check before long run is entered. If this fails,
// it will be waste of time to continue with the test.
Project p = new Project(projectName);
DummyHttpServletRequest req = new DummyHttpServletRequest();
assertFalse(framework.isAllowed(req, p));
// Create a thread that does reload() every now and then.
runThread = true;
final int maxReloadSleep = 10;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (runThread) {
framework.reload();
try {
Thread.sleep((long) (Math.random() % maxReloadSleep) + 1);
} catch (InterruptedException ex) {
}
}
}
});
t.start();
reloads = stats.getRequest("authorization_stack_reload");
assertNotNull(reloads);
// Process number or requests and check that framework decision is consistent.
for (int i = 0; i < 1000; i++) {
req = new DummyHttpServletRequest();
assertFalse(framework.isAllowed(req, p));
try {
// Should run more frequently than the thread performing reload().
Thread.sleep((long) (Math.random() % (maxReloadSleep / 3)) + 1);
} catch (InterruptedException ex) {
}
}
try {
// Terminate the thread.
runThread = false;
t.join();
} catch (InterruptedException ex) {
}
// Double check that at least one reload() was done.
reloads = stats.getRequest("authorization_stack_reload") - reloads;
System.out.println("number of reloads: " + reloads);
assertTrue(reloads > 0);
}
use of org.opensolaris.opengrok.web.Statistics in project OpenGrok by OpenGrok.
the class RuntimeEnvironmentTest method testSaveEmptyStatistics.
@Test
public void testSaveEmptyStatistics() throws IOException {
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
env.setStatistics(new Statistics());
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
env.saveStatistics(out);
Assert.assertEquals("{}", out.toString());
}
}
use of org.opensolaris.opengrok.web.Statistics in project OpenGrok by OpenGrok.
the class RuntimeEnvironmentTest method testLoadStatistics.
@Test
public void testLoadStatistics() throws IOException, ParseException {
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
String json = "{" + "\"requests_per_minute_max\":3," + "\"timing\":{" + "\"*\":2288," + "\"xref\":53," + "\"root\":2235" + "}," + "\"minutes\":756," + "\"timing_min\":{" + "\"*\":2," + "\"xref\":2," + "\"root\":2235" + "}," + "\"timing_avg\":{" + "\"*\":572.0," + "\"xref\":17.666666666666668," + "\"root\":2235.0" + "}," + "\"request_categories\":{" + "\"*\":4," + "\"xref\":3," + "\"root\":1" + "}," + "\"day_histogram\":[0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,1]," + "\"requests\":4," + "\"requests_per_minute_min\":1," + "\"requests_per_minute\":3," + "\"requests_per_minute_avg\":0.005291005291005291," + "\"month_histogram\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0]," + "\"timing_max\":{" + "\"*\":2235," + "\"xref\":48," + "\"root\":2235" + "}" + "}";
try (InputStream in = new StringInputStream(json)) {
env.loadStatistics(in);
}
Statistics stats = env.getStatistics();
Assert.assertNotNull(stats);
Assert.assertEquals(756, stats.getMinutes());
Assert.assertEquals(4, stats.getRequests());
Assert.assertEquals(3, stats.getRequestsPerMinute());
Assert.assertEquals(1, stats.getRequestsPerMinuteMin());
Assert.assertEquals(3, stats.getRequestsPerMinuteMax());
Assert.assertEquals(0.005291005291005291, stats.getRequestsPerMinuteAvg(), 0.00005);
Assert.assertArrayEquals(new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, stats.getDayHistogram());
Assert.assertArrayEquals(new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0 }, stats.getMonthHistogram());
Assert.assertEquals(createMap(new Object[][] { { "*", 4L }, { "xref", 3L }, { "root", 1L } }), stats.getRequestCategories());
Assert.assertEquals(createMap(new Object[][] { { "*", 2288L }, { "xref", 53L }, { "root", 2235L } }), stats.getTiming());
Assert.assertEquals(createMap(new Object[][] { { "*", 2L }, { "xref", 2L }, { "root", 2235L } }), stats.getTimingMin());
Assert.assertEquals(createMap(new Object[][] { { "*", 2235L }, { "xref", 48L }, { "root", 2235L } }), stats.getTimingMax());
}
Aggregations