Access Devise Session in Backbone Marionette? - ruby-on-rails

I'm working on creating a Rails app that uses Devise for user authentication and Backbone Marionette as the front end. I'm having trouble figuring out how to access the session that was created on the backend. I'd like to be able to grab say the username/email to display it in my Marionette app.
Also it might be useful to check to see if the session exists, though for the most part devise authentication in the controller seems to be working fairly well.
Any idea how I can access the current devise session in Backbone?
Thanks in advance!

Rails 3
The session cookies are stored as _app_session. They look obfuscated but they are just base64 encoded. You can use the atob function on the client to decode the session cookie and read any information you put in there. (In Rails 4 you are probably using encrypted session cookies and you will need to do something a little different)
An example cookie might look something like this:
"BAh7CEkiD3Nlc3Npb25faWQGOgZFVEkiJWNlZjFjMDhiNjYyNWEzZDI5YWM5MTJlMDY3MmQ0NTM4BjsAVEkiGXdhcmRlbi51c2VyLnVzZXIua2V5BjsAVFsISSIJVXNlcgY7AEZbBmkHSSIiJDJhJDEwJE5MYlhOWHFUMEtoZmdnNFliZHdyeE8GOwBUSSIQX2NzcmZfdG9rZW4GOwBGSSIxSSt6TnJsZm1FOTZTNWFRWGdSVWtGK2Zmd3BPVUxkQURjWHBqZ2NoZ05nMD0GOwBG"
It would decode into something like this:
atob(cookieStr);
"{I"session_id:ETI"%cef1c08b6625a3d29ac912e0672d4538;�TI"warden.user.user.key;�T[I" User;�F[iI""$2a$10$NLbXNXqT0Khfgg4YbdwrxO;�TI"_csrf_token;�FI"1I+zNrlfmE96S5aQXgRUkF+ffwpOULdADcXpjgchgNg0=;�F"
Rails 3/4
Rather than read from the session cookie I would add a separate cookie or just bootstrap your HTML code with the data you want.
Set your own cookie in your controller or devise hooks:
cookies[:my_data] = {
value: { username: "rocketman", email: "cliff.secord#gmail.com" }.to_json,
domain: "my.sweetapp.com"
}
In your client read that cookie: (use a lib like $.cookie to simplify the reading)
var cookieData, cookies = document.cookie.split('; ');
for (var i = 0, parts; (parts = cookies[i] && cookies[i].split('=')); i++) {
if (decode(parts.shift()) === "my_data") {
cookieData = JSON.parse(decode(parts.join('=')));
}
}
// Do something with cookieData;

Related

Passing extra query/form parameters through spring social

I'm building a Single Page Application using Spring Social and Spring Security generated by JHipster.
I'm trying to capture the original query parameters after a user has been authenticated by some social authentication provider.
Example:
calling /signin/someprovider?show=someEntityId and after a successful authentication redirects the user to /signup/ , I need a way to fetch 'someEntityID'.
I assume different http calls make it difficult to pass/store the parameters around.
Is there some Spring built-in functionality I can use/reuse or how does one solve this problem?
UPDATE
The thread of requests looks like this:
(1) browser-> http://localhost:9060/signin/authenticationProvider?show=**someEntityId**
<- redirect to https://authenticationProvider... &state=SomeState
(2) browser -> https://authenticationProvider
<- redirect to http://localhost:9060/signin/google?state=SomeState&code=SomeCode
(3) browser-> http://localhost:9060/signin/authenticationProvider?state=SomeState&code=SomeCode
<- redirect to http://localhost:9060/social/signup
(4) browser -> http://localhost:9060/social/signup
This ends up in
#GetMapping("/signup")
public RedirectView signUp(WebRequest webRequest, #CookieValue(name = "NG_TRANSLATE_LANG_KEY", required = false, defaultValue = Constants.DEFAULT_LANGUAGE) String langKey) {
try {
Connection<?> connection = providerSignInUtils.getConnectionFromSession(webRequest);
socialService.createSocialUser(connection, langKey.replace("\"", ""));
At this point it want to call a function with the original parameter someEntityId.
According to google oauth2 redirect_uri with several parameters the ?show=someEntityId parameter should be encoded in the state parameter of the Oauth2 request in order to survive
from (1) to (3). In (3) the state parameter has to be added to the redirect uri, such that the original parameter can be decoded in (4).
It looks like a lot of work, or am I missing something? It would be nice if there would be a way to have a session variable in which I could store the parameters at (1) and fetch them again when in (4).
Since version 1.1.3 Spring Social creates the state parameter on its own and uses it as a CSRF token, see https://pivotal.io/security/cve-2015-5258 - therefore you can (and should not) encode additional parameters in the state parameter.
Instead if the provider sign is enabled with a ProviderSignInController, a ProviderSignInInterceptor can be used to store such parameters intermediately in the session (in preSignIn(...) and postSignIn(...)).
I guess there is a similar approach if a SocialAuthenticationFilter is used.

Ember Simple Auth Device persist authentication information in LocalStorage

I can't seem to find a direct answer that deals with a code example of how it works but I'm using simple-auth 0.7.3. with ember-cli and simple-auth-devise.
I can authenticate just fine but once I refresh the page session is killed. I saw a previous post and the guy didn't have the right object but what about a case when the object is correct?
{"authenticator":"simple-auth-authenticator:devise","user_id":53,"user_token":"Vm2TwefZCwaAo8hfg&pT","user_email":"user9#redphone.com"}
Im not the sharpest knife in the draw but I'm hoping someone can shed some light on why a session is killed and how/where to prevent it.
Based on the what is being put in the localstorage:
{"authenticator":"simple-auth-authenticator:devise","user_id":53,"user_token":"Vm2TwefZCwaAo8hfg&pT","user_email":"user9#redphone.com"}
Ember simple auth is using "user" as a resourceName in the config:
Ember Simple Auth Devise
The resourceName is normally added when the server endpoint is expecting more than email,password. In this case the endpoint expects user_email,user_password.
And by default When you refresh a page simple auth checks the localstorage for
email,token. You have to also change that to user_email, user_token.
in the Config:
ENV['simple-auth-devise'] = {
authorizer: 'simple-auth-authorizer:devise',
serverTokenEndpoint: ENV.APP.HOST+'/' + ENV.NAMESPACE +'/users/sign_in',
resourceName: 'user',
tokenAttributeName: 'user_token',
identificationAttributeName: 'user_email'};
And that resolves the persistence issue.

Change server token end point for ember simple auth devise add on

I have an ember-cli app that uses ember simple auth(ember-simple-auth-devise) add on for authentication. I need to change the token end point of my authorizer to
http://example.com/api/v1/users/sign_in.
In my environment.js file I have added
ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:devise',
crossOriginWhitelist: ['http://example.com'] //For CORS
};
ENV['simple-auth-devise'] = {
serverTokenEndPoint : 'http://example.com/api/vi/users/sign_in'
}
But on logging in its still posts the credentials to the default url i.e.
http://example1.com/users/sign_in.
How can I change this url to use my rails app endpoint.
Maybe the problem is that the property key is serverTokenEndpoint with a lowercase p. If you go to API docs you can see the correct property name.

Shared authentication between rails and node.js with redis store

I have a rails app and a node.js app and I use Devise to authenticate users. I store the session with Redis. Now I'd like that when a user go to the node app, the app checks through socket.io whether the user is logged in or not. I managed to get the session datas from redis but I don't know how to interpret them to check if the user is logged in.
Here is my code for the node app which checks if the _session_id exists in the database and retrieves the session datas:
io.set('authorization', function (data, accept) {
if (data.headers.cookie) {
data.cookie = cookie.parse(data.headers.cookie);
data.sessionID = data.cookie['_session_id'];
redis.get(data.sessionID, function (err, session) {
if (err || !session) {
accept('Error', false);
} else {
data.session = session;
console.log(session);
accept(null, true);
}
});
} else {
return accept('No cookie transmitted.', false);
}
});
This is what the console.log(session) gives me:
{I"_csrf_token:EFI"1HPglfkCCagvb1LLraU1CEEyx7AtDzztqAEPY5G5lNgY=;FI"warden.user.user.key;TI" User;F[iI""$2a$10$IHq2WAhwbaqR4WWajRE/Yu;T
How can I check if a user is logged in the rails app with the node app?
Thanks
EDIT: It appears that the redis store gem I use calls a Marshalling method before storing the session in database. So I bypassed the problem by overriding the Marshalling method and stored the session datas in JSON format. It's not very elegant so if you find a better way to share sessions between rails and node.js, please let me know.
It might be easier to create your own oauth api(there's a railscast on how to do this oauth). As far as I know, devise is a ruby gem and isn't really cross-platform but oauth can be used in almost any language. You can add an oauth token to devise which should allow you to pass that token to node.js.
You can easily do it doing few tweaks to the index.js method in Rails-Cookie-Parser for Express https://github.com/instore/rails-cookie-parser library to use it without Express.
This library uses Marshal npm as its dependency
Note: You might need to decodeURIComponent("cookie value") since the original cookie is URL encoded

Is there a simple way to share session data stored in Redis between Rails and Node.js application?

I have a Rails 3.2 application that uses Redis as it's session store. Now I'm about to write a part of new functionality in Node.js, and I want to be able to share session information between the two apps.
What I can do manually is read the _session_id cookie, and then read from a Redis key named rack:session:session_id, but this looks kind of like a hack-ish solution.
Is there a better way to share sessions between Node.js and Rails?
I have done this but it does require making your own forks of things
Firstly you need to make the session key the same name. That's the easiest job.
Next I created a fork of the redis-store gem and modified where the marshalling. I need to talk json on both sides because finding a ruby style marshal module for javascript is not easy. The file where I alter marshalling
I also needed to replace the session middleware portion of connect. The hash that is created is very specific and doesn't match the one rails creates. I will need to leave this to you to work out because there might be a nicer way. I could have forked connect but instead I extracted a copy of connect > middleware > session out and required my own in.
You'll notice how the original adds in a base variable which aren't present in the rails version. Plus you need to handle the case when rails has created a session instead of node, that is what the generateCookie function does.
/***** ORIGINAL *****/
// session hashing function
store.hash = function(req, base) {
return crypto
.createHmac('sha256', secret)
.update(base + fingerprint(req))
.digest('base64')
.replace(/=*$/, '');
};
// generates the new session
store.generate = function(req){
var base = utils.uid(24);
var sessionID = base + '.' + store.hash(req, base);
req.sessionID = sessionID;
req.session = new Session(req);
req.session.cookie = new Cookie(cookie);
};
/***** MODIFIED *****/
// session hashing function
store.hash = function(req, base) {
return crypto
.createHmac('sha1', secret)
.update(base)
.digest('base64')
.replace(/=*$/, '');
};
// generates the new session
store.generate = function(req){
var base = utils.uid(24);
var sessionID = store.hash(req, base);
req.sessionID = sessionID;
req.session = new Session(req);
req.session.cookie = new Cookie(cookie);
};
// generate a new cookie for a pre-existing session from rails without session.cookie
// it must not be a Cookie object (it breaks the merging of cookies)
store.generateCookie = function(sess){
newBlankCookie = new Cookie(cookie);
sess.cookie = newBlankCookie.toJSON();
};
//... at the end of the session.js file
// populate req.session
} else {
if ('undefined' == typeof sess.cookie) store.generateCookie(sess);
store.createSession(req, sess);
next();
}
I hope this works for you. It took me quite a bit of digging around to make them talk the same.
I found an issue as well with flash messages being stored in json. Hopefully you don't find that one. Flash messages have a special object structure that json blows away when serializing. When the flash message is restored from the session you might not have a proper flash object. I needed to patch for this too.
This may be completely unhelpful if you're not planning on using this, but all of my session experience with node is through using Connect. You could use the connect session middlewhere and change the key id:
http://www.senchalabs.org/connect/session.html#session
and use this module to use redis as your session store:
https://github.com/visionmedia/connect-redis
I've never setup something like what your describing though, there may be some necessary hacking.

Resources