Kartones Blog

Be the change you wanna see in this world

Making Rails CookieStore more secure and sessions expirable

As lately is happening to me a lot, Ruby ecosystem has lots of tutorials and guides that range from beginner to intermediate, but lacks more advanced topics. Recently I had to implement a security feature that surprisingly wasn't present at Rails: Session invalidation when you change your password.

Many sites, CartoDB included, use Rails CookieStore, which is just cookie based session handling: You securely serialize and deserialize session data (usually the user identifier) and avoid storing sessions serverside. Really cool in theory but has a flaw: If there is no serverside session management, how do I signal a password change so the other cookies with my session for example at other browsers become invalid?

Reading the official Ruby on Rails Security Guide I hoped to find the answer, but no, instead it lists lots of security hardening points, but just recommends to make your session expire, use a general secret_key (but changing it would invalidate all sessions, not just a given user ones) and in the end to go for database-based session handling for proper security. Well, I agree it is better, but sometimes you cannot adopt some changes as easy as they seem, so... what about improving CookieStore?

First I went deep, checking CookieStore and its "mixin parent" AbstractStore source codes. They just wrap actual session handling on storing at a cookie, but the parent had an interesting method, generate_sid (session Id). Maybe if I could change the generation of the session would be enough... so I also checked Rack::Session::Abstract::ID, the parent of all stores. I did some tests inheriting from CookieStore (as I don't fancy monkey patching even if Rack's code suggests it) but quickly I found that when you are generating a sid, really you don't have context of "users".. and you shouldn't, because this is really inside. This is for people desiring to modify the session id generation algorithm, or the actual storage of session data.

So, I went up, because over Rails we use Warden to ease all authentication (we have user/pass, API key, OAuth...). Digging into its wiki I found that you can have more session data than just the user id that you deserialize into a full User object upon retrieving an existing session. But that example wasn't enough, as it only worked playing with default session scopes. We use scope-based sessions because our usernames are unique and cannot be repeated, so for example I can have a session cookie with the scope "kartones" and another with the scope "test" (or different roles, or other ideas you might have).

Cheking more about Warden, I found some interesting callbacks, but again the examples were silly and not too useful, so as usually happens with Ruby, it is better to again check the source code to see the internals. And inside hooks.rb I found the answer, in the documentation block of after_set_user. There, I could filter to handling authentications and store additional session data at Warden initializer file... something that if your password changes changes too, e.g.:

Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
  auth.session(opts[:scope])[:sec_token] = Digest::SHA1.hexdigest(user.crypted_password)
end

Now, editing the traditional Rails base ApplicationController I can add some methods to handle this additiona data:

def update_session_security_token(user)
  warden.session(user.username)[:sec_token] = Digest::SHA1.hexdigest(user.crypted_password)
end

def session_security_token_valid?(user)
  warden.session(user.username).key?(:sec_token) &&
  warden.session(user.username)[:sec_token] == Digest::SHA1.hexdigest(user.crypted_password)
end

def validate_session(user = current_user, reset_session_on_error = true)
  if session_security_token_valid?(user)
    true
  else
    reset_session if reset_session_on_error
    false
  end
end

And then just add the new logic to the authentication endpoints, for example:

def login_required
  is_auth = authenticated?(CartoDB.extract_subdomain(request))
  is_auth ? validate_session(current_user) : not_authorized
end

Now it would only remain to call update_session_security_token upon a password change, and all other cookie sessions will become invalid.

 

Why this is not an option either at Rails or Warden, I don't know, but I couldn't find a single tutorial, post or message detailing all this info, so let's hope this post helps fix that.

My dislike for open office spaces

Open office spaces are a logical step when you are a small company, but as you grow, it has become the "first cool thing to do with your office" in software development. I been working in them since 2008, and before intermittently at some clients while consulting. And the truth is that I still don't like them.

