ixtlan 0.4.0.pre4 → 0.4.0.pre5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+ module Ixtlan
4
+ class Configurator
5
+
6
+ def self.symbolize_keys(h)
7
+ result = {}
8
+
9
+ h.each do |k, v|
10
+ v = ' ' if v.nil?
11
+ if v.is_a?(Hash)
12
+ result[k.to_sym] = symbolize_keys(v) unless v.size == 0
13
+ else
14
+ result[k.to_sym] = v unless k.to_sym == v.to_sym
15
+ end
16
+ end
17
+
18
+ result
19
+ end
20
+
21
+ def self.load(file)
22
+ symbolize_keys(YAML::load(ERB.new(IO.read(file)).result)) if File.exists?(file)
23
+ end
24
+ end
25
+ end
@@ -4,6 +4,8 @@ module Ixtlan
4
4
 
5
5
  def self.included(base)
6
6
  base.send(:include, Ixtlan::Controllers::SearchQuery)
7
+
8
+ base.cache_headers :protected, false #no_store == false
7
9
  end
8
10
 
9
11
  public
@@ -11,7 +13,7 @@ module Ixtlan
11
13
  # GET /audits
12
14
  # GET /audits.xml
13
15
  def index
14
- @audits = Audit.all(query(:login, params[:query])) + Audit.all(query(:message, params[:query]))
16
+ @audits = Audit.all(query(:login, params[:query])).reverse + Audit.all(query(:message, params[:query])).reverse
15
17
 
16
18
  respond_to do |format|
17
19
  format.html
@@ -5,15 +5,22 @@ module Ixtlan
5
5
  def self.included(base)
6
6
  base.skip_before_filter :guard
7
7
  base.skip_before_filter :authenticate, :only => :destroy
8
+
9
+ # do not want to expose permissions settings on filesystem cache
10
+ base.cache_headers :private
8
11
  end
9
12
 
10
13
  protected
11
14
  def login_from_params
12
15
  auth = params[:authentication]
13
- User.authenticate(auth[:login], auth[:password])
16
+ User.authenticate(auth[:login], auth[:password]) if auth
14
17
  end
15
18
 
16
19
  public
20
+ def show
21
+ render_successful_login
22
+ end
23
+
17
24
  def create
18
25
  render_successful_login
19
26
  end
@@ -2,6 +2,10 @@ module Ixtlan
2
2
  module Controllers
3
3
  module ConfigurationsController
4
4
 
5
+ def self.included(base)
6
+ base.cache_headers :protected
7
+ end
8
+
5
9
  private
6
10
 
7
11
  CONFIGURATION = Object.full_const_get(::Ixtlan::Models::CONFIGURATION)
@@ -4,6 +4,7 @@ module Ixtlan
4
4
 
5
5
  def self.included(base)
6
6
  base.send(:include, Ixtlan::Controllers::SearchQuery)
7
+ base.cache_headers :protected
7
8
  end
8
9
 
9
10
  public
@@ -4,6 +4,8 @@ module Ixtlan
4
4
 
5
5
  def self.included(base)
6
6
  base.send(:include, Ixtlan::Controllers::SearchQuery)
7
+ # do not want to expose groups on filesystem cache
8
+ base.cache_headers :private
7
9
  end
8
10
 
9
11
  public
@@ -5,6 +5,7 @@ module Ixtlan
5
5
  def self.included(base)
6
6
  base.send(:include, Ixtlan::Controllers::SearchQuery)
7
7
  base.skip_before_filter :authenticate, :guard, :only => [:index,:show]
8
+ base.cache_headers :public, true # no_store == true
8
9
  end
9
10
 
10
11
  public
@@ -3,8 +3,10 @@ module Ixtlan
3
3
  module PermissionsController
4
4
 
5
5
  def self.included(base)
6
- # TODO the authenticate should NOT be there, i.e. it leaks too much info
7
- base.skip_before_filter :authenticate, :guard
6
+ base.skip_before_filter :guard
7
+
8
+ # do not want to expose permissions settings on filesystem cache
9
+ base.cache_headers :private
8
10
  end
9
11
 
10
12
  def index
@@ -2,6 +2,10 @@ module Ixtlan
2
2
  module Controllers
3
3
  module PhrasesController
4
4
 
5
+ def self.included(base)
6
+ base.cache_headers :protected
7
+ end
8
+
5
9
  private
6
10
 
7
11
  LOCALE = Object.full_const_get(::Ixtlan::Models::LOCALE)
@@ -10,7 +10,7 @@ module Ixtlan
10
10
 
11
11
  def query(parameter, value)
12
12
  args = {}
