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

Implementation of Oauth of Github, Google and Microsoft #4298

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

Conversation

feyruzb
Copy link
Collaborator

@feyruzb feyruzb commented Jul 18, 2024

fixes #4160

The right way it should look after logging in
Screenshot from 2024-07-18 17-38-29

new added button to log in with github
Screenshot from 2024-07-18 17-40-36

Changes:

  • added new buttons on login page for GitHub,Google Oauth authorization
  • added functions createLink and getOAuthToken into authentication.thrift
  • imported OAuth2Session in client.py
  • added a case for Oauth authorization in login_user function
  • added definition for thrift
  • imported OAuth2Session in authentication.py
  • added code to load the authentication configuration from
  • added oauth method for authentication in performLogin function
  • added oauth case in session manager
  • added fields for server_config file in the server_config.json
  • added oauth cases in auth.js
  • added reusable providers dict to server config to allow easier adding of new oauth providers
  • create a new function get_oauth_config for getting different providers configs in session manager
  • added documentation for configuration

@feyruzb feyruzb requested review from bruntib and vodorok as code owners July 18, 2024 15:47
@feyruzb feyruzb force-pushed the branch-2-backup branch 2 times, most recently from 5ce7f18 to 68eaf7b Compare July 25, 2024 11:05
@feyruzb feyruzb requested a review from dkrupp as a code owner July 29, 2024 15:14
@feyruzb feyruzb force-pushed the branch-2-backup branch 2 times, most recently from de2e213 to d3f6b29 Compare July 30, 2024 11:02
Copy link
Contributor

@vodorok vodorok left a comment

Choose a reason for hiding this comment

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

Please see my remarks.

I have some additional comments apart from the direct in code messages:

  • My major concern with the implementation is that the oauth related API and its implementation is not generalized enough. The configuration is good enough for the time being.
  • I am not sure if we are allowed to use the Git Hub logo in our repo.
  • Please invite @cservakt to review the JS and VueJS parts.

I did not do a thorough review of the oauth flow in authentication.py after you addressed the above issues I will do another round concentrating on that.

Thanks for the hard work!

web/server/config/server_config.json Outdated Show resolved Hide resolved
web/server/config/server_config.json Show resolved Hide resolved
docs/web/authentication.md Outdated Show resolved Hide resolved
web/api/authentication.thrift Outdated Show resolved Hide resolved
web/client/codechecker_client/client.py Outdated Show resolved Hide resolved
web/server/vue-cli/src/store/actions.type.js Show resolved Hide resolved
web/server/config/server_config.json Outdated Show resolved Hide resolved
web/server/codechecker_server/api/authentication.py Outdated Show resolved Hide resolved
web/server/codechecker_server/session_manager.py Outdated Show resolved Hide resolved
web/server/codechecker_server/session_manager.py Outdated Show resolved Hide resolved
@feyruzb feyruzb force-pushed the branch-2-backup branch 10 times, most recently from 12c68e7 to f064c2b Compare July 31, 2024 14:41
@feyruzb feyruzb requested a review from vodorok July 31, 2024 15:03
@feyruzb feyruzb force-pushed the branch-2-backup branch 3 times, most recently from b4d5a0a to d3847d6 Compare July 31, 2024 16:05
@feyruzb feyruzb force-pushed the branch-2-backup branch 2 times, most recently from 06d2ed8 to c2d4ba5 Compare January 15, 2025 15:59
Copy link
Member

@dkrupp dkrupp left a comment

Choose a reason for hiding this comment

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

Please make sure that you correctly and consistently use the token, session variable names.
Please consider factoring out the oauth access token into a separate table.
When do we remove rows from teh oauth session table?
How do we handle token refreshing? Would it be automated? what happens if an access token expires?

// Returns list of providers for oauth for respective appearence of buttons.
list<string> getOauthProviders(),

// Create a link for the user to log in for github Oauth.
Copy link
Member

Choose a reason for hiding this comment

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

why github? I guess you could write instead: Create a link for the user to log in with an Oauth provider

Copy link
Collaborator Author

@feyruzb feyruzb Feb 3, 2025

Choose a reason for hiding this comment

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

Fixed

try:
date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with DBSession(self.__config_db) as session:
session.execute("DELETE FROM oauth_sessions "
Copy link
Member

Choose a reason for hiding this comment

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

I guess we should not use direct SQL statements in codechecker code. You should use sqlachemy statments instead.
https://docs.sqlalchemy.org/en/20/tutorial/data_update.html#the-delete-sql-expression-construct

also see other examples from the codechecker codebase. then you can also remove the sqlite3 dependency.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed, now uses sqlachemy statements for removal of expired sessions.


LOG.info("State inserted successfully.")

except sqlite3.Error as e:
Copy link
Member

Choose a reason for hiding this comment

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

I think you should not use sqlite3 exception handling and in general direct sqlite3 dependency should be removed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Resolved. Replaced all SQLite3-specific exceptions with standard exceptions. sqlite3 dependency has been removed

@@ -167,6 +270,160 @@ def performLogin(self, auth_method, auth_string):
codechecker_api_shared.ttypes.ErrorCode.AUTH_DENIED,
msg)

