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

Add generic OIDC authentication flow #6783

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

Conversation

palash247
Copy link

@palash247 palash247 commented Feb 27, 2024

What type of PR is this?

  • Refactor
  • Feature
  • Bug Fix
  • New Query Runner (Data Source)
  • New Alert Destination
  • Other

Description

Generic OIDC login

Note: Seeking feedback

Problem

Currently, Redash is limited to supporting authentication via Google's OIDC. Expanding the authentication support to a generic OIDC flow increases Redash's accessibility and flexibility, making it a more inclusive tool for diverse environments.

Implementation Steps

To fully implement and integrate the generic OIDC authentication flow into Redash, the following steps need to be taken (Open for feedback):

  • Make OIDC Discovery Endpoint Configurable: This flexibility allows Redash to dynamically adapt to different IdPs by simply modifying configuration parameters.

  • Implement Routes for OIDC Authentication: Develop new routes within the application to handle the authentication process via OIDC.

  • Modify Login Templates: Update the UI components, specifically the login page templates, to include an OIDC login button.

  • Manual Testing with Multiple OIDC IdPs: To ensure compatibility and robustness, manually test the new authentication flow with multiple OIDC IdPs, including but not limited to Google, AWS, Okta, and Auth0. (Tested with Google and AWS Cognito)

  • Implement Unit Tests

  • Write Documentation for OIDC Configuration: Create detailed documentation to assist users in configuring OIDC with Redash. This documentation should cover configuration steps for different IdPs.

  • Mutate OIDC to include domain check: (not sure about this one) Current Google OIDC flow has domain verification, see if this can be made generic.

  • Replace Google OIDC with generic one

How is this tested?

  • Unit tests (pytest, jest)
  • E2E Tests (Cypress)
  • Manually
  • N/A

For testing manually, following steps should be more are less common among different IdPs.

  1. Configure an IdP with OIDC federation protocol and get the discovery endpoint, client id and secret id.
  2. Set 3 environment variables accordingly:
  • REDASH_OIDC_CLIENT_ID
  • REDASH_OIDC_CLIENT_SECRET
  • REDASH_OIDC_ISSUER_URL
  1. Check if Login with OIDC button available in the login page.
  2. Login
  • AWS Cognito
  • Google
  • Okta
  • Auth0
  • Azure

Related Tickets & Documents

#6781

Mobile & Desktop Screenshots/Recordings (if there are UI changes)

Screenshot 2024-02-27 at 2 43 36 PM

@palash247 palash247 changed the title Add generic OIDC authentication flow (#6781) Add generic OIDC authentication flow Feb 27, 2024
Copy link

codecov bot commented Feb 27, 2024

Codecov Report

Attention: Patch coverage is 25.00000% with 63 lines in your changes are missing coverage. Please review.

Project coverage is 63.17%. Comparing base (af0773c) to head (6649774).
Report is 53 commits behind head on master.

Current head 6649774 differs from pull request most recent head 98c6694

Please upload reports for the commit 98c6694 to get more accurate results.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6783      +/-   ##
==========================================
- Coverage   63.82%   63.17%   -0.65%     
==========================================
  Files         161      164       +3     
  Lines       13060    13285     +225     
  Branches     1803     1834      +31     
==========================================
+ Hits         8335     8393      +58     
- Misses       4425     4592     +167     
  Partials      300      300              
Files Coverage Δ
redash/authentication/__init__.py 81.53% <100.00%> (+0.19%) ⬆️
redash/settings/__init__.py 98.69% <100.00%> (+0.04%) ⬆️
redash/handlers/authentication.py 71.02% <44.44%> (-2.15%) ⬇️
redash/authentication/oidc.py 13.43% <13.43%> (ø)

... and 9 files with indirect coverage changes

@palash247 palash247 changed the title Add generic OIDC authentication flow WIP: Add generic OIDC authentication flow Feb 27, 2024
- Added a generic authentication flow for OIDC.
- Modified some templates to display OIDC login button.
- Added new env variables to support the OIDC auth flow. Mainly, OIDC
  discovery endpoint is configurable now.
- Added new routs for OIDC auth.
- Manually tested same flow with Google (without domain verification) and AWS Cognito.
redash/settings/__init__.py Outdated Show resolved Hide resolved
  - Fixed typo
  - Added unit tests cases
@palash247 palash247 changed the title WIP: Add generic OIDC authentication flow Add generic OIDC authentication flow Mar 26, 2024
@palash247
Copy link
Author

Hi @arikfr,
Can I please get some feedback over the approach?

Comment on lines +48 to +50
if response.status_code == 401:
logger.warning("Failed getting user profile (response code 401).")
return None
Copy link
Member

Choose a reason for hiding this comment

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

what about something like:

        if not response.ok:
            logger.warning(f"Failed getting user profile (response code {response.status_code}) - {response.text}.")
            return None

Comment on lines +27 to +30
if resp.status_code != 200:
logger.warning(
f"Unable to get configuration details (response code {resp.status_code}). Configuration URL: {url}"
)
Copy link
Member

Choose a reason for hiding this comment

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

  1. Let's consistently use response (I prefer) or resp.
        if not response.ok:
            logger.warning(
                f"Unable to get configuration details (response code {resp.status_code}). Configuration URL: {url} - {response.text}"
            )

name="oidc",
server_metadata_url=settings.OIDC_ISSUER_URL,
client_kwargs={
"scope": "openid email profile",
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we make the needed scopes a var too?
([Future PR?] propagate/sync groups or roles for "redash_admin"?)

},
)

def get_user_profile(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.

maybe the canonical get_userinfo instead of get_user_profile as profile is just one of the possible scopes. let's to avoid confusion.

access_token = resp["access_token"]

if access_token is None:
logger.warning("Access token missing in call back request.")
Copy link
Member

Choose a reason for hiding this comment

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

typo call back -> callback

else:
org = current_org

user = create_and_login_user(org, profile["name"], profile["email"])
Copy link
Member

Choose a reason for hiding this comment

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

  1. maybe allow choosing what field to use as the name?
  2. if email not verified, should we allow user creation? (avoid possible future CVE)

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.

None yet

3 participants