13
- args[:limit] = params[:limit].to_i + 1 if params[:limit]
13
+ args[:limit] = (params[:limit] || 10).to_i + 1 #if params[:limit]
14
14
  args[:offset] = params[:offset].to_i if params[:offset]
15
15
 
16
16
  if value
@@ -2,6 +2,10 @@ module Ixtlan
2
2
  module Controllers
3
3
  module TextsController
4
4
 
5
+ def self.included(base)
6
+ base.cache_headers :protected
7
+ end
8
+
5
9
  private
6
10
 
7
11
  LOCALE = Object.full_const_get(::Ixtlan::Models::LOCALE)
@@ -4,6 +4,10 @@ module Ixtlan
4
4
 
5
5
  include SearchQuery
6
6
 
7
+ def self.included(base)
8
+ base.cache_headers :protected, false # no_store == false
9
+ end
10
+
7
11
  private
8
12
 
9
13
  USER = Object.full_const_get(::Ixtlan::Models::USER)
@@ -5,6 +5,8 @@ module Ixtlan
5
5
  def self.included(base)
6
6
  # no guard since everyone needs to load the bundles
7
7
  base.skip_before_filter :guard
8
+
9
+ base.cache_headers :protected
8
10
  end
9
11
 
10
12
  def index
@@ -86,26 +86,33 @@ module Ixtlan
86
86
  @@map[controller.to_sym] = symbolize(map)
87
87
  end
88
88
 
89
+ ROLE = Models::Role
90
+ PERMISSION = Models::Permission
91
+
89
92
  def self.export_xml
93
+ xml = permissions.to_xml
94
+ repository(:guard_memory) do
95
+ PERMISSION.all.destroy!
96
+ ROLE.all.destroy!
97
+ end
98
+ xml
99
+ end
100
+
101
+ def self.permissions(user = nil)
90
102
  repository(:guard_memory) do
91
- role_const = Models::Role
92
- permission_const = Models::Permission
93
- root = role_const.create(:name => @@superuser)
103
+ root = ROLE.create(:name => @@superuser)
94
104
  @@map.each do |controller, actions|
95
105
  actions.each do |action, roles|
96
- permission = permission_const.create(:resource => controller, :action => action)
106
+ permission = PERMISSION.create(:resource => controller, :action => action)
97
107
  permission.roles << root
98
108
  roles.each do |role|
99
- r = role_const.create(:name => role)
109
+ r = ROLE.create(:name => role)
100
110
  permission.roles << r unless permission.roles.member? r
101
111
  end
102
112
  permission.save
103
113
  end
104
114
  end
105
- xml = permission_const.all.to_xml
106
- permission_const.all.destroy!
107
- role_const.all.destroy!
108
- xml
115
+ PERMISSION.all
109
116
  end
110
117
  end
111
118
 
@@ -19,9 +19,13 @@ module Ixtlan
19
19
 
20
20
  protected
21
21
 
22
+ def permissions
23
+ Guard.permissions(user)
24
+ end
25
+
22
26
  alias :to_x :to_xml_document
23
27
  def to_xml_document(opts, doc = nil)
24
- opts.merge!({:exclude => [:password,:user_id], :methods => [:user]})
28
+ opts.merge!({:exclude => [:password,:user_id], :methods => [:user, :permissions]})
25
29
  to_x(opts, doc)
26
30
  end
27
31
  end
@@ -1,8 +1,7 @@
1
1
  require 'ixtlan/optimistic_persistence_module'
2
+ require 'ixtlan/stale_resource_error'
2
3
 
3
- module DataMapper
4
-
5
- class StaleResource < StandardError; end
4
+ module Ixtlan
6
5
 
7
6
  module OptimisticPersistenceValidation
8
7
 
@@ -1,21 +1,60 @@
1
+ begin
2
+ require 'securerandom'
3
+ rescue LoadError
4
+ end
5
+
1
6
  module Ixtlan
2
7
  class Passwords
8
+ SecureRandom =
9
+ if defined?(::SecureRandom)
10
+ # Use Ruby's SecureRandom library if available.
11
+ ::SecureRandom
12
+ else
13
+ begin
14
+ # try if there is active support around ;-)
15
+ require 'active_supportt'
16
+ ::ActiveSupport::SecureRandom
17
+ rescue LoadError
18
+ warn 'could not find secure random implementation, fall back to rand()'
19
+ class Random
20
+ def self.random_number(n)
21
+ (rand * n).to_i
22
+ end
23
+ end
24
+ Random
25
+ end
26
+ end
27
+
3
28
  def self.generate(length=64)
4
29
  if length > 0
