#!/bin/bash ##### # ESGF Security Services # description: Security Services # #**************************************************************************** #* * #* Copyright (c) 2009, Lawrence Livermore National Security, LLC. * #* Produced at the Lawrence Livermore National Laboratory * #* Written by: Gavin M. Bell (gavin@llnl.gov) * #* LLNL-CODE-420962 * #* * #* All rights reserved. This file is part of the: * #* Earth System Grid Fed (ESGF) Node Software Stack, Version 1.0 * #* * #* For details, see http://esgf.org/ * #* Please also read this link * #* http://esgf.org/LICENSE * #* * #* * Redistribution and use in source and binary forms, with or * #* without modification, are permitted provided that the following * #* conditions are met: * #* * #* * Redistributions of source code must retain the above copyright * #* notice, this list of conditions and the disclaimer below. * #* * #* * Redistributions in binary form must reproduce the above copyright * #* notice, this list of conditions and the disclaimer (as noted below) * #* in the documentation and/or other materials provided with the * #* distribution. * #* * #* Neither the name of the LLNS/LLNL nor the names of its contributors * #* may be used to endorse or promote products derived from this * #* software without specific prior written permission. * #* * #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE * #* LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR * #* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * #* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * #* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * #* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * #* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * #* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * #* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * #* SUCH DAMAGE. * #* * #**************************************************************************** ##### #uses: perl, awk, ifconfig, tar, wget, curl, su, useradd, groupadd, # id, chmod, chown, chgrp, cut, svn, mkdir, killall, java, egrep, # lsof, unlink, ln, pax, keytool, openssl #note: usage of readlink not macosx friendly :-( usage of useradd / # groupadd is RedHat/CentOS dependent :-( DEBUG=${DEBUG:-0} VERBOSE=${VERBOSE:-0} envfile="/etc/esg.env" #-------------- #User Defined / Setable (public) #-------------- install_prefix=${install_prefix:-"/usr/local"} cdat_home=${cdat_home:-${install_prefix}/cdat} esg_root_dir=${esg_root_dir:-"/esg"} workdir=${workdir:-~/workbench/esg} install_manifest=${install_manifest:-"${esg_root_dir}/esgf-install-manifest"} #-------------- date_format=${date_format:-"+%Y_%m_%d_%H%M%S"} force_install=${force_install:-0} tomcat_user=${tomcat_user:-tomcat} tomcat_group=${tomcat_group:-$tomcat_user} tomcat_install_dir=${CATALINA_HOME:-${install_prefix}/tomcat} python_version=${python_version:-"2.6"} config_file=${esg_root_dir}/config/esgf.properties security_web_service_name="esgf-security" esgf_user_migration_launcher="esgf-user-migrate" esgf_policy_check_launcher="esgf-policy-check" init() { #[ -n "${envfile}" ] && [ -e "${envfile}" ] && source ${envfile} && ((VERBOSE)) && printf "security services: sourcing environment from: ${envfile} \n" security_app_context_root=${security_web_service_name:-esgf-security} esgf_security_version=${esgf_security_version:-"1.2.8"} esgf_security_db_version=${esgf_security_db_version:-"0.1.4"} esgf_security_egg_file=esgf_security-${esgf_security_db_version}-py${python_version}.egg #Database information.... node_db_name=${node_db_name:-"esgcet"} node_db_security_schema_name="esgf_security" postgress_driver=${postgress_driver:-org.postgresql.Driver} postgress_protocol=${postgress_protocol:-jdbc:postgresql:} postgress_host=${PGHOST:-localhost} postgress_port=${PGPORT:-5432} postgress_user=${PGUSER:-dbsuper} pg_sys_acct_passwd=${pg_sys_acct_passwd:=${pg_secret:=changeme}} } ##### # Install The ESGF Security Services ##### # - Takes boolean arg: 0 = setup / install mode (default) # 1 = updated mode # # In setup mode it is an idempotent install (default) # In update mode it will always pull down latest after archiving old # setup_security() { echo -n "Checking for esgf security (lib) [${esgf_security_version}]" local currently_installed_version="sed -n 's/^.*esgf-security=\(.[0-9]*\.[0-9]*\.[0-9]*\).*$/\1/p' ${install_manifest} 2> /dev/null" if [ -n "$currently_installed_version" ]; then check_version_with "esgf-security" "${currently_installed_version}" ${esgf_security_version} local ret=$? ((ret == 0)) && (( ! force_install )) && echo " [OK]" && return 0 fi init configure_postgress fetch_user_migration_launcher fetch_policy_check_launcher #migration niceness... clean_security_webapp_subsystem checked_done 0 } #-------------------------------------------------- #NOTE: This must be run AFTER the esg node web app # installation/configuration (setup_node_manager) #-------------------------------------------------- configure_postgress() { local upgrade=${1:-0} if [ $((sel & IDP_BIT )) != 0 ]; then init echo echo "*******************************" echo "Configuring Postgres... for ESGF Security" echo "*******************************" echo start_postgress if [ -z "$(postgres_list_dbs ${node_db_name})" ] ; then postgres_create_db ${node_db_name} || return 0 else if [ -n "$(postgres_list_db_schemas ${node_db_security_schema_name})" ]; then echo "Detected an existing security schema installation..." else postgres_clean_schema_migration "ESGF Security" fi fi mkdir -p ${workdir}/${node_dist_dir:-esgf-security-${esgf_security_version}}/db pushd ${workdir}/${node_dist_dir:-esgf-security-${esgf_security_version}}/db >& /dev/null [ $? != 0 ] && echo " ERROR: Could not find node distribution dir ${workdir}/${node_dist_dir}" && checked_done 1 #------------------------------------------------------------------------ #Based on the node type selection we build the appropriate database tables #------------------------------------------------------------------------ #download the egg file from the distribution server is necessary.... checked_get ${esgf_security_egg_file} ${esg_dist_url}/esgf-security/${esgf_security_egg_file} $((force_install)) (( $? > 1 )) && return 0 #install the egg.... source ${cdat_home}/bin/activate esgf-pub ((DEBUG)) && "easy_install ${esgf_security_egg_file}" conda install -y postgresql easy_install ${esgf_security_egg_file} [ $? != 0 ] && echo "ERROR: Could not create esgf security python module" && checked_done 1 if [ -n "$(postgres_list_db_schemas ${node_db_security_schema_name})" ]; then local default="N" ((force_install)) && default="Y" local dobackup read -p "Do you want to make a back up of the existing database schema [${node_db_name}:${node_db_security_schema_name}]? $([ "$default" = "N" ] && echo "[y/N]" || echo "[Y/n]") " dobackup [ -z "${dobackup}" ] && dobackup=${default} if [ "${dobackup}" = "Y" ] || [ "${dobackup}" = "y" ]; then echo "Creating a backup archive of the database schema [$node_db_name:${node_db_security_schema_name}]" backup_db -db ${node_db_name} -s ${node_db_security_schema_name} fi unset dobackup unset default echo fi #run the code to build the database and install sql migration... ((DEBUG)) && echo "$cdat_home/bin/esgf_security_initialize --dburl ${postgress_user}:${pg_sys_acct_passwd}@${postgress_host}:${postgress_port}/${node_db_name} -c" esgf_security_initialize --dburl ${postgress_user}:${pg_sys_acct_passwd}@${postgress_host}:${postgress_port}/${node_db_name} -c [ $? != 0 ] && echo "ERROR: Could not create esgf security database tables in ${node_db_name}" && checked_done 1 source deactivate write_security_db_install_log echo popd >& /dev/null echo echo checked_done 0 else debug_print "This function, configure_postgress(), is not applicable to current node type (${sel})" fi } write_security_db_install_log() { echo "$(date ${date_format}) python:esgf_security=${esgf_security_db_version} " >> ${install_manifest} dedup ${install_manifest} return 0 } #****************************************************************** # SECURITY SETUP #****************************************************************** security_startup_hook() { echo -n "Security Startup Hook: Setup policy and whitelists... " init echo -n "(p) " && _setup_policy_files && echo -n ":-) " [ $? != 0 ] && echo -n ":-(" echo -n "(w) " && _setup_static_whitelists "ats idp" && echo -n ":-) " [ $? != 0 ] && echo -n ":-(" echo } _setup_policy_files() { if [ $((sel & DATA_BIT+INDEX_BIT)) != 0 ]; then debug_print "setup_policy_files()... " local tmp_extract_dir=${esg_root_dir:-"/esg"}/tmp local policy_file_name="esgf_policies" local internal_jar_path="esg/security/config" local full_extracted_jar_dir="${tmp_extract_dir}/${internal_jar_path}" local app_path local security_jar_file if [ $((sel & DATA_BIT)) != 0 ]; then get_property_as orp_security_authorization_service_app_home app_path security_jar_file="${app_path}/WEB-INF/lib/esgf-security-${esgf_security_version}.jar" elif [ $((sel & INDEX_BIT)) != 0 ]; then get_property_as index_service_app_home app_path security_jar_file="${app_path}/WEB-INF/lib/esgf-security-${esgf_security_version}.jar" else echo "WE SHOULD NEVER BE HERE, BUT SINCE WE ARE WILL EXIT... (see esg-security->_setup_policy_files())" exit 1 fi ([ -z "${app_path}" ] || [ -z "${security_jar_file}" ] || [ ! -e "${security_jar_file}" ] || [ -z "${JAVA_HOME}" ]) && \ echo "Could not determine location of security jar, exiting..." && exit 2 debug_print "Using security jar file: ${security_jar_file}" #If old named file exists rename # esgf_polcies.xml -> esgf_policies_local.xml [ -f "${esg_config_dir}/${policy_file_name}.xml" ] && mv -v ${esg_config_dir}/${policy_file_name}{,_local}.xml # esgf_polcies_static.xml -> esgf_policies_common.xml [ -f "${esg_config_dir}/${policy_file_name}_static.xml" ] && mv -v ${esg_config_dir}/${policy_file_name}{_static,_common}.xml if [ ! -f "${esg_config_dir}/${policy_file_name}_local.xml" ]; then (mkdir -p ${tmp_extract_dir}; cd ${tmp_extract_dir}; $JAVA_HOME/bin/jar xvf ${security_jar_file} ${internal_jar_path}/${policy_file_name}_local.xml) cp -v ${full_extracted_jar_dir}/${policy_file_name}_local.xml ${esg_config_dir} chown ${tomcat_user}:${tomcat_group} ${esg_config_dir}/${policy_file_name}_local.xml && \ chmod 640 ${esg_config_dir}/${policy_file_name}_local.xml fi if [ ! -f "${esg_config_dir}/${policy_file_name}_common.xml" ]; then (mkdir -p ${tmp_extract_dir}; cd ${tmp_extract_dir}; $JAVA_HOME/bin/jar xf ${security_jar_file} ${internal_jar_path}/${policy_file_name}_common.xml) cp -v ${full_extracted_jar_dir}/${policy_file_name}_common.xml ${esg_config_dir} chown ${tomcat_user}:${tomcat_group} ${esg_config_dir}/${policy_file_name}_common.xml && \ chmod 640 ${esg_config_dir}/${policy_file_name}_common.xml fi else debug_print " WARNING: This function, setup_policy_files(), is not applicable to current node type (${sel})" fi } _setup_static_whitelists() { if [ $((sel & DATA_BIT+INDEX_BIT+IDP_BIT)) != 0 ]; then local service_types=($@) local service_type local app_config_dir="${orp_service_app_home:-${tomcat_install_dir:-/usr/local/tomcat}/webapps/esg-orp}/WEB-INF/classes/esg/orp/orp/config" local tmp_extract_dir=${esg_root_dir:-"/esg"}/tmp local internal_jar_path="esg/security/config" local full_extracted_jar_dir="${tmp_extract_dir}/${internal_jar_path}" local app_path local security_jar_file if [ $((sel & DATA_BIT)) != 0 ]; then get_property_as orp_security_authorization_service_app_home app_path security_jar_file="${app_path}/WEB-INF/lib/esgf-security-${esgf_security_version}.jar" elif [ $((sel & INDEX_BIT)) != 0 ]; then get_property_as index_service_app_home app_path security_jar_file="${app_path}/WEB-INF/lib/esgf-security-${esgf_security_version}.jar" elif [ $((sel & IDP_BIT)) != 0 ]; then get_property_as idp_service_app_home app_path security_jar_file="${app_path}/WEB-INF/lib/esgf-security-${esgf_security_version}.jar" else echo "ERROR: Could not find security jar file: esgf-security-${esgf_security_version}.jar" echo "WE SHOULD NEVER BE HERE, BUT SINCE WE ARE WILL EXIT... (see esg-security->_setup_policy_files())" exit 1 fi ([ -z "${app_path}" ] || [ -z "${security_jar_file}" ] || [ ! -e "${security_jar_file}" ] || [ -z "${JAVA_HOME}" ]) && \ echo "Could not determine location of security jar (esgf-security-${esgf_security_version}.jar), exiting..." && exit 2 debug_print "Using security jar file: ${security_jar_file}" for service_type in ${service_types[@]}; do if [ ! -f "${esg_config_dir}/esgf_${service_type}_static.xml" ] && [ -f "${app_config_dir}/esgf_${service_type}_static.xml" ]; then echo (mkdir -p ${tmp_extract_dir}; cd ${tmp_extract_dir}; $JAVA_HOME/bin/jar xf ${security_jar_file} ${internal_jar_path}/esgf_${service_type}_static.xml) cp -v ${full_extracted_jar_dir}/esgf_${service_type}_static.xml ${esg_config_dir} chown ${tomcat_user}:${tomcat_group} ${esg_config_dir}/esgf_${service_type}_static.xml && \ chmod 640 ${esg_config_dir}/esgf_${service_type}_static.xml fi done else debug_print " WARNING: This function, _setup_static_whitelists(), is not applicable to current node type (${sel})" fi } #****************************************************************** #****************************************************************** #-------------------------------------- # Clean / Uninstall this module... #-------------------------------------- clean_security_webapp_subsystem() { init perl -n -i -e'print unless m!webapp:esgf-security!' ${install_manifest} remove_property security_app_home #------------------------ # A bit of migration clean up of the now defunct esgf-security web app if [ -d "${tomcat_install_dir}/webapps/esgf-security" ]; then pushd "${tomcat_install_dir}/webapps/" >& /dev/null backup esgf-security echo -n "Removing defunct esgf-security webapp... " rm -rf ${tomcat_install_dir}/webapps/esgf-security [ $? == 0 ] && echo " [OK] " || echo " [FAIL] " popd >& /dev/null fi #------------------------ } #NOTE: There are certain fields that we are not pulling from (node_db_name and postgress_host). # If the fit hits the shan I want to make it clear that we are not nuking anyone else's database, etc. # strictly the "esgcet" database on "localhost" clean_security_database_subsystem_installation() { init local doit="N" if [ $((sel & IDP_BIT )) != 0 ]; then read -p "remove ESGF Security database, database subsystem AND DATA? (esgf_security.*) [y/N]: " doit if [ "doit" = "Y" ] || [ "$doit" = "y" ]; then if $(psql -U ${postgress_user} esgcet -c "\dt esgf_security.;" | egrep '^\([1-9]* row[s]?\)' >& /dev/null); then #Call me paranoid but I want some integrity check that this code is what is meant to be straight from the distribution. diff <(md5sum ${scripts_dir}/esg-security | tr -s " " | cut -d " " -f 1) <(curl -s -L --insecure ${esg_dist_url}/esgf-security/esg-security.md5 | tr -s " " | cut -d " " -f 1) >& /dev/null [ $? != 0 ] && echo " WARNING: Could not verify ${scripts_dir}/esg-security, aborting this uninstall" && return 3 echo "[VERIFIED]" backup_db -db ${node_db_name} -s security echo "removing esgf_security.* schema and tables and DATA" ${cdat_home}/bin/esgf_security_initialize --dburl ${postgress_user}:${pg_sys_acct_passwd}@localhost:${postgress_port}/esgcet -d 0 rm -rvf ${cdat_home}/envs/esgf-pub/bin/esgf_security_initialize && \ rm -rf ${cdat_home}/envs/esgf-pub/lib/python${python_version}/${esgf_security_egg_file} && \ perl -n -i -e'print unless m!python:esgf_security!' ${install_manifest} && echo "[REMOVED]" else echo " Could not find security tables in the database." fi fi else debug_print "This function, clean_security_database_subsystem_installation(), is not applicable to current node type (${sel})" fi return 0 } fetch_user_migration_launcher() { if [ $((sel & IDP_BIT )) != 0 ]; then pushd ${scripts_dir} >& /dev/null checked_get ${esgf_user_migration_launcher} ${esg_dist_url}/${security_web_service_name}/${esgf_user_migration_launcher} $((force_install)) (( $? > 1 )) && echo " ERROR: Could not download ${esg_dist_url}/${security_web_service_name}/${esgf_user_migration_launcher} :-(" && popd >& /dev/null && return 1 chmod 755 ${esgf_user_migration_launcher} popd >& /dev/null return 0 else debug_print "This function, fetch_user_migration_launcher(), is not applicable to current node type (${sel})" fi } fetch_policy_check_launcher() { if [ $((sel & IDP_BIT+DATA_BIT )) != 0 ]; then pushd ${scripts_dir} >& /dev/null checked_get ${esgf_policy_check_launcher} ${esg_dist_url}/${security_web_service_name}/${esgf_policy_check_launcher} $((force_install)) (( $? > 1 )) && echo " ERROR: Could not download ${esg_dist_url}/${security_web_service_name}/${esgf_policy_check_launcher} :-(" && popd >& /dev/null && return 1 chmod 755 ${esgf_policy_check_launcher} popd >& /dev/null return 0 else debug_print "This function, fetch_policy_check_launcher(), is not applicable to current node type (${sel})" fi }