Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Authors: Juan José Ramos

Status: Draft | Discussion Discussion | Development | Active | Dropped | Superseded

Superseded by: N/A

...

  • RestrictedMethodAuthorizer
  • GeodeBasedMethodAuthorizerUnrestrictedMethodAuthorizer
  • RegexBasedMethodAuthorizerRegExMethodAuthorizer
  • JavaBeanAccessorBasedMethodAuthorizerJavaBeanAccessorMethodAuthorizer

The RestrictedMethodAuthorizer will be the authorizer used by default out of the box, as it contains the list of methods per object type that are currently considered safe and it also prevents any possible re-introduction of CVE-2017-9795.

The GeodeBasedMethodAuthorizer will The UnrestrictedMethodAuthorizer will basically allow any method execution as long as the target object does not belong to a Geode package or, if it does belong to a geode package, it's considered safe (sub-set of methods already allowed by the RestrictedMethodAuthorizer). The other two authorizers will always delegate to RestrictedMethodAuthorizer and expand the set of allowed methods with whatever the internal implementation is configured to do. The JavaBeanAccessorBasedMethodAuthorizer JavaBeanAccessorMethodAuthorizer covers the most common use cases and requires little to no configuration effort. For those use cases not covered, the users can choose to use the RegexBasedMethodAuthorizer RegExMethodAuthorizer, which allows them to configure which methods to allow directly through regex expressions. If none of the above is a good fit for a particular situation, the user ultimately has the option to provide its own implementation of the MethodInvocationAuthorizer interface and do whatever needed in order to allow/deny the execution of particular methods.

All out of the box authorizers will be implemented to prevent security problems but, due to the fact that we can't automatically detect in place modifications nor automatically define the trust boundary, the configurable ones will require extra care regarding the configuration or domain model design on the user side. The following table presents a brief summary of what "threats" (of the ones shown within the Introduction) are fully addressed by each implementation, and which ones might be exploitable depending on how the administrator configures the authorizer (the details will be described in each individual section when applicable, and clear documentation around this should be added to the user guide if we choose to implement these authorizers).

Authorizer \ ThreatReflectionCache AccessRegion AccessEntry Modification
RestrictedMethodAuthorizer(tick)(tick)(tick)
(tick)
GeodeBasedMethodAuthorizer
UnrestrictedMethodAuthorizer
(tick)(tick)(tick)
cross (x)
(error)
RegexBasedMethodAuthorizer
RegExMethodAuthorizer(tick)(tick)(tick)(error)
JavaBeanAccessorBasedMethodAuthorizer
JavaBeanAccessorMethodAuthorizer(tick)(tick)(tick)(error)

Implementation Details

This section is just an overview and it contains some ideas of how the proposal could be achieved, no PoC has been done so far so the implementations details might change.

draw.io Diagram
bordertrue
viewerToolbartrue
fitWindowfalse
diagramNameTentativeClassDiagram
simpleViewerfalse
width
diagramWidth981
revision1217


Interface MethodInvocationAuthorizer (Public)

This interface is intended to be implemented by users that want a custom authorization mechanism, and by the out of the box implementations as well. The interface will have only one method and it should return a boolean indicating whether the specified method is allowed to be executed on the target object or not. For those situations on which the authorization can not be determined, the a non-checked NotAuthorizedException exception should be thrown.

The authorize method will be called for every traversed object as part of the query execution, so it's extremely important that the implementation is lighting fast.

...

  boolean authorize(Method method, Object target) throws NotAuthorizedException;

}


Implementations of this interface must be thread-safe as more than one thread might invoke the method at the same time.

...

The current RestrictedMethodInvocationAuthorizer implementation logic, but made public so applications can delegate to this class and use it as the starting point for providing custom authorizers. It twill be immutable and thread safe, and provide two new public methods (isAllowedGeodeMethod and isPermanentlyForbiddenMethod) that can be used by other classes in order to know whether a particular method on a particular object is already marked as safe or not.