5
30
  # A-Z starting with 97 and having 26 characters
6
31
  # a-z starting with 65 and having 26 characters
7
32
  # 0-9 starting with 48 and lies inside range starting with 33 and having 26 characters
8
33
  offset=[97, 65, 33]
9
-
10
- # collect random characters from the either of the above ranges
11
34
  begin
12
- pwd = (0..(length - 1)).collect do
13
- j = ActiveSupport::SecureRandom.random_number(78)
14
- (offset[j / 26] + (j % 26)).chr
15
- end.join
35
+ # collect random characters from the either of the above ranges
36
+ pwd = password(length, offset, 26)
16
37
  end while !((pwd =~ /[a-z]/) && (pwd =~ /[A-Z]/) && (pwd =~ /[!-;]/))
17
38
  pwd
18
39
  end
19
40
  end
41
+
42
+ def self.generate_numeric(length=64)
43
+ if length > 0
44
+ # 0-9 starting with 48 with range of 10 characters
45
+ offset=[48]
46
+ # collect random characters from the either of the above ranges
47
+ password(length, offset, 10)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def self.password(length, offset, max_range)
54
+ pwd = (0..(length - 1)).collect do
55
+ j = SecureRandom.random_number(offset.size * max_range)
56
+ (offset[j / max_range] + (j % max_range)).chr
57
+ end.join
58
+ end
20
59
  end
21
60
  end
@@ -0,0 +1,13 @@
1
+ require 'ixtlan/models'
2
+ require 'ixtlan/modified_by'
3
+ if ENV['RAILS_ENV']
4
+ require 'ixtlan/rails/error_handling'
5
+ require 'ixtlan/rails/cache_headers'
6
+ require 'ixtlan/rails/audit'
7
+ require 'ixtlan/rails/session_timeout'
8
+ require 'ixtlan/rails/unrestful_authentication'
9
+ require 'ixtlan/rails/guard'
10
+ require 'ixtlan/rails/timestamps_modified_by_filter'
11
+ require 'ixtlan/optimistic_persistence'
12
+ require 'ixtlan/rails/rescue_module'
13
+ end
@@ -0,0 +1,88 @@
1
+ module Ixtlan
2
+ module Rails
3
+ module CacheHeaders
4
+
5
+ protected
6
+
7
+ # Date: <ServercurrentDate>
8
+ # Expires: Fri, 01 Jan 1990 00:00:00 GMT
9
+ # Pragma: no-cache
10
+ # Cache-control: no-cache, must-revalidate
11
+ def no_caching(no_store = true)
12
+ if cachable_response?
13
+ response.headers["Date"] = timestamp
14
+ response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
15
+ response.headers["Pragma"] = "no-cache"
16
+ response.headers["Cache-Control"] = "no-cache, must-revalidate" + (", no-store" if no_store).to_s
17
+ end
18
+ end
19
+
20
+ # Date: <ServercurrentDate>
21
+ # Expires: Fri, 01 Jan 1990 00:00:00 GMT
22
+ # Cache-control: private, max-age=<1dayInSeconds>
23
+ def only_browser_can_cache(no_store = false, max_age_in_seconds = 0)
24
+ if cachable_response?
25
+ response.headers["Date"] = timestamp
26
+ response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 UTC"
27
+ response.headers["Cache-Control"] = "private, max-age=#{max_age_in_seconds}" + (", no-store" if no_store).to_s
28
+ end
29
+ end
30
+
31
+ # Date: <ServercurrentDate>
32
+ # Expires: <ServerCurrentDate + 1month>
33
+ # Cache-control: public, max-age=<1month>
34
+ def allow_browser_and_proxy_to_cache(no_store = false, max_age_in_seconds = 0)
35
+ if cachable_response?
36
+ now = Time.now
37
+ response.headers["Date"] = timestamp(now)
38
+ response.headers["Expires"] = timestamp(now + max_age_in_seconds)
39
+ response.headers["Cache-Control"] = "public, max-age=#{max_age_in_seconds}" + (", no-store" if no_store).to_s
40
+ end
41
+ end
42
+
43
+ def cache_headers
44
+ if(current_user)
45
+ case self.class.instance_variable_get(:@mode)
46
+ when :private
47
+ no_caching(self.class.instance_variable_get(:@no_store))
48
+ when :protected
49
+ only_browser_can_cache(self.class.instance_variable_get(:@no_store))
50
+ when :public
51
+ allow_browser_and_proxy_to_cache(self.class.instance_variable_get(:@no_store))
52
+ end
53
+ else
54
+ allow_browser_and_proxy_to_cache(self.class.instance_variable_get(:@no_store))
55
+ end
56
+ end
57
+
58
+ def self.included(base)
59
+ base.class_eval <<-EOS, __FILE__, __LINE__
60
+ def self.cache_headers(mode = nil, no_store = true)
61
+ if(mode)
62
+ raise "supported modi are :private, :protected and :public" unless [:private, :protected, :public].member? mode
63
+ @mode = mode
64
+ end
65
+ @no_store = no_store
66
+ end
67
+ alias :render_old :render
68
+ def render(*args)
69
+ cache_headers
70
+ render_old(*args)
71
+ end
72
+ EOS
73
+ end
74
+
75
+ private
76
+ def cachable_response?
77
+ request.method == :get &&
78
+ [200, 203, 206, 300, 301].member?(response.status)
79
+ end
80
+
81
+ def timestamp(now = Time.now)
82
+ now.utc.strftime "%a, %d %b %Y %H:%M:%S %Z"
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ ActionController::Base.send(:include, Ixtlan::Rails::CacheHeaders)
@@ -3,6 +3,8 @@ module Ixtlan
3
3
  module Rails