I come to the office primary to work. it sounds asocial* and maybe it is, but my main goal is to do my job. I can make friends, I can laugh and tell jokes, but the highest priority is to work, and, at least while coding, concentration is a basic need. It is not that I don't like seeing my colleages faces, in a friendly environment "without walls, all plain". It is more the fact that education and respect become vital, and building a culture of silence is not a trivial task.

Silent hours, public and/or private complaints, forbidding audio/video chats at working areas, listening to music the whole workshift, allowing remote work, clever rearrangement of teams to isolate or at least reduce hearing of noisy ones... I've seen a few approaches, but in the end until everybody learns to keep a "low noise volume", they are just mitigations.

I've also noticed that there are also virtual walls: teams still have to sit together or really near, so changing a team creates a cascade of people changing their things**. It might not always be the case, but I still have to see a fully de-centralized team that works always flawlessly.

So far, the best approach I've seen and the most comfortable working environments I've been at is to have separate rooms or at least physical walls separating teams. You distract and get distracted less, you can talk with the rest of the team, makes much easier being quiet, and there are always common areas like the kitchens (or a bar nearby!) to talk with the rest of the company while having a break.

Making an open space office work correctly is possible... but at Tuenti took years (and trying most if not all of the "hints" mentioned earlier). It seems to require quite some effort regarding education and respect.

 

* Back at my university days, as it was far away from home, if I was going to spend 2 hours per day on a train, I was going to either study or do assignments. That's why I never learned to play Mus or CounterStrike, but I managed to pass more than half of the studies working part-time and then going to the university.

** Up to the point I became a "nomad" at Tuenti by having just my laptop, my chair and a monitor in order to move "everything" quickly with the so frequent "reallocations" we had.

Book Review: The LEGO Mindstorms EV3 Discovery Book

The LEGO Mindstorms EV3 Discovery Book book cover

As lately I'm quite busy between my pretty dog, working, reading articles (of too varied topics to write about them I think) and trying to rest, I've just written another book review I had pending since a while. It's another book about LEGO Mindstorms EV3 (of which I have sadly my Node.js library quite adbandoned), so feel free to check it out if you like the topic.

Fight about the ethics, not about the tools

I've come to "hate" most development languages, sames as I don't really "love" any operating system, but it seems in our current society people must always take sides. You cannot just have a set of tools and choose whatever is best for the job: "Using still SQL? Dude, NoSQL is the future!", "Server-side code, are you from the past? Javascript-all-the-things!", "Scripted languages? Nothing like going down the metal with C++!". No matter what you choose, there will always be an opinion against it. No matter the choice, it will always look wrong to somebody somewhere.

 

There will always be fanatic tech wars, but there is something that I don't see many fights about: Fights about if something is ethical to do.

 

Let me start with a story I directly lived. At one of my previous jobs, one of the things from the company that hooked to join them me was that they had moral values: they donated a yearly % of total earnings to NGOs. Once in, we had the opportunity to work in a project related to image recognition that was related to the Spanish Department of Defense. Instead of saying "yes, show me the money" it was voted internally and rejected for being related to military. We declined a project for being unethical and related with weapons and wars. *

 

I've sometimes had to do things I was not happy with, be it directly building projects I didn't believed in or participating in others I wasn't happy or proud to be a part of due to some of its uses. I had once an internal fight and educated but firm boycott, I've always tried to express concerns and I openly say things I don't like. But I'll definetly avoid to work doing things that do harm instead of good. There's the saying "never say never", but I'd have to be really really desperate to work with the military. At my current job, anybody can install the opensource version and we cannot easily control that, but at least there's people building great things with the product, and that makes me happy enough despite possible "wrong uses".

 

I'd rather sleep well and feel I'm at least not doing any harm to the world rather than earn more money. If to be successful is to suffer the loss of ethics and moral, I'd rather be a mediocre player in the game.

 

* Sadly, years later the same company "was able" to employ a few consultants on the very same Spanish Department of Defense. Money changes people and ideals, but fortunately I had already left.

Freakend 2015 and my Gameboy Powerpoint-like ROM

