abstract_auth 0.1.0
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.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +19 -0
- data/LICENSE +21 -0
- data/README.md +110 -0
- data/Rakefile +12 -0
- data/abstract_auth.gemspec +24 -0
- data/lib/abstract_auth/abstract_auth.rb +21 -0
- data/lib/abstract_auth/errors.rb +16 -0
- data/lib/abstract_auth/version.rb +3 -0
- data/lib/abstract_auth.rb +26 -0
- data/test/abstract_auth_test.rb +89 -0
- data/test/test_helper.rb +3 -0
- metadata +112 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
abstract_auth (0.0.1)
|
5
|
+
module_ext (~> 0.1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
module_ext (0.1.0)
|
11
|
+
rake (0.8.7)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
abstract_auth!
|
18
|
+
module_ext (~> 0.1.0)
|
19
|
+
rake (~> 0.8.7)
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 Ryan Cook and Quick Left, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#AbstractAuth
|
2
|
+
|
3
|
+
##A Short Story
|
4
|
+
One day you, Sir Lucius Leftfoot, are hacking your little heart out, and
|
5
|
+
you realize that you're writing the same code over and over again to for
|
6
|
+
your clients. So, you think to yourself, "What if I packaged this up all
|
7
|
+
nice-like and set it free in the world for all the other knightly
|
8
|
+
developers to use in their apps?" Quickly, you realize that you can't go
|
9
|
+
calling...
|
10
|
+
|
11
|
+
current_user.role? :king_of_the_hood
|
12
|
+
|
13
|
+
...all willy-nilly to make sure you're dealing with an administrator of
|
14
|
+
the host application, even though that's the API you're used to using.
|
15
|
+
What's one to do when the authentication procedures of the end-use host
|
16
|
+
application are unknown? Have no fear - AbstractAuth is here to save
|
17
|
+
you!
|
18
|
+
|
19
|
+
##Use Case
|
20
|
+
|
21
|
+
AbstractAuth is for developers creating reusable components (e.g. Rails
|
22
|
+
3 Engine gems) that require authentication information from their host
|
23
|
+
applications. It aims to provide a consistent and configurable API that
|
24
|
+
you, the component creator, can setup and use, which the developer of the
|
25
|
+
host application will need to implement, so that you can properly secure
|
26
|
+
your functionality.
|
27
|
+
|
28
|
+
##How It Works
|
29
|
+
|
30
|
+
AbstractAuth works by allowing the developers implementing your tools to
|
31
|
+
specify code blocks that will be executed to produce the desired
|
32
|
+
response. The blocks are executed when you call them, and in the context
|
33
|
+
in which you call them.
|
34
|
+
|
35
|
+
##Examples
|
36
|
+
|
37
|
+
AbstractAuth will only step in if you instruct it to. Therefore, by
|
38
|
+
default, nothing will happen. Oh, you wanted something to happen? Try
|
39
|
+
this somewhere in a setup area of your app...
|
40
|
+
|
41
|
+
# Your setup code defining the API you expect your users to implement
|
42
|
+
AbstractAuth.setup do |config|
|
43
|
+
config.requires :authenticated_resource
|
44
|
+
end
|
45
|
+
|
46
|
+
Then, when you need it, you should be able to call `AbstractAuth.authenticated_resource`
|
47
|
+
and expect the host application to have provided the code that will
|
48
|
+
return to you the resource object that is currently authenticated (e.g.
|
49
|
+
User). How do you go about making sure a host application complies with
|
50
|
+
your every whim? In a Rails application, for instance, you could
|
51
|
+
instruct them to setup an abstract_auth.rb initializer in `config/initializers`
|
52
|
+
|
53
|
+
# The user's implementation of your desired API
|
54
|
+
AbstractAuth.implement :authenticated_resource do
|
55
|
+
current_user
|
56
|
+
end
|
57
|
+
|
58
|
+
We'll hold on to that fancy block of code and execute it at the right
|
59
|
+
time so that we're returning you exactly what you need.
|
60
|
+
|
61
|
+
Maybe, you want to create a separate login page with access to a
|
62
|
+
super-secret web page. The part of the process that's different here is
|
63
|
+
how you instruct your users to implement the desired functionality.
|
64
|
+
Continuing the Rails application example, say you setup the following
|
65
|
+
in your code...
|
66
|
+
|
67
|
+
# Your setup code defining the API you expect your users to implement
|
68
|
+
AbstractAuth.setup do |config|
|
69
|
+
config.requires :authenticate_resource, :authenticated_resource
|
70
|
+
end
|
71
|
+
|
72
|
+
Thus, a developer might implement the following...
|
73
|
+
|
74
|
+
# The user's implementation of your desired API
|
75
|
+
AbstractAuth.implement :authenticated_resource do
|
76
|
+
|
77
|
+
# A fancy helper method in the host app
|
78
|
+
current_user
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# The user's implementation of your desired API
|
83
|
+
# Note the arguments
|
84
|
+
AbstractAuth.implement :authenticate_resource do |username,password|
|
85
|
+
|
86
|
+
# Your user's custom authentication procedure
|
87
|
+
User.fancy_authenticate(username,password)
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
Assuming everything goes as planned, you would be able to call...
|
92
|
+
|
93
|
+
AbstractAuth.invoke( :authenticate_resource , username , password )
|
94
|
+
|
95
|
+
...to determine whether a resource was authenticated.
|
96
|
+
|
97
|
+
Finally, if you make a call to expected API that the host app has not
|
98
|
+
implemented, an `AbstractAuth::NotImplementedError` will be thrown.
|
99
|
+
|
100
|
+
##Notes
|
101
|
+
|
102
|
+
Remember above, when I said that AbstractAuth will, by default, not
|
103
|
+
intrude on your code unless you set it up to do so? I lied just a
|
104
|
+
little bit. AbstractAuth does require another gem called ModuleExt,
|
105
|
+
which monkey-patches the Module class to add some convenience
|
106
|
+
attributes functions. Don't be mad.
|
107
|
+
|
108
|
+
##License
|
109
|
+
|
110
|
+
MIT. See the LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "abstract_auth/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "abstract_auth"
|
7
|
+
s.version = AbstractAuth::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ryan Cook"]
|
10
|
+
s.email = ["ryan@quickleft.com"]
|
11
|
+
s.homepage = "https://github.com/cookrn/abstract_auth"
|
12
|
+
s.summary = %q{A gem to safely provide external application resources with a coherent and configurable API to a host application's authentication procedures.}
|
13
|
+
s.description = %q{A gem to safely provide external application resources with a coherent and configurable API to a host application's authentication procedures.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "abstract_auth"
|
16
|
+
|
17
|
+
s.add_dependency "module_ext", "~> 0.1.0"
|
18
|
+
s.add_development_dependency "rake", "~> 0.8.7"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AbstractAuth
|
2
|
+
|
3
|
+
def self.requires(*args)
|
4
|
+
args.each do |required_api|
|
5
|
+
raise AbstractAuth::Errors::MalformedRequirementError.new('You must define a requirement with a symbol!') unless required_api.is_a?(Symbol)
|
6
|
+
@@requirements.push required_api
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.implement( requirement , &blk )
|
11
|
+
raise AbstractAuth::Errors::MalformedImplementationError.new('You must define an implementation with a symbol!') unless requirement.is_a?(Symbol)
|
12
|
+
@@implementations.merge!( { requirement => blk } )
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.invoke( method , *args )
|
16
|
+
raise AbstractAuth::Errors::NonRequiredImplementationCallError.new('The requested implementation was not required!') unless @@requirements.include?(method)
|
17
|
+
raise AbstractAuth::Errors::NotImplementedError.new('The requirement was not implemented!') unless @@implementations.has_key?(method)
|
18
|
+
@@implementations[method].call(args)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AbstractAuth
|
2
|
+
|
3
|
+
module Errors
|
4
|
+
|
5
|
+
class MalformedImplementationError < StandardError; end
|
6
|
+
|
7
|
+
class MalformedRequirementError < StandardError; end
|
8
|
+
|
9
|
+
class NonRequiredImplementationCallError < StandardError; end
|
10
|
+
|
11
|
+
class NotImplementedError < StandardError; end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Requires
|
2
|
+
require 'module_ext'
|
3
|
+
|
4
|
+
module AbstractAuth
|
5
|
+
|
6
|
+
# Autoloads
|
7
|
+
autoload :Errors , 'abstract_auth/errors'
|
8
|
+
|
9
|
+
# Requires
|
10
|
+
require 'abstract_auth/abstract_auth'
|
11
|
+
|
12
|
+
# Define our container to hold implemented APIs
|
13
|
+
mattr_accessor :implementations
|
14
|
+
@@implementations = {}
|
15
|
+
|
16
|
+
# Define our container to hold APIs required to be implemented
|
17
|
+
mattr_accessor :requirements
|
18
|
+
@@requirements = []
|
19
|
+
|
20
|
+
# Yield AbstractAuth on setup for fancy configuration
|
21
|
+
def self.setup
|
22
|
+
yield self
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AbstractAuthTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_yields_self_on_setup
|
6
|
+
AbstractAuth.setup do |config|
|
7
|
+
assert_equal AbstractAuth , config
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_only_use_symbols_to_define_requirements
|
12
|
+
assert_raise AbstractAuth::Errors::MalformedRequirementError do
|
13
|
+
AbstractAuth.setup do |config|
|
14
|
+
config.requires "bad_def"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_only_use_symbols_to_define_implementations
|
20
|
+
assert_raise AbstractAuth::Errors::MalformedImplementationError do
|
21
|
+
AbstractAuth.implement "bad_def" do
|
22
|
+
p "don't do this"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_can_add_a_requirement
|
28
|
+
AbstractAuth.setup do |config|
|
29
|
+
config.requires :authenticated_user
|
30
|
+
end
|
31
|
+
assert AbstractAuth.requirements.include? :authenticated_user
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_can_add_multiple_requirements
|
35
|
+
AbstractAuth.setup do |config|
|
36
|
+
config.requires :authenticated_user, :authenticated_admin
|
37
|
+
end
|
38
|
+
assert AbstractAuth.requirements.include? :authenticated_user
|
39
|
+
assert AbstractAuth.requirements.include? :authenticated_admin
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_can_add_implementation
|
43
|
+
AbstractAuth.requires :authenticated_user
|
44
|
+
AbstractAuth.implement :authenticated_user do
|
45
|
+
TestUser.new
|
46
|
+
end
|
47
|
+
assert AbstractAuth.implementations.has_key? :authenticated_user
|
48
|
+
assert AbstractAuth.implementations[:authenticated_user].is_a? Proc
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_cannot_call_non_required_methods
|
52
|
+
assert_raise AbstractAuth::Errors::NonRequiredImplementationCallError do
|
53
|
+
AbstractAuth.invoke :not_required_method
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_cannot_call_non_implemented_methods
|
58
|
+
assert_raise AbstractAuth::Errors::NotImplementedError do
|
59
|
+
AbstractAuth.requires :a_sample_method
|
60
|
+
AbstractAuth.invoke :a_sample_method
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_can_invoke_requirement
|
65
|
+
AbstractAuth.requires :authenticate_user
|
66
|
+
AbstractAuth.implement :authenticate_user do |user_id,password|
|
67
|
+
return TestUser.new(user_id,password)
|
68
|
+
end
|
69
|
+
new_user = AbstractAuth.invoke( :authenticate_user , 'ronald' , 'macdonald' )
|
70
|
+
assert new_user.is_a? TestUser
|
71
|
+
assert_equal 'ronald' , new_user.username
|
72
|
+
assert_equal 'macdonald' , new_user.password
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
class TestUser
|
78
|
+
def initialize(username,password)
|
79
|
+
@username = username
|
80
|
+
@password = password
|
81
|
+
end
|
82
|
+
def username
|
83
|
+
@username
|
84
|
+
end
|
85
|
+
def password
|
86
|
+
@password
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: abstract_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ryan Cook
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-11 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: module_ext
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 27
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 1
|
33
|
+
- 0
|
34
|
+
version: 0.1.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 49
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 8
|
49
|
+
- 7
|
50
|
+
version: 0.8.7
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
description: A gem to safely provide external application resources with a coherent and configurable API to a host application's authentication procedures.
|
54
|
+
email:
|
55
|
+
- ryan@quickleft.com
|
56
|
+
executables: []
|
57
|
+
|
58
|
+
extensions: []
|
59
|
+
|
60
|
+
extra_rdoc_files: []
|
61
|
+
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- Gemfile
|
65
|
+
- Gemfile.lock
|
66
|
+
- LICENSE
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- abstract_auth.gemspec
|
70
|
+
- lib/abstract_auth.rb
|
71
|
+
- lib/abstract_auth/abstract_auth.rb
|
72
|
+
- lib/abstract_auth/errors.rb
|
73
|
+
- lib/abstract_auth/version.rb
|
74
|
+
- test/abstract_auth_test.rb
|
75
|
+
- test/test_helper.rb
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: https://github.com/cookrn/abstract_auth
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: abstract_auth
|
106
|
+
rubygems_version: 1.3.7
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: A gem to safely provide external application resources with a coherent and configurable API to a host application's authentication procedures.
|
110
|
+
test_files:
|
111
|
+
- test/abstract_auth_test.rb
|
112
|
+
- test/test_helper.rb
|