RedHat Ansible is a very flexible configuration management tool that comes with a variety of built in modules. One of these modules, ansible.builtin.uri, is provided as an alternative to using “curl” commands through the ansible.builtin.shell or ansible.builtin.command modules. However, the module documentation does not provide a specific example of how to use the URI module when leveraging token based authentication. This blog post shows examples of how this can be done using SonarQube API calls.
Example #1: User Name and Password authentication
When using the URI module for SonarQube API calls with user-name and password authentication (which can be retrieved from Ansible Vault if desired) it is necessary to provide the “user:” and “password:” fields as well as the “force_basic_auth”. In this example we will generate a new token for the provided default user using a unique token name:
# generate a new user token for this session using the project_key
- name: Generate a SonarQube Session Token
ansible.builtin.uri:
url: http://{{sonar_url}}:9000/api/user_tokens/generate
user: "{{sonar_user_name}}"
password: "{{sonar_user_pwd}}"
method: POST
force_basic_auth: yes
body_format: form-urlencoded
body:
name: "{{project_key}}"
register: get_sonor_output
no_log: true
- set_fact: sonar_admin_token="{{ get_sonor_output.json.token }}"
The return result will contain the newly generated token under the json{} section which can be stored to a variable using ‘set_fact’:
"json": {
"createdAt": "2022-05-31T20:34:12+0000",
"login": "admin",
"name": "costar125",
"token": "4f12fd916c878f936e9bf3f04fc460ee4b225be3"
},
By storing this token into a “fact” variable it can be used in subsequent API calls.
Example #2: Token based authentication – creating a project
In order to use a SonarQube derived token, the API expects the token in the “user:” field. However, the “password:” field must also be provided and be left as a ‘null’. This forces the URI module to generate a password-less API call that SonarQube is expecting. In this example, we use the token generated above to authenticate the API call in order to create a new SonarQube project. Note that if the project already exists it will generate an error. This can be avoided by a previous task API call to get all projects (using the unique project key) and then validate using a ‘when’ clause that the new project is not already present
- name: Get SonarQube Projects
ansible.builtin.uri:
url: http://{{sonar_url}}:9000/api/projects/search
user: "{{sonar_admin_token}}"
password: ""
method: GET
force_basic_auth: yes
body_format: form-urlencoded
body:
projects: "{{project_key}}"
no_log: false
register: get_sonar_projects
- set_fact: check_project_name="{{ get_sonar_projects.json.components | json_query(query) }}"
vars:
query: "[?name=='{{ project_name }}'].name"
- name: Create SonarQube Project
ansible.builtin.uri:
url: http://{{sonar_url}}:9000/api/projects/create
user: "{{sonar_admin_token}}"
password: ""
method: POST
force_basic_auth: yes
body_format: form-urlencoded
body:
name: "{{project_name}}"
project: "{{project_key}}"
visibility: public
register: create_sonor_output
no_log: false
when: check_project_name is not search(project_name|string)
Example #3: Token based authentication – revoking the token
Finally, if the token is not to be used further it can be revoked in the same manner that it was created:
# revoke the session token
- name: Revoke a SonarQube Session Token
ansible.builtin.uri:
url: http://{{sonar_url}}:9000/api/user_tokens/revoke
user: "{{sonar_admin_token}}"
password: ""
method: POST
force_basic_auth: yes
body_format: form-urlencoded
body:
name: "{{project_key}}"
status_code: [200, 204]
register: get_sonor_output
no_log: true
In this blog post we explored how the Ansible URI module can be used to a) generate a new security token, b) pass a security token to SonarQube APIs to create a new project (if not already present), and c) to revoke the newly created token at the end of the Ansible session. In these examples the SonarQube API call expected the token in the ‘user:’ field with a null password. Other API calls may require the “password:” field to contain the token and ignore the user field. Check your documentation carefully to see which approach is being used for the specific API calls.