Freakend 2015 Logo

I just came back from the awesome Freakend weekend event on its 2015 edition (4th one if I'm correct). From friday night to sunday afternoon we had a lot of talks (and discussions) either directly of videogames, or related to them. This year we were 48 people and the bar has raised so much I've felt like an infiltrate among so much enthusiasts and professionals, all doing or having done great projects. People from the major (and quite a few minor/indie) spanish videogame companies like MercurySteam, Digital Legends or Tequilla Works, people working at Remedy, "web"  games companies like PlaySpace... but it was enlightening because I saw people falling into one of two categories:

  • Professionals with lots of experience developing and/or producing videogames, serving as examples of when you achieve success
  • Indies, people building games on their spare time while working doing non-game oriented daily work, and other scenarios of pure passion.

In fact, having lunch on saturday and when I said I don't do videogames either on my spare time, I was asked a plain "and why not?". And it its true. It is as simple as that: grab some spare time and instead of playing another dumb AAA title or watching a silly movie, build small games, toy with game related stuff. Nothing except myself forbids me from doing that... so the one thing I've learned this freakend is to try to find time to actually do more what I like, not just read about it.

That said, after last year's project/presentation, and based on my null actual 3D game development skills, I decided to go for something real, something related with retro game dev or around it. Combined with my love for the Gameboy, it had to be something related with the beloved handheld from 1989. The initial topic was more regarding AI and using an emulator to try to make the computer beat Super Mario Land level 1 automatically, but as I digged into the source code of some emulators, I saw that I had to learn how the GB hardware works. And to my surprise, any CS student can really understand many things, as the hardware is a Z80 like 8bit CPU that was coded in Assembly. After some nights reading I decided I instead wanted to do either a game or something similar directly like people did in the early nineties.

And this is how the GBSlides idea was born... As I predicted I was going to have not enough time to build a full game (work, personal life, my young dog...) so I narrowed the scope to instead build a "Gameboy Powerpoint" and present the talk using a GB emulator.

 

I am just going to show very briefly three screenshots of the process and the results, as the talk and the source code are both available, along with a nice "development kit" (at http://kartones.net/Downloads/gbdevpack.zip) that contains all you need to create tiles, backgrounds, compile code, see samples and read the best documentation I found out there. Because sadly the original Gameboy scene is dying and many links are already broken, resources missing and wasn't easy to find and gather all pieces, so if at least I can help with that I'm happy enough.

 

This were my first experiments building tiles with GBTD and then loading and displaying them (kind of a hello world):

GBSlides screenshot 1

 

Once tile loading and map loading were done, I moved to building a system (a Ruby script) to read and convert from plain-text files into ASM's tile data (raw byte "arrays") inside include files to load into the ROM. It's complex because as the screen is 20x18 you have really few characters to explain things (I had to do my best to summarize). Example source and GB-displayed slide:

GBSlides screenshot 2

 

And once data loading was ready, I had the hardest fight, trying to read joypad input. It seems the hardware has an optimization of not checking input state if there isn't any sprite DMA operation (aka "if you're not drawing/managing sprites") because I got crazy trying to make it work and then found a sample that said "just do the sprite DMA and input read works" and it did, so the slide viewer was ready.

GBSlides screenshot 3

 

If you head to the code you can see the content was pretty basic (but not a bad overview considering what I've seen out there), and I haven't even used sprites on the talk, but time is limited and the MVP was showing slides and input handling. I also got quite nervous because after two days of amazing talks I felt I was cheating for giving such a entry level talk, but as I mentioned before I hope that at least the talk, sources and dev kit serves for someone who wants to start coding something with the Gameboy as a good and complete SDK.

I also have plans to keep learning more about this wonderful console and try to actually do some small games, because I've really enjoyed going so down into the metal and into such a restricted hardware. It's been also a nice exercise to switch to Assembler and I think is healty to use something so different instead of Ruby, C#, Javascript or SQL.