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

Multiple clients and scopes #52

Merged
merged 8 commits into from Nov 27, 2017
Merged

Multiple clients and scopes #52

merged 8 commits into from Nov 27, 2017

Conversation

@Natim
Copy link
Member

@Natim Natim commented Nov 22, 2017

@Natim Natim requested a review from leplatrem Nov 22, 2017
@vladikoff
Copy link

@vladikoff vladikoff commented Nov 22, 2017

Wow! The Speed! 🚤

@Natim
Copy link
Member Author

@Natim Natim commented Nov 22, 2017

Wow! The Speed! 🚤

To be honest I didn't expect it too be wrapped up so quickly but we paired with @leplatrem 🙌

@@ -45,6 +46,10 @@ def includeme(config):
settings['fxa-oauth.requested_scope'] = settings['fxa-oauth.scope']
settings['fxa-oauth.required_scope'] = settings['fxa-oauth.scope']

resources, scope_routing = parse_resources(settings)

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

parse_resources() might not be the best name

@@ -14,6 +14,8 @@

logger = logging.getLogger(__name__)

KEY = 'fxa_verified_token'

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

REIFY_KEY ?

@@ -49,6 +51,7 @@ class FxAOAuthAuthenticationPolicy(base_auth.CallbackAuthenticationPolicy):
def __init__(self, realm='Realm'):
self.realm = realm
self._cache = None
self._config = None

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

unused

return self._verify_token(token, request)

user_id, client_name = self._verify_token(token, request)

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

Don't add suffix if authentication failed, or no specific client name is configured

This comment has been minimized.

@Natim

Natim Nov 23, 2017
Author Member

Is it a comment you want to add?

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

Yes for the return user_id below

try:
profile = auth_client.verify_token(token=token, scope=aslist(scope))
user_id = profile['user']
scopes = profile['scope']

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

nit: plural vs singular

# Make sure the bearer token scopes don't match multiple configs.
if len([x for x in request.registry._fxa_oauth_scope_routing.keys()
if x and set(x.split()) & set(scopes)]) > 1:
logger.debug("Invalid FxA token: {} matches multiple config" % scopes)

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

We might want to warn no?

@@ -122,6 +141,11 @@ def _get_cache(self, request):

return self._cache

def callback(self, userid, request):
if request.bound_data[KEY][1] != "default":

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

no safety check here?

This comment has been minimized.

@rfk

rfk Nov 23, 2017

Is this adding additional principals, beyond the userid?

This comment has been minimized.

@Natim

Natim Nov 23, 2017
Author Member

Yes

@@ -122,6 +141,11 @@ def _get_cache(self, request):

return self._cache

def callback(self, userid, request):
if request.bound_data[KEY][1] != "default":
return ["fxa:{}".format(request.bound_data[KEY][0])]

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

I think this could be clearer with comments or intermediary variables

api_mocked.return_value = self.profile_data
principals = self.policy.effective_principals(self.request)
self.assertIn("fxa:33", principals)
self.assertIn("33-notes", principals)

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

AssertNotIn("33") ?



def parse_resources(settings):
resources = OrderedDict()

This comment has been minimized.

@leplatrem

leplatrem Nov 22, 2017
Contributor

if settings is not an ordered dict I don't think it makes sense

@leplatrem
Copy link
Contributor

@leplatrem leplatrem commented Nov 22, 2017

  • Update README / Documentation
if client_name is None or client_name == 'default':
return user_id

return '{}-{}'.format(user_id, client_name)

This comment has been minimized.

@rfk

rfk Nov 23, 2017

The doc at [1] suggests this should have an "fxa:" prefix, like "fxa:5998e2e2e81c40bdad6d08ac2773bf61-lockbox".

[1] https://docs.google.com/document/d/19Tg5AyRdHDP7z_J6kWM-JgiO6tB6FmUuEXUweENYZq8/edit?ts=5a155487#

This comment has been minimized.

@Natim

Natim Nov 23, 2017
Author Member

Yes this will be added by kinto.


# Make sure the bearer token scopes don't match multiple configs.
if len([x for x in request.registry._fxa_oauth_scope_routing.keys()
if x and set(x.split()) & set(scopes)]) > 1:

