Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 114 additions & 29 deletions integration_oidc_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ help() {
echo -e "\t OP_USE_LOGIN_TOKEN \t Use first access token obtained by IDP (true/false). Default: false"
echo -e "\t OP_STORAGE_AUDIENCE \t Name of the storage audience (Not required when using 'OP_USE_LOGIN_TOKEN=true')"
echo -e "\t OP_STORAGE_SCOPE \t Scope for token exchange (Not required when using 'OP_USE_LOGIN_TOKEN=true')"
echo -e ""
echo -e "CONVERT_EXISTING_CONNECTION \t\t Convert existing connection between OpenProject and Nextcloud (true/false)"
}

log_error() {
Expand Down Expand Up @@ -91,14 +93,20 @@ else
fi

# Validate required configs for integration setup
if [[ -z $NC_INTEGRATION_PROVIDER_TYPE ]] ||
[[ -z $NC_INTEGRATION_ENABLE_NAVIGATION ]] ||
[[ -z $NC_INTEGRATION_ENABLE_SEARCH ]]; then
log_error "Following configs are required for integration setup:\n NC_INTEGRATION_ENABLE_NAVIGATION\n NC_INTEGRATION_ENABLE_SEARCH\n NC_INTEGRATION_PROVIDER_TYPE"
if [[ -z $NC_INTEGRATION_PROVIDER_TYPE ]]; then
log_error "NC_INTEGRATION_PROVIDER_TYPE is required."
help
exit 1
fi

if [[ $CONVERT_EXISTING_CONNECTION != "true" ]]; then
if [[ -z $NC_INTEGRATION_ENABLE_NAVIGATION ]] || [[ -z $NC_INTEGRATION_ENABLE_SEARCH ]]; then
log_error "Following configs are required for integration setup:\n NC_INTEGRATION_ENABLE_NAVIGATION\n NC_INTEGRATION_ENABLE_SEARCH"
help
exit 1
fi
fi

if [[ $NC_INTEGRATION_PROVIDER_TYPE == "nextcloud_hub" ]]; then
if [[ -z $NC_INTEGRATION_OP_CLIENT_ID ]] || [[ -z $NC_INTEGRATION_OP_CLIENT_SECRET ]]; then
log_info "You can provide the following environment variables to create the predefined OIDC client:\n 'NC_INTEGRATION_OP_CLIENT_ID'\n 'NC_INTEGRATION_OP_CLIENT_SECRET'"
Expand Down Expand Up @@ -380,13 +388,12 @@ if [[ "$openproject_version" < "$OP_MINIMUM_VERSION" ]]; then
exit 1
fi

# API call to add storage
cat >${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_op_create_storage.json <<EOF
get_op_storage_req_data() {
cat <<EOF
{
"name": "${OP_STORAGE_NAME}",
"storageAudience": "${OP_STORAGE_AUDIENCE}",
"tokenExchangeScope": "${OP_STORAGE_SCOPE}",
"applicationPassword": "",
"_links": {
"origin": {
"href": "${NC_HOST}"
Expand All @@ -400,29 +407,111 @@ cat >${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_op_create_storage.json <<EOF
}
}
EOF
}

create_storage_response=$(
curl -s -X POST -u${OP_ADMIN_USERNAME}:${OP_ADMIN_PASSWORD} \
${OP_STORAGE_ENDPOINT} \
-H 'accept: application/hal+json' \
-H 'Content-Type: application/json' \
-H 'X-Requested-With: XMLHttpRequest' \
-d @${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_op_create_storage.json
)
setup_op_storage() {
local method=$1
local op_storage_id=$2
if [[ -n "$op_storage_id" ]]; then
OP_STORAGE_ENDPOINT="${OP_STORAGE_ENDPOINT}/${op_storage_id}"
fi
curl -s -w "\n%{http_code}" -X "$method" -u${OP_ADMIN_USERNAME}:${OP_ADMIN_PASSWORD} \
${OP_STORAGE_ENDPOINT} \
-H 'accept: application/hal+json' \
-H 'Content-Type: application/json' \
-H 'X-Requested-With: XMLHttpRequest' \
-d @${INTEGRATION_SETUP_TEMP_DIR}/get_op_storage_req_data.json
}

get_nc_integration_update_data() {
cat <<EOF
{
"values": {
"sso_provider_type": "$NC_INTEGRATION_PROVIDER_TYPE",
"authorization_method": "oidc"
}
}
EOF
}

setup_nc_integration() {
local method=$1
local req_data=$2

curl -s -w "\n%{http_code}" -X "$method" -u${NC_ADMIN_USERNAME}:${NC_ADMIN_PASSWORD} "${NC_INTEGRATION_BASE_URL}/setup" \
-H 'Content-Type: application/json' \
-d @${INTEGRATION_SETUP_TEMP_DIR}/"$req_data"
}

if [[ $CONVERT_EXISTING_CONNECTION == "true" ]]; then
OP_STORAGE_ID=$(curl -s -X GET -u${OP_ADMIN_USERNAME}:${OP_ADMIN_PASSWORD} \
${OP_STORAGE_ENDPOINT} | jq -r '._embedded.elements[] | select((.name | ascii_downcase ) == "nextcloud") | .id')
if [[ -z ${OP_STORAGE_ID} ]]; then
log_error "Failed to get the existing OpenProject storage ID"
exit 1
fi

get_op_storage_req_data > ${INTEGRATION_SETUP_TEMP_DIR}/get_op_storage_req_data.json
update_storage_response=$(setup_op_storage "PATCH" "$OP_STORAGE_ID" | tail -n1)
if [[ ${update_storage_response} != 200 ]]; then
log_error "Failed to update existing OpenProject storage"
exit 1
else
log_success "Successfully updated existing OpenProject storage"
fi

if [[ $INTEGRATION_SETUP_DEBUG != "true" ]]; then rm ${INTEGRATION_SETUP_TEMP_DIR}/get_op_storage_req_data.json; fi

if [[ $NC_INTEGRATION_PROVIDER_TYPE == "nextcloud_hub" ]]; then
createOidcClient
get_nc_integration_update_data |
jq --arg client_id "$NC_INTEGRATION_OP_CLIENT_ID" \
'.values.targeted_audience_client_id = $client_id' \
> "${INTEGRATION_SETUP_TEMP_DIR}/request_body_for_converting_existing_setup.json"

nc_integration_update_response=$(setup_nc_integration "PATCH" request_body_for_converting_existing_setup.json | tail -n1)
if [[ ${nc_integration_update_response} == 200 ]]; then
log_success "Successfully updated existing Nextcloud integration setup to Nextcloud hub OIDC provider setup"
else
log_error "Failed to update existing Nextcloud integration setup to Nextcloud hub OIDC provider setup"
exit 1
fi
elif [[ $NC_INTEGRATION_PROVIDER_TYPE == "external" ]]; then
get_nc_integration_update_data |
jq --arg provider_name "$NC_INTEGRATION_PROVIDER_NAME" \
'.values.oidc_provider = $provider_name' \
> "${INTEGRATION_SETUP_TEMP_DIR}/request_body_for_converting_existing_setup.json"

nc_integration_update_response=$(setup_nc_integration "PATCH" request_body_for_converting_existing_setup.json | tail -n1)
if [[ ${nc_integration_update_response} == 200 ]]; then
log_success "Successfully updated existing Nextcloud integration setup to external OIDC provider setup"
else
log_error "Failed to update existing Nextcloud integration setup to external OIDC provider setup"
exit 1
fi
fi

if [[ $INTEGRATION_SETUP_DEBUG != "true" ]]; then rm ${INTEGRATION_SETUP_TEMP_DIR}/request_body_for_converting_existing_setup.json; fi
exit 0
fi
Comment thread
Ashim-Stha marked this conversation as resolved.

if [[ $INTEGRATION_SETUP_DEBUG != "true" ]]; then rm ${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_op_create_storage.json; fi
# API call to add storage
get_op_storage_req_data | jq '.applicationPassword = ""' > ${INTEGRATION_SETUP_TEMP_DIR}/get_op_storage_req_data.json
op_storage_create_response=$(setup_op_storage "POST" | sed '$d')

if [[ $INTEGRATION_SETUP_DEBUG != "true" ]]; then rm ${INTEGRATION_SETUP_TEMP_DIR}/get_op_storage_req_data.json; fi
# check for errors
response_type=$(echo $create_storage_response | jq -r "._type")
response_type=$(echo $op_storage_create_response | jq -r "._type")
if [[ ${response_type} == "Error" ]]; then
error_message=$(echo $create_storage_response | jq -r ".message")
error_id=$(echo $create_storage_response | jq -r ".errorIdentifier")
error_message=$(echo $op_storage_create_response | jq -r ".message")
error_id=$(echo $op_storage_create_response | jq -r ".errorIdentifier")
if [[ ${error_id} == "urn:openproject-org:api:v3:errors:MultipleErrors" ]]; then
# If the files storage is already created with the provided Nextcloud host and storage name.
# We assume that the integration setup is already done in both applications.
# To check that, we parse the error messages.
# If there are only two error messages and those are about the Nextcloud host and name being taken.
# We assume the setup was already completed.
error_messages_grep=$(echo $create_storage_response | jq -r '.["_embedded"]["errors"] | .[].message')
error_messages_grep=$(echo $op_storage_create_response | jq -r '.["_embedded"]["errors"] | .[].message')
readarray -t error_messages <<<"$error_messages_grep"
error_count=0
host_already_taken=false
Expand All @@ -444,7 +533,7 @@ if [[ ${response_type} == "Error" ]]; then
logAlreadyCompletedIntegrationConfiguration
elif [[ ${error_id} == "urn:openproject-org:api:v3:errors:PropertyConstraintViolation" ]]; then
# A PropertyConstraintViolation is always a single error
error_messages_grep=$(echo $create_storage_response | jq -r '.message')
error_messages_grep=$(echo $op_storage_create_response | jq -r '.message')
if [[ "$error_messages_grep" == "Host has already been taken." || "$error_messages_grep" == "Name has already been taken." ]]; then
opCheckIntegrationConfiguration
ncCheckIntegrationConfiguration
Expand All @@ -464,10 +553,10 @@ if [[ ${response_type} == "Error" ]]; then
fi

# Required information from the above response
OP_STORAGE_ID=$(echo $create_storage_response | jq -e '.id')
OP_STORAGE_ID=$(echo $op_storage_create_response | jq -e '.id')

if [[ ${OP_STORAGE_ID} == null ]]; then
echo "${create_storage_response}" | jq
echo "${op_storage_create_response}" | jq
log_error "Response does not contain $OP_STORAGE_ID (id)."
log_error "Setup of OpenProject and Nextcloud integration failed."
exit 1
Expand Down Expand Up @@ -499,7 +588,7 @@ cat >${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_nc_integration_setup.json <<EO
"sso_provider_type": "$NC_INTEGRATION_PROVIDER_TYPE",
"authorization_method": "oidc",
"targeted_audience_client_id" : "$NC_INTEGRATION_OP_CLIENT_ID",
"default_enable_navigation": $NC_INTEGRATION_ENABLE_SEARCH,
"default_enable_navigation": $NC_INTEGRATION_ENABLE_NAVIGATION,
"default_enable_unified_search": $NC_INTEGRATION_ENABLE_SEARCH,
"setup_project_folder": $SETUP_PROJECT_FOLDER,
"setup_app_password": $SETUP_APP_PASSWORD
Expand All @@ -523,11 +612,7 @@ if [[ $NC_INTEGRATION_PROVIDER_TYPE != "nextcloud_hub" ]]; then
fi

# API call to set the openproject_client_id and openproject_client_secret to Nextcloud [integration_openproject]
nc_integration_setup_response=$(
curl -s -XPOST -u${NC_ADMIN_USERNAME}:${NC_ADMIN_PASSWORD} "${NC_INTEGRATION_BASE_URL}/setup" \
-H 'Content-Type: application/json' \
-d @${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_nc_integration_setup.json
)
nc_integration_setup_response=$(setup_nc_integration "POST" request_body_4_nc_integration_setup.json | sed '$d')

if [[ $INTEGRATION_SETUP_DEBUG != "true" ]]; then rm ${INTEGRATION_SETUP_TEMP_DIR}/request_body_4_nc_integration_setup.json; fi

Expand Down