Skip to content

Conversation

@evanpurkhiser
Copy link
Member

@evanpurkhiser evanpurkhiser commented Dec 7, 2017

Probably easiest to review the 4 commits individually.

This is a large refactoring of the v3 Integration setup pipeline to use a new style of user identity lookup, based on a new identity module, which provides a pipeline + identity providers.

This is the foundation for unifying the SSO Authentication identity, integrations identity, and (at some point probably in the far future) plugin identity (likely when they're moved to new-style integrations).

This implements the following:

  • The identity module, which provides an Identity pipeline, with a generic identity association finish_pipeline implementation. This may be used both directly as part of an identity association endpoint, as well as made part of a pipeline through the pipleline.NestedProviderView. A generic base OAuth2 provider is also implemented, which is mostly a copy and paste from both the auth module and integration modules implementations (which this will replace).

  • The OAuth identity provider supports scope customization through the pipeline config object.

  • The models.identity module has been updated with models that more accurately reflect how Identity is stored.

    • One identity per user

    • IdentityProvider is associated to an organization, allowing lookup of identity providers configured for an organization. Originally the idea was to have one identity provider per 'instance' of the identity provider, for example there'd be one Slack IDP since there's only one Sentry app on slack. However, with this implementation we'd stil need some way to know it's configured for an organization, and that linking table would likely take just as much space. Further, having a direct association to an identity provider makes generic identity association possible.

    • Also Important to note is that these tables were not yet in use outside of the feature-flagged v3 integrations, so there are two migrations here, the first simply removes the tables, the second re-creates the tables using the updated model fields.

  • The Integrations base object has it's id class attribute renamed to key. This is a little more clear as it differentiates it from the provider models database id.

  • Integrations now compose the slack identity provider pipeline to do setup and store the setup users identity.

@ghost
Copy link

ghost commented Dec 7, 2017

3 Warnings
⚠️ Changes require @getsentry/security sign-off
⚠️ You should update CHANGES due to the size of this PR
⚠️ PR includes migrations

Security concerns found

  • src/sentry/{integrations/oauth.py => identity/oauth2.py}

Migration Checklist

  • new columns need to be nullable (unless table is new)
  • migration with any new index needs to be done concurrently
  • data migrations should not be done inside a transaction
  • before merging, check to make sure there aren't conflicting migration ids

Generated by 🚫 danger

@evanpurkhiser evanpurkhiser force-pushed the refintegrations-composing-the-identity-pipeline branch 10 times, most recently from 1917af7 to a46346d Compare December 13, 2017 19:44
@evanpurkhiser
Copy link
Member Author

Assigning @dcramer since I know he knows this part of the code, but I know he's busy, so also assigning @alex-hofsteede for that knowledge share.

from sentry.utils.pipeline import PipelineProvider


class MigratingIdentityId(namedtuple('MigratingIdentityId', ['id', 'legacy_id'])):
Copy link
Contributor

Choose a reason for hiding this comment

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

Ha, haven't seen this trick before. I'm guessing it's just to avoid a bunch of self.foo = foo boilerplate?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I actually introduced this over here #6577, but am moving it into the identity module, and it will be removed from the auth provider later once the auth providers make use of the identity provider.


class IdentityManager(object):
def __init__(self):
self.__values = {}
Copy link
Contributor

Choose a reason for hiding this comment

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

If the values are assumed to be providers, then can we call this __providers ?

Copy link
Member Author

Choose a reason for hiding this comment

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

This manager was just copied over from other provider managers. The auth module and integration module both have one of these. At some point we'll likely want to just provide some general lookup manager that can be used to this fashion. It doesn't have anything specific to identity providers.

register = default_manager.register
unregister = default_manager.unregister

# TODO(epurkhiser): needs to be initialized some other way
Copy link
Contributor

Choose a reason for hiding this comment

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

does this need to be addressed before merge?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've updated the comment for this, but basically the idea is that this registering of the provider should happen with the slack plugin most likely.

oauth_access_token_url = 'https://slack.com/api/oauth.access'
oauth_authorize_url = 'https://slack.com/oauth/authorize'
oauth_scopes = tuple(sorted((
# TODO: Remove id and use key everywhere for integrations
Copy link
Contributor

Choose a reason for hiding this comment

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

this was done right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, updated. good catch.

assert resp.status_code == 200
self.assertDialogSuccess(resp)

integration = Integration.objects.get(provider=self.provider.id)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need any more tests aside from the ones refactored here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I have some identity linking acceptance tests that I need to finish up, I'll try and get those in here, but I'd like to get this merged in sooner than later, I'll try and get those in, but otherwise they'll come in as a separate PR I think.

Other than that more tests will show up as we solidify more of what integration setup looks like from a configuration standpoint

@evanpurkhiser evanpurkhiser force-pushed the refintegrations-composing-the-identity-pipeline branch 2 times, most recently from 582be30 to 8abad79 Compare December 21, 2017 19:23
Copy link
Contributor

@alex-hofsteede alex-hofsteede left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@mattrobenolt mattrobenolt left a comment

Choose a reason for hiding this comment

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

This migration is a blocker. Let's chat IRL to come up with the plan.

from sentry import options
from sentry.identity.oauth2 import OAuth2Provider

options.register('slack.client-id')
Copy link
Contributor

Choose a reason for hiding this comment

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

Set flags=FLAG_PRIORITIZE_DISK at least on these since I assume we'll be hardcoding these for us in config.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah these will be hardcoded in the configs. Updated here.


__all__ = ['IntegrationPipeline']

import json
Copy link
Contributor

Choose a reason for hiding this comment

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

Use sentry.utils.json instead unless there was a reason not to.

Copy link
Member Author

Choose a reason for hiding this comment

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

unique_together = (('idp', 'external_id'),)


class UserIdentity(Model):
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not actually drop this yet until a later migration.

Copy link
Member Author

Choose a reason for hiding this comment

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

__core__ = False

idp = FlexibleForeignKey('sentry.IdentityProvider')
user = FlexibleForeignKey(settings.AUTH_USER_MODEL)
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs to be nullable.

Copy link
Member Author

Choose a reason for hiding this comment

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


type = models.CharField(max_length=64)
instance = models.CharField(max_length=64)
organization = FlexibleForeignKey('sentry.Organization')
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, this migration is going to be problematic.

We need to come up with a transition plan. We can't drop and add these new columns at the same time, nor can we simply edit this unique_together, or add not nullable columns.

Copy link
Member Author

Choose a reason for hiding this comment

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

@evanpurkhiser
Copy link
Member Author

Talked IRL with @mattrobenolt. I've updated the description of the PR to note that the Identity models where not yet used anywhere outside of the V3 integration work, so the changes that were made to these tables can be safely be applied by dropping and recreating these tables as is done n the migrations here.

I will still however need to update the IDs of the migrations.

@evanpurkhiser evanpurkhiser force-pushed the refintegrations-composing-the-identity-pipeline branch 2 times, most recently from c4f666c to 448cc71 Compare January 3, 2018 23:04
@evanpurkhiser
Copy link
Member Author

@mattrobenolt: bumped my migrations.

@evanpurkhiser evanpurkhiser force-pushed the refintegrations-composing-the-identity-pipeline branch 2 times, most recently from e762f87 to bad62a0 Compare January 4, 2018 22:28
@evanpurkhiser evanpurkhiser force-pushed the refintegrations-composing-the-identity-pipeline branch from bad62a0 to 2fd8285 Compare January 8, 2018 21:21
@evanpurkhiser
Copy link
Member Author

Had to bump the migrations one more time because of #6147. Just need your sign off @mattrobenolt.

Copy link
Contributor

@mattrobenolt mattrobenolt left a comment

Choose a reason for hiding this comment

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

Punch it.

@evanpurkhiser evanpurkhiser merged commit b8cf1e2 into master Jan 8, 2018
@evanpurkhiser evanpurkhiser deleted the refintegrations-composing-the-identity-pipeline branch January 8, 2018 22:09
@github-actions github-actions bot locked and limited conversation to collaborators Dec 22, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants