blob: 8284ecc59f5bb1f717e4497ba2333148d5f7b67b [file] [log] [blame]
---
title: Method Invocation Authorizers
---
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
## <a id="overview"></a>Overview
When the `SecurityManager` is enabled, by default <%=vars.product_name%> throws a `NotAuthorizedException` when a `method` within a query is invoked and does not belong to the list of default allowed methods, given in [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
The `MethodInvocationAuthorizer` is used to determine whether a specific method invocation on a given object should be allowed or denied during the execution of a particular OQL query.
Allowing users to execute arbitrary methods on any object present within the <%=vars.product_name%> member's classpath could impact the integrity of the data and the system on which <%=vars.product_name%> is running.
In order to avoid this problem, it is always recommended to enable a `SecurityManager` at the cluster level, give users only the permissions they require, and configure a `MethodInvocationAuthorizer` that meets your needs.
The main threats to which a <%=vars.product_name%> cluster might be exposed without a `MethodInvocationAuthorizer` are highlighted below.
**Java Reflection**
Allows the user to do anything within the JVM.
``` pre
SELECT * FROM /region r WHERE r.getClass().forName('java.lang.Runtime').getDeclaredMethods()[0].invoke()
```
**Cache Modification**
Allows the user to do anything with the `Cache`: close it, access other regions, etc.
``` pre
SELECT * FROM /region.getCache().close()
```
**Region Modification**
Allows the user to destroy, add or invalidate the entire `Region`, or specific `entries`.
``` pre
SELECT * FROM /region.destroyRegion()
SELECT * FROM /region.put('xyz','abc')
SELECT * FROM /region.invalidate('xyz')
```
**Region Modification**
Allows the user to mutate the state of specific `entries`.
``` pre
`SELECT r.setName('newName') FROM /region r` |
```
## <a id="out_of_the_box_authorizers"></a><%=vars.product_name%> Authorizers
<%=vars.product_name%> provides four authorizers out of the box, each one designed and implemented for a specific use case in mind.
It is recommended to always use one of these authorizers, and only implement your own if your use case needs are not already met by one of them.
All of the implementations provided by <%=vars.product_name%> are designed to prevent security problems and have been thoroughly tested.
Extra care should be taken, however, when configuring the internals of some of the authorizers as an incorrect configuration might introduce security holes into the system.
The table below shows a summary of which security threats are fully addressed by each authorizer and which ones might be exploitable, depending on how they are configured (details are shown later for each implementation).
<img src="../../images/threatsAddressedByEachAuthorizer.png" class="image">
### <a id="restrictedMethodAuthorizer"></a>RestrictedMethodAuthorizer
The default `MethodInvocationAuthorizer` used by <%=vars.product_name%> to determine whether a method is allowed to be executed on a specific object instance or not.
The implementation forbids the invocation of all methods during a query execution, except for the ones shown below:
| Class | Allowed Methods |
|---------------------------------------------------------------------------|-----------------|
| `java.lang.Object` | `equals`, `toString`, `compareTo` |
| `java.lang.Boolean` | `booleanValue` |
| `java.lang.Number` | `byteValue`, `intValue`, `doubleValue`, `floatValue`, `longValue`, `shortValue` |
| `java.util.Date` | `after`, `before`, `getTime` |
| `java.sql.Timestamp` | `getNanos` |
| `java.lang.String` | `chartAt`, `codePointAt`, `codePointBefore`, `codePointCount`, `compareToIgnoreCase`, `concat`, `contains`, `contentEquals`, `endsWith`, `equalsIgnoreCase`, `getBytes`, `hashCode`, `indexOf`, `intern`, `isEmpty`, `lastIndexOf`, `length`, `matches`, `offsetByCodePoints`, `replace`, `replaceAll`, `replaceFirst`, `split`, `startsWith`, `substring`, `toCharArray`, `toLowerCase`, `toUpperCase`, `trim` |
| `java.util.Map.Entry`, `org.apache.geode.cache.Region.Entry` | `getKey`, `getValue` |
| `java.util.Collection`, `java.util.Map`, `org.apache.geode.cache.Region` | `get`, `entrySet`, `keySet`, `values`, `getEntries`, `getValues`, `containsKey` |
The authorizer also provides utilities that can be used by custom implementations to determine whether a method is permanently forbidden or, if the method belongs to <%=vars.product_name%>, whether it is considered safe to be used within a query execution.
The methods `getClass`, `readObject`, `readResolve`, `readObjectNoData`, `writeObject` and `writeReplace` are permanently forbidden.
The below table shows those methods that belong to <%=vars.product_name%> and are considered safe (for methods on `org.apache.geode.cache.Region`, the authorizer also verifies that the user has the `DATA:READ:RegionName` permission).
| Class | Allowed Methods |
|-------------------------------------------|---------------------------------------------------------------------------------|
| `org.apache.geode.cache.Region.Entry` | `getKey`, `getValue` |
| `org.apache.geode.cache.Region` | `get`, `entrySet`, `keySet`, `values`, `getEntries`, `getValues`, `containsKey` |
### <a id="unrestrictedMethodAuthorizer"></a>UnrestrictedMethodAuthorizer
A less restrictive `MethodInvocationAuthorizer` that allows any method invocation during the query execution as long as the following conditions are met:
- The method is not considered permanently forbidden by the [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
- The method does not belong to <%=vars.product_name%>, or does belong but is considered safe by the [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
This authorizer implementation addresses only three of the four main security risks: `Java Reflection`, `Cache Modification` and `Region Modification`.
The `Region Entry Modification` security risk still exists: users with the `DATA:READ:RegionName` permission will be able to execute ANY method (even those that mutate the object)
on the entries stored within the region and on instances used as bind parameters of the query, so this authorizer implementation must be used with extreme care.
**Note:**
Usage of this authorizer is recommended for secured clusters on which only trusted users and applications have access to the query engine.
It might also be used on clusters on which all entries stored are immutable.
### <a id="javaBeanAccessorMethodAuthorizer"></a>JavaBeanAccessorMethodAuthorizer
A more flexible `MethodInvocationAuthorizer` that allows methods to be invoked during a query execution if and only if all of the following conditions are met:
- The method is not considered permanently forbidden by the [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
- The method does not belong to <%=vars.product_name%>, or does belong but is considered safe by the [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
- The method follows the design patterns for accessor methods described in the [JavaBean Specification 1.01](https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/); that is, the method name begins with `is` or `get`.
- The target object on which the method will be executed belongs to a set of pre-configured packages.
When used as intended, and assuming that all region entries and bind parameters follow the [JavaBean Specification 1.01](https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/),
this authorizer implementation addresses all four security risks: `Java Reflection`, `Cache Modification`, `Region Modification` and `Region Entry Modification`.
It should be noted, however, that the `Region Entry Modification` security threat might be re-introduced: users with the `DATA:READ:RegionName` privilege will be able to execute any method whose name
starts with `is` or `get` on the objects stored within the region and on instances used as bind parameters, providing they are in the pre-configured packages. If those methods do not fully follow
the [JavaBean Specification 1.01](https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/) in that **accessors do not mutate the object state**, then instances could be potentially modified in place.
**Note:**
Usage of this authorizer is only recommended for secured clusters on which the user has full confidence in that all objects stored within the regions and used as bind parameters follow the
[JavaBean Specification 1.01](https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/).
It might also be used on clusters on which all entries stored are immutable.
### <a id="regExMethodAuthorizer"></a>RegExMethodAuthorizer
A fully flexible `MethodInvocationAuthorizer` that allows methods to be invoked during the query execution only if the the following conditions are met:
- The method is not considered permanently forbidden by the [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
- The method does not belong to <%=vars.product_name%>, or does belong but is considered safe by the [RestrictedMethodAuthorizer](method_invocation_authorizers.html#restrictedMethodAuthorizer).
- The fully qualified method name matches at least one of the pre-configured regular expressions.
When correctly configured, this authorizer implementation addresses the four main security risks: `Java Reflection`, `Cache Modification`, `Region Modification` and `Region Entry Modification`.
For the statement to remain true, however, the regular expressions used must be correctly configured so no mutator methods ever match. If the regular expressions are not restrictive enough,
the `Region Entry Modification` security risk might be potentially re-introduced: users with the `DATA:READ:RegionName` privilege will be able to execute methods (even those modifying the entry) on
the objects stored within the region and on instances used as bind parameters of the query.
**Note:**
This authorizer must be used with extreme care, it is the most powerful in terms of flexibility and versatility (full control through regular expressions regarding what to allow and what to forbid);
but it is also the most dangerous as one small mistake in the configured regular expressions can unexpectedly allow a wide variety of non safe methods to be executed.
**Note:**
Usage of this authorizer implementation is only recommended for scenarios in which the user knows exactly what code is deployed to the cluster, allowing a correct configuration of the regular expressions used.
It might also be used on clusters on which all entries stored are immutable.
## <a id="implementing_custom_authorizer"></a>Custom Authorizers
### How Authorization Works
It is important to note that the query engine does not have any information about the actual type of the objects while pre-processing or parsing the query itself, neither can it obtain these details before actually executing the query.
The actual check to determine whether a method is allowed or not must be executed while the objects are being traversed by the query engine in runtime.
The query engine, however, remembers whether a specific method has been already authorized or not for the current query execution context, meaning that **the authorization will be executed only once in the lifetime of a particular query
for every new method seen while traversing the objects**. Nevertheless, the authorizer implementation must be highly performant as it will be invoked by <%=vars.product_name%> in runtime during the actual query execution.
### Implementing a Method Authorizer
Complete these items to implement a custom method authorizer.
- Decide which methods from your domain model should be allowed to be invoked during a query execution.
- Decide which resources, if any, you will need in order to determine whether a method can be invoked or not.
- Implement the `initialize` method of the `MethodInvocationAuthorizer` interface to fully configure your implementation, based on the resources needed to execute the authorization.
- Implement the `authorize` method of the `MethodInvocationAuthorizer` interface. It must determine whether a `method` is allowed to be executed on a particular object instance during a query execution. The implementation should be **lightning fast** and **thread safe**.
## <a id="changing_method_authorizer"></a>Changing the Method Authorizer
You can set the `MethodInvocationAuthorizer` to be used by the query engine through the `gfsh` command-line utility.
In addition, you can modify the configured `MethodInvocationAuthorizer` while members are already running by using the [alter query-service](../../tools_modules/gfsh/command-pages/alter.html#topic_alter_query_service) command.
It is always advisable to make these changes during periods of low activity, though.
The following constraints apply when the `MethodInvocationAuthorizer` used by the cluster is changed in runtime:
- Queries started after the `MethodInvocationAuthorizer` is changed will use the newly configured authorizer.
- Queries in flight are not affected. Before the query starts, it picks up the already configured `MethodInvocationAuthorizer` and will use it until the execution finishes.
- Indexes configured with an expression using methods forbidden by the newly configured `MethodInvocationAuthorizer` will be marked as invalid the next time a mapping is added or removed from the index.
- Continuous queries already running will pick up the newly configured `MethodInvocationAuthorizer` the next time the CQ is processed upon the arrival of a cache event.
If the CQ has methods forbidden by the newly configured `MethodInvocationAuthorizer`, any subsequent execution will result in an error during the CQ processing, and the `onError` method will be invoked for the associated `CqListener`.
**Note:**
In order to improve performance, the continuous query engine uses an internal cache to avoid executing the query in scenarios for which the answer can be automatically inferred.
These results might become invalid after applying the new security rules, so <%=vars.product_name%> disables the usage of this optimization until the member is restarted or the query is registered again.