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

Support API key as password for excel feeds #35698

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

Conversation

gherceg
Copy link
Contributor

@gherceg gherceg commented Jan 28, 2025

Product Description

Adds support for 2FA/SSO users to configure their Excel dashboard feeds with basic auth, using the API key in place of the password.

We will need to update these docs to reflect this option for 2FA/SSO users.

Technical Summary

https://dimagi.atlassian.net/browse/SAAS-16493

We already have support for this in OData feeds (#24231), and this is attempting to achieve similar behavior for Excel dashboards. We've seen unreliable behavior with our Excel handles the Authorization header that holds the username and API key to the point where Excel will remove this header from the request entirely before sending it. This obviously results in a 401, and our users are left frustrated because they followed our documentation for setting up a data feed in Excel.

Honestly, my main concern is that we will start to use this on other endpoints, when in reality we should reserve this for exceptional use cases where it is our best, and possibly only option. The alternative in this case is to tell users to pass the credentials via URL parameters, but that seems even less ideal than what this PR does, and therefore I went with this approach.

Feature Flag

Safety Assurance

Safety story

Automated test coverage

Added test to ensure a 401 is still raised when the allow_api_key_as_password is set to False, which is what it defaults to. It is only set to True on this one endpoint (at the moment).

QA Plan

I think we ideally want to fast track this change, so I will test on staging with the help of those that have access to Excel, and see if QA is needed then.

https://dimagi.atlassian.net/browse/QA-7440

Rollback instructions

Excel dashboard feeds are currently broken for 2FA/SSO users on newer versions of excel, and if we tell users to adopt a new format configuring feeds, and then revert it, that would put us in an even worse situation.

Labels & Review

  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@dimagimon dimagimon added the Risk: High Change affects files that have been flagged as high risk. label Jan 28, 2025
@gherceg gherceg requested a review from esoergel January 28, 2025 23:48
Copy link

sentry-io bot commented Jan 28, 2025

🔍 Existing Issues For Review

Your pull request is modifying functions with the following pre-existing issues:

📄 File: corehq/apps/domain/decorators.py

Function Unhandled Issue
_inner UnboundLocalError: local variable 'success' referenced before assignment /a/{doma...
Event Count: 6
_inner AttributeError: type object 'EnterpriseReport' has no attribute 'API_USAGE' /a/{domain}/...
Event Count: 1
_inner AttributeError: 'NoneType' object has no attribute '_id' /a/{domain}/phone/restore/{...
Event Count: 1
_inner ValueError: not enough values to unpack (expected 2, got 1) /a/{domain}/phone/restor...
Event Count: 1

Did you find this useful? React with a 👍 or 👎

@gherceg gherceg marked this pull request as ready for review January 29, 2025 00:45
This ensures the function signatures for all login methods used in the
auth decorator map are consistent, but doesn't actually change any
behavior since the only time require_domain is explicitly set to False
is in our LoginAuthentication, which uses the regular auth anyway for
basic auth type anyway.
@@ -373,6 +375,7 @@ def get_multi_auth_decorator(default, allow_formplayer=False, oauth_scopes=None,
formplayer can not use the session cookie to auth. To allow formplayer access to the
endpoints we validate each formplayer request using a shared key. See the auth
function for more details.
:param allow_api_key_as_password: If True, allows API Key to be used in BASIC auth
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 the thing that you were referring to with this comment?

my main concern is that we will start to use this on other endpoints, when in reality we should reserve this for exceptional use cases where it is our best, and possibly only option

If yes, maybe add that concern to this docstring to warn future devs not to use it in exceptional circumstances? Possibly even rename the parameter to something like allow_api_key_as_password_EXCEPTIONAL_USE_ONLY to force anyone who uses it to type that out and as a flag to reviewers?

@gherceg gherceg changed the title Support API key as password in specific cases Support API key as password for excel feeds Jan 29, 2025
@gherceg gherceg added the awaiting QA QA in progress. Do not merge label Jan 31, 2025
@@ -416,6 +425,20 @@ def api_auth(*, allow_creds_in_data=True, oauth_scopes=None):
default=DIGEST,
oauth_scopes=oauth_scopes,
allow_creds_in_data=allow_creds_in_data,
allow_api_key_as_password=False, # if supporting digest auth, you cannot use an api key as a password
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 you think of enforcing the condition in this comment with an assertion in get_multi_auth_decorator?

I've probably got my head too deep in the auth code and lost sight of it, but do we have an explanation of why this is the case? Might be nice to include that here or possibly in the docstring of this function.

@@ -443,9 +467,16 @@ def get_auth_decorator_map(
'require_domain': require_domain,
'allow_sessions': allow_sessions,
}

Copy link
Contributor

Choose a reason for hiding this comment

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

re:

the only place we set require_domain to False is here, which we can safely say does not use the login_or_basic_or_api_key_ex function since allow_api_key_as_password defaults to False.

Would it make sense to assert that here?

Suggested change
assert not allow_api_key_as_password or require_domain, \
"It is unexpected to allow API key as password and not require domain"

I assume it's not easy or very meaningful to add tests to verify that our code never does that, but if it's possible to verify with a test then that might make sense too.

See determine_authtype_from_header for more details on how defaulting to BASIC drops DIGEST support
"""
return get_multi_auth_decorator(
default=BASIC,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious if defaulting to BASIC has any other side effects that may not be anticipated? I see we do this in other places such as mobile and odata auth decorators as well, so it seems safe.

)


def api_auth_no_digest(*, allow_creds_in_data=True, oauth_scopes=None, allow_api_key_as_password=False):
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the allow_api_key_as_password=False parameter needed here? The only place it is ever False is in tests. What do you think of eliminating it and always passing allow_api_key_as_password=True to get_multi_auth_decorator below?

Since this function is about allowing API key as password, would it make sense to rename it to make that more clear and instead explain the part about "no digest" in the docstring? Maybe something like api_auth_allow_key_as_password?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting QA QA in progress. Do not merge Risk: High Change affects files that have been flagged as high risk.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants