This is an automated email from the ASF dual-hosted git repository.
Cole-Greer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/master by this push:
new 29dd43fde4 CTR Docs Updates
29dd43fde4 is described below
commit 29dd43fde4e1834c94dcdddbb269f07c104b181f
Author: Cole Greer <[email protected]>
AuthorDate: Mon Jul 20 12:21:58 2026 -0700
CTR Docs Updates
- Update gremlin-socket-server tests dev for new HTTP format
- Update gremlin-server security docs
- Update docs/tinkeradoc-extension to Java 17+
---
docs/src/dev/developer/for-committers.asciidoc | 22 +-
docs/src/reference/gremlin-applications.asciidoc | 263 ++---------------------
docs/src/reference/gremlin-variants.asciidoc | 2 +
docs/tinkeradoc-extension/README.md | 3 -
docs/tinkeradoc-extension/pom.xml | 3 +-
5 files changed, 25 insertions(+), 268 deletions(-)
diff --git a/docs/src/dev/developer/for-committers.asciidoc
b/docs/src/dev/developer/for-committers.asciidoc
index c905138353..dd9936a70f 100644
--- a/docs/src/dev/developer/for-committers.asciidoc
+++ b/docs/src/dev/developer/for-committers.asciidoc
@@ -705,23 +705,21 @@ configured by `CucumberOptions` on "*FeatureTest" setups.
[[gremlin-socket-server-tests]]
=== Gremlin Socket Server Tests
-IMPORTANT: 4.0.0-beta.2 Release - Removes websockets. This section will be
updated as the new HTTP test server falls into place.
-
-`gremlin-socket-server` is an included test server for driver tests which
require predefined server
+`gremlin-socket-server` is an included HTTP test server for driver tests which
require predefined server
behavior. Typically, this is to test scenarios such as the server closing the
connection or returning
an error code but other response behavior can be added as needed for tests.
-Gremlin socket server uses the request id of incoming messages to determine
how to respond.
-Request ids are defined in `gremlin-tools/gremlin-socket-server/conf/*.yaml`.
The server side
-behavior for each request id is implemented in `TestWSGremlinInitializer`.
+Gremlin socket server uses the gremlin string of incoming requests to
determine how to respond.
+These gremlin strings are defined as constants in `SocketServerConstants`. The
server side
+behavior for each string is implemented in `TestHttpGremlinHandler`.
-To add new server side behavior, define a new request id in the config yaml,
then add a corresponding
-field in `SocketServerSettings`. In `TestWSGremlinInitializer`, add a new
block to the if else chain in the
-decode method which matches the request id. Define all server behavior and
responses in this block.
+To add new server side behavior, define a new gremlin string constant in
`SocketServerConstants`, then
+add a matching `case` to the switch statement in the `channelRead0` method of
`TestHttpGremlinHandler`.
+Define all server behavior and responses in this block.
-To write the driver test, send a request message to the gremlin socket server
port as if it were a normal
-gremlin server. Override the request id on the request with one defined in the
config yaml and gremlin
-socket server will respond according to the defined behavior.
+To write the driver test, send an HTTP request to the gremlin socket server
port as if it were a normal
+gremlin server, setting the `gremlin` field to one of the strings defined in
`SocketServerConstants` and
+gremlin socket server will respond according to the defined behavior.
Ensure that the socket server is running during driver tests. By default, a
docker image for
`gremlin-socket-server` is built during `mvn install`. The simplest way to use
the socket server during
diff --git a/docs/src/reference/gremlin-applications.asciidoc
b/docs/src/reference/gremlin-applications.asciidoc
index b2eb1435e6..1670e7748e 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -1315,7 +1315,7 @@ Gremlin Server with the
<<gremlin-java,`gremlin-driver`>>, set the `credentials`
when constructing the `Cluster`.
[source,java]
-Cluster cluster = Cluster.build().credentials("stephen", "password")
+Cluster cluster = Cluster.build().auth(Auth.basic("stephen", "password"))
.enableSsl(true).trustStore("server.jks").create();
If connecting with Gremlin Console, which utilizes `gremlin-driver` for remote
script execution, use the provided
@@ -1346,7 +1346,7 @@ $ bin/gremlin-server.sh
conf/gremlin-server-rest-secure.yaml
Once the server has started, issue a request passing the credentials with an
`Authentication` header, as described in
link:http://tools.ietf.org/html/rfc2617#section-2[RFC2617]. Here's a HTTP Basic
authentication example with cURL:
[source,text]
-curl -X POST --insecure -u stephen:password -d "{\"gremlin\":\"100-1\"}"
"https://localhost:8182"
+curl -X POST --insecure -u stephen:password -d "{\"gremlin\":\"g.V()\"}"
"https://localhost:8182"
[[credentials-dsl]]
==== Credentials Graph DSL
@@ -1403,7 +1403,6 @@ presence of operations such as:
* reading from a GraphTraversalSource
* writing to a GraphTraversalSource
-* presence of lambdas in bytecode
* script execution
* `VertexProgram` execution (OLAP)
* removal or modification of `TraversalStrategy` instances
@@ -1439,20 +1438,18 @@ on the requesting user or can seek externally.
. Apart from passing or denying requests, an `Authorizer` implementation can
actively modify the request, in particular
add the `TraversalStrategy` instances mentioned in item 1.
-IMPORTANT: This section is written with gremlin bytecode requests in mind.
Realizing authorization for script requests
-is hardly feasible, because such requests get full access to Gremlin Server's
execution environment. Although the section
+IMPORTANT: Realizing authorization for Groovy script requests is hardly
feasible, because such requests get full access
+to Gremlin Server's execution environment. Although the section
<<script-execution>> explains how the client access to this environment can be
restricted, it is not possible to deny
execution of `GraphFactory.open()` or `GraphTraversalSource.getGraph()`
methods without resorting to TinkerPop
implementation details (that is, internal API's that can change without
notice).
-IMPORTANT: 4.0.0-beta.2 Release - These authorization mechanisms don't
currently apply due to the removal of Bytecode.
-
The three mechanisms for authorization each have their merits in terms of
simplicity and flexibility. The table below
gives an overview.
[width="95%",cols="5,2,2,4",options="header"]
|=========================================================
-|Type (mechanism) |GraphTraversalSources |Groups |Bytecode analysis
+|Type (mechanism) |GraphTraversalSources |Groups |Request analysis
|Implicit (YAML config or init script) | all accessible |one
|`withStrategies()`
|Passive (pass/deny) | selected access |few |hybrid
|Active (inject) |selected access |many |hybrid
@@ -1477,256 +1474,20 @@ same graph can be reused with different
`SubgraphStrategies`. Now, authorization
accessible `GraphTraversalSources` and the authorizer can simply match the
requested access to a `GraphTraversalSource`
against the policies applicable to the authenticated user. Like for the active
authorization solution, other restrictions
such as read only access can be either applied at authorization time as policy
in the authorizer itself or at request
-execution time as a result of an applied `Strategy` (denoted as 'hybrid'
bytecode analysis in the table). A code
-example pursuing the former option is provided in the <<authz-code-example,
next section>>.
+execution time as a result of an applied `Strategy` (denoted as 'hybrid'
request analysis in the table).
-IMPORTANT: 4.0.0-beta.2 Release - passive and active authorization mechanisms
are not supported in this beta
-because bytecode has been replaced with GremlinLang.
+IMPORTANT: The passive and active mechanisms described above are not currently
implemented in 4.0.0-beta.3. They
+previously operated by analyzing Bytecode requests, which has been removed in
favor of GremlinLang, and the `Authorizer`
+interface does not currently apply authorization logic to GremlinLang
requests. Only the implicit mechanism (restricting
+`TraversalStrategy` instances configured via `traversalSources`, described
above) is functional today. Client
+authentication such as HTTP Basic or SigV4 is handled separately through
driver request interceptors. See
+<<gremlin-drivers-variants, Gremlin Drivers and Variants>>.
NOTE: Gremlin Server is not shipped with `Authorizer` implementations, because
these would heavily depend on the external
systems to integrate with, e.g. link:https://ldap.com/directory-servers/[LDAP
systems] or
link:https://ranger.apache.org/[Apache Ranger ]. However, third-party
implementations can be
offered as <<gremlin-plugins, gremlin plugins>>.
-[[authz-code-example]]
-===== Code example
-
-The two java classes below provide an example implementation of the
`Authorizer` interface; they originate from
-link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz[Gremlin
Server's test package].
-If you copy the files into a project, build them into a jar and add the jar to
Gremlin Server's CLASSPATH, you can use
-them by adding the following to Gremlin Server's yaml configuration file:
-
-[source, yaml]
-----
-authentication: {
- authenticator: org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator,
- config: {
- credentialsDb: conf/tinkergraph-credentials.properties}}
-authorization: {
- authorizer: org.yourpackage.AllowListAuthorizer,
- config: {
- authorizationAllowList: your/path/allow-list.yaml}}
-----
-
-The `AllowListAuthorizer` supports granting groups of users access to
statically configured `GraphTraversalSource`
-instances and to the "sandbox", where sandbox means that the group is allowed
anything unless restricted by Gremlin
-Server's <<script-execution,sandbox>>. For denying mutating steps and OLAP
operations in bytecode requests, the
-`AllowListAuthorizer` relies on the `ReadOnlyStrategy` and
`VertexProgramRestrictionStrategy` being present in the
-`GraphTraversalSource`. However, it always denies the use of lambdas in
bytecode requests unless the user has the
-"sandbox" grant. It uses the `BytecodeHelper.getLambdaLanguage()` method to
detect these.
-
-The grants to groups of users can be configured in a simple yaml file. In
addition to the special value "sandbox" for
-a grant for string based requests and lambdas, the special value "anonymous"
can be used to denote any user.
-
-[source,java]
-----
-package org.yourpackage;
-
-import org.apache.tinkerpop.gremlin.util.message.RequestMessage;
-import
org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
-import
org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
-import
org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
-import org.apache.tinkerpop.gremlin.server.Settings.AuthorizationSettings;
-import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
-
-import java.util.*;
-
-/**
- * Authorizes a user per request, based on a list that grants access to {@link
TraversalSource} instances for
- * bytecode requests and to gremlin server's sandbox for string requests and
lambdas. The {@link
- * AuthorizationSettings}.config must have an authorizationAllowList entry
that contains the name of a YAML file.
- * This authorizer is for demonstration purposes only. It does not scale well
in the number of users regarding
- * memory usage and administrative burden.
- */
-public class AllowListAuthorizer implements Authorizer {
-
- public static final String SANDBOX = "sandbox";
- public static final String REJECT_BYTECODE = "User not authorized for
bytecode requests on %s";
- public static final String REJECT_LAMBDA = "lambdas";
- public static final String REJECT_MUTATE = "the ReadOnlyStrategy";
- public static final String REJECT_OLAP = "the
VertexProgramRestrictionStrategy";
- public static final String REJECT_SUBGRAPH = "the SubgraphStrategy";
- public static final String REJECT_STRING = "User not authorized for
string-based requests.";
- public static final String KEY_AUTHORIZATION_ALLOWLIST =
"authorizationAllowList";
-
- // Collections derived from the list with allowed users for fast lookups
- private final Map<String, List<String>> usernamesByTraversalSource = new
HashMap<>();
- private final Set<String> usernamesSandbox = new HashSet<>();
-
- /**
- * This method is called once upon system startup to initialize the {@code
AllowListAuthorizer}.
- */
- @Override
- public void setup(final Map<String,Object> config) {
- AllowList allowList;
- final String file = (String) config.get(KEY_AUTHORIZATION_ALLOWLIST);
-
- try {
- allowList = AllowList.read(file);
- } catch (Exception e) {
- throw new IllegalArgumentException(String.format("Failed to read
list with allowed users from %s", file));
- }
- for (Map.Entry<String, List<String>> entry :
allowList.grants.entrySet()) {
- if (!entry.getKey().equals(SANDBOX)) {
- usernamesByTraversalSource.put(entry.getKey(), new
ArrayList<>());
- }
- for (final String group : entry.getValue()) {
- if (allowList.groups.get(group) == null) {
- throw new RuntimeException(String.format("Group '%s' not
defined in file with allowed users.", group));
- }
- if (entry.getKey().equals(SANDBOX)) {
- usernamesSandbox.addAll(allowList.groups.get(group));
- } else {
-
usernamesByTraversalSource.get(entry.getKey()).addAll(allowList.groups.get(group));
- }
- }
- }
- }
-
- /**
- * Checks whether a user is authorized to have a gremlin bytecode request
from a client answered and raises an
- * {@link AuthorizationException} if this is not the case. For a request
to be authorized, the user must either
- * have a grant for the requested {@link TraversalSource}, without using
lambdas, mutating steps or OLAP, or have a
- * sandbox grant.
- *
- * @param user {@link AuthenticatedUser} that needs authorization.
- * @param bytecode The gremlin {@link Bytecode} request to authorize the
user for.
- * @param aliases A {@link Map} with a single key/value pair that maps the
name of the {@link TraversalSource} in the
- * {@link Bytecode} request to name of one configured in
Gremlin Server.
- * @return The original or modified {@link Bytecode} to be used for
further processing.
- */
- @Override
- public Bytecode authorize(final AuthenticatedUser user, final Bytecode
bytecode, final Map<String, String> aliases) throws AuthorizationException {
- final Set<String> usernames = new HashSet<>();
-
- for (final String resource: aliases.values()) {
- usernames.addAll(usernamesByTraversalSource.get(resource));
- }
- final boolean userHasTraversalSourceGrant =
usernames.contains(user.getName()) ||
usernames.contains(AuthenticatedUser.ANONYMOUS_USERNAME);
- final boolean userHasSandboxGrant =
usernamesSandbox.contains(user.getName()) ||
usernamesSandbox.contains(AuthenticatedUser.ANONYMOUS_USERNAME);
- final boolean runsLambda =
BytecodeHelper.getLambdaLanguage(bytecode).isPresent();
- final boolean touchesReadOnlyStrategy =
bytecode.toString().contains(ReadOnlyStrategy.class.getSimpleName());
- final boolean touchesOLAPRestriction =
bytecode.toString().contains(VertexProgramRestrictionStrategy.class.getSimpleName());
- // This element becomes obsolete after resolving TINKERPOP-2473 for
allowing only a single instance of each traversal strategy.
- final boolean touchesSubgraphStrategy =
bytecode.toString().contains(SubgraphStrategy.class.getSimpleName());
-
- final List<String> rejections = new ArrayList<>();
- if (runsLambda) {
- rejections.add(REJECT_LAMBDA);
- }
- if (touchesReadOnlyStrategy) {
- rejections.add(REJECT_MUTATE);
- }
- if (touchesOLAPRestriction) {
- rejections.add(REJECT_OLAP);
- }
- if (touchesSubgraphStrategy) {
- rejections.add(REJECT_SUBGRAPH);
- }
- String rejectMessage = REJECT_BYTECODE;
- if (rejections.size() > 0) {
- rejectMessage += " using " + String.join(", ", rejections);
- }
- rejectMessage += ".";
-
- if ( (!userHasTraversalSourceGrant || runsLambda ||
touchesOLAPRestriction || touchesReadOnlyStrategy || touchesSubgraphStrategy)
&& !userHasSandboxGrant) {
- throw new AuthorizationException(String.format(rejectMessage,
aliases.values()));
- }
- return bytecode;
- }
-
- /**
- * Checks whether a user is authorized to have a script request from a
gremlin client answered and raises an
- * {@link AuthorizationException} if this is not the case.
- *
- * @param user {@link AuthenticatedUser} that needs authorization.
- * @param msg {@link RequestMessage} in which the {@link
org.apache.tinkerpop.gremlin.util.Tokens}.ARGS_GREMLIN argument can contain an
arbitrary succession of script statements.
- */
- public void authorize(final AuthenticatedUser user, final RequestMessage
msg) throws AuthorizationException {
- if (!usernamesSandbox.contains(user.getName())) {
- throw new AuthorizationException(REJECT_STRING);
- }
- }
-}
-----
-
-[source,java]
-----
-package org.yourpackage;
-
-import org.yaml.snakeyaml.TypeDescription;
-import org.yaml.snakeyaml.Yaml;
-import org.yaml.snakeyaml.constructor.Constructor;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * AllowList for the AllowListAuthorizer as configured by a YAML file.
- */
-public class AllowList {
-
- /**
- * Holds lists of groups by grant. A grant is either a TraversalSource
name or the "sandbox" value. With the
- * sandbox grant users can access all TraversalSource instances and
execute groovy scripts as string based
- * requests or as lambda functions, only limited by Gremlin Server's
sandbox definition.
- */
- public Map<String, List<String>> grants;
-
- /**
- * Holds lists of user names by groupname. The "anonymous" user name can
be used to denote any user.
- */
- public Map<String, List<String>> groups;
-
- /**
- * Read a configuration from a YAML file into an {@link AllowList} object.
- *
- * @param file the location of a AllowList YAML configuration file
- * @return An {@link Optional} object wrapping the created {@link
AllowList}
- */
- public static AllowList read(final String file) throws Exception {
- final InputStream stream = new FileInputStream(new File(file));
-
- final Constructor constructor = new Constructor(AllowList.class);
- final TypeDescription allowListDescription = new
TypeDescription(AllowList.class);
- allowListDescription.putMapPropertyType("grants", String.class,
Object.class);
- allowListDescription.putMapPropertyType("groups", String.class,
Object.class);
- constructor.addTypeDescription(allowListDescription);
-
- final Yaml yaml = new Yaml(constructor);
- return yaml.loadAs(stream, AllowList.class);
- }
-}
-----
-
-
-allow-list.yaml:
-[source,yaml]
-----
-grants: {
-gclassic: [groupclassic],
-gmodern: [groupmodern],
-gcrew: [groupclassic, groupmodern],
-ggrateful: [groupgrateful],
-sandbox: [groupsandbox]
-}
-
-groups: {
-groupclassic: [userclassic],
-groupmodern: [usermodern, stephen],
-groupsink: [usersink],
-groupgrateful: [anonymous],
-groupsandbox: [usersandbox, marko]
-}
-----
-
-
[[script-execution]]
==== Protecting Groovy Script Execution
diff --git a/docs/src/reference/gremlin-variants.asciidoc
b/docs/src/reference/gremlin-variants.asciidoc
index 885e4866c4..c853aacb67 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -1266,6 +1266,8 @@ Gremlin Server roughly uses this same approach when it
configures its serializer
ensure compatibility when making requests.
[[gremlin-java-streaming]]
+==== Streaming Deserialization
+
The driver streams and deserializes a response incrementally as it arrives
only when `GraphBinaryMessageSerializerV4`
is configured, which is the default. Any other `MessageSerializer`, such as a
GraphSON serializer, causes the driver to
buffer the full response body before deserializing it.
diff --git a/docs/tinkeradoc-extension/README.md
b/docs/tinkeradoc-extension/README.md
index 6903e2bfe7..d0e685b318 100644
--- a/docs/tinkeradoc-extension/README.md
+++ b/docs/tinkeradoc-extension/README.md
@@ -70,9 +70,6 @@ even though the code now lives in
`org.apache.tinkerpop.tinkeradoc`.
mvn clean install -f docs/tinkeradoc-extension/pom.xml
-Requires Java 11 or later, as AsciidoctorJ 2.5.x does. `asciidoctorj` is a
`provided` dependency because the
-`asciidoctor-maven-plugin` supplies it at documentation build time.
-
## Generating the Docs
Do not invoke this project directly to build documentation.
`bin/process-docs.sh` is the entrypoint: it validates the
diff --git a/docs/tinkeradoc-extension/pom.xml
b/docs/tinkeradoc-extension/pom.xml
index ee4a6491b2..d095d8b994 100644
--- a/docs/tinkeradoc-extension/pom.xml
+++ b/docs/tinkeradoc-extension/pom.xml
@@ -62,8 +62,7 @@ limitations under the License.
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
- <!-- AsciidoctorJ 2.5.x requires Java 11+ -->
- <release>11</release>
+ <release>17</release>
</configuration>
</plugin>
<plugin>