Extending/modifying ember-simple-auth to check for auth cookies - ember.js

I need to modify adaptive.js in ember-simple-auth for my app.
Ultimately I want the restore method to look for two particular cookie security tokens that is shared across our platforms and construct the simple auth localstorage object based on these cookies as a last resort if localStorage authentication data does not already exist in order to determine if the user is already authenticated.
I realise you can create a custom authenticator however the problem with extending Base is that when restore is called on your custom authorizer ember-simple-auth has already looked up localstorage for your auth data. If this isn't available restore never gets called. For this reason I believe I need to extend or modify the simple auth node module to my requirements.
Below is my simple attempt at trying to modify adaptive.js in ember-simple-auth within my app however when restore gets called it's never through the below:
import AdaptiveStore from 'ember-simple-auth/session-stores/adaptive';
AdaptiveStore.reopenClass({
restore(){
alert('do custom stuff here');
}
});

Using reopen worked for me:
import AdaptiveStore from 'ember-simple-auth/session-stores/adaptive';
export default AdaptiveStore.reopen({
restore(){
alert('do custom stuff here');
}
});

Related

Can I manually set session state to authenticated in embe simple auth?

I am using session based authentication common for django application (subdomainA.example.com) and SPA consuming django API (subdomainB.exmaple.com).
I check certain artifact in my custom authenticator's restore methdo to determine either user is currently authenticated (certain cookie - seems poor solution but any idea how to do it better) and if yes, I would like to set ember simple auth session as authenticated.
How should I do it?
this.set('session.isAuthenticated', true);
seems not working fine, because on invalidate I got error:
ember.debug.js:16624 Uncaught Error: Assertion Failed: Session#invalidate requires the session to be authenticated!
You cannot set the ESA session to authenticated manually. Actually any attempt to write the isAuthenticated property should result in an error.
What you can do is to implement a custom authenticator and use that to authenticate the session with some static data that you pass to the authenticate method, e.g.
this.get('session').authenticate('authenticator:my-authenticator', sessionData)
// app/authenticators/my-authenticator.js
…
authenticate(sessionData) {
return Ember.RSVP.resolve(sessionData);
}

How to persist current logged in user details across page reload in EmberJS?

