auth_scope 0.0.1

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: 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: