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

On each execute_get call, check age of auth token, reinitialize HubRestApi object if >= 1.5 hours. #118

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

ghost
Copy link

@ghost ghost commented Nov 6, 2020

Currently, the rest api bearer token is only valid for 2h.
If a HubRestApi object is used by a client script in the examples directory to create a custom report for a large set of components, the report could run longer than 2h using the same token.
Anything requested after 2h will get a 401 response from Black Duck Hub.
This enhancement will solve that potential problem since there is no way around it on the Black Duck Hub side.
On each execute_get call, check to see if the current HubRestApi object has existed for less than 1.5h, if older than 1.5h, reinitialize it with a new bearer token.

If a HubRestApi object is used by a client script in the examples directory to create a custom report for a large set of components, the report could run longer than 2h using the same token.
Anything requested after 2h will get a 401 response from Black Duck Hub.
This enhancement will solve that potential problem since there is no way around it on the Black Duck Hub side.
On each execute_get call, check to see if the current HubRestApi object has existed for less than 1.5h, if older than 1.5h, reinitialize it with a new bearer token.
Copy link
Collaborator

@mkumykov mkumykov left a comment

Choose a reason for hiding this comment

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

Very nice. it will make the library much friendlier and capable of supporting long running tasks.

Copy link
Collaborator

@jackeekaplan jackeekaplan left a comment

Choose a reason for hiding this comment

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

Being able to refresh the bearer token without having to create a new HubInstance is a great enhancement. I think it should be something the user can disable if they want to, for the same reasons that the bearer token expires.

def __init__(self, *args, **kwargs):
# Config needs to be an instance variable for thread-safety, concurrent use of HubInstance()
self.config = {}

self.read_config()
Copy link
Collaborator

Choose a reason for hiding this comment

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

why skip the try/except block?

Copy link
Author

Choose a reason for hiding this comment

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

I think that try/except block is checking if the .restconfig exists, if it doesn't check the args and write it.

Copy link
Author

Choose a reason for hiding this comment

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

I added a keyword argument named refresh_token that the client script can pass on instantiation. Refreshing the token is now off by default.

@@ -123,6 +128,9 @@ def __init__(self, *args, **kwargs):

def read_config(self):
try:
#always return to the examples directory to read the config
if not os.getcwd().endswith("examples"):
os.chdir(root_dir)
Copy link
Collaborator

Choose a reason for hiding this comment

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

could this potentially create a problem if you were calling this from another application that uses the blackduck library, rather than from the examples directory?

Copy link
Author

Choose a reason for hiding this comment

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

Hi, yes, this is a potential problem that I've been hoping to make progress on before merging. The root of the problem is that .restconfig is located in examples on the first HubRestApi object init. When a refresh actually does occur, .restconfig no longer exists in context at the time HubRestApi reinitializes itself, so I reset back to examples to ensure that .restconfig is available. There has to be a better approach, it's just not clear to me. Any ideas?

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the .restonfig.json is written to (or read from) the current working directory. It is not hard-coded to anything. So, if I invoke a program in /Users/gsnyder/Projects/sage for instance, the .restonfig.json needs to be in the /Users/gsnyder/Projects/sage directory for it to be read. Or, if I was initializing the HubInstance using parameters, then the .restconfig.json would be written to that directory.

Also, the config is saved in memory to self.config, so do we really need to read anything again?

Copy link
Author

Choose a reason for hiding this comment

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

I removed the hardcoded part. Now, it works under the assumption that .restconfig.json is in the current working directory.

length = len(response.text)
new_token = response.text
token_tail = new_token[length - 50: length]
print ("New token requested, using restconfig api token: {}".format(token_tail))
Copy link
Collaborator

Choose a reason for hiding this comment

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

We probably shouldn't be printing out the user's api token, same thing for the password below

Copy link
Author

Choose a reason for hiding this comment

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

Agreed, I'll go ahead and remove them. My wording is not clear. The actual text is from the bearer token which is available from the response. Not the private Black Duck api token from rest config.

Copy link
Collaborator

Choose a reason for hiding this comment

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

And if you are going to be printing the token, don't do so using print - make it a call to logger.debug(...) or logger.info(...), so it may at least be disabled by tweaking the log level.

@ghost
Copy link
Author

ghost commented Dec 17, 2020

Hi @jackeekaplan, with the most recent changes added to the branch, is it ok to merge? Or would you want to take a second look? I am certainly looking for feedback.

Thanks!

@@ -231,7 +248,26 @@ def get_limit_paramstring(self, limit):

def get_apibase(self):
return self.config['baseurl'] + "/api"


def reauthenticate(self, *args, **kwargs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, this really isn't a good idea. It would be far better to rerun auth rather than explicitly reinitialising the class.

Copy link
Author

Choose a reason for hiding this comment

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

I tried rerunning the call to authenticate in my first attempt. I couldn't get it to work, I'll revisit.
For my own understanding, what is the concern about reinitializing the class upon token expiration?

Thanks for taking a look!

Copy link
Collaborator

@OffBy0x01 OffBy0x01 Jan 11, 2021

Choose a reason for hiding this comment

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

It may have unexpected side effects down the line. Generally speaking in python the only time you should need to manually call __init__(...) is when initializing a parent class i.e. super().__init__(). I wouldn't enforce this sort of change at the library level.

length = len(response.text)
new_token = response.text
token_tail = new_token[length - 50: length]
print ("New token requested, using restconfig api token: {}".format(token_tail))
Copy link
Collaborator

Choose a reason for hiding this comment

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

And if you are going to be printing the token, don't do so using print - make it a call to logger.debug(...) or logger.info(...), so it may at least be disabled by tweaking the log level.

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

Successfully merging this pull request may close these issues.

5 participants