I use ember-simple-auth to manage authentication in my ember app.
The addon provides a session library which apparently stores the response from API server when I login using token authentication. The response contains typical oAuth2 response like access token, refresh token, expiry time etc. The library provides a boolean variable which tells if the user is authenticated or not currently.
I use an instance initializer which uses this boolean variable to fetch and store current user details. The code looks like this:
// app/instance-initializers/current-user.js
import Session from "ember-simple-auth/services/session";
export default {
name: "current-user",
before: "ember-simple-auth",
initialize: function(container) {
Session.reopen({
setCurrentUser: function() {
if (this.get('isAuthenticated')) {
container.lookup("service:store").find('user', 'me').then((user) => {
this.set('currentUser', user);
});
}
}.observes('isAuthenticated')
});
}
};
This works fine when I login and navigate across different routes in the app. The problem comes when I reload some page. The current user details somehow get erased and this setCurrentUser is also called but it gets called after all the hooks in the current route are called. So in hooks like model, beforeModel, setupController etc. session.currentUser is not set and it is set only after all these hooks are called.
How to avoid this? How to make the current user details available in route hooks on page reload?
New Answer
Completely ignore the below answer for now. Try to change your initializer to only fire after ember-simple-auth, like below:
// app/instance-initializers/current-user.js
import Session from "ember-simple-auth/services/session";
export default {
name: "current-user",
after: "ember-simple-auth",
Have a look at this part of the docs, some more information there regarding the initializer, and the let me know if you are using the following route mixin:
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
Previous Answer
I recommend you read through the session stores in the readme and try switch between session stores temporarily to see if that fixes your problem. Otherwise implement your own custom session store with local storage to make sure the persist & restore hooks work like expected.
The object you'll extend in that case looks like this(copied from readme):
// app/session-stores/application.js
import Base from 'ember-simple-auth/session-stores/base';
export default Base.extend({
persist() {
…
},
restore() {
…
}
});

Using ember-simple-auth when the login page is on another system

The page to login to our application is a jsp hosted on another machine. I have managed to get requests firing to this machine by modifying authenticated-route-mixin by allowing window.location.replace to be called if the route start with http.
beforeModel(transition) {
if (!this.get('session.isAuthenticated')) {
Ember.assert('The route configured as Configuration.authenticationRoute cannot implement the AuthenticatedRouteMixin mixin as that leads to an infinite transitioning loop!', this.get('routeName') !== Configuration.authenticationRoute);
transition.abort();
this.set('session.attemptedTransition', transition);
debugger;
if (Configuration.authenticationRoute.startsWith('http')) {
window.location.replace(Configuration.authenticationRoute);
} else {
this.transitionTo(Configuration.authenticationRoute);
}
} else {
return this._super(...arguments);
}
}
This is working but when I am redirected back to my application, ember-simple-auth thinks I am no longer logged in and redirects be back to the remote machine, which then sends me back to the application in an infinite loop.
Obviously I need to set something to let ember-simple-auth know that it it is actually logged in. Why is it not doing this automatically? What am I doing wrong?
I am pretty new to oAuth so I could be missing some basic setting here.
Here is the URL.
ENV['ember-simple-auth'] = {
authenticationRoute: 'https://our-server.com/opensso/oauth2/authorize?client_id=test-client-1&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fsecure'
};
Instead of modifying the AuthenticatedRouteMixin, I'd recommend handling your app-specific login in an Authenticator-- the key configuration primitive that Ember Simple Auth provides as part of its public API.
To the best of my understanding, on first loading the app, and checking to see if a user is authenticated, Ember Simple Auth will use the restore method, defined as part of the Authenticator API.
You can return a promise from restore that resolves or rejects to indicate whether the user is authenticated. How you check this is an implementation detail of your auth system.
I don't know how you're storing credential(s) on the client (would be great if you could provide more detail), but here's an example flow, using cookies for authentication:
Ember boots, ESA attempts to restore the session.
restore makes a simple AJAX request to a secured, "dummy" resource on your Java server-- and checks if it gets back a 200 or a 401.
We get a 401 back. The user isn't authenticated, so reject in the Promise returned from restore.
Let ESA redirect the user to your authentication route. Ideally, don't override the AuthenticatedRouteMixin-- instead, use the beforeModel hook in the authentication route to send users to your JSP login page.
The user correctly authenticates against the JSP form.
In its response, your Java server sets some kind of encrypted, signed session cookie (this is how it generally works with Rails) as a credential. In addition, it sends a redirect back to your Ember app.
Ember boots again, ESA calls restore again.
restore pings your Java server again, gets a 200 back (thanks to the cookie), and thus resolves its Promise.
ESA learns that the user's authenticated, and redirects to the 'route after authentication'.
Keep in mind that, at its core, ESA can only indicate to the client whether the backend considers it 'authenticated' or not. ESA can never be used to deny access to a resource-- only to show something different on the client, based on the last thing it heard from the backend.
Let me know if any of that was helpful.

Ember Simple Auth Logout Action with Django Backend

I'm using ember simple-auth library with ember simple-auth-token.
However, every time I perform a logout action, django does not delete the token of the logged in user.
I should point out that the frontend works like a charm!
I am wondering if there should be a change in the frontend or in the backend code.
The invalidate() method should normally take care of the token refresh action, right?.
Here is my code, which is pretty much the same as the code presented in the README of ember simple auth.
controller/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
actions: {
invalidateSession() {
this.get('session').invalidate();
}
}
});
Thanks in advance!
ember-simple-auth-token's authenticators don't implement the invalidate method that called upon session invalidation and can be used to send a request to the backend to invalidate the token. Without that method being implemented Ember Simple Auth simply deletes the token on the client side.
You should be able to extend the ember-simple-auth-token authenticator you're using and implement the invalidate method so that it sends a token invalidation request to the backend. Be sure to return a promise though.

Ember Simple Auth different redirects after authentication

I'm using Ember simple auth in my app and it's working great, but I've run into a scenario that I'm having trouble getting around.
The library lets you specify the route to redirect to after a successful authentication by overriding routeAfterAuthentication: 'index'. This is working fine, however, I'm finding myself in a situation where I want to have two different types of redirects. When a user first logs in, I want them to go to /dashboard, but when they first sign up and authenticate, I want them to go /settings.
I was hoping to be able to do something like this after successfully creating an account, but it's still trying to use the routeAfterAuthentication option for the transition:
var _this = this;
this.set('identification', _this.get('email'));
this.set('password', password);
this.send('authenticate', function() {
_this.transitionToRoute('settings');
}, function() {});
Is there a way to specify which route to transition to after authenticating on one-off basis? Maybe there's a better way to log someone after they create an account without needing to go through the authenticate() method?
You can simply override the sessionAuthenticated method in the application route and implement your own logic. Beware though that the default implementation will not always transition to routeAfterAuthentication-- if there's a previously intercepted transition stored in the session, sessionAuthenticated will retry that instead.