API authentication via SAML

Hi,

I have spent a bit of time and finally have kerberos authentication via SAML, Keycloak and FreeIPA working for AWX 17.1.0 for the web UI.

What I really want to get working though is API access from curl or ansible, without needing to pass username and password in. Is there a guide somewhere for this part? My hunting so far is looking like I need to create tokens to do any API work without usernames and passwords, and for that I would need to use the web UI to create the tokens if I want to do it with SAML auth, which feels like something is missing.

Many Thanks,

Kim

In case anyone else comes looking for this (https://xkcd.com/979/), here is where I have got to:

GET request to AWX SAML redirect, following redirections and using SPNEGO to pass kerberos credentials and cookie storage

returns an HTML form with a SAMLResponse field (base64 encoded SAML XML response) and javascript to submit the form if in a browser, also sets an AWX sessionid cookie and various Keycloak cookies

curl -b cookies.txt -c cookies.txt -L --negotiate -u : https://$AWX_HOST/sso/login/saml/?idp=$IDP_ID

POST request to AWX SAML complete endpoint passing form field values provided in the SAML response, also passing cookies retrieved previously.

No need to pass SPNEGO flags here or follow redirects

returns a redirect (that we can ignore), updates the AWX sessionid cookie and sets a csrftoken cookie

curl -b cookies.txt -c cookies.txt --data-urlencode “SAMLResponse@samlresponse.txt” -d ‘RelayState=TFSSO’ ‘https://$AWX_HOST/sso/complete/saml/’

GET/POST/PUT to api endpoints as required, providing sessionid and csrftoken cookies:

curl -b cookies.txt -c cookies.txt -L ‘https://$AWX_HOST/api/v2/me/’

Now that I know the mechanism I need to work on getting this usable in ansible… probably via a python module.

Kind Regards,

Kim

Hello,

Did you eventually implement a working solution?
I am basically trying to do the same thing with powershell.

I am using a web form which allows me to handle the authentication through a web browser. I cannot figure out if I need to save the cookies.

Are you using everytime the same cookies or the cookies from the step right before ?

Thank you

Hi Fabien,

Yes, I did get some ansible tasks working for our environment on Linux. A bit clunky, but we haven’t spent too much more time on it and are now moving away from AWX. I have pasted some code snippets below.

We get a session cookie and csrftoken for the AWX host and store it in the hostvars for that AWX host.

  • name: Get initial awx sessionid and SAMLRequest
    block:
  • name: start awx session
    delegate_to: localhost
    become: false
    command:
    cmd: “curl -s ‘https://{{ awx_host }}/sso/login/saml/?idp={{ saml_idp }}’ -c - -w %{redirect_url}”
    check_mode: false
    changed_when: false
    no_log: “{{ ansible_verbosity < 4 }}”
    register: awx_session
    tags:
  • skip_ansible_lint # get_uri module does not support SPNEGO/kerberos authentication
  • name: Set awx sessionid
    set_fact:
    awx_sessionid_cookie: “sessionid={{ awx_session.stdout | regex_search(‘.\s+sessionid\s+(.)’, ‘\1’) | first }}”
    no_log: “{{ ansible_verbosity < 4 }}”
  • name: Get XHTML SAMLResponse
    delegate_to: localhost
    become: false
    command:
    cmd: “curl -s --negotiate -u : ‘{{ (awx_session.stdout_lines | select(‘match’, ‘^https’) | list | first).split(’#‘)[0] }}’ -H ‘Cookie: {{ awx_sessionid_cookie }}’”
    check_mode: false
    changed_when: false
    no_log: “{{ ansible_verbosity < 4 }}”
    register: awx_session_saml_response
    tags:
  • skip_ansible_lint # get_uri module does not support SPNEGO/kerberos authentication
  • name: Assert that we received a SAMLResponse
    assert:
    that: “‘SAMLResponse’ in awx_session_saml_response.stdout”
    fail_msg: “Did not receive a SAMLResponse from keycloak server”
    success_msg: “Keycloak authentication successful”
  • name: Extract SAMLResponse
    set_fact:
    awx_session_saml_response: “{{ awx_session_saml_response.stdout_lines | select(‘search’, ‘name="SAMLResponse"’) | first | regex_search(‘value="([^"]*)’, ‘\1’) }}”
    no_log: “{{ ansible_verbosity < 4 }}”
  • name: Complete SAML authentication
    delegate_to: localhost
    become: false
    command:
    cmd: “curl -s -H ‘Cookie: {{ awx_sessionid_cookie }}’ -c - --data-urlencode ‘SAMLResponse={{ awx_session_saml_response }}’ --data ‘RelayState={{ saml_idp }}’ ‘https://{{ awx_host }}/sso/complete/saml/’”
    check_mode: false
    changed_when: false
    no_log: “{{ ansible_verbosity < 4 }}”
    register: awx_session
    tags:
  • skip_ansible_lint # get_uri module does not support SPNEGO/kerberos authentication
  • name: Update awx_session
    set_fact:
    awx_session:
    cookie: “sessionid={{ awx_session.stdout | regex_search(‘.\s+sessionid\s+(.)’, ‘\1’) | first }}”
    csrftoken: “{{ awx_session.stdout | regex_search(‘.\s+csrftoken\s+(.)’, ‘\1’) | first }}”
    awx_session_saml_response: “”
    awx_sessionid_cookie: “”
    delegate_to: “{{ awx_host }}”
    delegate_facts: true
    no_log: “{{ ansible_verbosity < 4 }}”
    rescue:
  • name: Notify of failure to get awx session
    debug:
    msg: “Failed to get an awx session for {{ awx_host }}”

Then we pass that cookie and token to all the API calls we make:

  • name: Get all job_templates
    delegate_to: localhost
    become: false
    uri:
    url: |
    https://{{ awx_host }}/api/v2/job_templates/?page_size={{ awx_api_page_size }}
    method: “GET”
    return_content: true
    status_code:
  • 200
  • 202
    headers:
    Cookie: “{{ hostvars[awx_host].awx_session.cookie }}; csrftoken={{ hostvars[awx_host].awx_session.csrftoken }}”
    X-CSRFTOKEN: “{{ hostvars[awx_host].awx_session.csrftoken }}”
    Referer: “https://{{ awx_host }}/”
    register: awx_api_job_templates_response
    check_mode: false
    changed_when: false

I hope that helps.

Kind Regards,

Kim

Hello,

Thank you for your answer and your solution.

It will try to adapt my script today.

Regards,

Fabien