From 9266c3ac58404894539e25e514d8d8a6775c701f Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 11 Mar 2015 01:12:23 -0700 Subject: add support for rotating tokens and sessions databases, and for a special tmp db for test users. --- app/models/account.rb | 23 ++++++------- app/models/temporary_user.rb | 78 ++++++++++++++++++++++++++++++++++++++++++++ app/models/token.rb | 13 +++++--- app/models/user.rb | 2 ++ 4 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 app/models/temporary_user.rb (limited to 'app/models') diff --git a/app/models/account.rb b/app/models/account.rb index e60a356..af470ed 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -20,7 +20,7 @@ class Account user = nil user = User.new(attrs) user.save - if user.persisted? + if !user.tmp? && user.persisted? identity = user.identity identity.user_id = user.id identity.save @@ -52,10 +52,12 @@ class Account def destroy(destroy_identity=false) return unless @user - if destroy_identity == false - Identity.disable_all_for(@user) - else - Identity.destroy_all_for(@user) + if !user.tmp? + if destroy_identity == false + Identity.disable_all_for(@user) + else + Identity.destroy_all_for(@user) + end end @user.destroy end @@ -84,12 +86,11 @@ class Account end def self.creation_problem?(user, identity) - user.nil? || - !user.persisted? || - identity.nil? || - !identity.persisted? || - user.errors.any? || - identity.errors.any? + return true if user.nil? || !user.persisted? || user.errors.any? + if !user.tmp? + return true if identity.nil? || !identity.persisted? || identity.errors.any? + end + return false end # You can hook into the account lifecycle from different engines using diff --git a/app/models/temporary_user.rb b/app/models/temporary_user.rb new file mode 100644 index 0000000..87800ed --- /dev/null +++ b/app/models/temporary_user.rb @@ -0,0 +1,78 @@ +# +# For users with login '*test_user*', we don't want to store these documents in +# the main users db. This is because we create and destroy a lot of test +# users. This weirdness of using a different db for some users breaks a lot of +# things, such as associations. However, this is OK for now since we don't need +# those for running the frequent nagios tests. +# +# This module is included in user.rb. This will only work if it is included +# after designs are defined, otherwise, the design definition will overwrite +# find_by_login(). +# + +module TemporaryUser + extend ActiveSupport::Concern + include CouchRest::Model::DatabaseMethod + + USER_DB = 'users' + TMP_USER_DB = 'tmp_users' + TMP_LOGIN = 'test_user' + + included do + use_database_method :db_name + + # since the original find_by_login is dynamically created with + # instance_eval, it appears that we also need to use instance eval to + # override it. + instance_eval <<-EOS, __FILE__, __LINE__ + 1 + def find_by_login(*args) + if args.grep(/#{TMP_LOGIN}/).any? + by_login.database(tmp_database).key(*args).first() + else + by_login.key(*args).first() + end + end + EOS + end + + module ClassMethods + def get(id, db = database) + super(id, db) || super(id, tmp_database) + end + alias :find :get + + # calls db_name(TMP_LOGIN), then creates a CouchRest::Database + # from the name + def tmp_database + choose_database(TMP_LOGIN) + end + + def db_name(login=nil) + if !login.nil? && login.include?(TMP_LOGIN) + TMP_USER_DB + else + USER_DB + end + end + + # create the tmp db if it doesn't exist. + # requires admin access. + def create_tmp_database! + design_doc.sync!(tmp_database.tap{|db|db.create!}) + end + end + + # + # this gets called each and every time a User object needs to + # access the database. + # + def db_name + self.class.db_name(self.login) + end + + # returns true if this User instance is stored in tmp db. + def tmp? + !login.nil? && login.include?(TMP_LOGIN) + end + +end diff --git a/app/models/token.rb b/app/models/token.rb index ff2ad12..4afd275 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -1,8 +1,15 @@ require 'digest/sha2' class Token < CouchRest::Model::Base + def self.expires_after + APP_CONFIG[:auth] && APP_CONFIG[:auth][:token_expires_after] + end - use_database :tokens + include CouchRest::Model::Rotation + rotate_database :tokens, + :every => 1.month, + :timestamp_field => :last_seen_at, + :timeout => self.expires_after.to_i # in minutes belongs_to :user @@ -23,10 +30,6 @@ class Token < CouchRest::Model::Base self.find Digest::SHA512.hexdigest(token) end - def self.expires_after - APP_CONFIG[:auth] && APP_CONFIG[:auth][:token_expires_after] - end - def self.expired return [] unless expires_after by_last_seen_at.endkey(expires_after.minutes.ago) diff --git a/app/models/user.rb b/app/models/user.rb index 9ac7d3d..52e20dd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -42,6 +42,8 @@ class User < CouchRest::Model::Base view :by_created_at end # end of design + include TemporaryUser # MUST come after designs are defined. + def self.login_starts_with(query) self.by_login.startkey(query).endkey(query + "\ufff0") end -- cgit v1.2.3