This comment has been minimized.

@rfk

rfk Nov 23, 2017

It's not clear to me whether this is doing what you intend. What if the scope routing here was something like:

{
  "profile https://identity.mozilla.com/app/notes": "notes",
  "profile https://identity.mozilla.com/app/lockbox": "lockbox",
}

Then it seems to me that a token with "profile https://identity.mozilla.com/app/lockbox" would also match the set-intersection check above for "profile https://identity.mozilla.com/app/notes", because they both contain the "profile" scope. Is that the intended behaviour?

Or, if the keys in _fxa_oauth_scope_routing are only ever intended to be a single scope like "https://identity.mozilla.com/app/notes" rather than a list of scopes, maybe we should explicitly error out rather than doing set(x.split()) and so-on here.

On a side note: there's a lot of string splitting and parsing being done here on each request, I wonder if it would make sense to parse the scopes into a set or frozenset during config loading to make the checking here quicker.

This comment has been minimized.

@Natim

Natim Nov 23, 2017
Author Member

Yes I need to add a few tests for that.


if client_name in ('relier', 'state', 'webapp'):
setting_basename = '{}.{}'.format(client_name, setting_basename)
client_name = 'default'

This comment has been minimized.

@rfk

rfk Nov 23, 2017

This mixing of client names with other config parameters seems kinda fragile to me. What if a future version of this library introduces a new config parameter, that happens to share a name with a client in my config?

How would it look if, instead, we used something like "fxa-oauth.clients.lockbox.required_scope" in order to ensure there can't be confusion between the client names and other config names?

README.rst Outdated
fxa-oauth.clients.todo.required_scope = profile app-todo


In that case Kinto will give you two different `user_id`:

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

Instead of in that case, I would say something like Depending on the requested scopes, Kinto Fxa will assign a user id or another (using suffix)

README.rst Outdated

In that case Kinto will give you two different `user_id`:

- `fxa:user_id-notes` for the former

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

fxa:{user_id}-notes ?

README.rst Outdated
- `fxa:user_id-notes` for the former
- `fxa:user_id-todo` for the later

Note that you can use `fxa:user_id` to explicitely share data between

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

you can still use the fxa:{user_id} principal

README.rst Outdated
access the todo app data.

The default buckets will also be isolated, one for `notes` and one for
`todo`.

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

👍

README.rst Outdated
apps for a given FxA user.

If you don't give any specific permission, it will be impossible for
someone login in with the `app-notes` scope in their Bearer token to

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

logged in?

return self._verify_token(token, request)

user_id, client_name = self._verify_token(token, request)

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

Yes for the return user_id below

scope = profile['scope']
client_name = client

# Make sure the bearer token scope don't match multiple configs.

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

scopes

client_name = client

# Make sure the bearer token scope don't match multiple configs.
if len([x for x in request.registry._fxa_oauth_scope_routing.keys()

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

Maybe we could declare routing_scopes outside the loop.
Plus we could iterate on it above instead of request.registry._fxa_oauth_scope_routing.items()


# Make sure the bearer token scope don't match multiple configs.
if len([x for x in request.registry._fxa_oauth_scope_routing.keys()
if x and set(x.split()).issubset(set(scope))]) > 1:

This comment has been minimized.

@leplatrem

leplatrem Nov 24, 2017
Contributor

nit: use intermediary variable to have a something like if len(intersecting_scopes) > 1

@Natim
Copy link
Member Author

@Natim Natim commented Nov 27, 2017

Tested and configured in the dev instance:

    "user": {
        "bucket": "159e598f-3c2b-6d93-9df9-74a334657c9e", 
        "id": "fxa:6ce43a4a28a74cb99b27243035c7dd55-notes", 
        "principals": [
            "fxa:6ce43a4a28a74cb99b27243035c7dd55-notes", 
            "system.Everyone", 
            "fxa:6ce43a4a28a74cb99b27243035c7dd55", 
            "system.Authenticated"
        ]
    }
@Natim Natim merged commit 6f4308a into master Nov 27, 2017
2 checks passed
2 checks passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details
@Natim Natim deleted the multiple-clients-and-scopes branch Nov 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants