Skip to content
This repository has been archived by the owner. It is now read-only.

feat(oauth): show permission screen for untrusted reliers #2377

Merged
merged 2 commits into from May 13, 2015

Conversation

@zaach
Copy link
Contributor

@zaach zaach commented May 5, 2015

I refactored sign up/in to use the account and user models, but still need to get the permission screen working.

cc @shane-tomlinson

@@ -0,0 +1,30 @@
<div id="main-content" class="card">
<header>
<h1 id="fxa-confirm-header">{{#t}}%serviceName)s would like to know...{{/t}}</h1>

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 5, 2015
Member

%(serviceName)s

@zaach zaach force-pushed the issue-2346 branch from 54493dc to efdf3c3 May 5, 2015
],
function (Cocktail, _, FormView, BaseView, Template, p, AuthErrors, Constants,
URL, ResendMixin, BackMixin, ServiceMixin) {
//var t = BaseView.t;

This comment has been minimized.

@vladikoff

vladikoff May 5, 2015
Contributor

extra comment

email: account.get('email'),
serviceName: this.relier.get('serviceName'),
termsUri: this.relier.get('termsUri'),
privacyUri: this.relier.get('termsUri'),

This comment has been minimized.

@pdehaan

pdehaan May 5, 2015
Contributor

this.relier.get('privacyUri')?

@zaach zaach force-pushed the issue-2346 branch from efdf3c3 to 01aecff May 6, 2015
@vladikoff vladikoff added this to the train 37 milestone May 6, 2015
return this.get('trusted');
},

needsPermissions: function (account) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

I'm waffling whether this should be on the relier on on the account. I can see it both ways.

Ask the account if the relier needs permission to access its information.
vs
Ask the relier if it needs permission to access the account.

The first makes more sense to me.

This comment has been minimized.

@zaach

zaach May 6, 2015
Author Contributor

I was also considering the broker? Dunno.

@@ -174,6 +175,54 @@ define([
.then(function () {
return profileImage;
});
},

signIn: function (relier) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

I totally dig this.

@@ -222,6 +222,22 @@ define([
return (Session.email && Session.sessionToken &&
(! Session.cachedCredentials ||
Session.cachedCredentials.email !== Session.email));
},

signInAccount: function (account, relier) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

YES! I'll be happy to update the PR I showed you to continue with these changes and rip a lot of this account management logic out of the views.

@@ -0,0 +1,30 @@
<div id="main-content" class="card">
<header>
<h1 id="fxa-confirm-header">{{#t}}%(serviceName)s would like to know...{{/t}}</h1>

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Do you want the id to be fxa-permissions-header or something different than confirm?

</div>

<div class="button-row">
<a id="proceed" class="button" href="#">{{#t}}Proceed{{/t}}</a>

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Not a normal submit button like the other templates?


context: function () {
var account = this.getAccount();
var serviceUri = URL.getOrigin(this.relier.get('redirectUri'))

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Something we may want to put on the relier when the redirectUri is set?


onSignUpSuccess: function (account) {
var self = this;
if (account.get('verified')) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

We so need an external state machine and to rip this stuff out of the views.

});
},

saveGrantedPermissions: function (clientId, scope) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

I do not see this called anywhere.

This comment has been minimized.

@zaach

zaach May 6, 2015
Author Contributor

Yeah, still WIP

return self.user.setSignedInAccount(account)
.then(function () {
return account;
console.log('account???', account.get('sessionToken'), account);

This comment has been minimized.

return p.reject(AuthErrors.toError('UNEXPECTED_ERROR'));
}
return self.broker.beforeSignIn(account.get('email'))
.then(function () {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Looks like an opportune time to re-indent this.

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 6, 2015

Overall, I dig this approach.

I would really like to see us move towards ripping the implicit state machine out of the views and into something self contained and duplicate logic can be reduced.

},

needsPermissions: function (account) {
return ! this.isTrusted() && ! account.hasGrantedPermissions(this.get('clientId'), this.get('scope'));

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Minor nit, but the intention could probably be easier to understand if it were re-written a bit like:

if (this.isTrusted()) {
  return false;
}
return ! account.hasGrantedPermissions(...

My guess is uglify will combine the two branches into something similar to what you have here.

return account;
console.log('account???', account.get('sessionToken'), account);
if (self.relier.needsPermissions(account)) {
self.navigate('signin_permissions', {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

How you pass the account is slightly different to how its done in onSignInUnverified

var preVerifyToken = self.relier.get('preVerifyToken');
var account = self.user.initAccount({
email: self.$('.email').val(),

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

At least the email should be updated to use getElementValue so that leading/trailing whitespace is trimmed.

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Side note - how have we gotten away with using .val() for so long?

}
},

onSignUpSuccess: function (account) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

Perhaps to avoid duplication with the signin/signup modules, these three functions could be extracted into one ore two mixins (one for sign in, one for sign up? overkill?) that are mixed in where needed?

'views/form',
'views/base',
'stache!templates/permissions',
'lib/promise',

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

I don't think p is used anywhere in this module.

This comment has been minimized.

@pdehaan

pdehaan May 8, 2015
Contributor

Ooohhh!!! I think i saw a grunt task for this the other day: grunt-amdcheck.

I did a quick test against master with this, grunttasks/amdcheck.js:

module.exports = function (grunt) {
  grunt.config('amdcheck', {
    app: {
      files: [{
        expand: true,
        cwd: 'app/',
        src: [
          '**/*.js',
          '!bower_components/**'
        ],
        dest: 'build/'
      }]
    }
  });
}

And got a lot of weird output, which may point to some unused and unloved requires:

Total unused dependencies: 89 in 64 files.
Total processed files: 251

The output is actually pretty long, so I'll file a separate bug which we can z-never it.


UPDATE: Filed as #2392

This comment has been minimized.

@zaach

zaach May 8, 2015
Author Contributor

FTR p is now used.

'stache!templates/permissions',
'lib/promise',
'lib/auth-errors',
'lib/constants',

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

I don't see Constants used anywhere either.

var self = this;
var account = self.getAccount();

self.logScreenEvent('proceed');

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 6, 2015
Member

As part of this PR, can you update the client-metrics doc?

@zaach zaach force-pushed the issue-2346 branch from 01aecff to bd778da May 7, 2015
@shane-tomlinson shane-tomlinson self-assigned this May 7, 2015
@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 7, 2015

@zaach - can you rebase this?

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 10, 2015

@zaach - this PR is epic! It's looking pretty good, mostly small nits at this point. I have to test it pretty thoroughly, I see you have already added functional tests. Have you tested the screen in mobile to ensure it looks good?

@@ -27,7 +27,8 @@ define([
verified: undefined,
profileImageUrl: undefined,
profileImageId: undefined,
lastLogin: undefined
lastLogin: undefined,
grantedPermissions: Object.create(null)

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 10, 2015
Member

A silly question, why Object.create(null) instead of a {}?

self.logScreenEvent('proceed');

return p().then(function () {
account.saveGrantedPermissions(self.relier.get('clientId'), self.relier.get('scope'));

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 10, 2015
Member

@zaach - I see the granted permissions are saved, yet when I go back through 321done's signin flow, I am re-asked for the permissions. Expected?

This comment has been minimized.

@zaach

zaach May 12, 2015
Author Contributor

Bah– so currently when a user signs in we create a new account object and store it in localStorage, overwriting the existing data (including saved permissions). We'll have to merge in the old account info before storing it.

assert.isTrue(relier.isTrusted.called);
});

it('should prompt when relier is untrusted and needs scopes', function () {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 10, 2015
Member

What if the scopes match the already granted permissions?

return false;
});
sinon.stub(account, 'hasGrantedPermissions', function () {
return false;

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 10, 2015
Member

Can you add a test case for true? I am seeing odd behavior in that I am being re-asked for permissions on 321done after I have already granted permissions. Is that the desired behavior? It feels a bit odd.

This comment has been minimized.

@zaach

zaach May 12, 2015
Author Contributor

Fixed.

});
sinon.stub(view.fxaClient, 'recoveryEmailStatus', function () {
return p.reject(assert.fail);
sinon.stub(user, 'signInAccount', function (account) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 10, 2015
Member

Less code is a beautiful thing.

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 10, 2015

@zaach - when local testing, I am re-asked for permissions for 321done even though I have granted them. If that is expected, no problem, but it feels odd.

Here is what the screen looks like in both desktop and mobile:

Desktop

screen shot 2015-05-10 at 20 01 10

Mobile

screen shot 2015-05-10 at 20 01 20

Maybe tighten up the space between the "Proceed" and "Cancel" buttons? @johngruen and @ryanfeeley?

@zaach zaach force-pushed the issue-2346 branch 2 times, most recently from 4acb60a to 58a59bf May 12, 2015
// returns true if all attributes within ALLOWED_KEYS are undefined
isEmpty: function () {
// returns true if all attributes within ALLOWED_KEYS are defaults
isDefault: function () {

This comment has been minimized.

var oldAccount = self.getAccountByUid(account.get('uid'));
if (! oldAccount.isDefault()) {
// allow new account attributes to override old ones
oldAccount.set(_.omit(account.attributes, function (val) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson May 12, 2015
Member

Can you add a note here that this is what allows permissions to remain persisted per relier across sign ins? I know my own memory and am afraid I'll forget in 6 months.

@zaach zaach force-pushed the issue-2346 branch from 58a59bf to 123821d May 12, 2015
@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 13, 2015

@zaach - I've been reviewing & testing this PR all morning, it looks really good! Well done!

I have a couple of small changes that I'd like to see that I will probably make myself and then merge:

  • auth_brokers->shouldPromptForPermissions doesn't actually use any info from the brokers and feels like it has feature envy of either the relier or the account. I'm going to move this function to the relier.
  • update the client events document to specify the full screen name for the events.
  • Two additional functional tests: signup->signin - no permissions should be requested. signin->signin - no permissions should be requested.
  • A long email address can overflow the container.

screen shot 2015-05-13 at 11 20 13

For the longer term, I think we should reconsider how we deal with account management when using multiple accounts. For example, if I sign in as user X, then sign in as user Y, then re-sign in as user X, I have to re-grant permissions.

* Move brokers->shouldPromptForPermissions to reliers->accountNeedsPermissions
* Ensure long email addresses wrap in the permissions page.
* Add the screen name to the event names in the permissions screen.
* Add functional tests to ensure re-signin after both signup and signin work as expected.
@coveralls
Copy link

@coveralls coveralls commented May 13, 2015

Coverage Status

Coverage increased (+0.04%) to 97.91% when pulling df3bb96 on issue-2346 into b0d96f8 on master.

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 13, 2015

For follow on - make the permissions screen generic. The permissions screen is currently hard coded to display the email permission.

shane-tomlinson pushed a commit that referenced this pull request May 13, 2015
feat(oauth): show permission screen for untrusted reliers

@zaach - this PR is awesome. Thank you for working through it with me, and for the cleanup you did along the way.

r=@shane-tomlinson
@shane-tomlinson shane-tomlinson merged commit a52d6fb into master May 13, 2015
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
@shane-tomlinson shane-tomlinson deleted the issue-2346 branch May 13, 2015
@ryanfeeley
Copy link
Contributor

@ryanfeeley ryanfeeley commented May 13, 2015

Man, the more I look at this, the more I think we should have gone with the original design of a read-only email field. Thoughts @shane-tomlinson @zaach? Should I just file a bug?

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 13, 2015

Should I just file a bug?

File it @ryanfeeley!

@zaach
Copy link
Contributor Author

@zaach zaach commented May 13, 2015

For example, if I sign in as user X, then sign in as user Y, then re-sign in as user X, I have to re-grant permissions.

Do you mean when the user clicks "Use different account"? In that case, yes, all localStorage is wiped out and you have to re-grant permissions. Our long term solution for this is the full-fledged account chooser screen #1844.

@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented May 13, 2015

Do you mean when the user clicks "Use different account"? In that case, yes, all localStorage is wiped out and you have to re-grant permissions. Our long term solution for this is the full-fledged account chooser screen #1844.

Yeah, the same also happens if an OAuth relier sends a user to signin with an email query parameter other than the currently signed in user.

@zaach
Copy link
Contributor Author

@zaach zaach commented May 13, 2015

Hmm, in that case we show the email form field but the cached credentials should still be intact. The only place I see where we clear cached credentials is here: https://github.com/mozilla/fxa-content-server/blob/master/app/scripts/views/sign_in.js#L208

@ryanfeeley
Copy link
Contributor

@ryanfeeley ryanfeeley commented May 13, 2015

Progress so far (showing editable Full name field for demo purposes only) permission
Button should not be blue (as full name cannot be empty in this example)

@ryanfeeley
Copy link
Contributor

@ryanfeeley ryanfeeley commented May 14, 2015

@vladikoff
Copy link
Contributor

@vladikoff vladikoff commented May 14, 2015

@ryanfeeley new bug #2423

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

7 participants