Skip to content

Commit

Permalink
admin.bash framework for hydra sync and refresh tokens
Browse files Browse the repository at this point in the history
This does not enable refresh tokens for admin.bash yet, but provides some of the framework. The IC test page has been enhanced to bring it in line with the DAM test page and to display the refresh token in its own input box.

PiperOrigin-RevId: 299609697
Change-Id: Ice4f55b79ea7a4103b3d1c7c98fd29c2a2456bb7
  • Loading branch information
cdvoisin authored and copybara-github committed Mar 8, 2020
1 parent 9156e8f commit 37c58c4
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 76 deletions.
141 changes: 105 additions & 36 deletions admin.bash
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ GREEN="\e[32m"
RED="\e[31m"
RESET="\e[0m"

IC_CLIENT_ID="903cfaeb-57d9-4ef6-5659-04377794ed65"
IC_CLIENT_SECRET="48f7e552-d9b7-42f3-ba76-e5ab5b3c70ab"
DAM_CLIENT_ID="903cfaeb-57d9-4ef6-5659-04377794ed65"
DAM_CLIENT_SECRET="48f7e552-d9b7-42f3-ba76-e5ab5b3c70ab"
# Default "Admin Tool" client IDs and secrets. Can override via "set ...".
IC_CLIENT_ID="1b2b57c0-46dc-48ce-bd5b-389f26489bcd"
IC_CLIENT_SECRET="94cb4a9b-2f96-4b59-851e-5791dd3040b4"
DAM_CLIENT_ID="0ef2f928-ba67-47b6-9cd6-288be82e3497"
DAM_CLIENT_SECRET="64f1b6b3-abbe-48b4-bfa9-67f6d1ab910d"

STATE_FILE=~/.fa_admin
API_VERSION="v1alpha"
REALM="master"
ENVIRONMENT=""