4
4
  module ErrorHandling
5
5
 
6
+ protected
7
+
6
8
  def log_user_error(exception)
7
9
  Ixtlan::UserLogger.new(Ixtlan::Rails::ErrorHandling).log_action(self, " - #{exception.class} - #{exception.message}")
8
10
  log_error(exception)
@@ -31,11 +33,11 @@ module Ixtlan
31
33
  end
32
34
 
33
35
  def render_error_page_with_session(status)
34
- render :template => "errors/error", :status => status
36
+ render :template => "errors/error_with_session", :status => status
35
37
  end
36
38
 
37
39
  def render_error_page(status)
38
- render :template => "sessions/login", :status => status
40
+ render :template => "sessions/error", :status => status
39
41
  end
40
42
 
41
43
  def page_not_found(exception)
@@ -26,3 +26,5 @@ module Ixtlan
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ ActionController::Base.send(:include, Ixtlan::Rails::RescueModule)
@@ -1,3 +1,4 @@
1
+
1
2
  module Ixtlan
2
3
  module Rails
3
4
  module UnrestfulAuthentication
@@ -49,15 +50,15 @@ module Rails
49
50
  session.clear
50
51
  render_login_page
51
52
  when :post
52
- user = login_from_params
53
+ user = login_from_params || "no username or password"
53
54
  if user.instance_of? String
54
- authentication_logger.log_user(params[:login] || params[:authentication][:login], user + " from IP #{request.headers['REMOTE_ADDR']}")
55
+ authentication_logger.log_user(params[:login] || (params[:authentication] || {})[:login], user + " from IP #{request.headers['REMOTE_ADDR']}")
55
56
  session.clear
56
57
  render_access_denied
57
58
  else
58
- authentication_logger.log_user(user.login, "logged in")
59
+ authentication_logger.log_user(user.nil? ? nil : user.login, "logged in")
59
60
  session.clear
60
- # reset_session
61
+ # reset session
61
62
  self.current_user = user
62
63
  render_successful_login
63
64
  end
@@ -82,7 +83,7 @@ module Rails
82
83
  authentication_logger.log_user(current_user.login, "logged out")
83
84
  current_user = nil
84
85
  session.clear
85
- # reset_session
86
+ # reset session
86
87
  render_logout_page
87
88
  false
88
89
  else
@@ -5,15 +5,15 @@ module Ixtlan
5
5
  def data=(data)
6
6
  d = {}
7
7
  data.each{|k,v| d[k.to_sym] = v}
8
- @user = d.delete(:user)
9
- @flash = d.delete(:flash)
10
- @expires_at = d.delete(:expires_at)
8
+ d.delete(:user)
11
9
  attribute_set(:raw_data, ::Base64.encode64(Marshal.dump(d)))
12
10
  end
13
11
 
14
12
  def data
15
- # user string for flash entry to allow the rails falsh to work properly !
16
- Marshal.load(::Base64.decode64(attribute_get(:raw_data))).merge({:user => @user, "flash" => @flash, :expires_at => @expires_at})
13
+ # use string for flash entry to allow the rails flash to work properly !
14
+ d = Marshal.load(::Base64.decode64(attribute_get(:raw_data)))
15
+ d["flash"] = d.delete(:flash)
16
+ d
17
17
  end
18
18
  end
19
19
  end
