- The impersonation route handler receives the email and authorization token as query parameters (from the admin panel) and processes them in the beforeModel() hook
- The authentication mechanism is initiated using the impersonation authenticator *but*
- the session data is changed to reflect what is normally used as a session authenticator (DeviseAuthenticator, in our case)
- Finally, sessionDataUpdated event is triggered which will eventually call DeviseAuthenticator's restore() without breaking the flow.
export default Ember.Route.extend({
beforeModel(transition) { // (1)
let email = transition.queryParams.email,
token = transition.queryParams.token;
this.get('session').authenticate('authenticator:impersonate', email, token).then(() => { // (2)
let authenticated = this.get('session.data.authenticated');
authenticated.authenticator = 'authenticator:devise'; // (3)
getOwner(this).lookup('authenticator:impersonate').trigger('sessionDataUpdated', authenticated); // (4)
}, () => {});
}
});
The session service will invoke the authenticate() method in order to authenticate itself.
// app/authenticators/impersonate.js
import Devise from 'ember-simple-auth/authenticators/devise';
export default Devise.extend({
authenticate(identification, token) {
return new Promise((resolve, reject) => {
const { resourceName, identificationAttributeName } = this.getProperties('resourceName', 'identificationAttributeName');
const data = {};
data[resourceName] = { token };
data[resourceName][identificationAttributeName] = identification;
this.makeRequest(data, { url: 'users/impersonate' }).then((response) => {
run(null, resolve, response);
}).catch((error) => run(null, reject, error));
});
}
});
The backend controller validates the authorization token and a JSON containing an authorization token and an identifier.
class Users::SessionsController < Devise::SessionsController
def impersonate
user_email = params[:user][:email].presence
user = user_email && User.find_by_email(user_email)
token = params[:user][:token]
if user && Devise.secure_compare(user.authorization_token, token)
render json: return_session(user), status: 201
end
end
end
Finally, the promise is resolved and its data is stored in the session.
Never put secrets in queryparams. A couple quick googles will explain why.
ReplyDelete