Commit c343bb43 authored by jackie / Andrea Ida Malkah Klaura's avatar jackie / Andrea Ida Malkah Klaura
Browse files

Initial commit

parents
This diff is collapsed.
# OIDC client stubs for AURA
In this repository we provide different client stubs and functions, which
can be used to authenticate against AURA components and use the resulting
bearer token to access the different AURA APIs.
Currently there are only bash functions implemented to retrieve tokens
from AURA Steering directly.
Planned and upcoming:
- Shell function to retrieve token via AURA tank
- Python functions
- Javascript functions
- Functions to refresh token before it expires
- Make bash functions fully POSIX/dash compliant
## Setup of the OIDC client
In any case you will need to have a correct setup of an OIDC client in the
AURA Steering component. The values you configure there have to correspond
with the values you set in your client config file, whether you use the
Shell, Python or Javascript functions.
Also make sure to have the correct response type set, that corresponds to
the OIDC flow you use in your client.
## Usage
For the shell functions take a look at [bash/main.sh](bash/main.sh) as a
starting point. This shows how to use the include files and get a token
with one of the three provided flows.
# The user name which should be used to authenticate
USERNAME="janedoe"
# The users password
PASSWORD="choose_a_secure_password_here"
# What scopes you want to access (should at least contain openid)
SCOPE="openid profile email"
# The base URL of AURA steering
BASE_URL="http://localhost:8000"
# The OIDC authorize endpoint
AUTHORIZE_ENDPOINT="/openid/authorize"
# ID of the OIDC client that is configured in AURA Steering
CLIENT_ID="123456"
# If an authorization code flow is choosen, a client secret will be needed
CLIENT_SECRET="abcdef123456789abcdef123456789abcdef123456789abcdef12345"
# The redirect URI that is configured in AURA steering for this client
REDIRECT_URI="http://localhost:8080/oidc_callback.html"
#!/bin/bash
# Include config and oidc functions
. ./config.sh
. ./oidc.inc.sh
VERBOSITY=0
GETOPTS_ERROR=false
while getopts ":vh" opt; do
case $opt in
v)
VERBOSITY=$((VERBOSITY+1))
;;
h)
echo "Usage: $0 [-d]"
echo
echo " -v Activate verbose output. Use several times to increase"\
"verbosity level."
echo " -h Show this description"
exit 0
;;
\?)
echo "Invalid option: -${OPTARG}" >&2
GETOPTS_ERROR=true
;;
esac
done
if [ "$GETOPTS_ERROR" = true ]; then
echo "Try -h for help"
exit 1
fi
if [ $VERBOSITY -ge 1 ]; then
echo "Applying verbositiy level: ${VERBOSITY}"
fi
## Use the following lines for an implicit flow
get_steering_implicit
echo "bearer token: ${TOKEN}"
echo "id token: ${ID_TOKEN}"
## Use the following lines for a hybrid flow
#get_steering_hybrid
## Use the following lines for an authorization code flow
#get_steering_auth_code
#echo "auth code: ${CODE}"
#get_steering_token_from_code
#echo "bearer token: ${TOKEN}"
#echo "id token: ${ID_TOKEN}"
#echo "refresh token: ${REFRESH_TOKEN}"
#echo "expires in: ${EXPIRES_IN}"
. ./steering_login.inc.sh
. ./steering_initiate.inc.sh
. ./steering_authorization.inc.sh
. ./steering_implicit.inc.sh
. ./steering_hybrid.inc.sh
make_nonce () {
base64 /dev/urandom | tr -d '/+[A-Z][g-z]' | dd bs=32 count=1 status=none | \
tr -d '\n'
}
# get_steering_authorization
#
# Facilitates OIDC Authorization Code Flow to retrieve an access code from
# the AURA steering server
#
# After successfully run, the $CODE variable is set.
get_steering_auth_code () {
NONCE=$(make_nonce)
STATE=$(make_nonce)
# initiate the OIDC flow with the correct response type
RESPONSE_TYPE="code"
initiate_flow
# the other stages will be handled by login form function
# afterwards we should receive the OUTPUT of the last curl call containing
# the callback URL with all the required info
handle_login_form
if [ $VERBOSITY -ge 1 ]; then
echo "Stage 4: processing the callback redirect URL"
fi
CALLBACK=$(echo -e "${OUTPUT}" | grep '< Location: ' | cut -f 3 -d " ")
CODE=$(echo "${CALLBACK}" | grep -o "code=.*&state" | \
cut -f 2 -d "=" | cut -f 1 -d "&"
)
if [ $VERBOSITY -ge 2 ]; then
echo "callback URL: ${CALLBACK}"
fi
if [ $VERBOSITY -ge 1 ]; then
echo "authorization code: ${CODE}"
fi
}
# get_steering_token_from_code
#
# Retrieves bearer and ID tokens from AURA steering, given a correct
# authorization code and clien secret are provided.
#
# After successfully run, the following variables are set:
# $TOKEN the bearer token to access the API
# $ID_TOKEN the ID token
# $REFRESH_TOKEN a refresh token to retrieve a new bearer token
# $EXPIRES_IN time when the current bearer token will expire (in seconds)
get_steering_token_from_code () {
OUTPUT=$(curl -s -X POST \
-H "Cache-Control: no-cache" \
-H "Content-Type: application/x-www-form-urlencoded" \
"http://localhost:8000/openid/token" \
-d "client_id=${CLIENT_ID}" \
-d "client_secret=${CLIENT_SECRET}" \
-d "code=${CODE}" \
-d "redirect_uri=${REDIRECT_URI}" \
-d "grant_type=authorization_code"
)
TOKEN=$(echo $OUTPUT | jq .access_token | tr -d '"')
ID_TOKEN=$(echo $OUTPUT | jq .id_token | tr -d '"')
REFRESH_TOKEN=$(echo $OUTPUT | jq .refresh_token | tr -d '"')
EXPIRES_IN=$(echo $OUTPUT | jq .expires_in)
if [ $VERBOSITY -ge 1 ]; then
echo "bearer token: ${TOKEN}"
echo "id token: ${ID_TOKEN}"
echo "refresh token: ${REFRESH_TOKEN}"
echo "expires in: ${EXPIRES_IN}"
fi
}
# get_steering_hybrid
#
# Facilitates OIDC Hybrid Flow to retrieve an authorization code as well as a
# bearer token and an ID token from the AURA steering server.
#
# After successfully run, the $CODE, $TOKEN and $ID_TOKEN variables are set.
get_steering_hybrid () {
NONCE=$(make_nonce)
STATE=$(make_nonce)
# initiate the OIDC flow with the correct response type
RESPONSE_TYPE="code%20id_token%20token"
initiate_flow
# the other stages will be handled by login form function
# afterwards we should receive the OUTPUT of the last curl call containing
# the callback URL with all the required info
handle_login_form
if [ $VERBOSITY -ge 1 ]; then
echo "Stage 4: processing the callback redirect URL"
fi
CALLBACK=$(echo -e "${OUTPUT}" | grep '< Location: ' | cut -f 3 -d " ")
TOKEN=$(echo "${CALLBACK}" | grep -o "access_token=.*&id_token" | \
cut -f 2 -d "=" | cut -f 1 -d "&"
)
ID_TOKEN=$(echo "${CALLBACK}" | grep -o "id_token=.*&token_type" | \
cut -f 2 -d "=" | cut -f 1 -d "&"
)
if [ $VERBOSITY -ge 2 ]; then
echo "callback URL: ${CALLBACK}"
fi
if [ $VERBOSITY -ge 1 ]; then
echo "bearer token: ${TOKEN}"
echo "id token: ${ID_TOKEN}"
fi
echo "TODO:"
echo " so far steering does not provide an authorization code"
echo " check, whether this is an issue with django-oidc-provider or"
echo " if we are missing something here"
echo " callback url:"
echo " ${CALLBACK}"
}
# get_steering_implicit
#
# Facilitates OIDC Implicit Flow to retrieve a bearer token and an ID token
# from the AURA steering server.
#
# After successfully run, the $TOKEN and $ID_TOKEN variables are set.
get_steering_implicit () {
NONCE=$(make_nonce)
STATE=$(make_nonce)
# initiate the OIDC flow with the correct response type
RESPONSE_TYPE="id_token%20token"
initiate_flow
# the other stages will be handled by login form function
# afterwards we should receive the OUTPUT of the last curl call containing
# the callback URL with all the required info
handle_login_form
if [ $VERBOSITY -ge 1 ]; then
echo "Stage 4: processing the callback redirect URL"
fi
CALLBACK=$(echo -e "${OUTPUT}" | grep '< Location: ' | cut -f 3 -d " ")
TOKEN=$(echo "${CALLBACK}" | grep -o "access_token=.*&id_token" | \
cut -f 2 -d "=" | cut -f 1 -d "&"
)
ID_TOKEN=$(echo "${CALLBACK}" | grep -o "id_token=.*&token_type" | \
cut -f 2 -d "=" | cut -f 1 -d "&"
)
if [ $VERBOSITY -ge 2 ]; then
echo "callback URL: ${CALLBACK}"
fi
if [ $VERBOSITY -ge 1 ]; then
echo "bearer token: ${TOKEN}"
echo "id token: ${ID_TOKEN}"
fi
}
# intiate_flow
#
# Initiates and OIDC flow, given the correct RESPONSE_TYPE, which has to
# be set before calling this function to one of the following three:
# code
# id_token%20token
# code%20id_token%20token
# This has to correspond with the Response Type that is set in the Django
# configuration for the OIDC client with the given CLIENT_ID
#
# On success this function returns a URL to the login form of AURA Steering,
# in order to authenticate and provide consent if needed. This is returned by
# setting the $LOGIN_FORM variable.
initiate_flow () {
if [ $VERBOSITY -ge 1 ]; then
echo "Stage 1: accessing the authorize endpoint"
fi
INIT_URL="${BASE_URL}${AUTHORIZE_ENDPOINT}?client_id=${CLIENT_ID}"
INIT_URL+="&redirect_uri=${REDIRECT_URI}&response_type=${RESPONSE_TYPE}"
INIT_URL+="&scope=${SCOPE// /+}&state=${STATE}&nonce=${NONCE}"
if [ $VERBOSITY -ge 2 ]; then
echo "Initiating flow at: ${INIT_URL}"
fi
OUTPUT=$(curl -s -v "${INIT_URL}" 2>&1)
LOGIN_FORM=$(echo -e "${OUTPUT}" | grep "< Location:" | cut -f 3 -d " " | \
tr -d '\r')
if [ $VERBOSITY -ge 2 ]; then
echo "login from URL: ${LOGIN_FORM}"
fi
}
# handle_login_form
#
# After an OIDC flow was initiated this function handles the login process
# at the IDP (AURA Steering).
#
# After success this function returns output of the last curl call containing
# the callback URL with all the required info in the $OUTPUT variable
handle_login_form () {
if [ $VERBOSITY -ge 1 ]; then
echo "stage 2: accessing the login form"
fi
OUTPUT=$(curl -s -v "${BASE_URL}${LOGIN_FORM}" 2>&1)
CSRF_TOKEN=$(echo -e "${OUTPUT}" | grep "< Set-Cookie:" | cut -f 4 -d " " | \
tr -d ';'
)
FORM_TAG=$(echo -e "${OUTPUT}" | grep "<form action=")
SUBMIT_URL=$(echo ${FORM_TAG} | grep -o 'action=".*"' | cut -f 2 -d '"')
CSRF_MW_TOKEN=$(echo ${FORM_TAG} | \
grep -o "name='csrfmiddlewaretoken' value='.*'" | cut -f 4 -d "'")
NEXT_FIELD=$(echo -e "${OUTPUT}" | grep '<input type="hidden" name="next" ' | \
grep -o 'value=".*"' | cut -f 2 -d '"'
)
NEXT_FIELD=$(echo ${NEXT_FIELD//&amp;/&})
if [ $VERBOSITY -ge 2 ]; then
echo "CSRF cookie: ${CSRF_TOKEN}"
echo "CSRF middleware token: ${CSRF_MW_TOKEN}"
echo "next field: ${NEXT_FIELD}"
echo "submit URL: ${SUBMIT_URL}"
fi
if [ $VERBOSITY -ge 1 ]; then
echo "stage 3: submitting login data"
fi
OUTPUT=$(curl -s -v --cookie ${CSRF_TOKEN} \
-F "username=${USERNAME}" -F "password=${PASSWORD}" \
-F "csrfmiddlewaretoken=${CSRF_MW_TOKEN}" -F "next=${NEXT_FIELD}" \
"${BASE_URL}${SUBMIT_URL}" 2>&1
)
CSRF_TOKEN=$(echo -e "${OUTPUT}" | grep "< Set-Cookie:" | \
grep -o "csrftoken=.*;" | cut -f 1 -d ';'
)
SESSION_ID=$(echo -e "${OUTPUT}" | grep "< Set-Cookie:" | \
grep -o "sessionid=.*;" | cut -f 1 -d ';'
)
if [ $VERBOSITY -ge 2 ]; then
echo "CSRF cookie: ${CSRF_TOKEN}"
echo "session cookie: ${SESSION_ID}"
fi
if [ $VERBOSITY -ge 1 ]; then
echo "stage 4: get token in final callback location"
fi
OUTPUT=$(curl -s -v --cookie "${CSRF_TOKEN}; ${SESSION_ID}" \
--referer "${BASE_URL}${SUBMIT_URL}" \
"${BASE_URL}${NEXT_FIELD}" 2>&1
)
# check if consent is required
echo -e "${OUTPUT}" | grep -q '<h1>Request for Permission</h1>'
if [ $? -eq 0 ]; then
# in this case we have to extract submit the consent form before we
# receive the final callback redirect
if [ $VERBOSITY -ge 1 ]; then
echo "steering requires explicit consent"
fi
CSRF_TOKEN=$(echo -e "${OUTPUT}" | grep "< Set-Cookie:" | \
grep -o "csrftoken=.*;" | cut -f 1 -d ';'
)
CSRF_MW_TOKEN=$(echo -e "${OUTPUT}" | \
grep -o "name='csrfmiddlewaretoken' value='.*'" | cut -f 4 -d "'"
)
SUBMIT_URL=$(echo -e "${OUTPUT}" | \
grep -o '<form method="post" action=".*">' | cut -f 4 -d '"'
)
if [ $VERBOSITY -ge 2 ]; then
echo "CSRF cookie: ${CSRF_TOKEN}"
echo "CSRF middleware token: ${CSRF_MW_TOKEN}"
echo "submit URL: ${SUBMIT_URL}"
fi
if [ $VERBOSITY -ge 1 ]; then
echo "submitting consent form"
fi
OUTPUT=$(curl -s -v --cookie "${CSRF_TOKEN}; ${SESSION_ID}" \
-F "csrfmiddlewaretoken=${CSRF_MW_TOKEN}" \
-F "client_id=${CLIENT_ID}" \
-F "redirect_uri=${REDIRECT_URI}" \
-F "response_type=id_token token" \
-F "scope=${SCOPE}" \
-F "state=${STATE}" \
-F "nonce=${NONCE}" \
-F "allow=Authorize" \
"${BASE_URL}${SUBMIT_URL}" 2>&1
)
# now we received the final callback redirect and can continue
# as if no consent would have been required explicitly
fi
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment