VIVO-660 Add an Authorization tabs to the developer panel

This commit is contained in:
j2blake 2014-01-07 15:08:30 -05:00
parent 0f0cac5d35
commit 54509b1aee
7 changed files with 285 additions and 60 deletions

View file

@ -0,0 +1,176 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import static edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization.INCONCLUSIVE;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
import edu.cornell.mannlib.vitro.webapp.utils.developer.Key;
/**
* If enabled in the developer settings (and log levels), log each
* PolicyDecision (subject to restrictions).
*
* Some restrictions apply to the logger as a whole. Others apply to the
* particular policy or the particular decision.
*/
public class PolicyDecisionLogger {
private static final Log log = LogFactory
.getLog(PolicyDecisionLogger.class);
private static final Pattern NEVER_MATCHES = Pattern.compile("^__NEVER__$");
private static final BasicPolicyDecision NULL_DECISION = new BasicPolicyDecision(
INCONCLUSIVE, "The decision was null.");
private final DeveloperSettings settings;
private final RequestedAction whatToAuth;
private final IdentifierBundle whoToAuth;
private final boolean enabled;
private final Pattern policyRestriction;
private final boolean skipInconclusive;
private final boolean includeIdentifiers;
public PolicyDecisionLogger(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
this.settings = DeveloperSettings.getInstance();
this.whoToAuth = whoToAuth;
this.whatToAuth = whatToAuth;
this.enabled = figureEnabled();
this.policyRestriction = figurePolicyRestriction();
this.skipInconclusive = figureSkipInconclusive();
this.includeIdentifiers = figureIncludeIdentifiers();
}
private boolean figureEnabled() {
return log.isInfoEnabled()
&& settings.getBoolean(Key.AUTHORIZATION_LOG_DECISIONS_ENABLE)
&& passesUserRestriction() && passesActionRestriction();
}
/**
* The identifier bundle passes if there is no restriction, or if the
* restriction pattern is found within concatenated string of the identifier
* bundle.
*
* If the restriction is invalid, the action fails.
*/
private boolean passesUserRestriction() {
Pattern userRestriction = compilePatternFromSetting(Key.AUTHORIZATION_LOG_DECISIONS_USER_RESTRICTION);
return userRestriction == null
|| userRestriction.matcher(String.valueOf(whoToAuth)).find();
}
/**
* The requested action passes if there is no restriction, or if the
* restriction pattern is found within the class name of the action.
*
* If the restriction is invalid, the action fails.
*/
private boolean passesActionRestriction() {
Pattern actionRestriction = compilePatternFromSetting(Key.AUTHORIZATION_LOG_DECISIONS_ACTION_RESTRICTION);
return actionRestriction == null
|| actionRestriction.matcher(String.valueOf(whatToAuth)).find();
}
/**
* Only compile the policy restriction pattern once.
*/
private Pattern figurePolicyRestriction() {
return compilePatternFromSetting(Key.AUTHORIZATION_LOG_DECISIONS_POLICY_RESTRICTION);
}
/**
* Do we log inconclusive decisions?
*/
private boolean figureSkipInconclusive() {
return settings
.getBoolean(Key.AUTHORIZATION_LOG_DECISIONS_SKIP_INCONCLUSIVE);
}
/**
* Do we include Identifiers in the log record?
*/
private boolean figureIncludeIdentifiers() {
return settings
.getBoolean(Key.AUTHORIZATION_LOG_DECISIONS_ADD_IDENTIFERS);
}
/**
* If no pattern was provided, return null. If an invalid pattern was
* provided, return a pattern that never matches.
*/
private Pattern compilePatternFromSetting(Key key) {
String setting = settings.getString(key);
if (setting.isEmpty()) {
return null;
} else {
try {
return Pattern.compile(setting);
} catch (Exception e) {
return NEVER_MATCHES;
}
}
}
/**
* If the logger and the policy and the decision all pass the restrictions,
* write to the log. A null decision is treated as inconclusive.
*/
public void log(PolicyIface policy, PolicyDecision pd) {
if (passesRestrictions(String.valueOf(policy), pd)) {
if (this.includeIdentifiers) {
log.info(String.format(
"Decision on %s by %s was %s; user is %s",
this.whatToAuth, policy, pd, this.whoToAuth));
} else {
log.info(String.format("Decision on %s by %s was %s",
this.whatToAuth, policy, pd));
}
}
}
private boolean passesRestrictions(String policyString, PolicyDecision pd) {
if (pd == null) {
pd = NULL_DECISION;
}
return enabled && passesPolicyRestriction(policyString)
&& passesConclusiveRestriction(pd);
}
private boolean passesPolicyRestriction(String policyString) {
return this.policyRestriction == null
|| this.policyRestriction.matcher(policyString).find();
}
private boolean passesConclusiveRestriction(PolicyDecision pd) {
return !(skipInconclusive && isInconclusive(pd));
}
private boolean isInconclusive(PolicyDecision pd) {
return pd == null || pd.getAuthorized() == INCONCLUSIVE;
}
public void logNoDecision(PolicyDecision pd) {
if (enabled) {
if (this.includeIdentifiers) {
log.info(pd.getMessage() + "; user is " + this.whoToAuth);
} else {
log.info(pd.getMessage());
}
}
}
}

