Authenticated proxy configuration with bash
Bash script which can be sourced to configure http_proxy
, https_proxy
and no_proxy
environment variables (used by most internet-capable Linux applications) for a specific proxy. Prompts for domain (defaults to the local domain if machine is domain joined through realmd), username (defaults to local username) and password, although it then puts it into the environment variable so retrievable by anyone with access to the subsequent environment. As a superficial level of security, it exports an env
bash function that wraps the usual command to redact the password.
get_user_input_default() {
# Function to get user input into a variable, falling back to
# default value if none given and optionally turning echo off
# (e.g. for passwords).
local read_opts="" read_prompt
if [[ $# -lt 2 ]] || [[ $# -gt 4 ]]
then
cat - >&2 <<EOF
Usage: get_user_input_default prompt variable_name [default_value] [secure]
prompt: Prompt to display to the user
variable_name: Name of variable to store the user input (or default if none
provided)
default_value: Optional default value, variable will be set to empty string
if not provided. Will be displayed in the prompt, if given.
'secure': Keyword 'secure' in the 4th position will turn off echoing user
input. To use 'secure' without a default value, pass the empty
string ("") as default_value.
EOF
return 1
fi
if [[ $# -eq 4 ]]
then
if [[ $4 == 'secure' ]]
then
read_opts="-s -r"
else
echo "'secure' is the valid option for 4th argument to get_user_input_default." >&2
return 1
fi
fi
read_prompt="$1"
if [[ $# -ge 3 ]]
then
read_prompt="$read_prompt ($3)"
fi
read $read_opts -p "$read_prompt: "
# Required as user's return press will not have been echoed in "secure" mode
[ $# -eq 4 ] && echo
# Remove spaces from response
REPLY="$( echo "$REPLY" | tr -d '[:space:]' )"
# If no reply and a default value, fall back to it
[ -z "$REPLY" ] && [ $# -ge 3 ] && REPLY="$3"
eval "$2=\"$REPLY\""
}
setup_proxy() {
local proxy_server="proxy.domain.tld" # Set your proxy server here
local - # Make shell options local to function
# Basic script safety - fail fast for:
# - errors
# - unset variables
# - turn off file globbing
# - if pipe line commands fail
set -euf -o pipefail
local default_domain default_user
local proxy_domain proxy_user proxy_password proxy_server
# Attempt to local the systems domain through realmd
if which realm &>/dev/null
then
# There should only be one but passed through head to be on the
# safe side.
default_domain=$( realm list | grep -B4 ' server-software: active-directory' | grep ' realm-name: ' | sed 's/^\s\+realm-name: \(.*\)$/\1/' | head -n1 )
else
# Fall back to no default
default_domain="_"
fi
default_user="$USER"
get_user_input_default "Proxy user's domain - use a single underscore (_) for no domain" proxy_domain "$default_domain"
get_user_input_default "Proxy username" proxy_user "$default_user"
get_user_input_default "Proxy password" proxy_password "" secure
# To allow for 'return to accept default' behaviour, use '_' for no
# domain (using blank as the default only works if there's no local
# domain from realmd, otherwise its impossible to differentiate
# blank from "use default"). If no domain, then nothing to do as
# the user is used as-is.
if [[ $proxy_domain != '_' ]]
then
if [[ $proxy_domain == *"."* ]]
then
# Domain contains a period, convert to url-encoded UPN suffix
# (user@domain.tld) fomat.
proxy_user="$proxy_user%40$proxy_domain"
else
# Convert to url-encoded old-style (domain\user) format
proxy_user="$proxy_domain%5C$proxy_user"
fi
fi
export http_proxy="http://$proxy_user:$proxy_password@$proxy_server"
export https_proxy="http://$proxy_user:$proxy_password@$proxy_server"
}
setup_noproxy() {
# Sets up sensible default proxy bypass rules
local domain
no_proxy=localhost,127.0.0.0/8
# Determine local domain, will disable proxy for it
domain=$( hostname -d )
[ -n "$domain" ] && no_proxy="$no_proxy,$domain"
# Ditto for local ip spaces (those not routed via a gateway)
for ip in $( ip route | grep -v via | cut -d' ' -f 1 )
do
no_proxy="$no_proxy,$ip"
done
export no_proxy
}
# Override the built-in `env` with one that sanitises the proxy
# password
env() {
command env "$@" | sed 's#\(_proxy=https\?://[^@]\+\):[^@]\+@#\1:**redacted**@#ig'
}
export -f env
setup_proxy
[ -z "$no_proxy" ] && setup_noproxy