# For curl debug use:
# CURL_OPTIONS="-v --trace-ascii /dev/stdout -s"
Expand All @@ -45,6 +47,7 @@ CURL_OPTIONS="-s"
# an access_token are required to identify the app and the user.
declare -A COMMANDS=(
# DAM commands
["check dam clients"]='dam_curl_client "/dam/${API_VERSION?}/${REALM?}/clients:sync"'
["print dam config"]='dam_curl_auth "/dam/${API_VERSION?}/${REALM?}/config"'
["print ic config history"]='dam_curl_auth "/dam/${API_VERSION?}/${REALM?}/config/history"'
["print dam info"]='curl_public "dam" "/dam"'
Expand All @@ -61,8 +64,9 @@ declare -A COMMANDS=(
["print dam roles"]='dam_curl_client "/dam/${API_VERSION?}/${REALM?}/damRoleCategories"'
["print dam translators"]='dam_curl_client "/dam/${API_VERSION?}/${REALM?}/passportTranslators"'
["print dam views"]='dam_curl_client "/dam/${API_VERSION?}/${REALM?}/flatViews"'
["sync dam config clients"]='dam_curl_auth "/dam/${API_VERSION?}/${REALM?}/config/clients:sync"'
["sync dam clients"]='dam_curl_client "/dam/${API_VERSION?}/${REALM?}/clients:sync" "POST"'
# IC commands
["check ic clients"]='ic_curl_client "/identity/${API_VERSION?}/${REALM?}/clients:sync"'
["print ic config"]='ic_curl_auth "/identity/${API_VERSION?}/${REALM?}/config"'
["print ic config history"]='ic_curl_auth "/identity/${API_VERSION?}/${REALM?}/config/history"'
["print ic idps"]='ic_curl_client "/identity/${API_VERSION?}/${REALM?}/identityProviders"'
Expand All @@ -71,18 +75,24 @@ declare -A COMMANDS=(
["print ic translators"]='ic_curl_client "/identity/${API_VERSION?}/${REALM?}/passportTranslators"'
["print ic user <name>"]='ic_curl_auth "/identity/scim/v2/${REALM?}/Users/$4"'
["print ic users"]='ic_curl_auth "/identity/scim/v2/${REALM?}/Users"'
["sync ic config clients"]='ic_curl_auth "/identity/${API_VERSION?}/${REALM?}/config/clients:sync"'
["sync ic clients"]='ic_curl_client "/identity/${API_VERSION?}/${REALM?}/clients:sync" "POST"'
# Admin state commands
["set state dam access_token <token>"]='state_update "DAM_ACCESS_TOKEN" "$5"'
["set state dam client <client_id>"]='state_update "DAM_CLIENT_ID" "$5"'
["set state dam secret <secret>"]='state_update "DAM_CLIENT_SECRET" "$5"'
["set state env <environment>"]='state_update "ENVIRONMENT" "$4"'
["set state ic access_token <token>"]='state_update "IC_ACCESS_TOKEN" "$5"'
["set state ic client <client_id>"]='state_update "IC_CLIENT_ID" "$5"'
["set state ic secret <secret>"]='state_update "IC_CLIENT_SECRET" "$5"'
["set state project <project_id>"]='state_update "PROJECT" "$4"'
["set state realm <realm>"]='state_update "REALM" "$4"'
# ["state_refresh dam"]='state_refresh "dam" "${DAM_CLIENT_ID}" "${DAM_CLIENT_SECRET}"'
# ["state_refresh ic"]='state_refresh "ic" "${IC_CLIENT_ID}" "${IC_CLIENT_SECRET}"'
["set dam access_token <token>"]='state_update "DAM_ACCESS_TOKEN" "$4"'
["set dam client <client_id>"]='state_update "DAM_CLIENT_ID" "$4"'
["set dam refresh_token <token>"]='state_update "DAM_REFRESH_TOKEN" "$4"'
["set dam secret <secret>"]='state_update "DAM_CLIENT_SECRET" "$4"'
["set env <environment>"]='state_update "ENVIRONMENT" "$3"'
["set ic access_token <token>"]='state_update "IC_ACCESS_TOKEN" "$4"'
["set ic client <client_id>"]='state_update "IC_CLIENT_ID" "$4"'
["set ic refresh_token <token>"]='state_update "IC_REFRESH_TOKEN" "$4"'
["set ic secret <secret>"]='state_update "IC_CLIENT_SECRET" "$4"'
["set project <project_id>"]='state_update "PROJECT" "$3"'
["set realm <realm>"]='state_update "REALM" "$3"'
["print state"]='state_print'
# ["refresh dam"]='refresh_access "dam" ${DAM_CLIENT_ID?} ${DAM_CLIENT_SECRET?} ${DAM_REFRESH_TOKEN?}'
# ["refresh ic"]='refresh_access "ic" ${IC_CLIENT_ID?} ${IC_CLIENT_SECRET?} ${IC_REFRESH_TOKEN?}'
["reset state"]='state_reset'
)

Expand All @@ -93,7 +103,9 @@ declare -A COMMAND_WHITELIST=(
["dam_curl_client"]=true
["ic_curl_auth"]=true
["ic_curl_client"]=true
["refresh_access"]=true
["state_print"]=true
["state_refresh"]=true
["state_reset"]=true
["state_update"]=true
)
Expand All @@ -113,7 +125,7 @@ state_update() {
state_save
}

# Loads a set of variables (i.e. state) from disk. See the "set state" commands
# Loads a set of variables (i.e. state) from disk. See the "set ..." commands
# for a list of such variables.
state_load() {
if test -f "${STATE_FILE?}"; then
Expand All @@ -127,7 +139,7 @@ state_load() {
NAME="${parts[0]}"
VALUE="${parts[1]}"
if [[ "${NAME}" == "" ]]; then
echo -e ${RED?}'invalid state "'"${setting}"'": recommend running "admin state reset"'${RESET?}
echo -e ${RED?}'invalid state "'"${setting}"'": recommend running "admin.bash reset state"'${RESET?}
exit 2
fi
# This check prevents injecting commands into this script by ensuring
Expand All @@ -136,7 +148,7 @@ state_load() {
if grep '^[-0-9a-zA-Z_.=]*$' <<<${setting} > /dev/null; then
export "$NAME"="$VALUE"
else
echo -e "${RED?}invalid characters in state \"${setting}\": recommend running \"admin state reset\"${RESET?}"
echo -e "${RED?}invalid characters in state \"${setting}\": recommend running \"admin.bash state reset\"${RESET?}"
exit 2
fi
done
Expand All @@ -145,7 +157,7 @@ state_load() {

# Generates the contents of the state as a string to be saved or printed.
state_string() {
STATE_STRING="PROJECT=${PROJECT}\nENVIRONMENT=${ENVIRONMENT}\nREALM=${REALM}\nDAM_CLIENT_ID=${DAM_CLIENT_ID}\nDAM_CLIENT_SECRET=${DAM_CLIENT_SECRET}\nIC_CLIENT_ID=${IC_CLIENT_ID}\nIC_CLIENT_SECRET=${IC_CLIENT_SECRET}\nDAM_ACCESS_TOKEN=${DAM_ACCESS_TOKEN}\nIC_ACCESS_TOKEN=${IC_ACCESS_TOKEN}\n"
STATE_STRING="PROJECT=${PROJECT}\nENVIRONMENT=${ENVIRONMENT}\nREALM=${REALM}\nDAM_CLIENT_ID=${DAM_CLIENT_ID}\nDAM_CLIENT_SECRET=${DAM_CLIENT_SECRET}\nIC_CLIENT_ID=${IC_CLIENT_ID}\nIC_CLIENT_SECRET=${IC_CLIENT_SECRET}\nDAM_REFRESH_TOKEN=${DAM_REFRESH_TOKEN}\nDAM_ACCESS_TOKEN=${DAM_ACCESS_TOKEN}\nIC_REFRESH_TOKEN=${IC_REFRESH_TOKEN}\nIC_ACCESS_TOKEN=${IC_ACCESS_TOKEN}\n"
}

# Generate all state as a string and print it.
Expand All @@ -168,6 +180,44 @@ state_reset() {
echo -e ${GREEN?}'state reset complete'${RESET?}
}

# state_refresh <dam|ic> <client_id> <client_secret>
# Present a login page link and ask user to paste refresh token.
state_refresh() {
local dash="-"
if [[ "${ENVIRONMENT}" == "" ]]; then
dash=""
fi
state_login_redirect "$1"

echo Visit: "${REDIRECT}?client_id=$2&client_secret=$3"
echo
read -p "Paste refresh token and press enter: " refresh

echo
if [[ "${refresh}" == "" ]]; then
echo -e ${RED?}'refresh token not provided'${RESET?}
exit 1
fi
if [[ "$1" == "ic" ]]; then
IC_REFRESH_TOKEN="${refresh}"
else
DAM_REFRESH_TOKEN="${refresh}"
fi
echo -e ${GREEN?}'received refresh token'${RESET?}

state_save
}

# state_login_redirect <dam|ic>
# Generate a URL to use for login
state_login_redirect() {
local dash="-"
if [[ "${ENVIRONMENT}" == "" ]]; then
dash=""
fi
REDIRECT="https://$1demo${dash}${ENVIRONMENT}-dot-${PROJECT}.appspot.com/test"
}

#####################################################
# Curl helper functions #
#####################################################
Expand All @@ -194,27 +244,24 @@ curl_public() {
echo
}

# curl_client <dam|ic> <resource_path> <client_id> <client_secret>
# curl_client <dam|ic> <resource_path> <client_id> <client_secret> [method]
# Generates a URL then performs a GET using curl as part of a RESTful API.
# Unlike curl_public, this function adds the client id/secret to the request.
curl_client() {
if [[ "$4" == "" ]]; then
echo -e "${RED?}client id and secret required: use \"admin set state $1 secret <paste_secret>\" etc${RESET?}"
echo -e "${RED?}client id and secret required: use \"admin set $1 secret <paste_secret>\" etc${RESET?}"
exit 2
fi
local method="$5"
if [[ "${method}" == "" ]]; then
method="GET"
fi
local dash="-"
if [[ "${ENVIRONMENT}" == "" ]]; then
dash=""
fi
RESULT=`curl ${CURL_OPTIONS} -X "GET" -H "Content-Type: application/x-www-form-urlencoded" "$1${dash}${ENVIRONMENT}-dot-${PROJECT}.appspot.com$2?client_id=$3&client_secret=$4"`
# Check to see if result is JSON, then pretty print in JSON if available.
`jq -e <<< "${RESULT}" > /dev/null 2>&1`
if [[ "$?" == "0" ]]; then
printf "`jq -e <<< "${RESULT}"`"
else
echo "${RESULT}"
fi
echo
RESULT=`curl ${CURL_OPTIONS} -X "${method}" -H "Content-Length: 0" -H "Content-Type: application/x-www-form-urlencoded" "$1${dash}${ENVIRONMENT}-dot-${PROJECT}.appspot.com$2?client_id=$3&client_secret=$4"`
curl_print
}

# curl_auth <dam|ic> <resource_path> <client_id> <client_secret> <access_token>
Expand All @@ -223,14 +270,18 @@ curl_client() {
# to the request.
curl_auth() {
if [[ "$5" == "" ]]; then
echo -e "${RED?}login access_token required: use \"admin set state $1 access_token <paste_token>\"${RESET?}"
echo -e "${RED?}login access_token required: use \"admin set $1 access_token <paste_token>\"${RESET?}"
exit 2
fi
local dash="-"
if [[ "${ENVIRONMENT}" == "" ]]; then
dash=""
fi
RESULT=`curl ${CURL_OPTIONS} -X "GET" -H "Authorization: bearer $5" -H "Content-Type: application/x-www-form-urlencoded" "$1${dash}${ENVIRONMENT}-dot-${PROJECT}.appspot.com$2?client_id=$3&client_secret=$4"`
curl_print
}

curl_print() {
# Check to see if result is JSON, then pretty print in JSON if available.
`jq -e <<< "${RESULT}" > /dev/null 2>&1`
if [[ "$?" == "0" ]]; then
Expand All @@ -249,10 +300,10 @@ dam_curl_auth() {
curl_auth "dam" "$1" "${DAM_CLIENT_ID}" "${DAM_CLIENT_SECRET}" "${DAM_ACCESS_TOKEN}"
}

# dam_curl_client <resource_path>
# dam_curl_client <resource_path> [method]
# Wrapper for curl_client that supplies a set of DAM inputs for client id/secret.
dam_curl_client() {
curl_client "dam" "$1" "${DAM_CLIENT_ID}" "${DAM_CLIENT_SECRET}"
curl_client "dam" "$1" "${DAM_CLIENT_ID}" "${DAM_CLIENT_SECRET}" "$2"
}

# ic_curl_auth <resource_path>
Expand All @@ -263,10 +314,24 @@ ic_curl_auth() {
curl_auth "ic" "$1" "${IC_CLIENT_ID}" "${IC_CLIENT_SECRET}" "${IC_ACCESS_TOKEN}"
}

# ic_curl_client <resource_path>
# ic_curl_client <resource_path> [method]
# Wrapper for curl_client that supplies a set of IC inputs for client id/secret.
ic_curl_client() {
curl_client "ic" "$1" "${IC_CLIENT_ID}" "${IC_CLIENT_SECRET}"
curl_client "ic" "$1" "${IC_CLIENT_ID}" "${IC_CLIENT_SECRET}" "$2"
}

# refresh_access <dam|ic> <client_id> <client_secret> <refresh_token>
# Use a refresh token to fetch a new access token and store it in state.
refresh_access() {
local basic_auth=`echo "$2:$3" | base64 -w 0 | sed 's/+/-/g; s/\//_/g'`
local dash="-"
if [[ "${ENVIRONMENT}" == "" ]]; then
dash=""
fi
state_login_redirect "$1"

RESULT=`curl ${CURL_OPTIONS} -X POST -H "Authorization: Basic ${basic_auth}" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: application/json" -d "grant_type=refresh_token&amp;redirect_uri=${REDIRECT}&amp;refresh_token=$4" https://$1${dash}${ENVIRONMENT}-dot-${PROJECT}.appspot.com/oauth2/token`
curl_print
}

#####################################################
Expand Down Expand Up @@ -334,7 +399,7 @@ run_command() {
# Check whitelist to see if this command is authorized to limit risk from
# variables injecting bad stuff.
if [[ "${COMMAND_WHITELIST[${args[0]}]}" == "" ]]; then
echo -e "${RED?}command \"${cmd}\" is not whitelisted and therefore this command is unauthorized${RESET?}"
echo -e "${RED?}command \"${args[0]}\" is not whitelisted and therefore this command is unauthorized${RESET?}"
exit 2
fi

Expand All @@ -355,6 +420,10 @@ state_load
# Lookup the command from COMMANDS, but adjust for the last input being a
# variable if the first word in the command is "set".
lookup="$@"
if [[ "${lookup}" == "" ]]; then
print_usage
exit 1
fi
words=( $lookup )
if [[ "${words[0]}" == "set" ]]; then
words[-1]=""
Expand Down
22 changes: 22 additions & 0 deletions assets/serve/css/icdemo-test.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ h3 .small {
.box {
margin: 20px 0 20px 0;
}
.error-info {
margin: 10px 10px;
padding: 5px 5px;
border: 1px solid red;
background: lightpink;
color: red;
}
.error {
margin: 5px 10px;
padding: 5px 5px;
border-bottom: 1px solid red;
font-weight: bold;
}
.error-desc, .error-hint {
padding: 5px 5px;
}
.error-hint {
color: black;
}
.hidden {
display: none;
}
pre {
border: 1px solid #888;
background: #eee;
Expand Down
4 changes: 2 additions & 2 deletions pages/damdemo/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
var state = window.localStorage.getItem('state');
if (!state) {
displayError(`request with invalid 'state' ${stateID}, no 'state' in database`,
`app maybe under attack.`);
`app maybe under attack or test page refreshed using same code.`);
return false;
}
var s = JSON.parse(state)
Expand Down Expand Up @@ -420,7 +420,7 @@
</script>
</head>
<body onload="init()">
<h1>Hydra Token Flow DAM Test</h1>
<h1>DAM Test Page</h1>
<div id="error_info" class="error-info hidden">
<div id="error" class="error"></div>
<div id="error_desc" class="error-desc"></div>
Expand Down
Loading

0 comments on commit 37c58c4

Please sign in to comment.