ixtlan-core 0.6.0 → 0.6.1

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.
Files changed (47) hide show
  1. data/README.md +64 -0
  2. data/features/headers.feature +12 -0
  3. data/features/step_definitions/simple_steps.rb +1 -0
  4. data/lib/ixtlan/core/active_record.rb +22 -0
  5. data/lib/ixtlan/core/active_record.rb~ +24 -0
  6. data/lib/ixtlan/core/controllers/configuration_controller.rb~ +9 -0
  7. data/lib/ixtlan/core/data_mapper.rb +23 -0
  8. data/lib/ixtlan/core/data_mapper.rb~ +18 -0
  9. data/lib/ixtlan/core/optimistic_active_record.rb~ +21 -0
  10. data/lib/ixtlan/core/{optimistic_data_mapper.rb → optimistic_data_mapper.rb~} +1 -1
  11. data/lib/ixtlan/core/railtie.rb +6 -6
  12. data/lib/ixtlan/core/x_content_headers.rb~ +32 -0
  13. data/lib/ixtlan/core/x_content_type_headers.rb~ +30 -0
  14. data/lib/ixtlan/core/x_xss_protection_headers.rb~ +30 -0
  15. data/spec/cache_headers_spec.rb~ +52 -0
  16. data/spec/configuration_manager_spec.rb~ +40 -0
  17. data/spec/controller.rb~ +8 -0
  18. data/spec/x_headers_spec.rb~ +74 -0
  19. metadata +24 -37
  20. data/lib/generators/ixtlan/base.rb +0 -45
  21. data/lib/generators/ixtlan/configuration_model/configuration_model_generator.rb +0 -12
  22. data/lib/generators/ixtlan/configuration_scaffold/configuration_scaffold_generator.rb +0 -12
  23. data/lib/generators/ixtlan/setup/setup_generator.rb +0 -38
  24. data/lib/generators/ixtlan/setup/templates/application_layout.html.erb +0 -17
  25. data/lib/generators/ixtlan/setup/templates/database.yml.example +0 -48
  26. data/lib/generators/ixtlan/setup/templates/error.html.erb +0 -1
  27. data/lib/generators/ixtlan/setup/templates/error_with_session.html.erb +0 -1
  28. data/lib/generators/ixtlan/setup/templates/gitignore +0 -2
  29. data/lib/generators/ixtlan/setup/templates/initializer.rb +0 -64
  30. data/lib/generators/ixtlan/setup/templates/preinitializer.rb +0 -31
  31. data/lib/generators/ixtlan/setup/templates/production.yml.example +0 -8
  32. data/lib/generators/ixtlan/setup/templates/stale.html.erb +0 -2
  33. data/lib/generators/model/model_generator.rb +0 -12
  34. data/lib/generators/rails/active_record/active_record_generator.rb +0 -40
  35. data/lib/generators/rails/active_record/model/migration.rb +0 -19
  36. data/lib/generators/rails/active_record/model/model.rb +0 -16
  37. data/lib/generators/rails/erb/erb_generator.rb +0 -37
  38. data/lib/generators/rails/erb/scaffold/_form.html.erb +0 -28
  39. data/lib/generators/rails/erb/scaffold/edit.html.erb +0 -24
  40. data/lib/generators/rails/erb/scaffold/index.html.erb +0 -49
  41. data/lib/generators/rails/erb/scaffold/new.html.erb +0 -11
  42. data/lib/generators/rails/erb/scaffold/show.html.erb +0 -30
  43. data/lib/generators/rails/scaffold_controller/scaffold_controller/controller.rb +0 -129
  44. data/lib/generators/rails/scaffold_controller/scaffold_controller/singleton_controller.rb +0 -43
  45. data/lib/generators/scaffold/scaffold_generator.rb +0 -35
  46. data/lib/generators/scaffold_controller/scaffold_controller_generator.rb +0 -34
  47. data/lib/ixtlan/core/optimistic_active_record.rb +0 -18
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Ixtlan #
2
+
3
+ this gem adds more security related headers to the response for a rails3 application. mainly inspired by
4
+ [google-gets-a-1-for-browser-security](http://www.barracudalabs.com/wordpress/index.php/2011/07/21/google-gets-a-1-for-browser-security-3/)
5
+ and
6
+ [HttpCaching](http://code.google.com/p/doctype/wiki/ArticleHttpCaching).
7
+ and
8
+ [Clickjacking](http://www.owasp.org/index.php/Clickjacking)
9
+
10
+ the extra headers are
11
+
12
+ * x-frame headers
13
+ * x-content-type headers
14
+ * x-xss-protection headers
15
+ * caching headers
16
+
17
+ the main idea is to set the default as strict as possible and the application might relax the setup here and there.
18
+
19
+ ## rails configuration ##
20
+
21
+ in _config/application.rb_ or in one of the _config/environments/*rb_ files or in an initializer. all three x-headers can be configured here, for example
22
+
23
+ config.x_content_type_headers = :nosniff
24
+
25
+ ## controller configuration ##
26
+
27
+ just add in your controller something like
28
+
29
+ x_xss_protection :block
30
+
31
+ ## option for each *render*, *send\_file*, *send\_data* methods
32
+
33
+ an example for an inline render
34
+
35
+ render :inline => 'behappy', :x_frame_headers => :deny
36
+
37
+ ## possible values ##
38
+
39
+ * x\_frame\_headers : `:deny, :sameorigin, :off` default `:deny`
40
+
41
+ * x\_content\_type\_headers : `:nosniff, :off` default `:nosniff`
42
+
43
+ * x\_xss\_protection\_headers : `:block, :disabled, :off` default `:block`
44
+
45
+ ## cache headers
46
+
47
+ the cache headers needs to have a **current\_user**, i.e. the current\_user method of the controller needs to return a non-nil value. further the the method needs to `:get` and the response status an "ok" status,
48
+
49
+ then you can use the controller configuration or the options with *render*, *send\_file* and *send\_data*.
50
+
51
+ ## possible values ##
52
+
53
+ * `:private` : which tells not to cache or store any data except the browser memory: [no caching](http://code.google.com/p/doctype/wiki/ArticleHttpCaching#No_caching)
54
+
55
+ * `:protected` : no caching but the browser: [Only the end user's browser is allowed to cache](http://code.google.com/p/doctype/wiki/ArticleHttpCaching#Only_the_end_user%27s_browser_is_allowed_to_cache)
56
+
57
+ * `:public` : caching is allowed: [Both browser and proxy allowed to cache](http://code.google.com/p/doctype/wiki/ArticleHttpCaching#Both_browser_and_proxy_allowed_to_cache)
58
+
59
+ * `:my_headers` : custom header method like
60
+
61
+ > def my_headers
62
+ no_store = false
63
+ no_caching(no_store)
64
+ end
@@ -0,0 +1,12 @@
1
+ Feature: Generators for Ixtlan Core
2
+
3
+ Scenario: Create a rails application and adding the ixtlan-core adds ixtlan generators
4
+ Given I create new rails application with template "headers.template" and "headers" tests
5
+ And I execute "rails generate scaffold user name:string --skip --migration"
6
+ And I execute "rake db:migrate test"
7
+ Then the output should contain "7 tests, 20 assertions, 0 failures, 0 errors" and "1 tests, 1 assertions, 0 failures, 0 errors"
8
+
9
+ Given me an existing rails application "headers" and "optimistic" files
10
+ And I execute "rails generate scaffold account name:string --skip --migration --timestamps --optimistic --modified-by user"
11
+ And I execute "rake db:migrate test"
12
+ Then the output should contain "14 tests, 30 assertions, 0 failures, 0 errors" and "2 tests, 2 assertions, 0 failures, 0 errors"
@@ -0,0 +1 @@
1
+ require 'maven/cucumber_steps'
@@ -0,0 +1,22 @@
1
+ module Ixtlan
2
+ module Core
3
+ module ActiveRecord
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+
8
+ def self.optimistic_find(updated_at, *args)
9
+ if updated_at
10
+ updated_at_date = new(:updated_at => updated_at).updated_at
11
+ # try different ways to use the date
12
+ # TODO maybe there is a nicer way ??
13
+ first(:conditions => ["id = ? and updated_at <= ? and updated_at >= ?", args[0], updated_at, updated_at_date - 0.001]) || first(:conditions => ["id = ? and updated_at <= ? and updated_at >= ?", args[0], updated_at_date, updated_at_date - 0.001])
14
+ # TODO make it work with different PKs
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ module Ixtlan
2
+ module Core
3
+ module OptimisticActiveRecord
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+
8
+ attr_accessor :current_user
9
+
10
+ def self.optimistic_find(updated_at, *args)
11
+ if updated_at
12
+ updated_at_date = new(:updated_at => updated_at).updated_at
13
+ # try different ways to use the date
14
+ # TODO maybe there is a nicer way ??
15
+ first(:conditions => ["id = ? and updated_at <= ? and updated_at >= ?", args[0], updated_at, updated_at_date - 0.001]) || first(:conditions => ["id = ? and updated_at <= ? and updated_at >= ?", args[0], updated_at_date, updated_at_date - 0.001])
16
+ # TODO make it work with different PKs
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ module Ixtlan
2
+ module Guard
3
+ module Controllers
4
+ module MaintenanceController
5
+
6
+ # GET /configuration
7
+ # GET /configuration.xml
8
+ # GET /configuration.json
9
+ def index
@@ -0,0 +1,23 @@
1
+ module Ixtlan
2
+ module Core
3
+ module DataMapper
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+
8
+ attr_accessor :current_user
9
+
10
+ def optimistic_find(updated_at, *args)
11
+ if updated_at
12
+ updated_at = new(:updated_at => updated_at).updated_at
13
+ # TODO make it work with different PKs
14
+ first(:id => args[0], :updated_at => updated_at)
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ module Ixtlan
2
+ module Core
3
+ module OptimisticDataMapper
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ def optimistic_find(updated_at, *args)
8
+ if updated_at
9
+ updated_at = new(:updated_at => updated_at).updated_at
10
+ # TODO make it work with different PKs
11
+ first(:id => args[0], :updated_at => updated_at)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module Ixtlan
2
+ module Core
3
+ module OptimisticActiveRecord
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ def self.optimistic_find(updated_at, *args)
8
+ p updated_at
9
+ updated_at = new(:updated_at => updated_at).updated_at
10
+ # TODO make it work with different PKs
11
+ r = first(:conditions => ["id = ? and updated_at = ?", args[0], updated_at])
12
+ p args[0]
13
+ p updated_at
14
+ p r
15
+ r
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -7,7 +7,7 @@ module Ixtlan
7
7
  def optimistic_find(updated_at, *args)
8
8
  updated_at = new(:updated_at => updated_at).updated_at
9
9
  # TODO make it work with different PKs
10
- first(:id => args[0], :updated_at => updated_at)
10
+ first(:id => args[0], :updated_at => updated_at])
11
11
  end
12
12
  end
13
13
  end
@@ -3,8 +3,8 @@ require 'ixtlan/core/cache_headers'
3
3
  require 'ixtlan/core/x_frame_headers'
4
4
  require 'ixtlan/core/x_content_type_headers'
5
5
  require 'ixtlan/core/x_xss_protection_headers'
6
- require 'ixtlan/core/optimistic_active_record'
7
- require 'ixtlan/core/optimistic_data_mapper'
6
+ require 'ixtlan/core/active_record'
7
+ require 'ixtlan/core/data_mapper'
8
8
  require 'ixtlan/core/configuration_rack'
9
9
  require 'ixtlan/core/configuration_manager'
10
10
  module Ixtlan
@@ -63,15 +63,15 @@ module Ixtlan
63
63
  app.config.middleware.use Ixtlan::Core::ConfigurationRack
64
64
  end
65
65
  config.after_initialize do |app|
66
- if defined? DataMapper
66
+ if defined? ::DataMapper
67
67
 
68
68
  ::DataMapper::Resource.send(:include,
69
- Ixtlan::Core::OptimisticDataMapper)
69
+ Ixtlan::Core::DataMapper)
70
70
 
71
- elsif defined? ActiveRecord
71
+ elsif defined? ::ActiveRecord
72
72
 
73
73
  ::ActiveRecord::Base.send(:include,
74
- Ixtlan::Core::OptimisticActiveRecord)
74
+ Ixtlan::Core::ActiveRecord)
75
75
 
76
76
  end
77
77
  end
@@ -0,0 +1,32 @@
1
+ module Ixtlan
2
+ module Core
3
+ module XFrameHeaders
4
+
5
+ protected
6
+
7
+ def x_frame_headers(mode = nil)
8
+ case mode || self.class.instance_variable_get(:@_x_frame_mode) || Rails.configuration.x_frame_headers
9
+ when :deny
10
+ response.headers["X-FRAME-OPTIONS"] = "DENY"
11
+ when :sameorigin
12
+ response.headers["X-FRAME-OPTIONS"] = "SAMEORIGIN"
13
+ when :off
14
+ else
15
+ warn "allowed values for x_frame_headers are :deny, :sameorigin, :off"
16
+ end
17
+ end
18
+
19
+ def self.included(base)
20
+ base.class_eval do
21
+ def self.x_frame_headers(mode)
22
+ if(mode)
23
+ @_x_frame_mode = mode.to_sym
24
+ else
25
+ @_x_frame_mode = nil
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ module Ixtlan
2
+ module Core
3
+ module XContentHeaders
4
+
5
+ protected
6
+
7
+ def x_content_headers(mode = nil)
8
+ case mode || self.class.instance_variable_get(:@_x_content_headers) || Rails.configuration.x_content_headers || :nosniff
9
+ when :nosniff
10
+ response.headers["X-Content-Type-Options"] = "nosniff"
11
+ when :off
12
+ else
13
+ warn "allowed values for x_content_headers are :nosniff, :off"
14
+ end
15
+ end
16
+
17
+ def self.included(base)
18
+ base.class_eval do
19
+ def self.x_content_headers(mode)
20
+ if(mode)
21
+ @_x_content_headers = mode.to_sym
22
+ else
23
+ @_x_content_headers = nil
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module Ixtlan
2
+ module Core
3
+ module XContentHeaders
4
+
5
+ protected
6
+
7
+ def x_content_headers(mode = nil)
8
+ case mode || self.class.instance_variable_get(:@_x_content_headers) || Rails.configuration.x_content_headers || :nosniff
9
+ when :nosniff
10
+ response.headers["X-Content-Type-Options"] = "nosniff"
11
+ when :off
12
+ else
13
+ warn "allowed values for x_content_headers are :nosniff, :off"
14
+ end
15
+ end
16
+
17
+ def self.included(base)
18
+ base.class_eval do
19
+ def self.x_content_headers(mode)
20
+ if(mode)
21
+ @_x_content_headers = mode.to_sym
22
+ else
23
+ @_x_content_headers = nil
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,52 @@
1
+ require 'controller'
2
+
3
+
4
+ class MyControllerWithUser < ControllerWithUser
5
+ cache_headers :private
6
+ end
7
+
8
+ [:render#, :send_file, :send_data
9
+ ].each do |method|
10
+ describe "cache-headers using controller method #{method}" do
11
+ context "with simple controller" do
12
+ subject { ControllerWithUser.new(Object.new) }
13
+
14
+ it 'should use default' do
15
+ subject.send method, :inline => "asd"
16
+ subject.response.headers.should == {"X-Frame-Options"=>"DENY", "X-Content-Type-Options"=>"nosniff", "X-XSS-Protection"=>"1; mode=block"}
17
+ end
18
+ it 'should use given option' do
19
+ subject.send method, :inline => "asd", :cache_headers => :protected
20
+ subject.response.headers.delete("Date").should_not be_nil
21
+ subject.response.headers.delete("Expires").should_not be_nil
22
+ subject.response.headers.should == {"Cache-Control"=>"private, max-age=0", "X-Frame-Options"=>"DENY", "X-Content-Type-Options"=>"nosniff", "X-XSS-Protection"=>"1; mode=block"}
23
+ end
24
+ end
25
+
26
+ context "with controller with header configuration" do
27
+ subject { MyControllerWithUser.new(Object.new) }
28
+
29
+ it 'should use configuration' do
30
+ subject.send method, :inline => "asd"
31
+ subject.response.headers.delete("Date").should_not be_nil
32
+ subject.response.headers.delete("Expires").should_not be_nil
33
+ subject.response.headers.should == {"Pragma"=>"no-cache", "Cache-Control"=>"no-cache, must-revalidate, no-store", "X-Frame-Options"=>"DENY", "X-Content-Type-Options"=>"nosniff", "X-XSS-Protection"=>"1; mode=block"}
34
+ end
35
+ it 'should use given option' do
36
+ subject.send method, :inline => "asd", :cache_headers => :public
37
+ subject.response.headers.delete("Date").should_not be_nil
38
+ subject.response.headers.delete("Expires").should_not be_nil
39
+ subject.response.headers.should == {"Cache-Control"=>"private, max-age=0", "X-Frame-Options"=>"DENY", "X-Content-Type-Options"=>"nosniff", "X-XSS-Protection"=>"1; mode=block"}
40
+ end
41
+ end
42
+
43
+ context "with simple controller without user" do
44
+ subject { MyControllerWithUser.new }
45
+
46
+ it 'should use default' do
47
+ subject.send method, :inline => "asd"
48
+ subject.response.headers.should == {"X-Frame-Options"=>"DENY", "X-Content-Type-Options"=>"nosniff", "X-XSS-Protection"=>"1; mode=block"}
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ require 'ixtlan/core/configuration_manager'
2
+
3
+ class ConfigModel
4
+
5
+ def self.instance
6
+ @instance ||= self.new
7
+ end
8
+
9
+ def self.after_save(method)
10
+ @method = method.to_sym
11
+ end
12
+
13
+ def self.save_method
14
+ @method
15
+ end
16
+
17
+ def save
18
+ sent self.class.save_method
19
+ end
20
+ end
21
+
22
+ describe Ixtlan::Core::ConfigurationManager do
23
+
24
+ # before :all do
25
+ # ConfigModel.sent :include, Ixtlan::Core::ConfigurationManager
26
+ # end
27
+
28
+ it "should" do
29
+ end
30
+
31
+ it "should register listeners and fire change events" do
32
+ # count = 0
33
+ # ConfigModel.instance.register("counter") do
34
+ # count += 1
35
+ # end
36
+ # ConfigModel.instance.save
37
+ # count.should == 1
38
+ end
39
+
40
+ end