in core/src/main/java/jenkins/security/stapler/TypedFilter.java [191:269]
public boolean keep(@NonNull Function function) {
if (function.getAnnotation(StaplerNotDispatchable.class) != null) {
// explicitly marked as an invalid getter
return false;
}
if (function.getAnnotation(StaplerDispatchable.class) != null) {
// explicitly marked as a valid getter
return true;
}
String signature = function.getSignature();
// check whitelist
ExtensionList<RoutingDecisionProvider> decision = ExtensionList.lookup(RoutingDecisionProvider.class);
if (decision.size() > 0) {
for (RoutingDecisionProvider provider : decision) {
RoutingDecisionProvider.Decision methodDecision = provider.decide(signature);
if (methodDecision == RoutingDecisionProvider.Decision.ACCEPTED) {
LOGGER.log(Level.CONFIG, "Function {0} is acceptable because it is whitelisted by {1}", new Object[]{signature, provider});
return true;
}
if (methodDecision == RoutingDecisionProvider.Decision.REJECTED) {
LOGGER.log(Level.CONFIG, "Function {0} is not acceptable because it is blacklisted by {1}", new Object[]{signature, provider});
return false;
}
Class<?> type = function.getReturnType();
if (type != null) {
String typeSignature = "class " + type.getCanonicalName();
RoutingDecisionProvider.Decision returnTypeDecision = provider.decide(typeSignature);
if (returnTypeDecision == RoutingDecisionProvider.Decision.ACCEPTED) {
LOGGER.log(Level.CONFIG, "Function {0} is acceptable because its type is whitelisted by {1}", new Object[]{signature, provider});
return true;
}
if (returnTypeDecision == RoutingDecisionProvider.Decision.REJECTED) {
LOGGER.log(Level.CONFIG, "Function {0} is not acceptable because its type is blacklisted by {1}", new Object[]{signature, provider});
return false;
}
}
}
}
if (PROHIBIT_STATIC_ACCESS && function.isStatic()) {
// unless whitelisted or marked as routable, reject static methods
return false;
}
if (function.getName().equals("getDynamic")) {
Class[] parameterTypes = function.getParameterTypes();
if (parameterTypes.length > 0 && parameterTypes[0] == String.class) {
// While this is more general than what Stapler can invoke on these types,
// The above is the only criterion for Stapler to attempt dispatch.
// Therefore prohibit this as a regular getter.
return false;
}
}
if (function.getName().equals("getStaplerFallback") && function.getParameterTypes().length == 0) {
// A parameter-less #getStaplerFallback() implements special fallback behavior for the
// StaplerFallback interface. We do not check for the presence of the interface on the current
// class, or the return type, as that could change since the implementing component was last built.
return false;
}
if (function.getName().equals("getTarget") && function.getParameterTypes().length == 0) {
// A parameter-less #getTarget() implements special redirection behavior for the
// StaplerProxy interface. We do not check for the presence of the interface on the current
// class, or the return type, as that could change since the implementing component was last built.
return false;
}
Class<?> returnType = function.getReturnType();
boolean isOk = isClassAcceptable(returnType);
LOGGER.log(Level.FINE, "Function analyzed: {0} => {1}", new Object[]{signature, isOk});
return isOk;
}