Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sudosoul/8a083c50368678ca9315bdb64ee60172 to your computer and use it in GitHub Desktop.
Save sudosoul/8a083c50368678ca9315bdb64ee60172 to your computer and use it in GitHub Desktop.
Ansible HTTP Digest Authentication- Resolve "Unsupported digest authentication algorithm 'SHA-256'" error from URI Module - Manually create Authorization Header
---
##########################################################################################
# HTTP Digest Auth with URI Module POC
#
# Usage:
# 1. Create a new playbook called `test.yml`
#
# 2. Run it via:
# ```
# ansible-playbook test.yml \
# -i inventory/some-inventory-directory \
# -l some-host-defined-in-the-above-inventory
# -e ansible_python_interpreter=/usr/bin/python3
# ```
#
# @author Rob Mullins <rob{{AT}}unqork.com>
##########################################################################################
- name: HTTP Digest Auth with URI Module POC
connection: local
hosts: all
gather_facts: false
#####################################################################################################
pre_tasks:
#####################################################################################################
# Define preknown defaults
#####################################################################################################
- set_fact:
api:
username: "apiUser"
password: "apiKey"
url: "https://example.com/api/v1.0/category/abc123/product/abc123"
requestMethod: "GET"
digestRequestValues:
# nonceCount - Prevents relay-attacks... indicates that this our first request with using the below cnonce value
nc: "00000001"
# clientNonce - A random string we create, used as a mutual secret in conjunction with 'nc'
cnonce: "{{ 99999999 | random | to_uuid | hash('md5') }}"
- set_fact:
api: "{{ api | combine( {'uri' : api.url.split('.com') | last }) }}"
#####################################################################################################
tasks:
#####################################################################################################
# Get Digest Auth response data
#####################################################################################################
- name: Make initial request to receive digest response data.
uri:
url: "{{ api.url }}"
method: "{{ api.requestMethod }}"
status_code: 401
register: unauthorizedApiResponse
- name: Create a dictionary containing the digest data from the www-authenticate response header.
set_fact:
digestResponseHeaderValues: "{{ digestResponseHeaderValues | default({}) | combine ({ (item.split('=')[0] | trim) : (item.split('=')[1] | regex_replace('\"', \"\")) }) }}"
with_items: "{{ unauthorizedApiResponse.www_authenticate.replace('Digest','').split(',') }}"
#####################################################################################################
# Calculate the SHA-256 hashed digest response value
# See https://en.wikipedia.org/wiki/Digest_access_authentication#Overview for the formula
#####################################################################################################
- name: "Calculate HA1 from the digest response formula - sha256(username:realm:password)"
set_fact:
digestRequestValues: "{{ digestRequestValues | combine ({ 'HA1' : [api.username, digestResponseHeaderValues.realm, api.password] | join(':') | hash('sha256') }) }}"
- name: "Calculate HA2 from the digest response formula - sha256(requestMethod:URI)"
set_fact:
digestRequestValues: "{{ digestRequestValues | combine ({ 'HA2' : [api.requestMethod, api.uri] | join(':') | hash('sha256') }) }}"
- name: "Build array containing the digest response values in proper sequence (HA1:nonce:nc:cnonce:qop:HA2)"
set_fact:
digestRequestValues: "{{ digestRequestValues | combine({ 'response' : ( ( digestRequestValues['response'] | default([]) ) + [item]) }) }}"
with_items:
- "{{ digestRequestValues.HA1 }}"
- "{{ digestResponseHeaderValues.nonce }}"
- "{{ digestRequestValues.nc }}"
- "{{ digestRequestValues.cnonce }}"
- "{{ digestResponseHeaderValues.qop }}"
- "{{ digestRequestValues.HA2 }}"
- name: "Create the final encrypted digest response string by joining the above elements - sha256(HA1:nonce:nc:cnonce:qop:HA2)"
set_fact:
digestRequestValues: "{{ digestRequestValues | combine({ 'response' : (digestRequestValues['response'] | join(':') | hash('sha256')) }) }}"
#####################################################################################################
# Send request with our manually constructed Digest Authorization header
#####################################################################################################
- name: "Build array containing each element of the digest (authorization) header"
set_fact:
digestAuthorizationHeader: "{{ digestAuthorizationHeader | default([]) + [item]}}"
with_items:
- "Digest username=\"{{ api.username }}\""
- "realm=\"{{ digestResponseHeaderValues.realm }}\""
- "nonce=\"{{ digestResponseHeaderValues.nonce }}\""
- "uri=\"{{ api.uri }}\""
- "cnonce=\"{{ digestRequestValues.cnonce }}\""
- "nc={{ digestRequestValues.nc }}"
- "qop={{ digestResponseHeaderValues.qop }}"
- "response=\"{{ digestRequestValues.response }}\""
- "algorithm=\"{{ digestResponseHeaderValues.algorithm }}\""
- name: "Create the final digest Authorization comma separated string"
set_fact:
digestAuthorizationHeader: "{{ digestAuthorizationHeader | join(', ') }}"
- name: Check to see if cluster already exists
uri:
url: "{{ api.url }}"
method: "{{ api.requestMethod }}"
status_code: 200,404
headers:
Authorization: "{{ digestAuthorizationHeader }}"
register: authorizedApiResponse
# Print the API response
- debug: "msg={{authorizedApiResponse}}"
#####################################################################################################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment