Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ONYX-26897 To reuse the token #185

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Conversation

Pooja-Gangwar
Copy link
Contributor

@Pooja-Gangwar Pooja-Gangwar commented Jan 6, 2023

Desired Outcome

The ansible-lookup-plugin does not support retries

Implemented Changes

Code fix is around supporting re-tries with authentication.
Create a mock test which can return 401 on first call and returns a token on subsequent call to prove re-try logic.

Meeting notes from 11/03/2022:

   Attendeess: [Jason Vanderhoof](https://ca-il-jira.il.cyber-ark.com:8443/secure/ViewProfile.jspa?name=jvanderhoof) , 
   [Andy Tinkham](https://ca-il-jira.il.cyber-ark.com:8443/secure/ViewProfile.jspa?name=atinkham) and 
    brugu.maharishi@cyberark.com

   Code fix is around supporting re-tries with authentication.
   Currently a single token is used to fetch one variable and is never re-used. In order to improve performance - ensure the 
   token can be used for it's life. Need to come up with better design to ensure token is stored securely.
   Need a security review on this project once code changes are done as we are modifying the way we authenticate and 
    storing tokens.
   It would be tough to re-create client environment, hence [Jason Vanderhoof](https://ca-il-jira.il.cyber- 
   ark.com:8443/secure/ViewProfile.jspa?name=jvanderhoof)  suggested to create a mock test which can return 401 on 
   first call and returns a token on subsequent call to prove re-try logic.

Connected Issue/Story

Jira ticket - ONYX-26897
Bug - https://cyberark.lightning.force.com/lightning/r/Case/5002J00001Y4ffFQAR/view

Definition of Done

At least 1 todo must be completed in the sections below for the PR to be
merged.

Changelog

  • The CHANGELOG has been updated, or
  • This PR does not include user-facing changes and doesn't require a
    CHANGELOG update

Test coverage

  • This PR includes new unit and integration tests to go with the code
    changes, or
  • The changes in this PR do not require tests

Documentation

  • Docs (e.g. READMEs) were updated in this PR
  • A follow-up issue to update official docs has been filed here: [insert issue ID]
  • This PR does not require updating any documentation

Behavior

  • This PR changes product behavior and has been reviewed by a PO, or
  • These changes are part of a larger initiative that will be reviewed later, or
  • No behavior was changed with this PR

Security

  • Security architect has reviewed the changes in this PR,
  • These changes are part of a larger initiative with a separate security review, or
  • There are no security aspects to these changes

@Pooja-Gangwar Pooja-Gangwar requested a review from a team as a code owner January 6, 2023 11:11
Pooja Gangwar added 2 commits January 7, 2023 13:36
Copy link
Contributor

@john-odonnell john-odonnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions:

  1. In the PR description, I notice a link to a Salesforce case, but I can't tell the connection between the case and this PR. Any more information here?
  2. We definitely want a security review with @andytinkham before merging this to make sure we're correctly handling token files.
  3. Caching the token will only improve performance on requests executed within the token's 8 minute lifetime. Could we implement a batch secret retrieval instead, without caching the token?
  4. You've added some more test cases, but none of them actually confirm the changed behavior - we need at least one more test that confirms a retrieved Conjur token is cached in a particular file.

Comment on lines +180 to +191
if response.getcode() == 200:
display.vvvv('Conjur token was successfully retrieved and authorized with {0} code and {1} username '.format(code, username))
return response.read()
if response.getcode() == 401:
raise AnsibleError('Conjur request has invalid authorization credentials as {0} and {1} response'.format(code, username))
if response.getcode() == 403:
raise AnsibleError('The controlling host\'s Conjur identity does not have authorization as \'{0}\' (got {1} response)'
.format(username, code))
if response.getcode() == 404:
raise AnsibleError('The token does not exist with {0} response '.format(code))
if response.getcode() == 500:
raise AnsibleError('Internal Server Error with {0} response'.format(code))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the purposes of determining whether an authentication request has failed or not, I don't know if we really need to capture all these conditions, or if we need to expose them to the Ansible client.

Suggested change
if response.getcode() == 200:
display.vvvv('Conjur token was successfully retrieved and authorized with {0} code and {1} username '.format(code, username))
return response.read()
if response.getcode() == 401:
raise AnsibleError('Conjur request has invalid authorization credentials as {0} and {1} response'.format(code, username))
if response.getcode() == 403:
raise AnsibleError('The controlling host\'s Conjur identity does not have authorization as \'{0}\' (got {1} response)'
.format(username, code))
if response.getcode() == 404:
raise AnsibleError('The token does not exist with {0} response '.format(code))
if response.getcode() == 500:
raise AnsibleError('Internal Server Error with {0} response'.format(code))
if code == 200:
display.vvvv('Conjur user {0} successfully authenticated'.format(username))
return response.read()
elif code == 500:
raise AnsibleError('Internal Server Error: {0}'.format(response.read()))
else:
raise AnsibleError('Authentication failed with status code {0}: {1}.'.format(code, response.read())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall I remove all except 200, 500 and 401 code . Please suggest .

@@ -0,0 +1 @@
token
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this file location is used for token storage, it should be added to .gitignore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes , it is there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now in new changes , I am not using any new file .

Comment on lines 348 to 349
path = '../../tests/conjur_variable/plugin_token.txt'
isExist = os.path.exists(path)
Copy link
Contributor

@john-odonnell john-odonnell Jan 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should definitely include a default token file path, but this path is relative to some unknown sub-directory of the project's root, and points to the test directory - probably don't want to hard-code this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure , I will update it .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 348 to 370
path = '../../tests/conjur_variable/plugin_token.txt'
isExist = os.path.exists(path)

isEmpty = 0
if ((isExist is True)):
isEmpty = os.path.getsize(path)

token = None
if 'authn_token_file' not in conf:
token = _fetch_conjur_token(
conf['appliance_url'],
conf['account'],
identity['id'],
identity['api_key'],
validate_certs,
cert_file
)
if ((isExist is False) or (isEmpty == 0)):
token = _fetch_conjur_token(
conf['appliance_url'],
conf['account'],
identity['id'],
identity['api_key'],
validate_certs,
cert_file
)
with open("plugin_token.txt", "wb") as binary_file:
binary_file.write(token)
else:
with open("plugin_token.txt", "rb") as f:
token = f.read()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we can use the existing authn_token_file configuration to clean this up a bit. Traditionally, it's used to point the service to an existing file that already contains a Conjur token, but maybe we could repurpose it to indicate that either:

  1. The file already exists and has a Conjur token, or
  2. The file does not exist, so we want to authenticate with Conjur and store our token there

Given that, we could probably re-arrange this bit:

if 'authn_token_file' not in conf:
    token = _fetch_conjur_token(...)
else:
    if os.path.exists(conf['authn_token_file']):
        with open(conf['authn_token_file'], 'rb') as f:
            token = f.read()
    else:
        token = _fetch_conjur_token(...)
        with open(conf['authn_token_file'], "wb") as f:
            f.write(token)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made changes to use the existing file "access_token" .

@@ -102,6 +102,7 @@
from ansible.module_utils.urls import open_url
from ansible.utils.display import Display
import ssl
from pathlib import Path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import is not used in these changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@Pooja-Gangwar
Copy link
Contributor Author

Pooja-Gangwar commented Jan 23, 2023

A few questions:

  1. In the PR description, I notice a link to a Salesforce case, but I can't tell the connection between the case and this PR. Any more information here? Ans - Sorry I missed to mention here , I worked on 11/03/2022 Meeting's comments , now these comments are available in PR and in Jira ticket comments section these comments were already available .
  2. We definitely want a security review with @andytinkham before merging this to make sure we're correctly handling token files. Ans - Sure, John
  3. Caching the token will only improve performance on requests executed within the token's 8 minute lifetime. Could we implement a batch secret retrieval instead, without caching the token? Ans- Please let's talk on it someday.
  4. You've added some more test cases, but none of them actually confirm the changed behavior - we need at least one more test that confirms a retrieved Conjur token is cached in a particular file. Ans -Sure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants