OASIS CMIS Repository Connector - opencrawling/opencrawling GitHub Wiki
Module: oc-cmis-repository-connector
Connector Class: org.opencrawling.cmis.CmisRepositoryConnector
Client Class: org.opencrawling.cmis.CmisClient
Document Builder: org.opencrawling.cmis.CmisDocumentBuilder
Security Mapper: org.opencrawling.cmis.CmisSecurityMapper
Spring Bean: @Component (activated when spring.opencrawling.connector.type=cmis or CONNECTOR_TYPE=cmis)
The OASIS CMIS Repository Connector provides OpenCrawling with native, high-performance connectivity to any Enterprise Content Management (ECM) system implementing the OASIS Content Management Interoperability Services (CMIS) 1.0 and 1.1 open standard.
Compatible out of the box with industry-leading ECM systems โ including Alfresco Content Services (ACS), OpenText Content Server / Documentum, IBM FileNet P8, Apache Chemistry InMemory / FileShare, Nuxeo, and Microsoft SharePoint (via CMIS bridges) โ this connector crawls folder hierarchies, executes CMIS-SQL queries, retrieves version series, extracts fine-grained Access Control Lists (ACLs), captures secondary types / aspects, and streams binary content payloads directly into OpenCrawling's RAG and vector ingestion pipelines.
Built entirely on modern Java 25 (java.net.http.HttpClient), the connector features zero legacy dependencies (avoiding deprecated Apache Chemistry client jars), leverages Java 25 Virtual Threads (StructuredTaskScope) for concurrent traversal, and seamlessly integrates with the Open Ingestion Standard (OIS) and OpenCrawling's Claim Check Pattern.
graph TD
subgraph ECM["Enterprise ECM Repositories (OASIS CMIS 1.0 / 1.1)"]
ACS["Alfresco Content Services"]
DCTM["OpenText Documentum"]
FN["IBM FileNet P8"]
NX["Nuxeo / Apache Chemistry"]
ACS & DCTM & FN & NX -->|CMIS 1.1 Browser Binding / JSON| Endpoint["CMIS REST Endpoint (:8080/.../versions/1.1/browser)"]
end
subgraph OpenCrawling["OpenCrawling Ingestion Runtime (Java 25)"]
CmisClient["CmisClient (Native JDK 25 HttpClient)"]
Connector["CmisRepositoryConnector (oc-cmis-repository-connector)"]
VThreads["Virtual Threads (StructuredTaskScope)"]
SecMap["CmisSecurityMapper (ACE -> OIS Permissions)"]
DocBld["CmisDocumentBuilder (Properties & Aspects)"]
ClaimCheck["Binary Content Stream (Claim Check Store)"]
Tika["Apache Tika Text Extraction"]
Endpoint <-->|HTTP GET / POST JSON| CmisClient
CmisClient --> Connector
Connector --> VThreads
VThreads --> SecMap
VThreads --> DocBld
VThreads -->|cmisselector=content| ClaimCheck
ClaimCheck --> Tika
OIS["OIS Document (UPSERT / Tombstone DELETE)"]
DocBld --> OIS
SecMap --> OIS
Tika --> OIS
OIS --> Kafka["Kafka Topic (opencrawling-raw-documents)"]
Kafka --> Ingestion["oc-ingestion-consumer (Chunking & Embeddings)"]
Ingestion --> Sinks[("Vector Stores: PGVector / Milvus / Qdrant / Solr / Luxir")]
end
subgraph AI["Enterprise AI & RAG Assistants"]
Sinks --> SecureMcp["OpenCrawling Secure MCP Server"]
SecureMcp -->|Zero-Trust ACL-Filtered RAG| Agents["AI Agents / Enterprise LLMs"]
end
-
Standardized OASIS CMIS 1.0 & 1.1 Support:
- Implements the CMIS 1.1 Browser Binding (JSON over HTTP/REST), providing superior serialization speed and payload efficiency compared to legacy AtomPub or SOAP bindings.
- Connects to any compliant CMIS service endpoint with standard HTTP Basic Authentication or Bearer tokens.
-
Zero Legacy Dependencies:
- Built using pure Java 25
HttpClientand Jackson JSON parsing. Eliminates bulky, end-of-life Apache Chemistry client libraries while delivering faster startup, smaller footprint, and full compatibility with modern JDK runtime modules.
- Built using pure Java 25
-
Flexible Crawl Modes:
-
Folder Hierarchy (
FOLDER): Recursively crawls folders and documents starting from a configurable root path (e.g./,/Company Home/Sites) or folder ID, with configurable exclusion rules (excluded-folder-paths). -
CMIS-SQL Query (
QUERY): Ingests documents using standard CMIS-SQL queries (e.g.SELECT * FROM cmis:document WHERE cmis:creationDate >= '2026-01-01T00:00:00.000Z'), allowing targeted, dynamic document selection. -
Change Log Ingestion (
changeLogEnabled): Consumes the repository change log (getContentChanges) using incremental change tokens for efficient near-real-time synchronization.
-
Folder Hierarchy (
-
Configurable Versioning Policies:
-
latest_major: Ingests only the latest released major version (cmis:isLatestMajorVersion = true), ideal for official corporate documentation. -
latest: Ingests the latest version (cmis:isLatestVersion = true), including work-in-progress minor revisions. -
all: Ingests all versions in the document version series.
-
-
Zero-Trust Access Control Lists (ACLs):
- Automatically inspects repository Access Control Entries (ACEs) and maps permissions (
cmis:read,cmis:write,cmis:all) into Open Ingestion Standard (OIS)SecurityConfigandPermissionRulestructures. - Distinguishes between user principals, organizational groups (
group:*), and public/everyone identities, preserving strict authorization barriers during vector search.
- Automatically inspects repository Access Control Entries (ACEs) and maps permissions (
-
Secondary Types & Aspects Extraction:
- Parses both concise (
succinctProperties) and verbose CMIS 1.1 property structures. - Automatically extracts secondary object type IDs (
cmis:secondaryObjectTypeIds) and all attached custom aspect properties (e.g., Alfrescocm:titled,cm:author, custom metadata namespaces).
- Parses both concise (
-
Claim Check Pattern for Large Binaries:
- Streams raw document content streams (
cmisselector=content) directly to the configured Claim Check store (local shared volume, Apache Ozone, AWS S3) with configurable size limits (max-content-size-bytes), passing lightweight URI references through Kafka.
- Streams raw document content streams (
-
Document Deletion & Tombstones:
- Generates standard OIS tombstone records (
DocumentAction.DELETE) when objects are removed or detected via change logs, triggering automated purging from downstream vector databases.
- Generates standard OIS tombstone records (
-
High-Throughput Concurrency with Virtual Threads:
- Leverages Java 25
StructuredTaskScopeand virtual threads (Thread.ofVirtual()) to parallelize folder traversal, document metadata enrichment, and binary content retrieval.
- Leverages Java 25
Configure the CMIS Repository Connector via application.yml or standard environment variables:
| Property Key | Environment Variable | Default | Description |
|---|---|---|---|
spring.opencrawling.connector.cmis.endpoint-url |
CMIS_ENDPOINT_URL |
http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/browser |
Base URL of the CMIS Browser Binding service |
spring.opencrawling.connector.cmis.binding-type |
CMIS_BINDING_TYPE |
browser |
Protocol binding: browser (JSON) or atompub
|
spring.opencrawling.connector.cmis.repository-id |
CMIS_REPOSITORY_ID |
"" (auto-discovered) |
Target repository ID (e.g. -default-); auto-discovers if empty |
spring.opencrawling.connector.cmis.username |
CMIS_USERNAME |
admin |
Repository authentication username |
spring.opencrawling.connector.cmis.password |
CMIS_PASSWORD |
admin |
Repository authentication password |
spring.opencrawling.connector.cmis.crawl-mode |
CMIS_CRAWL_MODE |
folder |
Ingestion mode: folder (hierarchy crawl) or query (CMIS-SQL) |
spring.opencrawling.connector.cmis.root-folder-path |
CMIS_ROOT_FOLDER_PATH |
/ |
Starting folder path for folder crawl mode |
spring.opencrawling.connector.cmis.root-folder-id |
CMIS_ROOT_FOLDER_ID |
"" |
Optional starting folder object ID (overrides path if specified) |
spring.opencrawling.connector.cmis.include-subfolders |
CMIS_INCLUDE_SUBFOLDERS |
true |
Recursively traverse subfolder hierarchies |
spring.opencrawling.connector.cmis.excluded-folder-paths |
CMIS_EXCLUDED_FOLDER_PATHS |
/Sites/trash,/System |
Comma-separated list of folder path prefixes to skip |
spring.opencrawling.connector.cmis.cmis-query |
CMIS_QUERY |
SELECT * FROM cmis:document |
CMIS-SQL query string for query crawl mode |
spring.opencrawling.connector.cmis.versions-mode |
CMIS_VERSIONS_MODE |
latest_major |
Version filter policy: latest_major, latest, or all
|
spring.opencrawling.connector.cmis.include-content-stream |
CMIS_INCLUDE_CONTENT_STREAM |
true |
Download binary content streams for text extraction |
spring.opencrawling.connector.cmis.max-content-size-bytes |
CMIS_MAX_CONTENT_SIZE_BYTES |
52428800 (50 MB) |
Maximum document file size to download |
spring.opencrawling.connector.cmis.include-acls |
CMIS_INCLUDE_ACLS |
true |
Extract and map Access Control Entries (ACEs) to OIS security rules |
spring.opencrawling.connector.cmis.include-secondary-types |
CMIS_INCLUDE_SECONDARY_TYPES |
true |
Extract secondary object type IDs and custom aspect properties |
spring.opencrawling.connector.cmis.change-log-enabled |
CMIS_CHANGE_LOG_ENABLED |
false |
Enable incremental change log synchronization |
spring.opencrawling.connector.cmis.change-log-token |
CMIS_CHANGE_LOG_TOKEN |
"" |
Initial change log token for incremental synchronization |
spring.opencrawling.connector.cmis.batch-size |
CMIS_BATCH_SIZE |
100 |
Number of objects fetched per CMIS pagination request |
spring.opencrawling.connector.cmis.timeout-seconds |
CMIS_TIMEOUT_SECONDS |
30 |
HTTP request timeout in seconds |
When launching jobs via the OpenCrawling Admin UI, REST API, or CLI, the SCAN_PATH parameter dynamically overrides the crawl target:
SCAN_PATH Value |
Behaviour |
|---|---|
/ or (empty)
|
Starts crawling from the repository root folder (/) |
/Company Home/Sites/finance |
Crawls folder hierarchy starting from specified path |
SELECT * FROM cmis:document WHERE ... |
Detected as CMIS-SQL query: automatically switches crawl mode to QUERY
|
f81d4fae-7dec-11d0-a765-00a0c91e6bf6 (UUID) |
Directly targets the folder with matching CMIS object ID |
Each crawled CMIS document is normalized into an OIS RepositoryDocument with structured metadata attributes:
| Metadata Attribute | Type | Description |
|---|---|---|
name |
STRING |
Document display name (cmis:name) |
cmis.objectId |
STRING |
Repository-wide unique CMIS object identifier |
cmis.name |
STRING |
Original document name |
cmis.baseTypeId |
STRING |
Base CMIS type (cmis:document, cmis:folder, etc.) |
cmis.objectTypeId |
STRING |
Primary object type definition (e.g. cm:content) |
cmis.secondaryObjectTypeIds |
LIST<STRING> |
Applied secondary types / aspects (e.g. P:cm:titled, P:cm:author) |
cmis.createdBy |
STRING |
Username of document author |
cmis.creationDate |
TIMESTAMP |
ISO-8601 creation timestamp |
cmis.lastModifiedBy |
STRING |
Username of last modifier |
cmis.lastModificationDate |
TIMESTAMP |
ISO-8601 modification timestamp |
cmis.versionLabel |
STRING |
Version label (e.g. 1.0, 2.1) |
cmis.isLatestVersion |
BOOLEAN |
Whether this is the latest version in the series |
cmis.isLatestMajorVersion |
BOOLEAN |
Whether this is the latest major release |
cmis.contentStreamLength |
LONG |
Binary content length in bytes |
cmis.contentStreamMimeType |
STRING |
Content MIME type (e.g. application/pdf, text/plain) |
cmis.contentStreamFileName |
STRING |
Original file attachment name |
cmis.path |
STRING |
Absolute folder hierarchy path within the repository |
<customProperty> |
Dynamic | All custom properties and aspect attributes mapped dynamically |
See Zero-Trust Security & ACL Management for the unified architecture covering CMIS, Alfresco, Flowable, and Camunda.
The connector's CmisSecurityMapper inspects CMIS Access Control Lists (ACLs) and maps them into OIS SecurityConfig:
-
Principal Resolution:
-
everyone,group_everyone,anonymous$\rightarrow$ publicidentity type. - Principals starting with
group:or containinggroup$\rightarrow$ groupidentity type. - Named user accounts
$\rightarrow$ useridentity type.
-
-
Permission Level Mapping:
- CMIS
cmis:all$\rightarrow$ OISadminpermission. - CMIS
cmis:write$\rightarrow$ OISwritepermission. - CMIS
cmis:read$\rightarrow$ OISreadpermission.
- CMIS
During vector retrieval, queries automatically enforce these permissions:
{
"security": {
"isExact": true,
"permissions": [
{
"principal": "GROUP_ENGINEERING",
"identityType": "group",
"access": "read"
},
{
"principal": "john.doe",
"identityType": "user",
"access": "write"
}
]
}
}In the production decoupled architecture, oc-crawler streams CMIS documents to Kafka, oc-ingestion-consumer chunks content, oc-embedding-service generates vector embeddings, and oc-writer-consumer writes to PostgreSQL PGVector:
services:
oc-crawler:
image: opencrawling/oc-runtime:latest
container_name: oc-crawler-cmis
environment:
CONNECTOR_TYPE: cmis
SCAN_PATH: /Company Home
CMIS_ENDPOINT_URL: http://alfresco:8080/alfresco/api/-default-/public/cmis/versions/1.1/browser
CMIS_REPOSITORY_ID: -default-
CMIS_USERNAME: admin
CMIS_PASSWORD: admin
CMIS_CRAWL_MODE: folder
CMIS_INCLUDE_SUBFOLDERS: "true"
CMIS_VERSIONS_MODE: latest_major
CMIS_INCLUDE_ACLS: "true"
CMIS_INCLUDE_CONTENT_STREAM: "true"
SPRING_OPENCRAWLING_CLAIM_CHECK_STORE: local
SPRING_OPENCRAWLING_CLAIM_CHECK_LOCAL_DIR: /data/claims
KAFKA_BOOTSTRAP_SERVERS: kafka:9092
volumes:
- shared-data:/data/claims
depends_on:
- kafka
- alfrescoFor quick local testing or single-container jobs:
services:
oc-runtime:
image: opencrawling/oc-runtime:latest
environment:
CONNECTOR_TYPE: cmis
SPRING_OPENCRAWLING_OUTPUT_TYPE: vector
CMIS_ENDPOINT_URL: http://cmis-server:8080/cmis/browser
CMIS_USERNAME: admin
CMIS_PASSWORD: admin
CMIS_CRAWL_MODE: folder
CMIS_ROOT_FOLDER_PATH: /
SPRING_AI_VECTORSTORE_PGVECTOR_URL: jdbc:postgresql://postgres:5432/opencrawlingThe OpenCrawling repository includes automated end-to-end integration tests for both direct and decoupled CMIS pipelines:
# Direct integration test with mock CMIS repository
./opencrawling-in-org/scripts/test-cmis-connector.sh
# Decoupled distributed test (Crawler -> Kafka -> Ingestion -> Embeddings -> PGVector)
./opencrawling-in-org/scripts/test-cmis-decoupled.sh
# Complete integration test runner
./run-integration-tests.sh scripts/test-cmis-decoupled.shAfter a crawl job finishes, verify ingested CMIS documents and chunks in PostgreSQL:
-- Check total embedded document chunks
SELECT count(*) FROM vector_store_1024;
-- Preview chunk content and CMIS metadata
SELECT id,
LEFT(content, 200) AS preview,
metadata->>'cmis.name' AS document_name,
metadata->>'cmis.objectId' AS object_id,
metadata->>'cmis.versionLabel' AS version,
metadata->>'cmis.path' AS cmis_path
FROM vector_store_1024
ORDER BY id
LIMIT 10;
-- Test ACL-aware semantic similarity search
SELECT id,
LEFT(content, 300) AS preview,
metadata->>'cmis.name' AS document_name,
1 - (embedding <=> (SELECT embedding FROM vector_store_1024 LIMIT 1)) AS similarity
FROM vector_store_1024
WHERE metadata->'security'->'permissions' @> '[{"principal":"GROUP_ENGINEERING"}]'
ORDER BY similarity DESC
LIMIT 5;