wonk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 92f29786fc9cbfa1480097fac4e051b309b5ddbb
4
+ data.tar.gz: 04cf619c2d64501f71bdbf26cd595b5bed2884e9
5
+ SHA512:
6
+ metadata.gz: 0d3504ee7182a04fb77d7d30c2ef3b10bcbe0507bb577cfe0d00bf3b20107a9078dcd3bc3b6a4328828b46ec45a7e9d6040622911fee10c0c0ad0d2bdf45978e
7
+ data.tar.gz: 2ceda66d909dbf09bbc025a0ca2d5e2028e34634d3c390e2ceb84932841d3567c2ff49dc422784337ed0b6a30c5df48bf8c6b2b8012aa0308b8d5b692ca465af
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.12.5
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at ed@edropple.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wonk.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Ed Ropple
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Wonk
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/wonk`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'wonk'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install wonk
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/wonk. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "wonk"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/wonk.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "wonk/version"
2
+
3
+ require 'ice_nine'
4
+ require 'active_support'
5
+ require 'active_support/core_ext'
6
+
7
+ require 'logger'
8
+
9
+ module Wonk
10
+ mattr_accessor :logger
11
+ @logger = Logger.new($stderr)
12
+
13
+ mattr_accessor :aws_region
14
+ end
15
+
16
+ Dir["#{__dir__}/**/*.rb"] \
17
+ .each { |f| require_relative f }
18
+
@@ -0,0 +1,46 @@
1
+ module Wonk
2
+ class Concretizer
3
+ CAPTURE_REGEXP = /!<(?<directive>.*?)>/
4
+
5
+ class DirectiveEvaluator
6
+ attr_reader :env
7
+
8
+ def initialize(env)
9
+ @env = env
10
+ end
11
+
12
+ def evaluate(directive)
13
+ instance_eval directive
14
+ end
15
+ end
16
+
17
+ def concretize(text, env)
18
+ raise "'text' must be a String." unless text.is_a?(String)
19
+ raise "'env' must be a Hash." unless env.is_a?(Hash)
20
+
21
+ env = env.deep_dup.deep_symbolize_keys
22
+
23
+ working = []
24
+ until(working[-2] == "" && working[-1] == "") do
25
+ if (working.size == 0)
26
+ working = text.partition(CAPTURE_REGEXP)
27
+ else
28
+ working[-1] = working[-1].partition(CAPTURE_REGEXP)
29
+ working = working.flatten
30
+ end
31
+ end
32
+ working.reject! { |t| t.empty? }
33
+
34
+ evaluator = DirectiveEvaluator.new(env)
35
+
36
+ working.map do |token|
37
+ match = CAPTURE_REGEXP.match(token)
38
+ if match.nil?
39
+ token
40
+ else
41
+ evaluator.evaluate(match['directive'])
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/wonk/error.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Wonk
2
+ class Error < StandardError; end
3
+ end
@@ -0,0 +1,91 @@
1
+ require 'wonk/policy_validators/validator'
2
+ require 'wonk/policy_validators/aws_ec2_validator'
3
+ require 'wonk/policy_validators/username_password_validator'
4
+
5
+ require 'wonk/policy_result'
6
+
7
+ module Wonk
8
+ class Policy
9
+ VALIDATORS = {
10
+ 'username-password' => Wonk::PolicyValidators::UsernamePasswordValidator,
11
+ 'aws-ec2' => Wonk::PolicyValidators::AwsEC2Validator
12
+ }
13
+
14
+ attr_reader :validators
15
+ attr_reader :content
16
+
17
+ def initialize(validators:, content:)
18
+ raise "all entries in 'validators' must be of type Wonk::PolicyValidator::Validator" \
19
+ unless validators.all? { |v| v.is_a?(Wonk::PolicyValidators::Validator) }
20
+ raise "'content' must be an Array." unless content.is_a?(Array)
21
+
22
+ @validators = IceNine.deep_freeze(validators.map { |v| v.clone })
23
+ @content = IceNine.deep_freeze(content.map { |r| r.deep_dup })
24
+ end
25
+
26
+ def authenticate_from_submission(submission)
27
+ passed_validators =
28
+ validators.map do |v|
29
+ [ v, v.authenticate_from_submission(submission) ]
30
+ end.select { |vt| vt[1].success? }
31
+
32
+ concretizer = self.class.concretizer_class.new
33
+
34
+ concretized_content =
35
+ content.map do |c|
36
+ # TODO: these should probably be made into a separate class, but marshaling is annoying
37
+ passed_validators.map do |vt|
38
+ validator = vt[0]
39
+ validator_result = vt[1]
40
+
41
+ concretize_recursively(c, concretizer, validator_result.environment)
42
+ end
43
+ end
44
+
45
+ PolicyResult.new(successful: !passed_validators.empty?,
46
+ concretized_content: concretized_content)
47
+ end
48
+
49
+ private
50
+
51
+ def concretize_recursively(value, concretizer, environment)
52
+ if value.is_a?(String)
53
+ concretizer.concretize(value, environment).join('')
54
+ elsif value.respond_to?(:each_pair) # is a hash or hashlike object
55
+ value.map { |k, v| [ k, concretize_recursively(v, concretizer, environment) ] }.to_h
56
+ elsif value.respond_to?(:map)
57
+ value.map { |v| concretize_recursively(v, concretizer, environment) }
58
+ else
59
+ value
60
+ end
61
+ end
62
+
63
+ def self.concretizer_class
64
+ Concretizer
65
+ end
66
+
67
+
68
+ def self.from_hash(name, hash)
69
+ hash = hash.deep_symbolize_keys
70
+ validator_hashes = hash[:validators] || []
71
+ content = hash[:content] || []
72
+
73
+ raise "policy '#{name}' must have at least one validator." \
74
+ unless validator_hashes.is_a?(Array) && !validator_hashes.empty?
75
+ raise "policy '#{name}' must have a 'content' array, even if it's empty." \
76
+ unless content.is_a?(Array)
77
+
78
+
79
+ validators =
80
+ validator_hashes.map do |vh|
81
+ vc = VALIDATORS[vh[:type]]
82
+
83
+ raise "policy '#{name}' has no validator for type '#{vh[:type]}'." if vc.nil?
84
+
85
+ vc.new(vh[:parameters] || {})
86
+ end
87
+
88
+ Policy.new(validators: validators, content: content)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,15 @@
1
+ module Wonk
2
+ class PolicyResult
3
+ attr_reader :concretized_content
4
+
5
+ def initialize(successful:, concretized_content: nil)
6
+ @successful = !!successful
7
+
8
+ @concretized_content = IceNine.deep_freeze((concretized_content || []).deep_dup)
9
+ end
10
+
11
+ def success?
12
+ @successful
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ require 'wonk/policy_validators/aws_ec2/rule'
2
+
3
+ module Wonk
4
+ module PolicyValidators
5
+ module AwsEC2
6
+ class HasRoleWithRule
7
+ attr_reader :name
8
+
9
+ def initialize(parameters)
10
+ @name = Regexp.new(parameters[:name]) if parameters[:name]
11
+
12
+ @iam_rsrc = Aws::IAM::Resource.new(region: Wonk.aws_region)
13
+ end
14
+
15
+ def try_match(instance, identity)
16
+ if instance.iam_instance_profile.nil?
17
+ RuleResult.new(successful: false)
18
+ else
19
+ instance_profile =
20
+ @iam_rsrc.instance_profile(instance.iam_instance_profile.arn.split('/').last)
21
+
22
+ roles = instance_profile.roles
23
+
24
+ match_role = roles.map do |role|
25
+ if @name.nil?
26
+ [ role, true, {} ]
27
+ else
28
+ match = @name.match(role.name)
29
+
30
+ if !match.nil?
31
+ [ role, true, Hash[match.names.zip(match.captures)] ]
32
+ else
33
+ [ role, false, {} ]
34
+ end
35
+ end
36
+ end.find { |rt| rt[1] == true }
37
+
38
+ RuleResult.new(successful: !match_role.nil?,
39
+ captures: match_role[2] || {})
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ require 'wonk/policy_validators/aws_ec2/rule_result'
2
+
3
+ module Wonk
4
+ module PolicyValidators
5
+ module AwsEC2
6
+ class Rule
7
+ def initialize(parameters)
8
+ raise "#{self.class.name} can't be directly initialized."
9
+ end
10
+
11
+ def try_match(instance, identity)
12
+ raise "#{self.class.name}#try_match(instance, identity) must be implemented."
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module Wonk
2
+ module PolicyValidators
3
+ module AwsEC2
4
+ class RuleResult
5
+ attr_reader :captures
6
+
7
+ def initialize(successful:, captures: nil)
8
+ @successful = !!successful
9
+
10
+ @captures = IceNine.deep_freeze((captures || []).deep_dup)
11
+ end
12
+
13
+ def success?
14
+ @successful
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,145 @@
1
+ require 'wonk/policy_validators/validator'
2
+ require 'wonk/policy_validators/aws_ec2/rule'
3
+ require 'wonk/policy_validators/aws_ec2/has_role_with_rule'
4
+
5
+ require 'aws-sdk'
6
+
7
+ module Wonk
8
+ module PolicyValidators
9
+ class AwsEC2Validator < Validator
10
+ AWS_PUBLIC_CERTIFICATE = <<-PKCS.strip_heredoc
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw
13
+ FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD
14
+ VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z
15
+ ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u
16
+ IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl
17
+ cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt/5e
18
+ ih5OO6kK/n1Lzllr7D8ZwtQP8fOEpp5E2ng+D6Ud1Z1gYipr58Kj3nssSNpI6bX3
19
+ VyIQzK7wLclnd/YozqNNmgIyZecN7EglK9ITHJLP+x8FtUpt3QbyYXJdmVMegN6P
20
+ hviYt5JH/nYl4hh3Pa1HJdskgQIVALVJ3ER11+Ko4tP6nwvHwh6+ERYRAoGBAI1j
21
+ k+tkqMVHuAFcvAGKocTgsjJem6/5qomzJuKDmbJNu9Qxw3rAotXau8Qe+MBcJl/U
22
+ hhy1KHVpCGl9fueQ2s6IL0CaO/buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF
23
+ lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE/Gf
24
+ MNmP9CM5eovQOGx5ho8WqD+aTebs+k2tn92BBPqeZqpWRa5P/+jrdKml1qx4llHW
25
+ MXrs3IgIb6+hUIB+S8dz8/mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9+EUAH5mw
26
+ vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw
27
+ 7HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K
28
+ -----END CERTIFICATE-----
29
+ PKCS
30
+
31
+ AWS_GOVCLOUD_CERTIFICATE = <<-PKCS.strip_heredoc
32
+ -----BEGIN CERTIFICATE-----
33
+ MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw
34
+ FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD
35
+ VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z
36
+ ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u
37
+ IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl
38
+ cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt/5e
39
+ ih5OO6kK/n1Lzllr7D8ZwtQP8fOEpp5E2ng+D6Ud1Z1gYipr58Kj3nssSNpI6bX3
40
+ VyIQzK7wLclnd/YozqNNmgIyZecN7EglK9ITHJLP+x8FtUpt3QbyYXJdmVMegN6P
41
+ hviYt5JH/nYl4hh3Pa1HJdskgQIVALVJ3ER11+Ko4tP6nwvHwh6+ERYRAoGBAI1j
42
+ k+tkqMVHuAFcvAGKocTgsjJem6/5qomzJuKDmbJNu9Qxw3rAotXau8Qe+MBcJl/U
43
+ hhy1KHVpCGl9fueQ2s6IL0CaO/buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF
44
+ lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE/Gf
45
+ MNmP9CM5eovQOGx5ho8WqD+aTebs+k2tn92BBPqeZqpWRa5P/+jrdKml1qx4llHW
46
+ MXrs3IgIb6+hUIB+S8dz8/mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9+EUAH5mw
47
+ vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw
48
+ 7HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K
49
+ -----END CERTIFICATE-----
50
+ PKCS
51
+
52
+ RULES_MAP = {
53
+ 'has-role-with' => Wonk::PolicyValidators::AwsEC2::HasRoleWithRule
54
+ }
55
+
56
+ attr_reader :rules
57
+
58
+ def initialize(parameters)
59
+ raise "Wonk.aws_region must be set to use AwsEC2Validator." if Wonk.aws_region.nil?
60
+
61
+ @identity_cert =
62
+ case Wonk.aws_region
63
+ when 'us-gov-west-1'
64
+ AWS_GOVCLOUD_CERTIFICATE
65
+ else
66
+ AWS_PUBLIC_CERTIFICATE
67
+ end
68
+
69
+ @ec2_rsrc = Aws::EC2::Resource.new(region: Wonk.aws_region)
70
+ @iam_rsrc = Aws::IAM::Resource.new(region: Wonk.aws_region)
71
+
72
+ @rules =
73
+ (parameters[:rules] || []).map do |rule_definition|
74
+ rule_class = RULES_MAP[rule_definition[:type]]
75
+
76
+ raise "no rule class for type '#{rule_definition[:type]}'" if rule_class.nil?
77
+
78
+ rule_class.new(rule_definition[:parameters] || {})
79
+ end.freeze
80
+ end
81
+
82
+ def validator_name
83
+ 'aws-ec2'
84
+ end
85
+
86
+ def do_authenticate(submission)
87
+ env = { captures: {} }
88
+
89
+ success =
90
+ [ :document, :signature ].each do |n|
91
+ raise ValidatorError, "'#{n}' is required." unless submission.key?(n)
92
+ end
93
+
94
+ pemmed_signature = <<-PKCS.strip_heredoc
95
+ -----BEGIN PKCS7-----
96
+ #{submission[:signature]}
97
+ -----END PKCS7-----
98
+ PKCS
99
+
100
+ Dir.mktmpdir do |dir|
101
+ cert_path = "#{dir}/cert.pem"
102
+ signature_path = "#{dir}/signature.pem"
103
+ data_path = "#{dir}/data.json"
104
+
105
+ IO.write(cert_path, @identity_cert)
106
+ IO.write(signature_path, pemmed_signature)
107
+ IO.write(data_path, submission[:document])
108
+
109
+ `openssl smime -verify -inform PEM -in '#{signature_path}' -content '#{data_path}' -certfile '#{cert_path}' -noverify > /dev/null 2>&1`
110
+
111
+ if $?.success?
112
+ instance_identity = JSON.parse(submission[:document]).deep_symbolize_keys
113
+
114
+ instance_id = instance_identity[:instanceId]
115
+
116
+ env[:instance_id] = instance_identity[:instanceId]
117
+ env[:account_id] = instance_identity[:accountId]
118
+
119
+ instance = @ec2_rsrc.instance(instance_id)
120
+
121
+ rule_result =
122
+ begin
123
+ @rules.map { |rule| rule.try_match(instance, instance_identity) }.find(&:success?)
124
+ rescue Aws::Errors::MissingCredentialsError => err
125
+ Wonk.logger.error "No AWS credentials found!"
126
+ raise err
127
+ end
128
+
129
+ if !rule_result.nil?
130
+ env[:captures].merge!(rule_result.captures)
131
+
132
+ true
133
+ else
134
+ false
135
+ end
136
+ else
137
+ false
138
+ end
139
+ end
140
+
141
+ ValidatorResult.new(successful: success, environment: env)
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,34 @@
1
+ require 'bcrypt'
2
+
3
+ require 'wonk/policy_validators/validator'
4
+ require 'wonk/policy_validators/validator_result'
5
+
6
+ module Wonk
7
+ module PolicyValidators
8
+ class UsernamePasswordValidator < Validator
9
+ def initialize(parameters)
10
+ [:username, :password_hash].each do |n|
11
+ raise "parameter '#{n}' required for #{self.class.name}" unless parameters.key?(n)
12
+ end
13
+
14
+ @username = parameters[:username]
15
+ @password_hash = BCrypt::Password.new(parameters[:password_hash])
16
+ end
17
+
18
+ def validator_name
19
+ 'username-password'
20
+ end
21
+
22
+ def do_authenticate(submission)
23
+ [ :username, :password ].each do |n|
24
+ raise ValidatorError, "'#{n}' is required." unless submission.key?(n)
25
+ end
26
+
27
+ ValidatorResult.new(
28
+ successful: @username == submission[:username] && @password_hash == submission[:password],
29
+ environment: {}
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ require 'ice_nine'
2
+
3
+ module Wonk
4
+ module PolicyValidators
5
+ class Validator
6
+ def initialize(parameters)
7
+ raise "#{self.class.name} can't be directly initialized."
8
+ end
9
+
10
+ def validator_name
11
+ raise "#{self.class.name}#validator_name must be implemented."
12
+ end
13
+
14
+ def authenticate_from_submission(submission)
15
+ if !submission.key?(:authentication_type)
16
+ ValidatorResult.new(successful: false, environment: {})
17
+ else
18
+ if submission[:authentication_type] == validator_name
19
+ begin
20
+ do_authenticate(submission)
21
+ rescue ValidatorError => err
22
+ Wonk.logger.warn "Validator failed with reason: #{err.message}"
23
+ ValidatorResult.new(successful: false, environment: {})
24
+ rescue StandardError => err
25
+ Wonk.logger.error "Unrecognized error rescued from validator #{self.class.name}: #{err}"
26
+ ValidatorResult.new(successful: false, environment: {})
27
+ end
28
+ else
29
+ ValidatorResult.new(successful: false, environment: {})
30
+ end
31
+ end
32
+ end
33
+
34
+ def do_authenticate(submission)
35
+ raise "#{self.class.name}#do_authenticate(request) must be implemented."
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ require 'wonk/error'
2
+
3
+ module Wonk
4
+ module PolicyValidators
5
+ class ValidatorError < Wonk::Error; end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module Wonk
2
+ module PolicyValidators
3
+ class ValidatorResult
4
+ attr_reader :environment
5
+
6
+ def initialize(successful:, environment:)
7
+ @successful = !!successful
8
+ @environment = environment.deep_dup.deep_symbolize_keys
9
+ raise "environment must be a Hash." unless @environment.is_a?(Hash)
10
+
11
+ @environment[:captures] ||= {}
12
+ end
13
+
14
+ def success?
15
+ @successful
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Wonk
2
+ VERSION = "0.1.0"
3
+ end
data/wonk.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wonk/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wonk"
8
+ spec.version = Wonk::VERSION
9
+ spec.authors = ["Ed Ropple"]
10
+ spec.email = ["ed@edropple.com"]
11
+
12
+ spec.summary = "A policy specification gem."
13
+ spec.homepage = "http://edboxes.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.12"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.0"
24
+
25
+ spec.add_runtime_dependency 'activesupport', '~> 5.0.0'
26
+ spec.add_runtime_dependency 'ice_nine', '~> 0.11.2'
27
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wonk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ed Ropple
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 5.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 5.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: ice_nine
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.11.2
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.11.2
83
+ description:
84
+ email:
85
+ - ed@edropple.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - CODE_OF_CONDUCT.md
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - bin/console
99
+ - bin/setup
100
+ - lib/wonk.rb
101
+ - lib/wonk/concretizer.rb
102
+ - lib/wonk/error.rb
103
+ - lib/wonk/policy.rb
104
+ - lib/wonk/policy_result.rb
105
+ - lib/wonk/policy_validators/aws_ec2/has_role_with_rule.rb
106
+ - lib/wonk/policy_validators/aws_ec2/rule.rb
107
+ - lib/wonk/policy_validators/aws_ec2/rule_result.rb
108
+ - lib/wonk/policy_validators/aws_ec2_validator.rb
109
+ - lib/wonk/policy_validators/username_password_validator.rb
110
+ - lib/wonk/policy_validators/validator.rb
111
+ - lib/wonk/policy_validators/validator_error.rb
112
+ - lib/wonk/policy_validators/validator_result.rb
113
+ - lib/wonk/version.rb
114
+ - wonk.gemspec
115
+ homepage: http://edboxes.com
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.5.1
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: A policy specification gem.
139
+ test_files: []