auth_scope 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9a769a8c4cd7cce6e3a9b2526a1d5c6f8242b91
4
+ data.tar.gz: 94f0698f3d63887e2612c0c108814329e6979d33
5
+ SHA512:
6
+ metadata.gz: 5ba43d4cc8eb9da44324f7a1f8a17b0d38a6d231e2b415bc437298fa8f3b7db39598b8f1e23e9cffaf62446d1b889ffc7952ba092a07e23dccb63c9142a08410
7
+ data.tar.gz: 96fde064c62572ff4a885ada8b9f8e7af9ec43a404eb189b936bfc9b9294bcee4c1d734b545ed7ec09f428273705e0fc27726c2444061a8b2292bc1bd5d39840
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in auth_scope.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'guard'
8
+ gem 'guard-rspec'
9
+ end
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Michael Bleigh
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # AuthScope
2
+
3
+ AuthScope is a simple library for describing authorization patterns through strings.
4
+ It is intended to work in conjunction with (for example) an OAuth 2.0 API.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'auth_scope'
11
+
12
+ ## Scope Structure
13
+
14
+ Authorization scope strings look something like this:
15
+
16
+ user:email apps:one,another:read profile:*
17
+
18
+ Spaces delimit individual authorization grants and can be treated as
19
+ completely independent of one another. When specified together they are
20
+ considered to authorize additively, meaning that authorization is granted
21
+ if *any* of the provided scopes are matched.
22
+
23
+ The `:` or **namespace** delimiter lets you create generic and specific
24
+ permissions. `user:email` is more specific than `user` for instance.
25
+
26
+ The `,` or **batch** delimiter allows you to apply a scope to multiple
27
+ resouces at the same namespace level. `user:email,avatar` is equivalent
28
+ to asking for a scope of `user:email user:avatar`.
29
+
30
+ The `*` or **wildcard** is used to indicate permissiveness for a single
31
+ namespace. For instance, `user:*` would grant access to `user:email`
32
+ but not `user:email:write`.
33
+
34
+ The `**` or **global wildcard** is used to indicate permissiveness for
35
+ any number of namespaces. `**` would grant access to **everything**, and
36
+ `user:**:write` would grant access to any `write` permissions, even if
37
+ deeply nested.
38
+
39
+ The more namespaces a scope has, the greater permission it authorizes.
40
+ Each segment of a namespace is considered to be granted, so a scope of
41
+ `user:email` grants both `user` and `user:email` scopes.
42
+
43
+ ## Usage
44
+
45
+ In simple terms, you will initialize an AuthScope with a string and query
46
+ its authorization using the `can?` method:
47
+
48
+ ```ruby
49
+ require 'auth_scope'
50
+
51
+ scope = AuthScope.new("user:email apps:foo,bar:*")
52
+
53
+ scope.can? "user:email" # => true
54
+ scope.can? "user:write" # => false
55
+ scope.can? "apps:foo:write" # => true
56
+ ```
57
+
58
+ You may also specify an array of authorization strings. This is treated no
59
+ differently than space delimiting:
60
+
61
+ ```ruby
62
+ scope = AuthScope.new("user:email", "apps:foo,bar:*")
63
+ ```
64
+
65
+ The `any?` method tests a set of potential authorizations to see if any match:
66
+
67
+ ```ruby
68
+ scope = AuthScope.new("admin")
69
+ scope.any? "user:email", "admin" # => true
70
+ ```
71
+
72
+ The `all? method tests that each of a set of authorizations is a match:
73
+
74
+ ```ruby
75
+ scope = AuthScope.new("admin")
76
+ scope.all? "user:email", "admin" # => false
77
+ ```
78
+
79
+ ### Object Scopes
80
+
81
+ It will often be useful for an object to be able to describe its own scope.
82
+ AuthScope will call `to_scope` on passed-in arguments before checking them.
83
+ For example:
84
+
85
+ ```ruby
86
+ class User
87
+ def to_scope
88
+ "user:#{id}"
89
+ end
90
+ end
91
+
92
+ scope = AuthScope.new("user:123:write")
93
+ scope.can? user, "write" # => true
94
+ scope.can? another_user, "write" # => false
95
+ ```
96
+
97
+ ## Contributing
98
+
99
+ 1. Fork it ( https://github.com/divshot/auth_scope/fork )
100
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
101
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
102
+ 4. Push to the branch (`git push origin my-new-feature`)
103
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
6
+ rescue LoadError
7
+ puts "RSpec is not installed, skipping."
8
+ end
9
+
10
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'auth_scope/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "auth_scope"
8
+ spec.version = AuthScope::VERSION
9
+ spec.authors = ["Michael Bleigh"]
10
+ spec.email = ["mbleigh@mbleigh.com"]
11
+ spec.summary = %q{Authorization library using namespaced strings. Great for OAuth 2.0 APIs.}
12
+ spec.description = %q{Authorization library using namespaced strings. Great for OAuth 2.0 APIs.}
13
+ spec.homepage = "https://github.com/divshot/auth_scope"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
data/lib/auth_scope.rb ADDED
@@ -0,0 +1,46 @@
1
+ class AuthScope
2
+ def initialize(*scopes)
3
+ @tree = {}
4
+ scopes.join(" ").split(" ").each{|s| add(s) }
5
+ end
6
+
7
+ def add(scope_string)
8
+ roots = [@tree]
9
+
10
+ scope_string.split(":").each do |parts|
11
+ roots = parts.split(",").map do |part|
12
+ roots.map{|r| r[part.to_s] ||= {}; r[part.to_s]}
13
+ end.flatten
14
+ end
15
+ end
16
+
17
+ def can?(*args)
18
+ subject = subject.respond_to?(:to_scope) ? subject.to_scope : subject.to_s
19
+ parts = args.map{|arg| (arg.respond_to?(:to_scope) ? arg.to_scope : arg.to_s).split(":") }.flatten.map(&:to_s)
20
+ roots = [@tree]
21
+ parts.each do |part|
22
+ return true if roots.detect{|r| r.key?('**')}
23
+ is_last = part == parts.last
24
+ if roots.detect{|r| r.key?('*')}
25
+ roots = roots.map{|r| [r[part], r['*']].compact }.flatten
26
+ else
27
+ return false unless roots.detect{|r| r.key?(part)}
28
+ roots = roots.map{|r| r[part] }.flatten
29
+ end
30
+ end
31
+ true
32
+ end
33
+
34
+ def any?(*scopes)
35
+ scopes = scopes.join(" ").split(" ")
36
+ !!scopes.detect{|scope| can?(scope)}
37
+ end
38
+
39
+ def all?(*scopes)
40
+ scopes = scopes.join(" ").split(" ")
41
+ scopes.each{|scope| return false unless can?(scope) }
42
+ true
43
+ end
44
+ end
45
+
46
+ require "auth_scope/version"
@@ -0,0 +1,3 @@
1
+ class AuthScope
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe AuthScope do
4
+ subject{ AuthScope.new(@scope || "user:email") }
5
+
6
+ describe '#can?' do
7
+ it 'should authorize for any segment of a chain' do
8
+ @scope = "foo:bar:baz"
9
+ should_authorize "foo"
10
+ should_authorize "foo:bar"
11
+ should_authorize "foo:bar:baz"
12
+ end
13
+
14
+ it 'should not work for a non-specified subsegment' do
15
+ @scope = "user:read"
16
+ should_not_authorize "user:write"
17
+ end
18
+
19
+ it 'should not work for a deeper namespace' do
20
+ @scope = "user"
21
+ should_not_authorize "user:write"
22
+ end
23
+
24
+ it 'should work from multiple defined scopes' do
25
+ @scope = "user apps"
26
+ should_authorize "user"
27
+ should_authorize "apps"
28
+ end
29
+
30
+ context 'wildcards' do
31
+ it 'should allow wildcards to represent any scope' do
32
+ @scope = "user:*"
33
+ should_authorize "user:email"
34
+ should_authorize "user:write"
35
+ end
36
+
37
+ it 'should not grant multi-level authorization with wildcards' do
38
+ @scope = "user:*"
39
+ should_not_authorize "user:write:another"
40
+ end
41
+
42
+ it 'should work with lower namespaces and wildcards' do
43
+ @scope = "user:*:write"
44
+ should_authorize "user:bob:write"
45
+ should_authorize "user:frank:write"
46
+ should_not_authorize "user:bob:read"
47
+ end
48
+ end
49
+
50
+ context 'batch delimiter' do
51
+ it 'should work for each specified in the batch' do
52
+ @scope = "user,app:write"
53
+ should_authorize "user:write"
54
+ should_authorize "app:write"
55
+ should_not_authorize "book:write"
56
+ end
57
+
58
+ it 'should work on multiple levels' do
59
+ @scope = "user,app:read,write"
60
+ should_authorize "user:write"
61
+ should_authorize "app:read"
62
+ end
63
+ end
64
+
65
+ context 'global wildcards' do
66
+ it 'should work for any level of specificity' do
67
+ @scope = "user:**"
68
+ should_authorize "user:abc:write:foo"
69
+ end
70
+
71
+ it 'should work as a catch-all if supplied alone' do
72
+ @scope = "**"
73
+ should_authorize "foo:bar:baz"
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#any?' do
79
+ it 'should authorize any of the supplied scopes' do
80
+ @scope = "user:foo:write"
81
+ expect(subject).to be_any('user:foo:write', 'admin')
82
+ end
83
+ end
84
+
85
+ describe '#all?' do
86
+ it 'should authorize only with ALL of the supplied scopes' do
87
+ @scope = "user admin"
88
+ expect(subject).to be_all("user", "admin")
89
+ expect(subject).not_to be_all("user", "bork")
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,24 @@
1
+ require 'auth_scope'
2
+
3
+ module SpecHelpers
4
+ def should_authorize(scope)
5
+ expect(subject).to be_can(scope)
6
+ end
7
+
8
+ def should_not_authorize(scope)
9
+ expect(subject).not_to be_can(scope)
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+
18
+ # Run specs in random order to surface order dependencies. If you find an
19
+ # order dependency and want to debug it, you can fix the order by providing
20
+ # the seed, which is printed after each run.
21
+ # --seed 1234
22
+ config.order = 'random'
23
+ config.include SpecHelpers
24
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auth_scope
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bleigh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '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: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Authorization library using namespaced strings. Great for OAuth 2.0 APIs.
56
+ email:
57
+ - mbleigh@mbleigh.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - Gemfile
65
+ - Guardfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - auth_scope.gemspec
70
+ - lib/auth_scope.rb
71
+ - lib/auth_scope/version.rb
72
+ - spec/auth_scope_spec.rb
73
+ - spec/spec_helper.rb
74
+ homepage: https://github.com/divshot/auth_scope
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.0.14
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Authorization library using namespaced strings. Great for OAuth 2.0 APIs.
98
+ test_files:
99
+ - spec/auth_scope_spec.rb
100
+ - spec/spec_helper.rb
101
+ has_rdoc: