Merge pull request #1375 from Alfresco/feature/ACS-2438_backport

This commit is contained in:
Domenico Sibilio
2022-03-02 15:36:07 +01:00
committed by GitHub
37 changed files with 322 additions and 827 deletions
+6 -1
View File
@@ -14,7 +14,12 @@ do
echo "Waiting for Service to start using endpoint: ${endpoint}"
until [[ "$(curl --output /dev/null -w ''%{http_code}'' --silent --head --fail ${endpoint})" == 200 ]] || [ "$COUNTER" -eq "$TIMEOUT" ]; do
additional_args=()
if [[ $endpoint == *"solr"* ]]; then
additional_args+=(-H "X-Alfresco-Search-Secret: secret")
fi
until [[ "$(curl --output /dev/null -w ''%{http_code}'' "${additional_args[@]}" --silent --head --fail ${endpoint})" == 200 ]] || [ "$COUNTER" -eq "$TIMEOUT" ]; do
printf '.'
sleep $WAIT_INTERVAL
COUNTER=$(($COUNTER+$WAIT_INTERVAL))
+6 -6
View File
@@ -10,14 +10,14 @@
<name>Search Analytics E2E Tests</name>
<description>Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share</description>
<properties>
<tas.rest.api.version>1.49</tas.rest.api.version>
<tas.cmis.api.version>1.16</tas.cmis.api.version>
<tas.utility.version>3.0.33</tas.utility.version>
<tas.rest.api.version>1.73</tas.rest.api.version>
<tas.cmis.api.version>1.31</tas.cmis.api.version>
<tas.utility.version>3.0.48</tas.utility.version>
<rm.version>3.3.1</rm.version>
<suiteXmlFile>src/test/resources/SearchSuite.xml</suiteXmlFile>
<test.exclude />
<test.include />
<jackson.databind.version>2.9.10.5</jackson.databind.version>
<jackson.databind.version>2.9.10.8</jackson.databind.version>
<licenseName>community</licenseName>
</properties>
<build>
@@ -129,7 +129,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<version>1.18.20</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -171,4 +171,4 @@
</snapshots>
</repository>
</repositories>
</project>
</project>
+3 -1
View File
@@ -129,7 +129,7 @@ def getSolrcoreReplacements(sharding, communication, fingerprint):
solrcoreReplacements['alfresco.encryption.ssl.truststore.location=.*'] = 'alfresco.encryption.ssl.truststore.location=\\\\\\/opt\\\\\\/alfresco-search-services\\\\\\/keystore\\\\\\/ssl-repo-client.truststore'
solrcoreReplacements['alfresco.encryption.ssl.truststore.type=.*'] = 'alfresco.encryption.ssl.truststore.type=JCEKS'
elif communication == 'none':
solrcoreReplacements['alfresco.secureComms=https'] = 'alfresco.secureComms=none'
solrcoreReplacements['alfresco.secureComms=https'] = r'alfresco.secureComms=none\\\\\\\nalfresco.allowUnauthenticatedSolrEndpoint=true'
else :
solrcoreReplacements['alfresco.secureComms=https'] = 'alfresco.secureComms=secret'
return solrcoreReplacements
@@ -325,6 +325,8 @@ if __name__ == '__main__':
if args.communication == 'mtls':
addAlfrescoMtlsConfig(dcYaml['services']['alfresco']['build']['args'])
addAlfrescoVolumes(dcYaml['services']['alfresco'])
elif args.communication == 'none':
dcYaml['services']['alfresco']['build']['args']['SOLR_COMMS'] = 'none'
if not args.share:
deleteServices(dcYaml, 'share', 'alfresco-pdf-renderer', 'imagemagick')
@@ -42,6 +42,12 @@ RUN if [ "$$SOLR_COMMS" == "https" ] ; then \
truststoreFile=\"\/usr\/local\/tomcat\/alf_data\/keystore\/ssl.truststore\"\n\
truststorePass=\"$${TRUSTSTORE_PASS}\" truststoreType=\"$${TRUSTSTORE_TYPE}\" clientAuth=\"want\" sslProtocol=\"TLS\">\n\
<\/Connector>/g" $${TOMCAT_DIR}/conf/server.xml; \
elif [ "$$SOLR_COMMS" == "none" ] ; then \
sed -i "s/<filter-class>org.alfresco.web.app.servlet.AlfrescoX509ServletFilter<\/filter-class>/&\n\
<init-param>\n\
<param-name>allow-unauthenticated-solr-endpoint<\/param-name>\n\
<param-value>true<\/param-value>\n\
<\/init-param>/" $${TOMCAT_DIR}/webapps/alfresco/WEB-INF/web.xml; \
fi
# Expose keystore folder
-11
View File
@@ -1,11 +0,0 @@
# docker-compose related environments
ALFRESCO_IMAGE=quay.io/alfresco/alfresco-governance-repository-enterprise
ALFRESCO_TAG=latest
SHARE_IMAGE=quay.io/alfresco/alfresco-governance-share-enterprise
SHARE_TAG=latest
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/insight-engine
SEARCH_TAG=latest
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
-9
View File
@@ -1,9 +0,0 @@
include ../Makefile
include .env
# CURRENT_DIR is the folder where this Makefile is saved
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
start: ## 0 - starts search service with SSL enabled
$(dc) config && $(dc) up -d && \
make wait
@@ -1,65 +0,0 @@
version: '3'
services:
alfresco:
image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG}
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=8983
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
-Xms1g -Xmx1g
"
ports:
- "7203:7203" #JMX connect via service:jmx:rmi:///jndi/rmi://localhost:7203/jmxrmi
- "5005:5005" #Java debugging
- "8081:8080" #Browser port for Alfresco
share:
image: ${SHARE_IMAGE}:${SHARE_TAG}
environment:
- REPO_HOST=alfresco
- REPO_PORT=8080
- "CATALINA_OPTS= -Xms500m -Xmx500m"
ports:
- 8082:8080 #Browser port for Share
postgres:
image: ${POSTGRES_IMAGE}:${POSTGRES_TAG}
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
ports:
- 5432:5432
search:
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
environment:
#Solr needs to know how to register itself with Alfresco
- SOLR_ALFRESCO_HOST=alfresco
- SOLR_ALFRESCO_PORT=8080
#Alfresco needs to know how to call solr
- SOLR_SOLR_HOST=search
- SOLR_SOLR_PORT=8983
#Create the default alfresco and archive cores
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
ports:
- 8083:8983 #Browser port
activemq:
image: ${ACTIVEMQ_IMAGE}:${ACTIVEMQ_TAG}
ports:
- 8161:8161 # Web Console
- 5672:5672 # AMQP
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
-11
View File
@@ -1,11 +0,0 @@
# docker-compose related environments
ALFRESCO_IMAGE=alfresco/alfresco-content-repository
ALFRESCO_TAG=6.1.0-EA3
SHARE_IMAGE=alfresco/alfresco-share
SHARE_TAG=6.0
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/search-services
SEARCH_TAG=latest
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
-68
View File
@@ -1,68 +0,0 @@
include ../../Makefile
include .env
# the suffix of the backup taken in time. It can be overriden on runtime: make SUFIX=T1 backup-perform
SUFIX ?=T0
# CURRENT_DIR is the folder where this Makefile is saved
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
# this is used also in compose yml files
export HOST_BACKUP_LOCATION:=$(CURRENT_DIR)/host-bkp
ifeq ($(dc-backup),)
dc-backup:=$(dc) -f ../docker-compose.yml -f docker-compose.backup.yml
endif
backup-prepare: clean ## 1 - prepare backup for testing
@echo "Starting Backup Prepare" && \
$(sudo) rm -rf $(HOST_BACKUP_LOCATION) && \
mkdir -p $(HOST_BACKUP_LOCATION)/alf_data && \
mkdir -p $(HOST_BACKUP_LOCATION)/solr/archive && \
mkdir -p $(HOST_BACKUP_LOCATION)/solr/alfresco && \
mkdir -p $(HOST_BACKUP_LOCATION)/db && \
$(sudo) chmod -R 777 $(HOST_BACKUP_LOCATION) && \
$(dc-backup) up -d
backup-perform: ## 2 - perform the backup of alf_data and db data
@echo "Starting Backup Perform" && \
$(sudo) rm -rf $(HOST_BACKUP_LOCATION)_$(SUFIX) && \
$(sudo) chmod -R 777 $(HOST_BACKUP_LOCATION) && \
$(dc-backup) stop alfresco && \
$(dc-backup) exec postgres bash -c 'pg_dump --dbname=postgresql://alfresco:alfresco@127.0.0.1:5432/alfresco' > $(HOST_BACKUP_LOCATION)/db/alfresco.pg && \
cp -R $(HOST_BACKUP_LOCATION) $(HOST_BACKUP_LOCATION)_$(SUFIX) && \
$(dc-backup) start alfresco
backup-restore: clean ## 3 - start restoring from backup location
@echo "Starting Backup Restore" && \
$(sudo) rm -rf $(HOST_BACKUP_LOCATION) && \
mkdir -p $(HOST_BACKUP_LOCATION) && \
cp -rf $(HOST_BACKUP_LOCATION)_$(SUFIX)/alf_data $(HOST_BACKUP_LOCATION)/alf_data && \
cp -rf $(HOST_BACKUP_LOCATION)_$(SUFIX)/db/ $(HOST_BACKUP_LOCATION)/db/ && \
cp -rf $(HOST_BACKUP_LOCATION)_$(SUFIX)/solr $(HOST_BACKUP_LOCATION)/solr && \
$(sudo) chmod -R 777 $(HOST_BACKUP_LOCATION) && \
$(dc-backup) up -d postgres && sleep 30 && \
$(dc-backup) exec postgres bash -c 'psql --dbname=postgresql://alfresco:alfresco@127.0.0.1:5432/alfresco < /backup/db/alfresco.pg' && \
$(dc-backup) up -d
all: show-config ## 0 - executes the entire backup process
# perform the backup and waits until the server is starting
# do some change on backed up data
# then restore from backup and check the content is restored as expected
make backup-prepare wait && \
make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-backup-suite.xml
make backup-perform wait && \
make run-mvn-tests suiteXmlFile=./src/test/resources/search-on-backup-suite.xml
make backup-restore wait && \
make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-backup-suite.xml
show-config: ## show compose configuration
$(dc-backup) config
clean: ## kill containers, remove volumes and data
$(dc-backup) kill && $(dc-backup) rm -fv
$(sudo) rm -rf $(HOST_BACKUP_LOCATION)
tail-logs: ## tails all container logs
$(dc-backup) logs -f
-49
View File
@@ -1,49 +0,0 @@
# About
Testing the Backup of SearchService product
**Build Plan:** https://bamboo.alfresco.com/bamboo/browse/SAD-QAB
![](docs/backup.png?raw=true)
# Steps
* **a)** prepare the backup
```shel
make backup-prepare wait
```
>more details on Makefile [task](Makefile#L27).
* **b)** create some data manually or using automated tests found on this project
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-backup-suite.xml
```
* **c)** perform the backup of data
```shel
make backup-perform wait
```
* **d)** now you can also update the data/remove it from TS, or even remove the entire volumes
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-on-backup-suite.xml
# or
make clean
```
* **e)** at any time you can restore the backup
```shel
make backup-restore wait
```
* **f)** now you can check the data from point **b)** is corectly recovered
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-backup-suite.xml
```
# All in one
At any time you can run the `make all` taks that will execute all the above commands for you
```shel
make all
```
# Environment Settings
Pay attention at the values that exist in [.env](.env) file. These settings will be picked up in custom docker-compose.*.yml file(s)
@@ -1,39 +0,0 @@
version: '3'
services:
alfresco:
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=8983
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
-Dsolr.backup.alfresco.remoteBackupLocation=/backup/solr/alfresco/
-Dsolr.backup.alfresco.numberToKeep=1
-Dsolr.backup.archive.remoteBackupLocation=/backup/solr/archive/
-Dsolr.backup.archive.numberToKeep=1"
volumes:
- ${HOST_BACKUP_LOCATION}/alf_data:/usr/local/tomcat/alf_data
search:
environment:
- VERSION=${SEARCH_TAG}
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
volumes:
- ${HOST_BACKUP_LOCATION}/solr:/backup/solr
postgres:
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
volumes:
- ${HOST_BACKUP_LOCATION}/db:/backup/db
Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

-11
View File
@@ -1,11 +0,0 @@
# docker-compose related environments
ALFRESCO_IMAGE=alfresco/alfresco-content-repository
ALFRESCO_TAG=6.1.0-EA3
SHARE_IMAGE=alfresco/alfresco-share
SHARE_TAG=6.0
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/search-services
SEARCH_TAG=latest
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
-16
View File
@@ -1,16 +0,0 @@
ARG SEARCH_TAG=latest
FROM quay.io/alfresco/search-services:$SEARCH_TAG
LABEL creator="Paul Brodner" maintainer="Alfresco Search Services Team"
ARG SCRIPTS_FOLDER=
USER root
RUN echo " &" >> $DIST_DIR/solr/bin/search_config_setup.sh && \
echo "bash -c \"find $DIST_DIR/scripts/ -maxdepth 1 -type f -executable -name '*.sh' -exec {} \\;\"" >> $DIST_DIR/solr/bin/search_config_setup.sh && \
echo "bash -c \"tail -f $DIST_DIR/logs/solr.log\"" >> $DIST_DIR/solr/bin/search_config_setup.sh
USER solr
COPY ${SCRIPTS_FOLDER}/* ${DIST_DIR}/scripts/
# we need this, because we tail on it in the search_config_setup.sh (see above)
RUN touch ./logs/solr.log
-21
View File
@@ -1,21 +0,0 @@
include ../../Makefile
include .env
# CURRENT_DIR is the folder where this Makefile is saved
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
ifeq ($(dc-custom),)
dc-custom:=$(dc) -f ../docker-compose.yml -f docker-compose.custom.yml
endif
## ---- CUSTOM
build: ## 1 - build a custom image: $ make SCRIPTS_FOLDER=spellcheck build
ifndef SCRIPTS_FOLDER
@echo SCRIPTS_FOLDER not defined "Usage: make SCRIPTS_FOLDER=spellcheck build"
exit 1
endif
$(dc-custom) build --force-rm --no-cache --pull --build-arg SCRIPTS_FOLDER=$(SCRIPTS_FOLDER)
start: ## 2 - starts the custom image built: $ make start
$(dc-custom) up -d && make wait
-25
View File
@@ -1,25 +0,0 @@
# About
Start Search Service with a custom configuration
# Steps
* **a)** under `custom` folder create a new folder that will hold all settings
>checkout [spellcheck](.spellcheck) folder for example
>add here any shell scripts that will enable/disable a particular setting
* **b)** build the new image setting SCRIPTS_FOLDER to you folder already created
```shel
make SCRIPTS_FOLDER=spellcheck build
```
>notice that out [docker-compose.custom.yml](.custom/docker-compose.custom.yml) file is using a [Dockerfile](.custom/Dockerfile) to built you new image.
> at runtime, all shell scripts from your folder are executed and the settings are applied.
* **c)** the image is built locally, now start it up
```shel
make start
```
# Environment Settings
Pay attention at the values that exist in [.env](.env) file. These settings will be picked up in custom docker-compose.*.yml file(s)
@@ -1,9 +0,0 @@
version: '3'
services:
search:
build:
context: ./custom
dockerfile: Dockerfile
image: quay.io/alfresco/search-services-custom:${SEARCH_TAG}
volumes:
- .:/backup
@@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -ex
echo "Enabling SpellCheck"
cat <<EOF >> /opt/alfresco-search-services/solrhome/conf/shared.properties
# Enabling SpellCheck
# configuration:
# * http://docs.alfresco.com/6.0/concepts/solr-shared-properties.html
# * https://docs.alfresco.com/5.2/tasks/solr6-install-withoutSSL.html
# test it: http://docs.alfresco.com/6.0/concepts/search-api-spellcheck.html
# Suggestable Properties
alfresco.suggestable.property.0={http://www.alfresco.org/model/content/1.0}name
alfresco.suggestable.property.1={http://www.alfresco.org/model/content/1.0}title
alfresco.suggestable.property.2={http://www.alfresco.org/model/content/1.0}description
alfresco.suggestable.property.3={http://www.alfresco.org/model/content/1.0}content
EOF
-63
View File
@@ -1,63 +0,0 @@
version: '3'
services:
alfresco:
image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG}
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=8983
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
"
ports:
- "7203:7203" #JMX connect via service:jmx:rmi:///jndi/rmi://localhost:7203/jmxrmi
- "5005:5005" #Java debugging
- "8081:8080" #Browser port for Alfresco
share:
image: ${SHARE_IMAGE}:${SHARE_TAG}
environment:
- REPO_HOST=alfresco
- REPO_PORT=8080
ports:
- 8082:8080 #Browser port for Share
postgres:
image: ${POSTGRES_IMAGE}:${POSTGRES_TAG}
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
ports:
- 5432:5432
search:
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
environment:
#Solr needs to know how to register itself with Alfresco
- SOLR_ALFRESCO_HOST=alfresco
- SOLR_ALFRESCO_PORT=8080
#Alfresco needs to know how to call solr
- SOLR_SOLR_HOST=search
- SOLR_SOLR_PORT=8983
#Create the default alfresco and archive cores
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
ports:
- 8083:8983 #Browser port
activemq:
image: ${ACTIVEMQ_IMAGE}:${ACTIVEMQ_TAG}
ports:
- 8161:8161 # Web Console
- 5672:5672 # AMQP
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
-11
View File
@@ -1,11 +0,0 @@
# docker-compose related environments
ALFRESCO_IMAGE=alfresco/alfresco-content-repository
ALFRESCO_TAG=6.1.0-EA3
SHARE_IMAGE=alfresco/alfresco-share
SHARE_TAG=6.0
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/search-services
SEARCH_TAG=latest
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
@@ -1,22 +0,0 @@
# About
Start Alfresco services and scale SOLR to multiple instances, behind a LB.
# Steps
* **a)** Start Alfresco
```
docker-compose up -d
```
* **b)** Scale SOLR to 2 instances
```
docker-compose scale solr=2
```
>it's possible at this time to restart `alfresco` service if there are not results returned by LB
```
docker-compose restart alfresco
```
@@ -1,72 +0,0 @@
version: '3'
services:
alfresco:
image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG}
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=80
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
"
ports:
- "7203:7203" #JMX connect via service:jmx:rmi:///jndi/rmi://localhost:7203/jmxrmi
- "5005:5005" #Java debugging
- "8081:8080" #Browser port for Alfresco
share:
image: ${SHARE_IMAGE}:${SHARE_TAG}
environment:
- REPO_HOST=alfresco
- REPO_PORT=8080
ports:
- 8082:8080 #Browser port for Share
postgres:
image: ${POSTGRES_IMAGE}:${POSTGRES_TAG}
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
ports:
- 5432:5432
search:
image: dockercloud/haproxy
links:
- solr
ports:
- 8083:80 #Browser port
volumes:
- /var/run/docker.sock:/var/run/docker.sock
solr:
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
environment:
#Solr needs to know how to register itself with Alfresco
- SOLR_ALFRESCO_HOST=alfresco
- SOLR_ALFRESCO_PORT=8080
#Alfresco needs to know how to call solr
- SOLR_SOLR_HOST=search
- SOLR_SOLR_PORT=8983
#Create the default alfresco and archive cores
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
ports:
- 8983 #Browser port
activemq:
image: ${ACTIVEMQ_IMAGE}:${ACTIVEMQ_TAG}
ports:
- 8161:8161 # Web Console
- 5672:5672 # AMQP
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
-11
View File
@@ -1,11 +0,0 @@
# docker-compose related environments
ALFRESCO_IMAGE=alfresco/alfresco-content-repository
ALFRESCO_TAG=6.1.0-EA3
SHARE_IMAGE=alfresco/alfresco-share
SHARE_TAG=6.0
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/search-services
SEARCH_TAG=latest
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
-41
View File
@@ -1,41 +0,0 @@
include ../../Makefile
include .env
# CURRENT_DIR is the folder where this Makefile is saved
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
ifeq ($(dc-upgrade),)
dc-upgrade:=$(dc) -f ../docker-compose.yml -f docker-compose.upgrade.yml
endif
## ---- UPGRADE
set_version ?=latest # default version that will be used in tasks
as-previous: clean ## 1 - install the previous version: $ make set_version=1.2.1 as-previous
rm -rf ./solr-data && \
rm -rf ./solr-contentstore && \
rm -f ./image-digests.txt
export SEARCH_TAG=$(set_version) && \
$(dc-upgrade) pull && \
echo "\n====Previous====" > image-digests.txt && \
$(dc-upgrade) config --resolve-image-digests >> image-digests.txt && \
$(dc-upgrade) up -d && \
docker ps
as-current: ## 2 - upgrade previous to this version $ make set_version=2.0.x as-current
$(dc-upgrade) kill search && \
$(dc-upgrade) rm -f search && \
export SEARCH_TAG=$(set_version) && \
$(dc-upgrade) pull search && \
echo "\n====Current====" >> image-digests.txt && \
$(dc-upgrade) config --resolve-image-digests >> image-digests.txt && \
$(dc-upgrade) up -d search && \
docker ps
#
# Run the following commands if you need to test the upgrade e2e
#
#make set_version=1.2.1 as-previous wait
#make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-upgrade-suite.xml
#make set_version=2.0.x as-current wait
#make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-upgrade-suite.xml
-31
View File
@@ -1,31 +0,0 @@
# About
Testing the Upgrade of SearchService product
**Build Plan:** https://bamboo.alfresco.com/bamboo/browse/SAD-QAUP
![](docs/upgrade.png?raw=true)
# Steps
* **a)** start the initial version
```shel
make set_version=1.2.1 as-previous wait
```
>notice that new folders will appear on you "upgrade" folder with data from container(s)
* **b)** create some data manually or using automated tests found on this project
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-upgrade-suite.xml
```
* **c)** now upgrade to new version
```shel
make set_version=2.0.x as-current wait
```
* **d)** and test that upgrade data exist
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-upgrade-suite.xml
```
# Environment Settings
Pay attention at the values that exist in [.env](.env) file. These settings will be picked up in custom docker-compose.*.yml file(s)
@@ -1,10 +0,0 @@
version: '3'
services:
search:
environment:
- VERSION=${SEARCH_TAG}
image: quay.io/alfresco/search-services:${SEARCH_TAG}
volumes:
- "./upgrade/solr-data:/opt/alfresco-search-services/data"
- "./upgrade/solr-contentstore:/opt/alfresco-search-services/contentstore"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

-15
View File
@@ -1,15 +0,0 @@
# docker-compose related environments
ALFRESCO_IMAGE=alfresco/alfresco-content-repository
ALFRESCO_TAG=6.1.0-EA3
SHARE_IMAGE=alfresco/alfresco-share
SHARE_TAG=6.0
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/search-services
SEARCH_TAG=latest
DIST_DIR_PATH=/opt/alfresco-search-services
#SEARCH_IMAGE=quay.io/alfresco/insight-engine
#SEARCH_TAG=lates
#DIST_DIR_PATH=/opt/alfresco-insight-engine
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
-39
View File
@@ -1,39 +0,0 @@
include ../Makefile
include .env
# CURRENT_DIR is the folder where this Makefile is saved
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SEARCH_IMAGE ?=quay.io/alfresco/search-services
SEARCH_TAG ?=latest # default version that will be used in tasks
as-previous: clean ## 1 - install the previous version: $ make SEARCH_IMAGE=quay.io/alfresco/search-services SEARCH_TAG=1.2.1 as-previous
rm -rf ./solr-data && \
rm -rf ./solr-contentstore && \
rm -f ./image-digests.txt && \
export SEARCH_TAG=$(SEARCH_TAG) && \
export SEARCH_IMAGE=$(SEARCH_IMAGE) && \
$(dc) pull && \
echo "\n====Previous====" > image-digests.txt && \
$(dc) config --resolve-image-digests >> image-digests.txt && \
$(dc) up -d && \
docker ps
as-current: ## 2 - upgrade previous to this version $ make SEARCH_IMAGE=quay.io/alfresco/search-services SEARCH_TAG=2.0.x as-current
$(dc) kill search && \
$(dc) rm -f search && \
export SEARCH_TAG=$(SEARCH_TAG) && \
export SEARCH_IMAGE=$(SEARCH_IMAGE) && \
$(dc) pull search && \
echo "\n====Current====" >> image-digests.txt && \
$(dc) config --resolve-image-digests >> image-digests.txt && \
$(dc) up -d search && \
docker ps
#
# Run the following commands if you need to test the upgrade e2e
#
#make SEARCH_IMAGE=quay.io/alfresco/search-services SEARCH_TAG=1.2.1 as-previous wait
#make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-upgrade-suite.xml
#make SEARCH_IMAGE=quay.io/alfresco/search-services SEARCH_TAG=2.0.x as-current wait
#make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-upgrade-suite.xml
-66
View File
@@ -1,66 +0,0 @@
version: '3'
services:
alfresco:
image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG}
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=8983
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
"
ports:
- "7203:7203" #JMX connect via service:jmx:rmi:///jndi/rmi://localhost:7203/jmxrmi
- "5005:5005" #Java debugging
- "8081:8080" #Browser port for Alfresco
share:
image: ${SHARE_IMAGE}:${SHARE_TAG}
environment:
- REPO_HOST=alfresco
- REPO_PORT=8080
ports:
- 8082:8080 #Browser port for Share
postgres:
image: ${POSTGRES_IMAGE}:${POSTGRES_TAG}
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
ports:
- 5432:5432
search:
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
environment:
#Solr needs to know how to register itself with Alfresco
- SOLR_ALFRESCO_HOST=alfresco
- SOLR_ALFRESCO_PORT=8080
#Alfresco needs to know how to call solr
- SOLR_SOLR_HOST=search
- SOLR_SOLR_PORT=8983
#Create the default alfresco and archive cores
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
ports:
- 8083:8983 #Browser port
volumes:
- "./upgrade/solr-data:${DIST_DIR_PATH}/data"
- "./upgrade/solr-contentstore:/opt/${DIST_DIR_PATH}/contentstore"
activemq:
image: ${ACTIVEMQ_IMAGE}:${ACTIVEMQ_TAG}
ports:
- 8161:8161 # Web Console
- 5672:5672 # AMQP
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
@@ -19,6 +19,7 @@ rest.rmPath=alfresco/api/-default-/public/gs/versions/1
solr.scheme=http
solr.server=localhost
solr.port=8083
solr.secret=secret
#Solr Indexing Time
# Use 1s and 60 attempts, see AbstractE2EFunctionalTest.SEARCH_MAX_ATTEMPTS
+37 -10
View File
@@ -158,10 +158,10 @@ $ unzip alfresco-search-services-*.zip
$ cd alfresco-search-services
```
Change default Alfresco Communication protocol to `none`.
Change default Alfresco Communication protocol to `none`, and set `alfresco.allowUnauthenticatedSolrEndpoint` to `true`:
```bash
$ sed -i 's/alfresco.secureComms=https/alfresco.secureComms=none/' solrhome/templates/rerank/conf/solrcore.properties
$ sed -i 's/alfresco.secureComms=https/alfresco.secureComms=none\nalfresco.allowUnauthenticatedSolrEndpoint=true/' solrhome/templates/rerank/conf/solrcore.properties
```
*Note* Above line is written in GNU sed, you can use `gsed` from Mac OS X or just edit the file with a Text Editor.
@@ -293,8 +293,8 @@ The following environment variables are supported:
| SEARCH_LOG_LEVEL | ERROR, WARN, INFO, DEBUG or TRACE | The root logger level. |
| ENABLE_SPELLCHECK | true or false | Whether spellchecking is enabled or not. |
| DISABLE_CASCADE_TRACKING | true or false | Whether cascade tracking is enabled or not. Disabling cascade tracking will improve performance, but result in some feature loss (e.g. path queries). |
| ALFRESCO_SECURE_COMMS | https or none | Whether communication with the repository is secured. See below. |
| SOLR_SSL_... | --- | These variables are also used to configure SSL. See below. |
| ALFRESCO_SECURE_COMMS | secret or https | This property instructs Solr if it should enable Shared Secret authentication or mTLS authentication with HTTPS. See below. |
**Using Mutual Auth TLS (SSL)**
@@ -328,20 +328,39 @@ SOLR Web Console will be available at:
*Note* You must install the `browser.p12` certificate in your browser in order to access to this URL.
**Using Plain HTTP**
**Using Shared Secret Authentication**
By default Docker image is using SSL, so it's required to add an environment variable `ALFRESCO_SECURE_COMMS=none` to use SOLR in plain HTTP mode.
An alternative is to use a shared secret in order to secure repo <-> solr communication. You just need to set `ALFRESCO_SECURE_COMMS=secret` **AND** `JAVA_TOOL_OPTIONS="-Dalfresco.secureComms.secret=my_super_secret_secret"`.
By default, the SOLR Web Console will be available at:
[http://localhost:8983/solr](http://localhost:8983/solr)
but you can also start the Jetty server in SSL mode as explained above, in that case the SOLR Web Console will be available at:
[https://localhost:8983/solr](https://localhost:8983/solr)
*Note* You must install the `browser.p12` certificate in your browser in order to access to this URL.
In both cases, when trying to access the SOLR Web Console you will have to provide the `X-Alfresco-Search-Secret` header in the request, specifying as its value the same value that was used for the `-Dalfresco.secureComms.secret` property.
You can do so natively on Safari through the `Dev Tools > Local Overrides` feature, or with a browser extension on Google Chrome/Firefox/Opera/Edge: [ModHeader](https://modheader.com/).
**Using Shared Secret Authentication**
By default Docker image is using SSL, so it's required to add an environment variable `ALFRESCO_SECURE_COMMS=secret` AND `JAVA_TOOL_OPTIONS="-Dalfresco.secureComms.secret=my_super_secret_secret"` to use SOLR with Shared Secret authentication.
To run the docker image:
```bash
$ docker run -p 8983:8983 -e ALFRESCO_SECURE_COMMS=none -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive searchservices:develop
$ docker run -p 8983:8983 -e ALFRESCO_SECURE_COMMS=secret -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive -e JAVA_TOOL_OPTIONS="-Dalfresco.secureComms.secret=my_super_secret_secret" searchservices:develop
```
SOLR Web Console will be available at:
[http://localhost:8983/solr](http://localhost:8983/solr)
You will have to provide the `X-Alfresco-Search-Secret` header in the request, specifying as its value the same value that was used for the `-Dalfresco.secureComms.secret` property.
**Enabling YourKit Java Profiler**
This Docker Image includes [YourKit Java Profiler](https://www.yourkit.com/java/profiler/) server service. In order to enable this service, so the SOLR JVM can be inspected with the YourKit local program, additional configuration is required to set the YourKit `agentpath`. Mapping the exposed profiling port (10001 by default) is also required.
@@ -369,13 +388,16 @@ solr6:
SOLR_SOLR_HOST: "solr6"
SOLR_SOLR_PORT: "8983"
# HTTP settings
ALFRESCO_SECURE_COMMS: "none"
ALFRESCO_SECURE_COMMS: "secret"
#Create the default alfresco and archive cores
SOLR_CREATE_ALFRESCO_DEFAULTS: "alfresco,archive"
SOLR_JAVA_MEM: "-Xms2g -Xmx2g"
SOLR_OPTS: "
-agentpath:/usr/local/YourKit-JavaProfiler-2019.8/bin/linux-x86-64/libyjpagent.so=port=10001,listen=all
"
JAVA_TOOL_OPTIONS: "
-Dalfresco.secureComms.secret=my_super_secret_secret
"
ports:
- 8083:8983 #Browser port
- 10001:10001 #YourKit port
@@ -400,7 +422,7 @@ During deployment time whenever Search Services or Insight Engine image starts,
To run the docker image:
```bash
$ docker run -p 8984:8983 -e REPLICATION_TYPE=slave -e ALFRESCO_SECURE_COMMS=none -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive searchservices:develop
$ docker run -p 8984:8983 -e REPLICATION_TYPE=slave -e ALFRESCO_SECURE_COMMS=secret -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive -e JAVA_TOOL_OPTIONS="-Dalfresco.secureComms.secret=my_super_secret_secret" searchservices:develop
```
Solr-slave End point: [http://localhost:8984/solr](http://localhost:8984/solr)
@@ -408,7 +430,7 @@ To generate your own Docker-compose file please follow [generator-alfresco-docke
### Use Alfresco Search Services Docker Image with Docker Compose
Sample configuration in a Docker Compose file using **Plain HTTP** protocol to communicate with Alfresco Repository.
Sample configuration in a Docker Compose file using **Shared Secret Authentication** to communicate with Alfresco Repository.
```
solr6:
@@ -422,10 +444,13 @@ solr6:
SOLR_SOLR_HOST: "solr6"
SOLR_SOLR_PORT: "8983"
# HTTP settings
ALFRESCO_SECURE_COMMS: "none"
ALFRESCO_SECURE_COMMS: "secret"
#Create the default alfresco and archive cores
SOLR_CREATE_ALFRESCO_DEFAULTS: "alfresco,archive"
SOLR_JAVA_MEM: "-Xms2g -Xmx2g"
JAVA_TOOL_OPTIONS: "
-Dalfresco.secureComms.secret=my_super_secret_secret
"
ports:
- 8083:8983 #Browser port
```
@@ -434,6 +459,8 @@ SOLR Web Console will be available at:
[http://localhost:8983/solr](http://localhost:8983/solr)
You will have to provide the `X-Alfresco-Search-Secret` header in the request, specifying as its value the same value that was used for the `-Dalfresco.secureComms.secret` property.
Sample configuration in a Docker Compose file using **Mutual Auth TLS (SSL)** protocol to communicate with Alfresco Repository.
@@ -2,7 +2,7 @@
* #%L
* Alfresco Search Services
* %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,6 +26,8 @@
package org.alfresco.solr.security;
import static org.alfresco.solr.security.SecretSharedPropertyCollector.SECURE_COMMS_PROPERTY;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
@@ -49,6 +51,8 @@ import org.apache.solr.security.AuthenticationPlugin;
public class SecretSharedAuthPlugin extends AuthenticationPlugin
{
private static final String SECURE_COMMS_NONE = "none";
/**
* Verify that request header includes "secret" word when using "secret" communication method.
* "alfresco.secureComms.secret" value is expected as Java environment variable.
@@ -69,10 +73,17 @@ public class SecretSharedAuthPlugin extends AuthenticationPlugin
return true;
}
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN,
"Authentication failure: \"" + SecretSharedPropertyCollector.SECRET_SHARED_METHOD_KEY
+ "\" method has been selected, use the right request header with the secret word");
String errorMessage = "Authentication failure: \"" + SecretSharedPropertyCollector.SECRET_SHARED_METHOD_KEY
+ "\" method has been selected, use the right request header with the secret word";
setErrorResponse(response, errorMessage);
return false;
}
else if (SECURE_COMMS_NONE.equals(SecretSharedPropertyCollector.getCommsMethod())
&& !SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint())
{
String errorMessage = "Authentication failure: \"" + SECURE_COMMS_PROPERTY
+ "=none\" is no longer supported. Please use \"https\" or \"secret\" instead.";
setErrorResponse(response, errorMessage);
return false;
}
@@ -81,6 +92,12 @@ public class SecretSharedAuthPlugin extends AuthenticationPlugin
}
private void setErrorResponse(ServletResponse response, String errorMessage) throws IOException
{
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, errorMessage);
}
@Override
public void init(Map<String, Object> parameters)
{
@@ -26,13 +26,21 @@
package org.alfresco.solr.security;
import static java.util.function.Predicate.not;
import org.alfresco.httpclient.HttpClientFactory;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.config.ConfigUtil;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Consumer;
/**
* Provides property values for Alfresco Communication using "secret" method:
@@ -45,15 +53,28 @@ import java.util.Set;
public class SecretSharedPropertyCollector
{
public final static String SECRET_SHARED_METHOD_KEY = "secret";
public static final String SECRET_SHARED_METHOD_KEY = "secret";
// Property names for "secret" communication method
static final String SECURE_COMMS_PROPERTY = "alfresco.secureComms";
private final static String SHARED_SECRET = "alfresco.secureComms.secret";
private final static String SHARED_SECRET_HEADER = "alfresco.secureComms.secret.header";
static final String SHARED_SECRET = "alfresco.secureComms.secret";
static final String ALLOW_UNAUTHENTICATED_SOLR_PROPERTY = "alfresco.allowUnauthenticatedSolrEndpoint";
private static final String SHARED_SECRET_HEADER = "alfresco.secureComms.secret.header";
// Save communication method as static value in order to improve performance
static String commsMethod;
// Memoize read properties to improve performance
static final Map<String, String> PROPS_CACHE = new ConcurrentHashMap<>();
// Ordered list of property location functions
private static final ArrayList<BiFunction<String, String, Set<String>>> PROPERTY_LOCATORS = new ArrayList<>();
static
{
// Environment variables
PROPERTY_LOCATORS.add((name, defaultValue) -> toSet(ConfigUtil.locateProperty(name, null)));
// Shared configuration (shared.properties file)
PROPERTY_LOCATORS.add((name, defaultValue) -> toSet(AlfrescoSolrDataModel.getCommonConfig().getProperty(name)));
// Configuration for each deployed SOLR Core
PROPERTY_LOCATORS.add(SecretSharedPropertyHelper::getPropertyFromCores);
}
/**
* Check if communications method is "secret"
@@ -65,50 +86,63 @@ public class SecretSharedPropertyCollector
SecretSharedPropertyCollector.SECRET_SHARED_METHOD_KEY);
}
/**
* Check if unauthenticated Solr access is allowed
* @return true if unauthenticated Solr access is allowed
*/
public static boolean isAllowUnauthenticatedSolrEndpoint()
{
return Boolean.parseBoolean(PROPS_CACHE.computeIfAbsent(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY,
key -> getProperty(key, "false")));
}
/**
* Get communication method from environment variables, shared properties or core properties.
* @return Communication method: none, https, secret
*/
static String getCommsMethod()
{
if (commsMethod == null)
return PROPS_CACHE.computeIfAbsent(SECURE_COMMS_PROPERTY,
key -> getProperty(key, "none", uniqueSecureCommsValidator()));
}
private static String getProperty(String name, String defaultValue)
{
return getProperty(name, defaultValue, null);
}
private static String getProperty(String name, String defaultValue, Consumer<Set<String>> propertySetValidator)
{
// Loop orderly through the property locators until the property is found
Set<String> propertySet = PROPERTY_LOCATORS.stream()
.map(propertyLocator -> propertyLocator.apply(name, defaultValue))
.filter(not(Set::isEmpty))
.findFirst()
.orElse(Set.of());
if (propertySetValidator != null)
{
// Environment variable
commsMethod = ConfigUtil.locateProperty(SECURE_COMMS_PROPERTY, null);
if (commsMethod == null)
{
// Shared configuration (shared.properties file)
commsMethod = AlfrescoSolrDataModel.getCommonConfig().getProperty(SECURE_COMMS_PROPERTY);
if (commsMethod == null)
{
// Get configuration from deployed SOLR Cores
Set<String> secureCommsSet = SecretSharedPropertyHelper.getCommsFromCores();
// In case of multiple cores, *all* of them must have the same secureComms value.
// From that perspective, you may find the second clause in the conditional statement
// below not strictly necessary. The reason is that the check below is in charge to make
// sure a consistent configuration about the secret shared property has been defined in all cores.
if (secureCommsSet.size() > 1 && secureCommsSet.contains(SECRET_SHARED_METHOD_KEY))
{
throw new RuntimeException(
"No valid secure comms values: all the cores must be using \"secret\" communication method but found: "
+ secureCommsSet);
}
return commsMethod =
secureCommsSet.isEmpty()
? null
: secureCommsSet.iterator().next();
}
}
// Run the propertySetValidator to eg. verify value uniqueness among multiple cores
propertySetValidator.accept(propertySet);
}
return commsMethod;
return propertySet.isEmpty() ? null : propertySet.iterator().next();
}
private static Consumer<Set<String>> uniqueSecureCommsValidator()
{
// In case of multiple cores, *all* of them must have the same secureComms value.
// From that perspective, you may find the second clause in the conditional statement
// below not strictly necessary. The reason is that the check below is in charge to make
// sure a consistent configuration about the secret shared property has been defined in all cores.
return secureCommsSet -> {
if (secureCommsSet.size() > 1 && secureCommsSet.contains(SECRET_SHARED_METHOD_KEY))
{
throw new RuntimeException(
"No valid secure comms values: all the cores must be using \"secret\" communication method but found: "
+ secureCommsSet);
}
};
}
/**
@@ -126,7 +160,8 @@ public class SecretSharedPropertyCollector
if (secret == null || secret.length() == 0)
{
throw new RuntimeException("Missing value for " + SHARED_SECRET + " configuration property");
throw new RuntimeException("Missing value for " + SHARED_SECRET + " configuration property. Make sure to"
+ " pass this property as a JVM Argument (eg. -D" + SHARED_SECRET + "=my-secret-value).");
}
return secret;
@@ -167,4 +202,16 @@ public class SecretSharedPropertyCollector
return properties;
}
private static Set<String> toSet(String value)
{
Set<String> propertySet = new HashSet<>();
if (value != null)
{
propertySet.add(value);
}
return propertySet;
}
}
@@ -58,11 +58,12 @@ class SecretSharedPropertyHelper
};
/**
* Read different values of "alfresco.secureComms" property from every "solrcore.properties" files.
*
* Read different values of the specified property from every "solrcore.properties" file.
* @param name The name of the property to read
* @param defaultValue The default value for the given property
* @return List of different communication methods declared in SOLR Cores.
*/
static Set<String> getCommsFromCores()
static Set<String> getPropertyFromCores(String name, String defaultValue)
{
try (Stream<Path> walk = Files.walk(Paths.get(SolrResourceLoader.locateSolrHome().toString())))
{
@@ -74,7 +75,7 @@ class SecretSharedPropertyHelper
return solrCorePropertiesFiles.stream()
.map(toProperties)
.map(properties -> properties.getProperty(SECURE_COMMS_PROPERTY, "none"))
.map(properties -> properties.getProperty(name, defaultValue))
.collect(toSet());
}
catch (IOException e)
@@ -35,8 +35,12 @@ import java.util.Properties;
import java.util.Set;
import static java.util.Collections.emptySet;
import static org.alfresco.solr.security.SecretSharedPropertyCollector.ALLOW_UNAUTHENTICATED_SOLR_PROPERTY;
import static org.alfresco.solr.security.SecretSharedPropertyCollector.PROPS_CACHE;
import static org.alfresco.solr.security.SecretSharedPropertyCollector.SECRET_SHARED_METHOD_KEY;
import static org.alfresco.solr.security.SecretSharedPropertyCollector.SECURE_COMMS_PROPERTY;
import static org.alfresco.solr.security.SecretSharedPropertyCollector.SHARED_SECRET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -45,30 +49,133 @@ import static org.mockito.Mockito.mockStatic;
public class SecretSharedPropertyCollectorTest
{
private final static String A_COMMS_METHOD = "aCommsMethod";
private final static String SET_THROUGH_SYSTEM_PROPERTY = "aCommsMethod_SetThroughSystemProperty";
private final static String SET_THROUGH_ALFRESCO_COMMON_CONFIG = "aCommsMethod_SetThroughAlfrescoCommonConfig";
private final static String COMMS_METHOD_FROM_SOLRCORE = "aCommsMethod_FromSolrCore";
private static final String A_COMMS_METHOD = "aCommsMethod";
private static final String SET_THROUGH_SYSTEM_PROPERTY = "aCommsMethod_SetThroughSystemProperty";
private static final String SET_THROUGH_ALFRESCO_COMMON_CONFIG = "aCommsMethod_SetThroughAlfrescoCommonConfig";
private static final String COMMS_METHOD_FROM_SOLRCORE = "aCommsMethod_FromSolrCore";
private static final String SECRET_VALUE = "my-secret";
private static final String SECURE_COMMS_NONE = "none";
private static final String TRUE = "true";
private static final String FALSE = "false";
private static final Set<String> PROPS_TO_CLEAR = Set.of(SHARED_SECRET, SECURE_COMMS_PROPERTY, ALLOW_UNAUTHENTICATED_SOLR_PROPERTY);
@Before
public void setUp()
{
SecretSharedPropertyCollector.commsMethod = null;
assertNull(System.getProperty(SECURE_COMMS_PROPERTY));
assertNull(AlfrescoSolrDataModel.getCommonConfig().getProperty(SECURE_COMMS_PROPERTY));
PROPS_CACHE.clear();
for (String property : PROPS_TO_CLEAR)
{
assertNull(System.getProperty(property));
assertNull(AlfrescoSolrDataModel.getCommonConfig().getProperty(property));
}
}
@After
public void tearDown()
{
System.clearProperty(SECURE_COMMS_PROPERTY);
AlfrescoSolrDataModel.getCommonConfig().remove(SECURE_COMMS_PROPERTY);
for (String property : PROPS_TO_CLEAR)
{
System.clearProperty(property);
AlfrescoSolrDataModel.getCommonConfig().remove(property);
}
}
@Test
public void getSecret_shouldReturnTheSecretValue()
{
System.setProperty(SecretSharedPropertyCollector.SHARED_SECRET, SECRET_VALUE);
assertEquals(SECRET_VALUE, SecretSharedPropertyCollector.getSecret());
}
@Test(expected = RuntimeException.class)
public void getSecretWithMissingSecretValue_shouldThrowException()
{
SecretSharedPropertyCollector.getSecret();
}
@Test
public void allowUnauthenticatedSolrIsNotSet_shouldReturnFalse()
{
try(MockedStatic<SecretSharedPropertyHelper> mock = mockStatic(SecretSharedPropertyHelper.class))
{
mock.when(() -> SecretSharedPropertyHelper.getPropertyFromCores(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, FALSE))
.thenReturn(emptySet());
assertFalse(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
}
@Test
public void allowUnauthenticatedSolrIsTrueThroughSystemProperty_shouldReturnTrue()
{
System.setProperty(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, TRUE);
assertTrue(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
@Test
public void allowUnauthenticatedSolrIsFalseThroughSystemProperty_shouldReturnFalse()
{
System.setProperty(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, FALSE);
assertFalse(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
@Test
public void allowUnauthenticatedSolrIsTrueThroughAlfrescoProperties_shouldReturnTrue()
{
try(MockedStatic<AlfrescoSolrDataModel> mock = mockStatic(AlfrescoSolrDataModel.class))
{
var alfrescoCommonConfig = new Properties();
alfrescoCommonConfig.setProperty(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, TRUE);
mock.when(AlfrescoSolrDataModel::getCommonConfig).thenReturn(alfrescoCommonConfig);
assertTrue(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
}
@Test
public void allowUnauthenticatedSolrIsFalseThroughAlfrescoProperties_shouldReturnFalse()
{
try(MockedStatic<AlfrescoSolrDataModel> mock = mockStatic(AlfrescoSolrDataModel.class))
{
var alfrescoCommonConfig = new Properties();
alfrescoCommonConfig.setProperty(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, FALSE);
mock.when(AlfrescoSolrDataModel::getCommonConfig).thenReturn(alfrescoCommonConfig);
assertFalse(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
}
@Test
public void allowUnauthenticatedSolrIsTrueThroughSolrCores_shouldReturnTrue()
{
try(MockedStatic<SecretSharedPropertyHelper> mock = mockStatic(SecretSharedPropertyHelper.class))
{
mock.when(() -> SecretSharedPropertyHelper.getPropertyFromCores(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, FALSE))
.thenReturn(Set.of(TRUE));
assertTrue(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
}
@Test
public void allowUnauthenticatedSolrIsFalseThroughSolrCores_shouldReturnFalse()
{
try(MockedStatic<SecretSharedPropertyHelper> mock = mockStatic(SecretSharedPropertyHelper.class))
{
mock.when(() -> SecretSharedPropertyHelper.getPropertyFromCores(ALLOW_UNAUTHENTICATED_SOLR_PROPERTY, FALSE))
.thenReturn(Set.of(FALSE));
assertFalse(SecretSharedPropertyCollector.isAllowUnauthenticatedSolrEndpoint());
}
}
@Test
public void commsMethodIsNotNull_shouldReturnThatValue()
{
SecretSharedPropertyCollector.commsMethod = A_COMMS_METHOD;
PROPS_CACHE.put(SECURE_COMMS_PROPERTY, A_COMMS_METHOD);
assertEquals(A_COMMS_METHOD, SecretSharedPropertyCollector.getCommsMethod());
assertFalse(SecretSharedPropertyCollector.isCommsSecretShared());
@@ -77,7 +184,7 @@ public class SecretSharedPropertyCollectorTest
@Test
public void commsMethodIsNotNullAndIsSecret_shouldReturnThatValue()
{
SecretSharedPropertyCollector.commsMethod = SECRET_SHARED_METHOD_KEY;
PROPS_CACHE.put(SECURE_COMMS_PROPERTY, SECRET_SHARED_METHOD_KEY);
assertEquals(SECRET_SHARED_METHOD_KEY, SecretSharedPropertyCollector.getCommsMethod());
assertTrue(SecretSharedPropertyCollector.isCommsSecretShared());
@@ -121,7 +228,8 @@ public class SecretSharedPropertyCollectorTest
{
try(MockedStatic<SecretSharedPropertyHelper> mock = mockStatic(SecretSharedPropertyHelper.class))
{
mock.when(SecretSharedPropertyHelper::getCommsFromCores).thenReturn(Set.of(COMMS_METHOD_FROM_SOLRCORE));
mock.when(() -> SecretSharedPropertyHelper.getPropertyFromCores(SECURE_COMMS_PROPERTY, SECURE_COMMS_NONE))
.thenReturn(Set.of(COMMS_METHOD_FROM_SOLRCORE));
assertEquals(COMMS_METHOD_FROM_SOLRCORE, SecretSharedPropertyCollector.getCommsMethod());
assertFalse(SecretSharedPropertyCollector.isCommsSecretShared());
@@ -140,7 +248,8 @@ public class SecretSharedPropertyCollectorTest
{
try(MockedStatic<SecretSharedPropertyHelper> mock = mockStatic(SecretSharedPropertyHelper.class))
{
mock.when(SecretSharedPropertyHelper::getCommsFromCores).thenReturn(emptySet());
mock.when(() -> SecretSharedPropertyHelper.getPropertyFromCores(SECURE_COMMS_PROPERTY, SECURE_COMMS_NONE))
.thenReturn(emptySet());
assertNull(SecretSharedPropertyCollector.getCommsMethod());
assertFalse(SecretSharedPropertyCollector.isCommsSecretShared());
@@ -156,10 +265,11 @@ public class SecretSharedPropertyCollectorTest
{
try(MockedStatic<SecretSharedPropertyHelper> mock = mockStatic(SecretSharedPropertyHelper.class))
{
mock.when(SecretSharedPropertyHelper::getCommsFromCores)
.thenReturn(Set.of(COMMS_METHOD_FROM_SOLRCORE, SECRET_SHARED_METHOD_KEY));
mock.when(() -> SecretSharedPropertyHelper.getPropertyFromCores(SECURE_COMMS_PROPERTY, SECURE_COMMS_NONE))
.thenReturn(Set.of(COMMS_METHOD_FROM_SOLRCORE, SECRET_SHARED_METHOD_KEY));
SecretSharedPropertyCollector.getCommsMethod();
}
}
}
@@ -3,6 +3,10 @@ set -e
# By default its going to deploy "Master" setup configuration with "REPLICATION_TYPE=master".
# Slave replica service can be enabled using "REPLICATION_TYPE=slave" environment value.
log_warn() {
echo -e " ====WARN==== \n$*\nWARN CODE was $LOG_WARN" >&2
}
RERANK_TEMPLATE_PATH=$PWD/solrhome/templates/rerank/conf
NORERANK_TEMPLATE_PATH=$PWD/solrhome/templates/noRerank/conf
SOLR_RERANK_CONFIG_FILE=$RERANK_TEMPLATE_PATH/solrconfig.xml
@@ -86,17 +90,26 @@ if [[ ! -z "$SOLR_JAVA_MEM" ]]; then
fi
# By default Docker Image is using TLS Mutual Authentication (SSL) for communications with Repository
# Plain HTTP can be enabled by setting ALFRESCO_SECURE_COMMS to 'none'
if [[ "none" == "$ALFRESCO_SECURE_COMMS" ]]; then
sed -i 's/alfresco.secureComms=https/alfresco.secureComms=none/' $SOLR_RERANK_CORE_FILE $SOLR_NORERANK_CORE_FILE
# Apply also the setting to existing SOLR cores property files when existing
if [[ -f ${PWD}/solrhome/alfresco/conf/solrcore.properties ]]; then
sed -i 's/alfresco.secureComms=https/alfresco.secureComms=none/' ${PWD}/solrhome/alfresco/conf/solrcore.properties
fi
if [[ -f ${PWD}/solrhome/archive/conf/solrcore.properties ]]; then
sed -i 's/alfresco.secureComms=https/alfresco.secureComms=none/' ${PWD}/solrhome/archive/conf/solrcore.properties
fi
fi
# Plain HTTP with a secret word in the request header can be enabled by setting ALFRESCO_SECURE_COMMS to 'secret',
# the secret word should be defined as a JVM argument like so: JAVA_TOOL_OPTIONS="-Dalfresco.secureComms.secret=my-secret-value"
case "$ALFRESCO_SECURE_COMMS" in
secret)
sed -i "s/alfresco.secureComms=https/alfresco.secureComms=secret\n/" $SOLR_RERANK_CORE_FILE $SOLR_NORERANK_CORE_FILE
if [[ -f ${PWD}/solrhome/alfresco/conf/solrcore.properties ]]; then
sed -i "s/alfresco.secureComms=https/alfresco.secureComms=secret\n/" ${PWD}/solrhome/alfresco/conf/solrcore.properties
fi
if [[ -f ${PWD}/solrhome/archive/conf/solrcore.properties ]]; then
sed -i "s/alfresco.secureComms=https/alfresco.secureComms=secret\n/" ${PWD}/solrhome/archive/conf/solrcore.properties
fi
;;
https|'')
;;
*)
LOG_WARN=1
;;
esac
[ -z $LOG_WARN ] || log_warn "something was wrong with the authentication config, defaulting to https mTLS auth.\nIf mTLS is not properly configured Search service might not work"
if [[ true == "$ENABLE_SPELLCHECK" ]]; then
sed -i 's/#alfresco.suggestable.property/alfresco.suggestable.property/' ${PWD}/solrhome/conf/shared.properties