Skip to content

Conversation

@lluisCM
Copy link
Contributor

@lluisCM lluisCM commented Dec 11, 2024

Resolves :

  • CLICKUP-
  • FT-
  • SENTRY-
  • ZENDESK-
  • I have added automatic tests where applicable.
  • The PR contains a description of what has been changed.
  • The description contains manual test instructions.
  • The PR contains update to the release notes.
  • The PR contains update to the documentation.

This PR has been tested on :

  • Windows.
  • MacOs.
  • Linux.

Overview

Purpose:
Authenticate and session library and Authenticator and session tools basic functionality is in.

Scope:

Implementation Details

Approach:

Reasoning:

Changes:

Trade-offs:

Testing

Tests Added:

Manual Testing:

Testing Environment:

Notes for Reviewers

Focus Areas:

Dependencies:

Known Issues:

@lluisCM lluisCM requested a review from a team as a code owner December 11, 2024 12:50
Copy link
Contributor

@dennisweil dennisweil left a comment

Choose a reason for hiding this comment

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

I don't quite understand why an internal webserver is needed for the authentication.

# :coding: utf-8
# :copyright: Copyright (c) 2024 ftrack

import logging
Copy link
Contributor

Choose a reason for hiding this comment

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

Small, unimportant detail reg. code styling:
Imports should be alphabetically ordered.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be discussed

:param redirect_port: The port on which the local web server will run.
"""
try:
self._server_url: str = url_checker(
Copy link
Contributor

Choose a reason for hiding this comment

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

This check should be moved into a setter method.
We might only want to check for the validity of the URL when actually trying to authenticate. We can safely tolerate a non-valid url unless we try to contact the server.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lets talk about this one. I wanted to avoid a setter method here as I don't want to give access to anyone to change the server url.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed on leaving it protected until we have another necessity.

logging.error(f"Invalid server URL: {e}")
raise
self._credential_provider_instance: "CredentialProvider" = (
credential_provider_factory.create_credential_provider()
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming this methong simply create would be sufficient. The name/type of the factory class already makes it quite obvious what it will create.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would prefer to make it specific. If we start using create build or this kind of generic names, it ends up beign very difficult to navigate through the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed to change it to a more generic name "make".

def redirect_uri(self):
return self._redirect_uri

def browser_authenticate(self) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

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

We might have different methods for authentication. Naming should follow a pattern of .... I'd recommend to rename the method to authenticate_browser and in extension also rename the other authentication methods according to this schema.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see the difference?
I mean I currently have browser_authenticate and credential_authenticate as methods. why flipping the order will make it best practice?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed to change this to authenticate_browser and authenticate_credential. Because this way you can .authenticate_... and it will show you the available possibilities.

server_thread.join()
except Exception as e:
logging.error(
f"An error occurred during browser authentication: {e}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of adding the actual exception into the log string, it's better to use the keyword argument exc_info=True, which will automatically add the error and the stack trace to the logging message.

General Discussion topic:
Where should exception handling happen? I have a small preference for deferring the handling of exceptions into the usage code, rather than the library code. We should raise here, but handling the exception should be done outside of this scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lets talk about 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.

Agreed on following exc_info "pattern". And agreed on always raising on libraries to propagate the error.

@@ -0,0 +1,120 @@
# :coding: utf-8
Copy link
Contributor

Choose a reason for hiding this comment

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

Concistency:

Use the TYPE_CHECKING mechanism for type hints as in the other files.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you talk about the credentialProvider import. I can't use type_checking because I need it on the :
isinstance(value, CredentialProvider...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We will maintain consistency in the Typing checking using strings.

logging.basicConfig(level=logging.INFO)


class SessionProvider:
Copy link
Contributor

Choose a reason for hiding this comment

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

Consistency:

Using consistent patterns. This should also have a factory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why? this is equivalent to the authenticate module, not to the credential or webserver helpers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed to use it as it is for now until we start using it and we see what needs it has, then we will rename it or adapt it.

self._session = self.load_session()
return self._session

def load_session(
Copy link
Contributor

Choose a reason for hiding this comment

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

load_session implies that we're dealing with a stored/cached session while in reality, we're creating a new session.
Naming it new_session or create_session makes the intent clearer.
If the load refers to the cretendials, we should name it as new_session_from_stored_credentials.

logging.basicConfig(level=logging.INFO)


def wait_for_event_hub_connection(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd propose to use a more generic retry library. This is a good one:
https://github.com/jd/tenacity

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think might not be worth having a new dependency to a library here... But lets discuss 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.

Agreed on improving names to connect to the event hub thread



# Generic URL Checker Dispatcher
def url_checker(url: str, checkers: list) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

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

If we have a function like this, we should use it and implement our ftrack checkers to be provided to this function.

However, the functionality seems generic enough, that python's builtin functionality should be more than enough:

url_valid = all([check_function(url) for check_function in checker_functions])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting, lets talk about 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.

Lets remove the url_checker and use the ftrack_url_checker everywhere.

@lluisCM
Copy link
Contributor Author

lluisCM commented Dec 16, 2024

I don't quite understand why an internal webserver is needed for the authentication.

It is needed to redirect the webbrowser authentication and read the credentials from there.

Copy link
Contributor

@dennisweil dennisweil left a comment

Choose a reason for hiding this comment

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

Approved except for a small discussion point regarding singular/plura.

@lluisCM lluisCM merged commit 63b45f7 into backlog/monorepo-refactor-2025/story Dec 19, 2024
1 check passed
@lluisCM lluisCM deleted the backlog/monorepo-refactor-2025/authenticate-library branch December 19, 2024 11:13
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.

3 participants