elif auth_method == "oauth":
date_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
provider, url = auth_string.split("@")
Copy link
Member

Choose a reason for hiding this comment

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

could you please comment above what the auth_string is expected to look like in this case? an example is good enough.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed, added a comment with example of auth_string in case of OAuth authentication..

@timeit
def createLink(self, provider):
"""
For creating a autehntication link for OAuth for specified provider
Copy link
Member

Choose a reason for hiding this comment

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

Please describe better what the funtion is expected to do.
This function returns an URL given the provider.
It also creates a session and inserts something(insertDataOauth()) in the dabase.

Copy link
Collaborator Author

@feyruzb feyruzb Feb 4, 2025

Choose a reason for hiding this comment

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

Fixed, extended description of what the function does.

@@ -630,6 +669,65 @@ def create_session(self, auth_string):

return local_session

def create_session_oauth(self, provider, username, token):
Copy link
Member

Choose a reason for hiding this comment

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

please call token as access_token. If I understand correctly here token is the oauth access token

}

# Generate a new token and create a local session.
token = generate_session_token()
Copy link
Member

Choose a reason for hiding this comment

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

this is the codechecker session token, right?
maybe call is codechecker_session_token

# Generate a new token and create a local session.
token = generate_session_token()
# token_d is the access token of the oauth provider.
token_d = user_data.get('oauth_access_token')
Copy link
Member

Choose a reason for hiding this comment

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

why not call it oauth_access_token then?


if allowed_users == ["*"] or username in allowed_users:
LOG.info("User %s is authorized.", username)
session = self.__manager.create_session_oauth(
Copy link
Member

Choose a reason for hiding this comment

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

this is the codechecker session, right?
call it session_codecheker

code_verifier=pkce_verifier
)
# inserting data in database
self.insertDataOauth(state=state,
Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, we insert a row in this table every time a user tries to login. Then when will a row be removed from this table. Or will it grow indefinitely?

@feyruzb feyruzb force-pushed the branch-2-backup branch 2 times, most recently from ba4683b to 3417d4d Compare February 3, 2025 14:27
@feyruzb feyruzb force-pushed the branch-2-backup branch 7 times, most recently from d107d90 to fcc5cd5 Compare February 3, 2025 18:06
Copy link
Contributor

@bruntib bruntib left a comment

Choose a reason for hiding this comment

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

Thank you for this development. This is a great and important work!

@@ -16,6 +16,9 @@ Table of Contents
* [<i>LDAP</i> authentication](#ldap-authentication)
* [Configuration options](#configuration-options)
* Membership in custom groups with [<i>regex_groups</i>](#regex_groups-authentication)
Copy link
Contributor

Choose a reason for hiding this comment

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

The regex_groups could be a sub-point like OAuth authentication.

// Returns list of providers for oauth for respective appearence of buttons.
list<string> getOauthProviders(),

// Create a link for the user to log in for github Oauth.
Copy link
Contributor

Choose a reason for hiding this comment

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

Not just github.

"< DATETIME(\"" + date + "\")")
session.commit()
LOG.info("Expired state, validation codes removed successfully.")
except sqlite3.Error as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it catching only sqlite3 errors? How about other database engines?


LOG.info("State inserted successfully.")

except sqlite3.Error as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it catching only sqlite3 errors? How about other database engines?

@timeit
def createLink(self, provider):
"""
For creating a autehntication link for OAuth for specified provider
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
For creating a autehntication link for OAuth for specified provider
For creating an authentication link for OAuth for specified provider.

Comment on lines +376 to +383
user_info = None
username = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary initialization.

Comment on lines +390 to +398
# if the provider is github it fetches primary email
# from another api endpoint to maintain username as email
# consistency between GitHub and other providers
Copy link
Contributor

Choose a reason for hiding this comment

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

What do we use "username" for in CodeChecker? If we want to identify authorized users by their e-mail addresses, then couldn't we use the "email" attribute of their user info? In this case it wouldn't be needed to distinguish GitHub here.

provider_cfg = self.__auth_config.get(
'method_oauth', {}).get("providers", {}).get(provider, {})

# turn off configuration if it is set to default values
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this protection? I would say that examples can be provided in the documentation, but the template config file can have empty values and OAuth method being disabled.

@@ -64,6 +66,10 @@ def setup_class_common():

codechecker.add_test_package_product(host_port_cfg, TEST_WORKSPACE)

subprocess.Popen(["python3", "oauth_server.py"],
cwd="tests/functional/authentication")
sleep(5)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this sleep() operation intended or accidental?

self.last_access = last_access if last_access else datetime.now()

def get_access_token(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is this function used?

@feyruzb feyruzb force-pushed the branch-2-backup branch 2 times, most recently from 1f5985d to 45aa94d Compare February 4, 2025 15:47
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.

OpenID Connect based authentication (oauth)
7 participants