ixtlan 0.4.0.pre4 → 0.4.0.pre5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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