@@ -0,0 +1,19 @@
1
+ require 'rack_datamapper/session/abstract/store'
2
+ module Ixtlan
3
+ class SessionWithCache < DataMapper::Session::Abstract::Session
4
+
5
+ def data=(data)
6
+ d = {}
7
+ data.each{|k,v| d[k.to_sym] = v}
8
+ @user = d.delete(:user)
9
+ @flash = d.delete(:flash)
10
+ @expires_at = d.delete(:expires_at)
11
+ attribute_set(:raw_data, ::Base64.encode64(Marshal.dump(d)))
12
+ end
13
+
14
+ def data
15
+ # use string key for flash entry to allow the rails flash to work properly !
16
+ Marshal.load(::Base64.decode64(attribute_get(:raw_data))).merge({:user => @user, "flash" => @flash, :expires_at => @expires_at})
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
- class Ixtlan
2
- VERSION = '0.4.0.pre4'.freeze
1
+ module Ixtlan
2
+ VERSION = '0.4.0.pre5'.freeze
3
3
  end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ lib_path = (Pathname(__FILE__).dirname.parent.expand_path + 'lib').to_s
3
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
4
+
5
+ require 'ixtlan/passwords'
6
+
7
+ describe Ixtlan::Passwords do
8
+
9
+ it 'should create a password of given length' do
10
+ pwd = Ixtlan::Passwords.generate(123)
11
+ ((pwd =~ /[a-z]/) && (pwd =~ /[A-Z]/) && (pwd =~ /[!-;]/)).should be_true
12
+ pwd.size.should == 123
13
+ end
14
+
15
+ it 'should create a numeric password of given length' do
16
+ pwd = Ixtlan::Passwords.generate_numeric(321)
17
+ pwd.should =~ /^[0-9]*$/
18
+ pwd.size.should == 321
19
+ end
20
+
21
+ end
@@ -12,6 +12,7 @@ require 'slf4r'
12
12
  require 'ixtlan' / 'models'
13
13
  require 'ixtlan' / 'user_logger'
14
14
  require 'ixtlan' / 'modified_by'
15
+ require 'ixtlan' / 'models' / 'audit'
15
16
  require 'ixtlan' / 'models' / 'domain'
16
17
  require 'ixtlan' / 'models' / 'locale'
17
18
  require 'ixtlan' / 'models' / 'group'
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 0
7
7
  - 4
8
8
  - 0
9
- - pre4
10
- version: 0.4.0.pre4
9
+ - pre5
10
+ version: 0.4.0.pre5
11
11
  platform: ruby
12
12
  authors:
13
13
  - mkristian
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-05 00:00:00 +05:30
18
+ date: 2010-07-19 00:00:00 +05:30
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -163,6 +163,7 @@ files:
163
163
  - lib/dm-serializer/xml_serializers/libxml.rb
164
164
  - lib/dm-serializer/xml_serializers/nokogiri.rb
165
165
  - lib/dm-serializer/xml_serializers/rexml.rb
166
+ - lib/ixtlan/rails.rb
166
167
  - lib/ixtlan/child_path.rb
167
168
  - lib/ixtlan/rolling_file.rb
168
169
  - lib/ixtlan/cms_script.rb
@@ -170,6 +171,8 @@ files:
170
171
  - lib/ixtlan/logger_config.rb
171
172
  - lib/ixtlan/models.rb
172
173
  - lib/ixtlan/audit_config.rb
174
+ - lib/ixtlan/session_with_cache.rb
175
+ - lib/ixtlan/configurator.rb
173
176
  - lib/ixtlan/audit_rack.rb
174
177
  - lib/ixtlan/session.rb
175
178
  - lib/ixtlan/optimistic_persistence.rb
@@ -218,6 +221,7 @@ files:
218
221
  - lib/ixtlan/mailer/password.erb
219
222
  - lib/ixtlan/rails/timestamps_modified_by_filter.rb
220
223
  - lib/ixtlan/rails/rescue_module.rb
224
+ - lib/ixtlan/rails/cache_headers.rb
221
225
  - lib/ixtlan/rails/audit.rb
222
226
  - lib/ixtlan/rails/error_handling.rb
223
227
  - lib/ixtlan/rails/migrations.rb
@@ -256,6 +260,7 @@ files:
256
260
  - spec/text_spec.rb
257
261
  - spec/user_logger_spec.rb
258
262
  - spec/unrestful_authentication_spec.rb
263
+ - spec/passwords_spec.rb
259
264
  - spec/guards/samples.rb
260
265
  has_rdoc: true
261
266
  homepage: http://github.com/mkristian/ixtlan-core
@@ -301,3 +306,4 @@ test_files:
301
306
  - spec/text_spec.rb
302
307
  - spec/user_logger_spec.rb
303
308
  - spec/unrestful_authentication_spec.rb
309
+ - spec/passwords_spec.rb