Configuration Options

Create a new QueryServiceConfig element at the CacheConfig level to contain any configuration related to OQL, including the custom MethodInvocationAuthorizer. Even though at the beginning this new configuration element will be used to configure only the MethodInvocationAuthorizer implementation, it’s worth noting that it provides a single configuration entry point for the whole query engine. This basically means that it can also be used in the future to allow further additions and configuration options, even replacing the current system properties used to configure the QueryService with new child elements and/or attributes.

...

  • Too restrictive (minus).
  • User can't use methods in queries (minus).
  • User can't use non-public fields in queries as the implicit method invocation is also denied (minus).

...

UnrestrictedMethodAuthorizer

Allow any method execution as long as the target object does not belong to a Geode package, or does belong but it's marked as safe (Region.get, Region.entrySet, Region.keySet, Region.values, Region.getEntries, Region.getValues, Region.containsKey, Region.getKey and Region.getValue). Some known dangerous methods (like getClass) will also be rejected, no matter whether the target object belongs to a Geode package or not. The implementation will be immutable and thread-safe.

...

  if (restrictedAuthorizer.isKnownDangerousMethodisPermanentlyForbiddenMethod(method, target) {

    return false;

...

  return restrictedAuthorizer.isAllowedGeodeMethod(method, target);

}

Advantages

  • Easy to use tinymce.emotions_dlg.add(plus).
  • No extra configuration needed tinymce.emotions_dlg.add(plus).
  • Implicit and Explicit methods can be executed on objects stored within the regions (plus).

...

  • In place modifications are allowed (minus).
  • Users with DATA:READ:RegionName privileges can modify the entries within the region through methods that mutate the object, thus part of CVE-2017-9795 can be re-introduced (minus).

...

RegExMethodAuthorizer

Methods allowed to be executed should match some regex expression(s) configured by the user, similar to what we currently do today with the PDX ReflectionBasedAutoSerializer. The implementation will have an internal structure containing already compiled Pattern instances and use them to verify the actual method that should be executed by the OQL engine, denying or allowing the execution based on the match result. If there is no match, it will delegate the final decision to the RestrictedMethodAuthorizer. The implementation will be immutable and thread-safe.

...

  if (restrictedAuthorizer.isKnownDangerousMethodisPermanentlyForbiddenMethod(method, target) {

    return false;

...

  • Performance impact (minus).
  • Customers still need to configure “something” (the regex) (minus).
  • Customers need to learn regex expressions, if they don't do already (minus).
  • Operators with little Regex knowledge can accidentally allow everything depending on which wildcards are used and, thus, reintroduce part of CVE-2017-9795 (minus).

...

JavaBeanAccessorMethodAuthorizer

Allow the OQL engine to execute any method that follows the design patterns for accessor methods described in the JavaBean specification 1.01; that is, basically, allow any method starting with get or is. For extra security, only methods belonging to classes under certain packages (configured by the user) should be allowed, and some known dangerous methods (like getClass) should be disabled. If there is no match, it will delegate the final decision to the RestrictedMethodAuthorizer. The implementation will be immutable and thread-safe.

...

  if (restrictedAuthorizer.isKnownDangerousMethodisPermanentlyForbiddenMethod(method, target) {

    return false;

...

# Customer deploys the jar and configures the GeodeBasedMethodAuthorizerthe UnrestrictedMethodAuthorizer

$> deploy --jar=/tmp/model-1.0.0.jar

$> alter query-service --method-authorizer=GeodeBasedMethodAuthorizerUnrestrictedMethodAuthorizer


# All classes follow the JavaBean specification 1.01 for accessor methods

# Customer deploys the jar and configures the JavaBeanAccessorBasedMethodAuthorizer JavaBeanAccessorMethodAuthorizer

$> deploy --jar=/tmp/model-1.0.0.jar

$> alter query-service --method-authorizer=JavaBeanAccessorBasedMethodAuthorizerJavaBeanAccessorMethodAuthorizer{'packages' : 'order.model,tickets.model'}

...

# Customer deploys the jar and configures the JavaBeanAccessorBasedMethodAuthorizer JavaBeanAccessorMethodAuthorizer

$> deploy --jar=/tmp/model-1.0.0.jar

$> alter query-service --method-authorizer=JavaBeanAccessorBasedMethodAuthorizerJavaBeanAccessorMethodAuthorizer{'packages' : 'order.model,tickets.model'}

...

# These methods need to be accessed through OQL right away in production, so they configure RegexBasedMethodAuthorizer RegExMethodAuthorizer with the required regex to allow default java bean accessors (get*|is*) + methods starting with "calculate*"

alter query-service --method-authorizer=RegexBasedMethodAuthorizerRegExMethodAuthorizer{'patterns' : 'model.*(get|is|calculate)'}

...

# After removing all "calculateXXXX" methods the customer deploys the new model and re-configures the JavaBeanAccessorBasedMethodAuthorizerJavaBeanAccessorMethodAuthorizer

deploy --jar=/tmp/model-2.0.0.jar

alter query-service --method-authorizer=JavaBeanAccessorBasedMethodAuthorizerJavaBeanAccessorMethodAuthorizer{'packages' : 'order.model,tickets.model'}

...

  • Easy to implement (plus).
  • No extra configuration or changes needed (plus).
  • Addition of new resource permission DATA:QUERY:RegionName (minus).
  • Confusing. Multiple roles are required for “the same” OQL execution operation (minus).

Prior Art

There are some existing frameworks/solutions that might accomplish the same as this proposal. However, we believe that those solutions are inferior for the reasons below.

Spring Method Security & Shiro Annotation-based Authorization

Both Spring Method Security and Shiro Annotation-based Authorization allow the user to annotate the classes in order to explicitly configure which roles/permissions are required to execute the relevant method, similar to what this proposal tries to accomplish through the discarded AnnotationBasedMethodAuthorizer. Annotations are really popular within the Java world and these approaches are extremely powerful and configurable.

The primary problem with these solutions is that they force the user to modify the domain model and, also, add extra unnecessary coupling. With this proposal, anyway, the user can ultimately use these frameworks by just providing their own authorizer implementation and check the annotation in order to allow/deny the method execution.

Errata

  1. The contract for the interface MethodInvocationAuthorizer won't include a throws clause for the NotAuthorizedException class, that exception was designed to indicate that the subject is not allowed to execute a particular operation, not to indicate that a problem has occurred and that the authorization can not be determined. Since Geode can't do anything to recover from such errors and doesn't have any insights about the actual implementation, a non checked exception should be thrown whenever there's an error while executing the authorization logic.
  2. Authorizer Implementations won't have Based as part of the actual name since the word doesn't add anything useful to the class name.
  3. Class name for GeodeBasedMethodAuthorizer was changed to MethodUnrestrictedMethodAuthorizer.
  4. Method name isKnownDangerousMethod was changed to isPermanentlyForbiddenMethod.
  5. The IndexManager was modified to throw an exception and mark the index as invalid whenever the removal of an entry from an index fails. This was the behaviour used when adding mappings to an index, so the class was fixed to keep consistency between the different operations and to be able to mark existing indexes as invalid whenever a newly configured MethodInvocationAuthorizer doesn't allow the method invocations included within the index expression (see GEODE-7486 and GEODE-7351).
  6. The CQ Engine was modified to always use the most up to date configured MethodInvocationAuthorizer. Whenever the MethodInvocationAuthorizer is changed in runtime, all running CQs are updated to use it in order to avoid security issues and previously cached results are invalidated/cleared as cached keys may not be valid anymore (see GEODE-7487GEODE-7497 and GEODE-7351).