stratagem 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/Manifest +99 -0
  2. data/Rakefile +17 -0
  3. data/bin/stratagem +10 -0
  4. data/init.rb +2 -0
  5. data/lib/bootstrap.rb +31 -0
  6. data/lib/stratagem/authentication.rb +64 -0
  7. data/lib/stratagem/auto_mock/aquifer.rb +86 -0
  8. data/lib/stratagem/auto_mock/factory.rb +213 -0
  9. data/lib/stratagem/auto_mock/value_generator.rb +174 -0
  10. data/lib/stratagem/auto_mock.rb +6 -0
  11. data/lib/stratagem/blocker.rb +16 -0
  12. data/lib/stratagem/client.rb +32 -0
  13. data/lib/stratagem/command.rb +13 -0
  14. data/lib/stratagem/commands/analyze.rb +22 -0
  15. data/lib/stratagem/commands/base.rb +11 -0
  16. data/lib/stratagem/commands/devel_crawl.rb +27 -0
  17. data/lib/stratagem/commands/devel_mock.rb +10 -0
  18. data/lib/stratagem/commands.rb +7 -0
  19. data/lib/stratagem/crawler/authentication.rb +109 -0
  20. data/lib/stratagem/crawler/form.rb +101 -0
  21. data/lib/stratagem/crawler/html_utils.rb +92 -0
  22. data/lib/stratagem/crawler/session.rb +296 -0
  23. data/lib/stratagem/crawler/site_model.rb +138 -0
  24. data/lib/stratagem/crawler/trace_utils.rb +10 -0
  25. data/lib/stratagem/crawler.rb +9 -0
  26. data/lib/stratagem/extensions/class.rb +9 -0
  27. data/lib/stratagem/extensions/hash.rb +16 -0
  28. data/lib/stratagem/extensions/module.rb +11 -0
  29. data/lib/stratagem/extensions/object.rb +15 -0
  30. data/lib/stratagem/extensions/red_parse.rb +86 -0
  31. data/lib/stratagem/extensions/string.rb +20 -0
  32. data/lib/stratagem/extensions.rb +6 -0
  33. data/lib/stratagem/framework_extensions/controllers/action_controller.rb +10 -0
  34. data/lib/stratagem/framework_extensions/controllers/action_mailer.rb +12 -0
  35. data/lib/stratagem/framework_extensions/controllers.rb +5 -0
  36. data/lib/stratagem/framework_extensions/models/adapters/active_model/detect.rb +7 -0
  37. data/lib/stratagem/framework_extensions/models/adapters/active_model/extensions.rb +35 -0
  38. data/lib/stratagem/framework_extensions/models/adapters/active_model/metadata.rb +103 -0
  39. data/lib/stratagem/framework_extensions/models/adapters/active_model/tracing.rb +50 -0
  40. data/lib/stratagem/framework_extensions/models/adapters/authlogic/detect.rb +11 -0
  41. data/lib/stratagem/framework_extensions/models/adapters/authlogic/extensions.rb +10 -0
  42. data/lib/stratagem/framework_extensions/models/adapters/authlogic/metadata.rb +30 -0
  43. data/lib/stratagem/framework_extensions/models/adapters/authlogic/tracing.rb +4 -0
  44. data/lib/stratagem/framework_extensions/models/adapters/common/authentication_metadata.rb +21 -0
  45. data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/detect.rb +13 -0
  46. data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/extensions.rb +19 -0
  47. data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/metadata.rb +30 -0
  48. data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/tracing.rb +4 -0
  49. data/lib/stratagem/framework_extensions/models/annotations.rb +79 -0
  50. data/lib/stratagem/framework_extensions/models/detect.rb +7 -0
  51. data/lib/stratagem/framework_extensions/models/metadata.rb +85 -0
  52. data/lib/stratagem/framework_extensions/models/mocking.rb +23 -0
  53. data/lib/stratagem/framework_extensions/models/tracing.rb +71 -0
  54. data/lib/stratagem/framework_extensions/models.rb +21 -0
  55. data/lib/stratagem/framework_extensions/rails.rb +8 -0
  56. data/lib/stratagem/framework_extensions.rb +6 -0
  57. data/lib/stratagem/interface/browser.rb +37 -0
  58. data/lib/stratagem/interface/public/images/backgrounds/content.png +0 -0
  59. data/lib/stratagem/interface/public/images/backgrounds/shadow.png +0 -0
  60. data/lib/stratagem/interface/public/javascripts/jquery-1.4.2.min.js +154 -0
  61. data/lib/stratagem/interface/public/javascripts/stratagem.js +27 -0
  62. data/lib/stratagem/interface/public/javascripts/stratagem_debug.js +53 -0
  63. data/lib/stratagem/interface/public/stylesheets/960.css +1 -0
  64. data/lib/stratagem/interface/public/stylesheets/reset.css +10 -0
  65. data/lib/stratagem/interface/public/stylesheets/stratagem.css +20 -0
  66. data/lib/stratagem/interface/public/stylesheets/stratagem_debug.css +20 -0
  67. data/lib/stratagem/interface/views/debug.haml +43 -0
  68. data/lib/stratagem/interface/views/index.haml +35 -0
  69. data/lib/stratagem/labs/auto_mock.rb +7 -0
  70. data/lib/stratagem/labs/crawler.rb +0 -0
  71. data/lib/stratagem/logger.rb +46 -0
  72. data/lib/stratagem/model/application.rb +157 -0
  73. data/lib/stratagem/model/components/base.rb +55 -0
  74. data/lib/stratagem/model/components/controller.rb +118 -0
  75. data/lib/stratagem/model/components/model.rb +170 -0
  76. data/lib/stratagem/model/components/reference.rb +30 -0
  77. data/lib/stratagem/model/components/route.rb +53 -0
  78. data/lib/stratagem/model/components/static_file.rb +18 -0
  79. data/lib/stratagem/model/components/view.rb +186 -0
  80. data/lib/stratagem/model/parse_util.rb +61 -0
  81. data/lib/stratagem/model.rb +12 -0
  82. data/lib/stratagem/model_builder.rb +146 -0
  83. data/lib/stratagem/recipes/deploy.rb +30 -0
  84. data/lib/stratagem/scan/checks/capistrano/secure_deploy.rb +43 -0
  85. data/lib/stratagem/scan/checks/email_address.rb +15 -0
  86. data/lib/stratagem/scan/checks/error_pages.rb +25 -0
  87. data/lib/stratagem/scan/checks/filter_parameter_logging.rb +6 -0
  88. data/lib/stratagem/scan/checks/mongo_mapper/base.rb +19 -0
  89. data/lib/stratagem/scan/checks/mongo_mapper/foreign_keys_exposed.rb +32 -0
  90. data/lib/stratagem/scan/checks/routes.rb +16 -0
  91. data/lib/stratagem/scan/checks/ssl/secure_login_page.rb +19 -0
  92. data/lib/stratagem/scan/checks/ssl/secure_login_submit.rb +18 -0
  93. data/lib/stratagem/scan/result.rb +45 -0
  94. data/lib/stratagem/scan.rb +19 -0
  95. data/lib/stratagem/scanner.rb +32 -0
  96. data/lib/stratagem/site_crawler.rb +47 -0
  97. data/lib/stratagem/snapshot.rb +33 -0
  98. data/lib/stratagem.rb +77 -0
  99. data/lib/tasks/_old_stratagem.rake +99 -0
  100. data/stratagem.gemspec +56 -0
  101. metadata +380 -0