View file

@ -103,14 +103,16 @@ public class PolicyList extends ArrayList<PolicyIface> implements PolicyIface{
protected PolicyDecision checkAgainstPolicys( IdentifierBundle whoToAuth, RequestedAction whatToAuth){
PolicyDecision pd = null;
PolicyDecisionLogger logger = new PolicyDecisionLogger(whoToAuth, whatToAuth);
for(PolicyIface policy : this){
try{
pd = policy.isAuthorized(whoToAuth, whatToAuth);
logger.log(policy, pd);
if( pd != null ){
if( pd.getAuthorized() == Authorization.AUTHORIZED )
break;
return pd;
if( pd.getAuthorized() == Authorization.UNAUTHORIZED )
break;
return pd;
if( pd.getAuthorized() == Authorization.INCONCLUSIVE )
continue;
} else{
@ -120,7 +122,10 @@ public class PolicyList extends ArrayList<PolicyIface> implements PolicyIface{
log.error("ignoring exception in policy " + policy.toString(), th );
}
}
log.debug("decision " + pd + " for " + whatToAuth);
pd = new BasicPolicyDecision(Authorization.INCONCLUSIVE,
"No policy returned a conclusive decision on " + whatToAuth);
logger.logNoDecision(pd);
return pd;
}

View file

@ -205,6 +205,7 @@ public class DeveloperSettings {
Properties dsProps = new Properties();
dsProps.load(reader);
devSettings.updateFromProperties(dsProps);
log.info(devSettings);
ss.info(this, "Loaded the 'developer.properties' file: "
+ devSettings);
} catch (FileNotFoundException e) {

View file

@ -24,7 +24,7 @@ public enum Key {
ENABLED("developer.enabled", true),
/**
* If the developer panel is enabled, can a non-logged-in user change the
* If the developer panel is enabled, may an anonymous user change the
* settings?
*/
PERMIT_ANONYMOUS_CONTROL("developer.permitAnonymousControl", true),
@ -84,7 +84,45 @@ public enum Key {
* Tell the ShortViewLogger to note the use of non-default short views.
*/
PAGE_CONTENTS_LOG_CUSTOM_SHORT_VIEW(
"developer.pageContents.logCustomShortView", true);
"developer.pageContents.logCustomShortView", true),
/**
* Enable the PolicyDecisionLogger.
*/
AUTHORIZATION_LOG_DECISIONS_ENABLE(
"developer.authorization.logDecisions.enable", true),
/**
* Enable the PolicyDecisionLogger.
*/
AUTHORIZATION_LOG_DECISIONS_ADD_IDENTIFERS(
"developer.authorization.logDecisions.addIdentifiers", true),
/**
* Enable the PolicyDecisionLogger.
*/
AUTHORIZATION_LOG_DECISIONS_SKIP_INCONCLUSIVE(
"developer.authorization.logDecisions.skipInconclusive", true),
/**
* Don't log policy decisions unless the requested action meets this
* restriction.
*/
AUTHORIZATION_LOG_DECISIONS_ACTION_RESTRICTION(
"developer.authorization.logDecisions.actionRestriction", false),
/**
* Don't log policy decisions unless the identifier bundle meets this
* restriction.
*/
AUTHORIZATION_LOG_DECISIONS_USER_RESTRICTION(
"developer.authorization.logDecisions.userRestriction", false),
/**
* Don't log policy decisions unless the policy meets this restriction.
*/
AUTHORIZATION_LOG_DECISIONS_POLICY_RESTRICTION(
"developer.authorization.logDecisions.policyRestriction", false);
private static final Log log = LogFactory.getLog(Key.class);
private final String propertyName;

View file

@ -10,6 +10,9 @@ div.developer {
div.developer #developerPanelBody {
display: none;
}
#developerPanelBody * {
line-height: 1em;
font-size: small;
}

View file

@ -48,11 +48,19 @@ function DeveloperPanel(developerAjaxUrl) {
document.getElementById("developer_i18n_defeatCache").disabled = !developerEnabled;
document.getElementById("developer_i18n_logStringRequests").disabled = !developerEnabled;
document.getElementById("developer_loggingRDFService_enable").disabled = !developerEnabled;
document.getElementById("developer_authorization_logDecisions_enable").disabled = !developerEnabled;
var rdfServiceEnabled = developerEnabled && document.getElementById("developer_loggingRDFService_enable").checked;
document.getElementById("developer_loggingRDFService_stackTrace").disabled = !rdfServiceEnabled;
document.getElementById("developer_loggingRDFService_queryRestriction").disabled = !rdfServiceEnabled;
document.getElementById("developer_loggingRDFService_stackRestriction").disabled = !rdfServiceEnabled;
var authLoggingEnabled = developerEnabled && document.getElementById("developer_authorization_logDecisions_enable").checked;
document.getElementById("developer_authorization_logDecisions_skipInconclusive").disabled = !authLoggingEnabled;
document.getElementById("developer_authorization_logDecisions_addIdentifiers").disabled = !authLoggingEnabled;
document.getElementById("developer_authorization_logDecisions_actionRestriction").disabled = !authLoggingEnabled;
document.getElementById("developer_authorization_logDecisions_policyRestriction").disabled = !authLoggingEnabled;
document.getElementById("developer_authorization_logDecisions_userRestriction").disabled = !authLoggingEnabled;
}
function collectFormData() {

View file

@ -1,12 +1,18 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#macro showCheckbox key>
<#macro showCheckbox key, labelText>
<label>
<input type="checkbox" id="${key}" <#if settings[key]>checked</#if>>
${labelText}
</label>
</#macro>
<#macro showTextbox key>
<#macro showTextbox key, labelText>
<label>
${labelText}
<input type="text" id="${key}" size="30" value="${settings[key]}" >
</label>
</#macro>
<#if !settings.developer_enabled>
@ -21,14 +27,10 @@
</h1>
<div id="developerPanelBody">
<div>
<label>
<@showCheckbox "developer_enabled" />
Enable developer mode
</label>
<label>
<@showCheckbox "developer_permitAnonymousControl" />
Allow anonymous user to see and modify developer settings
</label>
<@showCheckbox "developer_enabled",
"Enable developer mode" />
<@showCheckbox "developer_permitAnonymousControl",
"Allow anonymous user to see and modify developer settings" />
</div>
<div id="developerTabs">
@ -41,26 +43,18 @@
<div class="devright">
<div class="container">
Page configuration
<label>
<@showCheckbox "developer_pageContents_logCustomListView" />
Log the use of custom list view XML files.
</label>
<label>
<@showCheckbox "developer_pageContents_logCustomShortView" />
Log the use of custom short views in search, index and browse pages.
</label>
<@showCheckbox "developer_pageContents_logCustomListView",
"Log the use of custom list view XML files." />
<@showCheckbox "developer_pageContents_logCustomShortView" ,
"Log the use of custom short views in search, index and browse pages."/>
</div>
<div class="container">
Language support
<label>
<@showCheckbox "developer_i18n_defeatCache" />
Defeat the cache of language property files
</label>
<label>
<@showCheckbox "developer_i18n_logStringRequests" />
Log the retrieval of language strings
</label>
<@showCheckbox "developer_i18n_defeatCache",
"Defeat the cache of language property files" />
<@showCheckbox "developer_i18n_logStringRequests",
"Log the retrieval of language strings" />
</div>
<div class="container">
@ -77,43 +71,43 @@
<div class="devleft">
<div class="container">
Freemarker templates
<label>
<@showCheckbox "developer_defeatFreemarkerCache" />
Defeat the template cache
</label>
<label>
<@showCheckbox "developer_insertFreemarkerDelimiters" />
Insert HTML comments at start and end of templates
</label>
<@showCheckbox "developer_defeatFreemarkerCache",
"Defeat the template cache" />
<@showCheckbox "developer_insertFreemarkerDelimiters",
"Insert HTML comments at start and end of templates" />
</div>
<div class="container">
SPARQL Queries
<label>
<@showCheckbox "developer_loggingRDFService_enable" />
Log each query
</label>
<@showCheckbox "developer_loggingRDFService_enable",
"Log each query" />
<div class="within">
<label>
<@showCheckbox "developer_loggingRDFService_stackTrace" />
Add stack trace
</label>
<label>
Restrict by query string
<@showTextbox "developer_loggingRDFService_queryRestriction" />
</label>
<label>
Restrict by calling stack
<@showTextbox "developer_loggingRDFService_stackRestriction" />
</label>
<@showCheckbox "developer_loggingRDFService_stackTrace",
"Add stack trace" />
<@showTextbox "developer_loggingRDFService_queryRestriction",
"Restrict by query string" />
<@showTextbox "developer_loggingRDFService_stackRestriction",
"Restrict by calling stack" />
</div>
</div>
</div>
</div>
<div id="developerTabAuthorization">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
<@showCheckbox "developer_authorization_logDecisions_enable",
"Write policy decisions to the log" />
<div class="within">
<@showCheckbox "developer_authorization_logDecisions_skipInconclusive",
"Skip inconclusive decisions" />
<@showCheckbox "developer_authorization_logDecisions_addIdentifiers",
"Include the user identifiers in the log record" />
<@showTextbox "developer_authorization_logDecisions_actionRestriction",
"Restrict by requested action" />
<@showTextbox "developer_authorization_logDecisions_policyRestriction",
"Restrict by policy name" />
<@showTextbox "developer_authorization_logDecisions_userRestriction",
"Restrict by user identifiers" />
</div>
</div>
</div>