diff --git a/defaults/main.yml b/defaults/main.yml index 6f555e4..c84d2fa 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -9,6 +9,7 @@ threescale_cicd_production_environment_name: production threescale_cicd_default_staging_suffix: -staging threescale_cicd_default_production_suffix: "" threescale_cicd_default_apicast_scheme: https +threescale_cicd_openapi_smoketest_default_scope: openid threescale_cicd_default_oauth_scopes: openid: Any OpenID Connect token threescale_cicd_application_plans: diff --git a/tasks/create_default_application.yml b/tasks/create_default_application.yml index 9593ac1..55ccfe1 100644 --- a/tasks/create_default_application.yml +++ b/tasks/create_default_application.yml @@ -29,10 +29,12 @@ - set_fact: threescale_cicd_tmp_search_criteria: 'app_id' + threescale_cicd_tmp_app_id_field: 'application_id' when: 'threescale_cicd_api_security_scheme.type == ''oauth2''' - set_fact: threescale_cicd_tmp_search_criteria: 'user_key' + threescale_cicd_tmp_app_id_field: 'user_key' when: 'threescale_cicd_api_security_scheme.type == ''apiKey''' - name: Check if the default application exists @@ -49,7 +51,7 @@ when: 'threescale_cicd_default_application_id is not defined and threescale_cicd_default_application_appid is defined and threescale_cicd_tmpresponse.status == 200' - set_fact: - threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ (threescale_cicd_access_token|urlencode) ~ "&plan_id=" ~ threescale_cicd_default_application_plan_id ~ "&name=" ~ (threescale_cicd_default_application_name|urlencode) ~ "&description=" ~ (threescale_cicd_default_application_description|urlencode) ~ "&" ~ threescale_cicd_tmp_search_criteria ~ "=" ~ (threescale_cicd_default_application_appid|urlencode) }}' + threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ (threescale_cicd_access_token|urlencode) ~ "&plan_id=" ~ threescale_cicd_default_application_plan_id ~ "&name=" ~ (threescale_cicd_default_application_name|urlencode) ~ "&description=" ~ (threescale_cicd_default_application_description|urlencode) ~ "&" ~ threescale_cicd_tmp_app_id_field ~ "=" ~ (threescale_cicd_default_application_appid|urlencode) }}' - name: Create the application uri: @@ -78,3 +80,6 @@ - set_fact: threescale_cicd_default_application_details: '{{ threescale_cicd_tmpresponse.json.application }}' when: 'threescale_cicd_default_application_id is defined' + +- include_tasks: patch_default_application_for_oauth.yml + when: 'threescale_cicd_api_security_scheme.type == ''oauth2''' diff --git a/tasks/main.yml b/tasks/main.yml index dee2d70..6ec3afc 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -15,10 +15,15 @@ threescale_cicd_sso_issuer_endpoint: '{{ (hostvars[groups[''sso''][0]].scheme|default(''https'')) ~ ''://'' ~ hostvars[groups[''sso''][0]].client_id ~ '':'' ~ hostvars[groups[''sso''][0]].client_secret ~ ''@'' ~ groups[''sso''][0] ~ ''/auth/realms/'' ~ hostvars[groups[''sso''][0]].realm }}' when: 'threescale_cicd_sso_issuer_endpoint is not defined and ''sso'' in groups and groups[''sso''] > 0' -- name: Set the threescale_cicd_sso_realm_endpoint variable from the inventory +- name: Set the threescale_cicd_sso_realm_endpoint variable from the threescale_cicd_sso_issuer_endpoint set_fact: - threescale_cicd_sso_realm_endpoint: '{{ (hostvars[groups[''sso''][0]].scheme|default(''https'')) ~ ''://'' ~ groups[''sso''][0] ~ ''/auth/realms/'' ~ hostvars[groups[''sso''][0]].realm }}' - when: 'threescale_cicd_sso_realm_endpoint is not defined and ''sso'' in groups and groups[''sso''] > 0' + threescale_cicd_sso_realm_endpoint: '{{ (threescale_cicd_sso_issuer_endpoint|urlsplit(''scheme'')) ~ ''://'' ~ (threescale_cicd_sso_issuer_endpoint|urlsplit(''hostname'')) ~ (threescale_cicd_sso_issuer_endpoint|urlsplit(''path'')) }}' + when: 'threescale_cicd_sso_realm_endpoint is not defined and threescale_cicd_sso_issuer_endpoint is defined' + +- name: Set the threescale_cicd_sso_admin_endpoint variable from the threescale_cicd_sso_realm_endpoint + set_fact: + threescale_cicd_sso_admin_endpoint: '{{ threescale_cicd_sso_realm_endpoint|replace(''/auth/realms/'', ''/auth/admin/realms/'') }}' + when: 'threescale_cicd_sso_admin_endpoint is not defined' - name: Set the threescale_cicd_apicast_sandbox_endpoint variable from the inventory set_fact: @@ -33,6 +38,7 @@ # Load the API definition from the provided OpenAPI file - import_tasks: read_openapi_file.yml + - name: Compute the service system_name set_fact: threescale_cicd_api_system_name: '{{ threescale_cicd_api_environment_name ~ "_" ~ threescale_cicd_api_system_name }}' @@ -76,6 +82,10 @@ threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''auth_user_key'': threescale_cicd_api_security_scheme.name }) }}' when: 'threescale_cicd_api_security_scheme.type == ''apiKey''' +- set_fact: + threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''oidc_issuer_endpoint'': threescale_cicd_sso_issuer_endpoint }) }}' + when: 'threescale_cicd_api_security_scheme.type == ''oauth2''' + - set_fact: threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''sandbox_endpoint'': threescale_cicd_apicast_sandbox_endpoint }) }}' when: 'threescale_cicd_apicast_sandbox_endpoint is defined' diff --git a/tasks/patch_default_application_for_oauth.yml b/tasks/patch_default_application_for_oauth.yml new file mode 100644 index 0000000..7701c00 --- /dev/null +++ b/tasks/patch_default_application_for_oauth.yml @@ -0,0 +1,61 @@ +--- + +- name: Prepare the OAuth Request to RH-SSO (static params) + set_fact: + threescale_cicd_tmp_body: "" + +- name: Prepare the OAuth Request to RH-SSO (urlencode dynamic params) + set_fact: + threescale_cicd_tmp_body: '{{ threescale_cicd_tmp_body ~ "&" ~ threescale_cicd_tmp_param.key ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}' + with_dict: + client_id: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''username'') }}' + client_secret: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''password'') }}' + scope: '{{ threescale_cicd_openapi_smoketest_default_scope }}' + grant_type: client_credentials + loop_control: + loop_var: threescale_cicd_tmp_param + +- name: Authenticate to RH-SSO using the 3scale service account + uri: + url: '{{ threescale_cicd_sso_realm_endpoint }}/protocol/openid-connect/token' + body: '{{ threescale_cicd_tmp_body }}' + method: POST + validate_certs: no + return_content: yes + register: threescale_cicd_tmpresponse + retries: '{{ threescale_cicd_retries }}' + delay: '{{ threescale_cicd_delay }}' + # temporary fix for https://github.com/ansible/ansible/issues/28078 + until: 'threescale_cicd_tmpresponse|success' + +- name: Extract the access_token + set_fact: + threescale_cicd_openapi_tmp_access_token: '{{ threescale_cicd_tmpresponse.json |json_query("access_token") }}' + +- name: Wait for the new client to appear in RH-SSO + uri: + url: '{{ threescale_cicd_sso_admin_endpoint }}/clients?clientId={{ threescale_cicd_default_application_appid|urlencode }}' + method: GET + validate_certs: no + return_content: yes + headers: + Authorization: 'Bearer {{ threescale_cicd_openapi_tmp_access_token }}' + register: threescale_cicd_tmpresponse + retries: '{{ threescale_cicd_retries }}' + delay: '{{ threescale_cicd_delay }}' + until: 'threescale_cicd_tmpresponse|success and threescale_cicd_tmpresponse.json|length > 0' + +- set_fact: + threescale_cicd_default_application_sso_id: '{{ threescale_cicd_tmpresponse.json[0].id }}' + threescale_cicd_tmp_body: '{{ threescale_cicd_tmpresponse.json[0]|combine({ ''serviceAccountsEnabled'': true, ''standardFlowEnabled'': false, ''implicitFlowEnabled'': false, ''directAccessGrantsEnabled'': true }) }}' + +- name: Patch the client in RH-SSO to support the "client_credentials" and "password" grant_type. + uri: + url: '{{ threescale_cicd_sso_admin_endpoint }}/clients/{{ threescale_cicd_default_application_sso_id|urlencode }}' + method: PUT + validate_certs: no + body: '{{ threescale_cicd_tmp_body|to_json }}' + status_code: '200,204' + headers: + Authorization: 'Bearer {{ threescale_cicd_openapi_tmp_access_token }}' + Content-Type: 'application/json' diff --git a/tasks/read_openapi_file.yml b/tasks/read_openapi_file.yml index 0220dab..df716df 100644 --- a/tasks/read_openapi_file.yml +++ b/tasks/read_openapi_file.yml @@ -140,7 +140,7 @@ - name: Find the correct backend_version to use set_fact: - threescale_cicd_api_backend_version: 'oauth' + threescale_cicd_api_backend_version: 'oidc' when: 'threescale_cicd_api_security_scheme.type == ''oauth2''' - name: Extract the backend hostname from OpenAPI diff --git a/tasks/smoke_tests_oauth.yml b/tasks/smoke_tests_oauth.yml index 9004006..94b792c 100644 --- a/tasks/smoke_tests_oauth.yml +++ b/tasks/smoke_tests_oauth.yml @@ -1,4 +1,36 @@ --- -- name: TODO - fail: +- name: Prepare the OAuth Request to RH-SSO (static params) + set_fact: + threescale_cicd_tmp_body: "" + +- name: Prepare the OAuth Request to RH-SSO (urlencode dynamic params) + set_fact: + threescale_cicd_tmp_body: '{{ threescale_cicd_tmp_body ~ "&" ~ threescale_cicd_tmp_param.key ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}' + with_dict: + client_id: '{{ threescale_cicd_default_application_details.client_id }}' + client_secret: '{{ threescale_cicd_default_application_details.client_secret }}' + scope: '{{ threescale_cicd_openapi_smoketest_default_scope }}' + grant_type: client_credentials + loop_control: + loop_var: threescale_cicd_tmp_param + +- name: Authenticate to RH-SSO using the default application credentials + uri: + url: '{{ threescale_cicd_sso_realm_endpoint }}/protocol/openid-connect/token' + body: '{{ threescale_cicd_tmp_body }}' + method: POST + validate_certs: no + return_content: yes + register: threescale_cicd_tmpresponse + retries: '{{ threescale_cicd_retries }}' + delay: '{{ threescale_cicd_delay }}' + # temporary fix for https://github.com/ansible/ansible/issues/28078 + until: 'threescale_cicd_tmpresponse|success' + +- name: Extract the access_token + set_fact: + threescale_cicd_openapi_smoketest_access_token: '{{ threescale_cicd_tmpresponse.json |json_query("access_token") }}' + +- set_fact: + threescale_cicd_openapi_smoketest_headers: "{{ threescale_cicd_openapi_smoketest_headers|combine({ 'Authorization': 'Bearer ' ~ threescale_cicd_openapi_smoketest_access_token }) }}"