@@ -0,0 +1,186 @@
1
+ module Stratagem::Model::Component
2
+ class View < Base
3
+ include Stratagem::Model::ParseUtil
4
+
5
+ RAILS_FORM_FIELDS = ['check_box', 'file_field', 'hidden_field', 'password_field', 'radio_button', 'text_area', 'text_field']
6
+
7
+ attr_reader :extension, :render_path # as seen by the controllers
8
+
9
+ def initialize(render_path)
10
+ render_path =~ /\.(.*)/
11
+ @extension = $1
12
+ @path = render_path
13
+ @render_path = render_path.gsub(/\..*/, '')
14
+ end
15
+
16
+ def read
17
+ File.open(full_path) {|file| file.readlines().join }
18
+ end
19
+
20
+ def partial?
21
+ File.basename(render_path) =~ /^_/
22
+ end
23
+
24
+ def full_path
25
+ File.join(RAILS_ROOT, 'app', 'views', render_path+'.'+extension)
26
+ end
27
+
28
+ def directory
29
+ File.dirname(full_path)
30
+ end
31
+
32
+ def export
33
+ begin
34
+ {
35
+ :type => :view,
36
+ :path => @path,
37
+ :render_path => @render_path,
38
+ :forms => forms.map {|form| form.export }
39
+ }
40
+ rescue
41
+ logger.fatal($!)
42
+ nil
43
+ end
44
+ end
45
+
46
+ def rendered_by
47
+
48
+ end
49
+
50
+ def forms
51
+ # extract ruby from the html
52
+ ruby = ruby_blocks(approximate_html).join("\n")
53
+
54
+ # dump ruby into a parse tree
55
+ begin
56
+ parse_tree = RedParse.new(ruby).parse
57
+ # find the form nodes and send to a specialized function
58
+ forms = []
59
+ walk_tree(parse_tree) do |node|
60
+ if (node.kind_of?(RedParse::CallNode) && (node.name =~ /form_/) && (node.block))
61
+ forms << walk_form(node)
62
+ end
63
+ end
64
+ forms
65
+ rescue
66
+ puts "ERROR: Unable to parse ruby. - #{$!.message}"
67
+ puts ruby
68
+ []
69
+ end
70
+ end
71
+
72
+ def approximate_html
73
+ html = read().gsub(RUBY_REGEX) do |match|
74
+ handle_render(match)
75
+ end
76
+ html
77
+ end
78
+
79
+ def handle_render(ruby)
80
+ # remove the surrounding ruby indicators
81
+ result = ruby
82
+ ruby = ruby.stratagem_strip_erb
83
+ if (ruby =~ /^render/)
84
+ # load into parse tree
85
+
86
+ parse_tree = RedParse.new(ruby).parse
87
+
88
+ parse_tree.walk {|parent,i,subi,node|
89
+ case node
90
+ when RedParse::CallNode #... do something with method calls
91
+ params = node.params.first # render always takes a hash
92
+ render_path = nil
93
+ passed_vars = {}
94
+ if (params.kind_of?(RedParse::StringNode))
95
+ render_path = params.first.to_s
96
+ else
97
+ render_path = params.get(:partial).first.split('/')
98
+ object = params.get(:object).name if params.get(:object)
99
+
100
+ locals = params.get(:locals)
101
+ render_path.last.gsub!(/^/, '_')
102
+ render_path = render_path.join('/')
103
+ end
104
+
105
+ full_path = nil
106
+ if (render_path =~ /\//)
107
+ full_path = File.join(RAILS_ROOT, 'app', 'views', render_path+"."+extension)
108
+ else
109
+ full_path = File.join(directory, render_path+"."+extension)
110
+ end
111
+
112
+ begin
113
+ result = File.read(full_path)
114
+ rescue
115
+ puts "ERROR: #{full_path} not found"
116
+ end
117
+ end
118
+ }
119
+ end
120
+ result
121
+ end
122
+
123
+ private
124
+
125
+ def walk_tree(tree)
126
+ tree.walk {|parent,i,subi,node|
127
+ yield node
128
+ case node
129
+ when RedParse::SequenceNode
130
+ node.each {|child|
131
+ walk_tree(child) { yield }
132
+ }
133
+ end
134
+ }
135
+ end
136
+
137
+ def walk_form(form_node)
138
+ form = Form.new(nil)
139
+
140
+ form_node.block.each {|node|
141
+ case node
142
+ when RedParse::CallNode
143
+ RAILS_FORM_FIELDS.each {|field_name|
144
+ if (node.name.include?(field_name) && node.params)
145
+ param = node.params.first
146
+ value = param.methods_include?(:val) ? param.val : param.to_s
147
+ form.add_field(value, node.name)
148
+ break
149
+ end
150
+ }
151
+ end
152
+ }
153
+ form
154
+ end
155
+ end
156
+
157
+ class Form
158
+ attr_reader :fields
159
+
160
+ def initialize(model)
161
+ @fields = []
162
+ end
163
+
164
+ def add_field(name, type)
165
+ @fields << FormField.new(name, type)
166
+ end
167
+
168
+ def export
169
+ {:model => @model, :fields => @fields.map {|f| f.export } }
170
+ end
171
+ end
172
+
173
+ class FormField
174
+ attr_reader :name, :field_type
175
+
176
+ def initialize(name, field_type)
177
+ @name = name
178
+ @field_type = field_type
179
+ end
180
+
181
+ def export
182
+ {:name => @name, :field_type => @field_type }
183
+ end
184
+ end
185
+ end
186
+
@@ -0,0 +1,61 @@
1
+ module Stratagem::Model
2
+ module ParseUtil
3
+ RUBY_REGEX = /\<\%(.*?\%)\>/m
4
+ RUBY_OUTPUT_REGEX = /\<\%\=(.*?\%)\>/m
5
+
6
+ def self.find_classes(parse_tree)
7
+ class_names = qualified_class_name(parse_tree)
8
+ class_names.map {|name|
9
+ clazz = Kernel
10
+ begin
11
+ name.split('::').each {|part| clazz = clazz.const_get(part) }
12
+ clazz
13
+ rescue
14
+ $!
15
+ end
16
+ }
17
+ end
18
+
19
+ # assumes a single class in the tree
20
+ # will return the qualified class name (modules + class)
21
+ def self.qualified_class_name(parse_tree)
22
+ qualified_names = []
23
+ path = []
24
+ parse_tree.walk {|parent,i,subi,node|
25
+ path.pop while (path.include?(parent) && (path.last != parent))
26
+ path << parent unless path.last == parent
27
+ qualified_names << (path.clone << node) if node.kind_of?(RedParse::ClassNode)
28
+ true
29
+ }
30
+
31
+ qualified_names.map! {|qualified_name|
32
+ qualified_name.select {|node| node.kind_of?(RedParse::ModuleNode) || node.kind_of?(RedParse::ClassNode)}.map {|node|
33
+ begin
34
+ node.name.ident
35
+ rescue
36
+ node.name
37
+ end
38
+ }.join('::')
39
+ }
40
+ qualified_names
41
+ end
42
+
43
+ def ruby_output_blocks(view_erb)
44
+ view_erb.scan(RUBY_OUTPUT_REGEX).flatten.map {|line|
45
+ line.strip.gsub(/^\=\s*/, '').gsub(/\%$/, '').gsub(/\-$/, '')
46
+ }
47
+ end
48
+
49
+ def ruby_blocks(view_erb)
50
+ view_erb.scan(RUBY_REGEX).flatten.map {|line|
51
+ line.strip.gsub(/^\=\s*/, '').gsub(/\%$/, '').gsub(/\-$/, '')
52
+ }
53
+ end
54
+
55
+ def gsub_ruby_blocks(view_erb)
56
+ view_erb.gsub(RUBY_REGEX) {|ruby|
57
+ yield ruby
58
+ }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,12 @@
1
+ module Stratagem::Model
2
+ end
3
+
4
+ require 'stratagem/model/application'
5
+ require 'stratagem/model/parse_util'
6
+ require 'stratagem/model/components/base'
7
+ require 'stratagem/model/components/reference'
8
+ require 'stratagem/model/components/model'
9
+ require 'stratagem/model/components/view'
10
+ require 'stratagem/model/components/controller'
11
+ require 'stratagem/model/components/route'
12
+ require 'stratagem/model/components/static_file'
@@ -0,0 +1,146 @@
1
+ module Stratagem
2
+ class ModelBuilder
3
+ attr_reader :parsed_models, :parsed_controllers, :aquifer
4
+
5
+ def initialize
6
+ @model = Stratagem::Model::Application.instance
7
+ @aquifer = Stratagem::AutoMock::Aquifer.init(@model)
8
+ end
9
+
10
+ def run
11
+ load_plugins
12
+ load_public
13
+ load_template_paths
14
+ load_routes
15
+ load_models
16
+
17
+ print_errors
18
+
19
+ @aquifer.fill
20
+ @model
21
+ end
22
+
23
+ def log(msg)
24
+ Stratagem.logger.debug msg
25
+ end
26
+
27
+ def print_errors
28
+ @model.routes.invalid.each {|route|
29
+ puts "route: #{route.route.to_s} is invalid"
30
+ }
31
+
32
+ @model.controllers.missing.each {|controller, routes|
33
+ puts "controller: #{controller}, with #{routes.size} routes is missing"
34
+ }
35
+ end
36
+
37
+ def load_plugins()
38
+ loader = Rails::Plugin::Loader.new(Rails::Initializer.new(Rails::Configuration.new))
39
+ loader.load_plugins
40
+ @model.plugins << loader.initializer.loaded_plugins
41
+ end
42
+
43
+ def load_models()
44
+ # load files into classes
45
+ log "loading models"
46
+ root = File.join(RAILS_ROOT, 'app','models')
47
+ load_files(File.join(root)).map {|model|
48
+ models = Stratagem::Model::Component::Model.load_all(File.join(root, model))
49
+ models.each do |c|
50
+ log "\t#{c.klass.name} loaded from #{model}"
51
+
52
+ references = []
53
+ @model.controllers.each do |controller|
54
+ references += controller.modifies(c)
55
+ end
56
+ log "\t\t#{references.size} references from controllers"
57
+ c.model_referenced_by = references
58
+ end
59
+ @model.models << models
60
+ }
61
+ log ""
62
+ end
63
+
64
+ def load_public
65
+ log "loading static files"
66
+ Dir[File.join(RAILS_ROOT, 'public', '**', '*.html')].each {|static|
67
+ static.gsub!(RAILS_ROOT, '').gsub!(/^\/public\//, '')
68
+ @model.static_files << Stratagem::Model::Component::StaticFile.new(static)
69
+ log "\t#{static}"
70
+ }
71
+ log ""
72
+ end
73
+
74
+ def load_template_paths
75
+ log "loading templates"
76
+ root = File.join(RAILS_ROOT, 'app','views')
77
+ load_files(root).map {|template|
78
+ @model.views << Stratagem::Model::Component::View.new(template)
79
+ log "\t#{template}"
80
+ }
81
+ log ""
82
+ end
83
+
84
+ def load_routes
85
+ log 'loading routes'
86
+ root = File.join(RAILS_ROOT, 'app','controllers')
87
+ ActionController::Routing::Routes.routes.each {|route|
88
+ route_container = Stratagem::Model::Component::Route.new(route)
89
+ @model.routes << route_container
90
+ begin
91
+ filename = File.join(root, "#{route.parameter_shell[:controller]}_controller.rb")
92
+
93
+ controllers = @model.controllers.select {|c| c.path == filename }
94
+ unless controllers.size > 0
95
+ controllers = Stratagem::Model::Component::Controller.load_all(filename)
96
+ puts "loading controllers from #{filename} -> controllers #{controllers.map {|c| c.klass.name }.inspect}"
97
+ @model.controllers << controllers
98
+ end
99
+
100
+ controller_name = route.parameter_shell[:controller].gsub('/','::').split('::').map {|part| part.camelcase }.join('::')
101
+ controller_name << 'Controller'
102
+ controller_class = controllers.find {|controller| controller.klass.name == controller_name }
103
+ controller_object = controller_class ? controller_class.klass.new : nil
104
+ controller_action = route.parameter_shell[:action].to_sym
105
+
106
+ if (controller_object) && (controller_object.methods_include?(controller_action))
107
+ controllers.each do |controller|
108
+ controller.add_routable_action(controller_action, route.conditions[:method] || :get)
109
+ end
110
+ else
111
+ # if the controller does not contain the indicated method
112
+ # then check for a template that may be rendered anyway
113
+ log "\tinvalid route #{route.to_s}"
114
+ unless @model.views.find {|v| v.render_path == "#{route.parameter_shell[:controller]}/#{controller_action}" }
115
+ # route is invalid
116
+ @model.routes.invalid << Stratagem::Model::Component::Route.new(route)
117
+ log "\tinvalid route #{route.to_s}"
118
+ end
119
+ end
120
+
121
+ rescue Errno::ENOENT
122
+ @model.routes.invalid << Stratagem::Model::Component::Route.new(route)
123
+ rescue MissingSourceFile
124
+ @model.routes.invalid << Stratagem::Model::Component::Route.new(route)
125
+ end
126
+ }
127
+ log ""
128
+ end
129
+
130
+ def load_files(base_dir,path=[],file_list=[])
131
+ dir = File.join(base_dir, *path)
132
+ files = Dir.new(dir).entries
133
+ files.each do |file|
134
+ next if file =~ /^\./
135
+
136
+ if (File.directory?(File.join(dir, file)))
137
+ load_files(base_dir, path + [file], file_list)
138
+ else
139
+ file_path = File.join(path, file)
140
+ file_list << file_path
141
+ end
142
+ end
143
+ file_list
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,30 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :stratagem do
3
+
4
+ desc "Analyzes your server environments for correct configuration and gem versions."
5
+ task :default do
6
+ servers = find_servers_for_task(current_task)
7
+ servers.each do |server|
8
+ puts "listing gems on #{server.host}"
9
+ run "gem list", :hosts => server do |ch, stream, data|
10
+ if stream == :err
11
+ logger.fatal "ERROR listing gems #{data}"
12
+ else # stream == :out
13
+ gems = {}
14
+ data.split("\n").each do |line|
15
+ line =~ /(.*)\s\((.*)\)/
16
+ name = $1
17
+ versions = $2.split(', ')
18
+ gems[name] = versions
19
+ end
20
+ end
21
+ end
22
+ end
23
+ # variables.each do |k,v| p k; end
24
+ # run "echo 'hi'"
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
@@ -0,0 +1,43 @@
1
+ require 'uri'
2
+
3
+ # Stratagem::Scan::Checks::SecureDeploy
4
+ module Stratagem::Scan::Checks::Capistrano
5
+ class SecureDeploy < Stratagem::Scan::Checks::Base
6
+ SECURE_PROTOCOLS = ['https']
7
+
8
+ def run
9
+ begin
10
+ gem 'capistrano'
11
+ require 'capistrano/configuration'
12
+
13
+ begin
14
+ config = Capistrano::Configuration.new
15
+ config.load "config/deploy"
16
+
17
+ vars = config.variables
18
+ repository_url = vars[:repository]
19
+ if (repository_url)
20
+ uri = URI::parse(repository_url)
21
+ unless (SECURE_PROTOCOLS.include?(uri.scheme.downcase))
22
+ result(
23
+ :concern_type => :best_practice,
24
+ :unique => 'repository_url',
25
+ :component => nil,
26
+ :payload => repository_url)
27
+ end
28
+ else
29
+ puts "Unable to locate Capistrano repository in deploy script"
30
+ end
31
+ rescue ArgumentError
32
+ puts "Capistrano deploy script could not be loaded. - #{$!.message}"
33
+ rescue LoadError
34
+ puts "Capistrano deploy script not found. - #{$!.message}"
35
+ puts $!.class.name
36
+ end
37
+ rescue Gem::LoadError
38
+ puts "ERROR: Unable to load Capistrano"
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ # Stratagem::Scan::Checks::EmailAddress
2
+
3
+ module Stratagem::Scan::Checks
4
+ class EmailAddress < Base
5
+ include ViewBase
6
+
7
+ Scanner = Regexp.compile(/\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/)
8
+
9
+ def scan(view)
10
+ view.scan(Scanner).uniq.each do |email|
11
+ result(:concern_type => :warning, :unique => email, :payload => email)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # Stratagem::Scan::Checks::ErrorPages
2
+
3
+ module Stratagem::Scan::Checks
4
+ class ErrorPages < Base
5
+ include ViewBase
6
+
7
+ Strings = {
8
+ 404 => ['The page you were looking for doesn\'t exist.', 'You may have mistyped the address or the page may have moved.'],
9
+ 500 => ['We\'re sorry, but something went wrong.', 'We\'ve been notified about this issue and we\'ll take a look at it shortly.']
10
+ }
11
+
12
+ def scan(view)
13
+ Strings.each {|type, set|
14
+ matched = true
15
+ set.each {|s|
16
+ unless view.include?(s)
17
+ matched = false
18
+ break
19
+ end
20
+ }
21
+ result(:concern_type => :best_practice, :unique => type, :payload => type) if (matched)
22
+ }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ # note -
2
+ # should render views
3
+ # look at form paths
4
+ # anything that is "password"
5
+ # should be filtered
6
+ # also password, password_confirmation
@@ -0,0 +1,19 @@
1
+ module Stratagem::Scan::Checks::MongoMapper
2
+ class Base < Stratagem::Scan::Checks::Base
3
+ alias_method :parent_result, :result
4
+
5
+ def run
6
+ if (self.class.method_defined?(:scan))
7
+ application_model.models.each {|model|
8
+ log "scanning model #{model.klass.name}"
9
+ scan(model)
10
+ }
11
+ end
12
+ end
13
+
14
+ def result(hash)
15
+ hash[:specialization] = :mongo_mapper
16
+ parent_result(hash)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ # Stratagem::Scan::Checks::MassAssignment
2
+
3
+ module Stratagem::Scan::Checks::MongoMapper
4
+ class ForeignKeysExposed < Base
5
+
6
+ def description
7
+ "analyzes application to find models vulnerable to mass assignment"
8
+ end
9
+
10
+ def scan(model)
11
+ return unless model.methods_include?(:stratagem)
12
+
13
+ # look up the controllers that reference it
14
+ instance = model.klass.new
15
+ assignable_keys = model.model_assignable_attributes & instance.stratagem.foreign_keys
16
+ if (assignable_keys.size > 0)
17
+ references = application_model.controllers.map {|controller| controller.modifies(model) }.flatten.compact
18
+ concern_type = references.size > 0 ? :error : :best_practice
19
+ solution_payload = assignable_keys
20
+ result(
21
+ :concern_type => concern_type,
22
+ :unique => model.klass.name,
23
+ :payload => model.klass.name,
24
+ :component => model,
25
+ :confirmed => false,
26
+ :solution_payload => solution_payload
27
+ )
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ # Stratagem::Scan::Checks::EmailAddress
2
+
3
+ module Stratagem::Scan::Checks
4
+ class Routes < Base
5
+ def run
6
+ application_model.routes.invalid.each {|route|
7
+ payload = {
8
+ :path => route.route.segments.inject("") { |str,s| str << s.to_s },
9
+ :method => route.route.conditions[:method],
10
+ :requirements => route.route.requirements
11
+ }
12
+ result :concern_type => :best_practice, :unique => payload.inspect, :payload => payload
13
+ }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # Stratagem::Scan::Checks::EmailAddress
2
+
3
+ module Stratagem::Scan::Checks::Ssl
4
+ class SecureLoginPage < Stratagem::Scan::Checks::Base
5
+ def run
6
+ auth = application_model.crawler.authentication
7
+ if (auth.success && !auth.login_page.response.request.ssl?)
8
+
9
+ route = application_model.routes.recognize(auth.login_page)
10
+ payload = {
11
+ :path => auth.login_page.response.request.path,
12
+ :method => auth.login_page.response.request.method,
13
+ :action => route.action
14
+ }
15
+ result :concern_type => :error, :unique => :secure_login_page, :component => route.controller, :payload => payload
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # Stratagem::Scan::Checks::EmailAddress
2
+
3
+ module Stratagem::Scan::Checks::Ssl
4
+ class SecureLoginSubmit < Stratagem::Scan::Checks::Base
5
+ def run
6
+ auth = application_model.crawler.authentication
7
+ if (auth.success && !auth.ssl)
8
+ route = application_model.routes.recognize(auth.response_page)
9
+ payload = {
10
+ :path => auth.response_page.response.request.path,
11
+ :method => auth.response_page.response.request.method,
12
+ :action => route.action
13
+ }
14
+ result :concern_type => :error, :unique => :secure_login_submit, :component => route.controller, :payload => payload
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ # Stratagem::Scan::Result
2
+
3
+ module Stratagem::Scan
4
+ # Each security check emits 1 or more result objects based on its findings
5
+ # Payload is an arbitrary piece of data that the check produces. It must be able to be encoded to JSON
6
+ # Unique is a value that identifies the check result within the namespace of the check
7
+ class Result
8
+ attr_accessor :unique, :check, :component, :payload, :line_number, :code, :passed, :concern_type, :confirmed, :solution_payload, :specialization
9
+
10
+ # passed = true / false
11
+ def initialize(args)
12
+ args.each {|key,value| self.send("#{key}=", value) }
13
+ end
14
+
15
+ def export
16
+ h = {
17
+ :guid => guid,
18
+ :check_name => check_name,
19
+ :specialization => specialization,
20
+ :component => component_name,
21
+ :payload => payload,
22
+ :line_number => line_number,
23
+ :code => code,
24
+ :concern_type => concern_type,
25
+ :confirmed => confirmed || false,
26
+ :solution_payload => solution_payload
27
+ }
28
+ h[:path] = component.path.gsub(RAILS_ROOT+'/', '') if component
29
+ h
30
+ end
31
+
32
+ def component_name
33
+ component ? component.name : nil
34
+ end
35
+
36
+ def check_name
37
+ check ? check.name : nil
38
+ end
39
+
40
+ def guid
41
+ "#{check_name.underscore}:#{(component_name || '').underscore}:#{unique.to_s.underscore}"
42
+ end
43
+ end
44
+ end
45
+