Skip to content

Instantly share code, notes, and snippets.

@tompave
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompave/4634ee65c8cea5a068fd to your computer and use it in GitHub Desktop.
Save tompave/4634ee65c8cea5a068fd to your computer and use it in GitHub Desktop.
Poor Man's cross-authentication
# impersonation_utilities.rb
require 'digest/md5'
module ImpersonationUtilities
SHARED_SECRET = "I'm a secret string!"
TOKEN_VALID_FOR_DAYS = 1
class << self
def generate_token(user_id)
Digest::MD5.hexdigest(SHARED_SECRET + user_id.to_s + time_dependant_salt)
end
def verify(token, user_id)
token == generate_token(user_id)
end
private
def time_dependant_salt
t = Time.now
day = (t.yday / TOKEN_VALID_FOR_DAYS.to_f).ceil
t.year.to_s + day.to_s
end
end
end
class PseudoImpersonationRequestsController < ManagementController
# POST /manage/impersonation_request
#
# params:
# user_id
#
def impersonation_request
user = User.where(id: params[:user_id]).first
if user
token = ImpersonationUtilities.generate_token(user.id)
url = build_url(user.id, token)
redirect_to(url)
else
head 404
end
end
private
def build_url(user_id, token)
'https://www.example.com/impersonate' + build_query_string(user_id, token)
end
def build_query_string(user_id, token)
"?id=#{user_id}&token=#{token}"
end
end
class PseudoImpersonationsController < ApplicationController
# GET /impersonate
#
# params:
# token
# user_id
#
def impersonate
if params[:token] && params[:user_id]
if ImpersonationUtilities.verify(params[:token], params[:user_id])
user = User.find(params[:user_id])
sign_in(user)
redirect_to root_path
else
head 401
end
else
head 406
end
end
end
<%= link_to "login as #{@user.email}",
manage_impersonation_request_path(@user.id),
method: :post,
target: :blank %>
@tompave
Copy link
Author

tompave commented Aug 20, 2014

Also look at this gist from one of Devise's leads.

Devise used to include a token authenticable module (useful for APIs), but they removed it in more recent releases.

The rationale was that each developer/app usually has very specific needs, and they didn't feel they could guarantee a secure enough, good for everyone, generic implementation.

@tompave
Copy link
Author

tompave commented Aug 20, 2014

Instead of @user.id, it is possible to use a user-unique token or salt.

Devise, for example, uses a portion of the encripted password:
https://github.com/plataformatec/devise/blob/master/lib/devise/models/database_authenticatable.rb#L136

It's (reasonably definitely, on this planet) unique, it expires each time a user updates its password, and it is not a risk if leaked (it's a substring of a bycript-hash).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment