API authentication via SAML

268 views
Skip to first unread message

Kim Covil

unread,
Apr 1, 2021, 2:09:05 PM4/1/21
to AWX Project
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

Kim Covil

unread,
Apr 9, 2021, 3:13:56 PM4/9/21
to AWX Project
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 "SAMLRe...@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

Fabien Carré

unread,
Oct 4, 2023, 10:42:58 AM10/4/23
to AWX Project
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

Kim Covil

unread,
Oct 4, 2023, 1:29:57 PM10/4/23
to awx-p...@googlegroups.com
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

--
You received this message because you are subscribed to a topic in the Google Groups "AWX Project" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/awx-project/6TCZJiqFAiA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to awx-project...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/awx-project/f5b85107-b591-4e21-ae59-2d729f229e1en%40googlegroups.com.

Fabien Carré

unread,
Oct 5, 2023, 6:22:20 AM10/5/23
to AWX Project
Hello,

Thank you for your answer and your solution.

It will try to adapt my script today.

Regards,

Fabien
Reply all
Reply to author
Forward
0 new messages