VIVO-660 Add an Authorization tabs to the developer panel
This commit is contained in:
parent
0f0cac5d35
commit
54509b1aee
7 changed files with 285 additions and 60 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -10,6 +10,9 @@ div.developer {
|
|||
|
||||
div.developer #developerPanelBody {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#developerPanelBody * {
|
||||
line-height: 1em;
|
||||
font-size: small;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue