diff --git a/e2e-test/helpers/wait-service-to-start.sh b/e2e-test/helpers/wait-service-to-start.sh index 2f599ba94..bbe1ac48f 100755 --- a/e2e-test/helpers/wait-service-to-start.sh +++ b/e2e-test/helpers/wait-service-to-start.sh @@ -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)) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index fdad64ffb..7c1844646 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -10,14 +10,14 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.49 - 1.16 - 3.0.33 + 1.73 + 1.31 + 3.0.48 3.3.1 src/test/resources/SearchSuite.xml - 2.9.10.5 + 2.9.10.8 community @@ -129,7 +129,7 @@ org.projectlombok lombok - 1.18.12 + 1.18.20 test @@ -171,4 +171,4 @@ - + \ No newline at end of file diff --git a/e2e-test/python-generator/generator.py b/e2e-test/python-generator/generator.py index 889f6fabe..be8f7eb02 100644 --- a/e2e-test/python-generator/generator.py +++ b/e2e-test/python-generator/generator.py @@ -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') diff --git a/e2e-test/python-generator/templates/alfresco/Dockerfile.template b/e2e-test/python-generator/templates/alfresco/Dockerfile.template index 3438f963e..9ba789e6f 100755 --- a/e2e-test/python-generator/templates/alfresco/Dockerfile.template +++ b/e2e-test/python-generator/templates/alfresco/Dockerfile.template @@ -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/org.alfresco.web.app.servlet.AlfrescoX509ServletFilter<\/filter-class>/&\n\ + \n\ + allow-unauthenticated-solr-endpoint<\/param-name>\n\ + true<\/param-value>\n\ + <\/init-param>/" $${TOMCAT_DIR}/webapps/alfresco/WEB-INF/web.xml; \ fi # Expose keystore folder diff --git a/e2e-test/qa/compatibility/.env b/e2e-test/qa/compatibility/.env deleted file mode 100644 index be96f1b9c..000000000 --- a/e2e-test/qa/compatibility/.env +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/compatibility/Makefile b/e2e-test/qa/compatibility/Makefile deleted file mode 100644 index 2844d8cb6..000000000 --- a/e2e-test/qa/compatibility/Makefile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/compatibility/docker-compose.yml b/e2e-test/qa/compatibility/docker-compose.yml deleted file mode 100644 index 6c07160e3..000000000 --- a/e2e-test/qa/compatibility/docker-compose.yml +++ /dev/null @@ -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 diff --git a/e2e-test/qa/search/backup/.env b/e2e-test/qa/search/backup/.env deleted file mode 100644 index 4b81b609b..000000000 --- a/e2e-test/qa/search/backup/.env +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/backup/Makefile b/e2e-test/qa/search/backup/Makefile deleted file mode 100644 index 16a5472df..000000000 --- a/e2e-test/qa/search/backup/Makefile +++ /dev/null @@ -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 diff --git a/e2e-test/qa/search/backup/README.md b/e2e-test/qa/search/backup/README.md deleted file mode 100644 index 2f1679ccc..000000000 --- a/e2e-test/qa/search/backup/README.md +++ /dev/null @@ -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) diff --git a/e2e-test/qa/search/backup/docker-compose.backup.yml b/e2e-test/qa/search/backup/docker-compose.backup.yml deleted file mode 100644 index 71b61f3e4..000000000 --- a/e2e-test/qa/search/backup/docker-compose.backup.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/backup/docs/backup.png b/e2e-test/qa/search/backup/docs/backup.png deleted file mode 100644 index 2bec6377f..000000000 Binary files a/e2e-test/qa/search/backup/docs/backup.png and /dev/null differ diff --git a/e2e-test/qa/search/custom/.env b/e2e-test/qa/search/custom/.env deleted file mode 100644 index 4b81b609b..000000000 --- a/e2e-test/qa/search/custom/.env +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/custom/Dockerfile b/e2e-test/qa/search/custom/Dockerfile deleted file mode 100644 index b37b029ff..000000000 --- a/e2e-test/qa/search/custom/Dockerfile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/custom/Makefile b/e2e-test/qa/search/custom/Makefile deleted file mode 100644 index 3114c2a0d..000000000 --- a/e2e-test/qa/search/custom/Makefile +++ /dev/null @@ -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 diff --git a/e2e-test/qa/search/custom/README.md b/e2e-test/qa/search/custom/README.md deleted file mode 100644 index 082a1eb01..000000000 --- a/e2e-test/qa/search/custom/README.md +++ /dev/null @@ -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) diff --git a/e2e-test/qa/search/custom/docker-compose.custom.yml b/e2e-test/qa/search/custom/docker-compose.custom.yml deleted file mode 100644 index bba4ea17c..000000000 --- a/e2e-test/qa/search/custom/docker-compose.custom.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: '3' -services: - search: - build: - context: ./custom - dockerfile: Dockerfile - image: quay.io/alfresco/search-services-custom:${SEARCH_TAG} - volumes: - - .:/backup diff --git a/e2e-test/qa/search/custom/spellcheck/enable-spellcheck.sh b/e2e-test/qa/search/custom/spellcheck/enable-spellcheck.sh deleted file mode 100755 index d241ed55d..000000000 --- a/e2e-test/qa/search/custom/spellcheck/enable-spellcheck.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -set -ex - -echo "Enabling SpellCheck" -cat <> /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 \ No newline at end of file diff --git a/e2e-test/qa/search/docker-compose.yml b/e2e-test/qa/search/docker-compose.yml deleted file mode 100644 index b18d4fdd1..000000000 --- a/e2e-test/qa/search/docker-compose.yml +++ /dev/null @@ -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 diff --git a/e2e-test/qa/search/master-master/.env b/e2e-test/qa/search/master-master/.env deleted file mode 100644 index 4b81b609b..000000000 --- a/e2e-test/qa/search/master-master/.env +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/master-master/README.md b/e2e-test/qa/search/master-master/README.md deleted file mode 100644 index 9a7c342f2..000000000 --- a/e2e-test/qa/search/master-master/README.md +++ /dev/null @@ -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 - ``` \ No newline at end of file diff --git a/e2e-test/qa/search/master-master/docker-compose.yml b/e2e-test/qa/search/master-master/docker-compose.yml deleted file mode 100644 index b7047bcd4..000000000 --- a/e2e-test/qa/search/master-master/docker-compose.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/upgrade/.env b/e2e-test/qa/search/upgrade/.env deleted file mode 100644 index 4b81b609b..000000000 --- a/e2e-test/qa/search/upgrade/.env +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/upgrade/Makefile b/e2e-test/qa/search/upgrade/Makefile deleted file mode 100644 index f4cf4dad8..000000000 --- a/e2e-test/qa/search/upgrade/Makefile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/search/upgrade/README.md b/e2e-test/qa/search/upgrade/README.md deleted file mode 100644 index fae181d47..000000000 --- a/e2e-test/qa/search/upgrade/README.md +++ /dev/null @@ -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) diff --git a/e2e-test/qa/search/upgrade/docker-compose.upgrade.yml b/e2e-test/qa/search/upgrade/docker-compose.upgrade.yml deleted file mode 100644 index 63ed716b2..000000000 --- a/e2e-test/qa/search/upgrade/docker-compose.upgrade.yml +++ /dev/null @@ -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" - \ No newline at end of file diff --git a/e2e-test/qa/search/upgrade/docs/upgrade.png b/e2e-test/qa/search/upgrade/docs/upgrade.png deleted file mode 100644 index 3d36c9e54..000000000 Binary files a/e2e-test/qa/search/upgrade/docs/upgrade.png and /dev/null differ diff --git a/e2e-test/qa/upgrade/.env b/e2e-test/qa/upgrade/.env deleted file mode 100644 index 12e1e73f3..000000000 --- a/e2e-test/qa/upgrade/.env +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/upgrade/Makefile b/e2e-test/qa/upgrade/Makefile deleted file mode 100644 index b6be7f6dd..000000000 --- a/e2e-test/qa/upgrade/Makefile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/e2e-test/qa/upgrade/docker-compose.yml b/e2e-test/qa/upgrade/docker-compose.yml deleted file mode 100644 index a25eaeebd..000000000 --- a/e2e-test/qa/upgrade/docker-compose.yml +++ /dev/null @@ -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 diff --git a/e2e-test/src/test/resources/default.properties b/e2e-test/src/test/resources/default.properties index 822a78906..cdea4f50e 100644 --- a/e2e-test/src/test/resources/default.properties +++ b/e2e-test/src/test/resources/default.properties @@ -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 diff --git a/search-services/README.md b/search-services/README.md index 3e2fc017b..a029fd0fa 100644 --- a/search-services/README.md +++ b/search-services/README.md @@ -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. diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedAuthPlugin.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedAuthPlugin.java index 302459b63..ff05bea2e 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedAuthPlugin.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedAuthPlugin.java @@ -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 parameters) { diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java index f37ec1067..5e3517975 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java @@ -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 PROPS_CACHE = new ConcurrentHashMap<>(); + // Ordered list of property location functions + private static final ArrayList>> 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> propertySetValidator) + { + // Loop orderly through the property locators until the property is found + Set 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 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> 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 toSet(String value) + { + Set propertySet = new HashSet<>(); + + if (value != null) + { + propertySet.add(value); + } + + return propertySet; + } + } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyHelper.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyHelper.java index 785e931e5..4a7caec03 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyHelper.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyHelper.java @@ -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 getCommsFromCores() + static Set getPropertyFromCores(String name, String defaultValue) { try (Stream 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) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/security/SecretSharedPropertyCollectorTest.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/security/SecretSharedPropertyCollectorTest.java index 27313f364..97bf0a388 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/security/SecretSharedPropertyCollectorTest.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/security/SecretSharedPropertyCollectorTest.java @@ -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 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 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 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 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 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 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 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 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 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(); } } + } diff --git a/search-services/packaging/src/docker/search_config_setup.sh b/search-services/packaging/src/docker/search_config_setup.sh index aabcf63bb..89688e905 100644 --- a/search-services/packaging/src/docker/search_config_setup.sh +++ b/search-services/packaging/src/docker/search_config_setup.sh @@ -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