rack-auth 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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/Rakefile +2 -0
- data/lib/rack/auth.rb +66 -0
- data/rack-auth.gemspec +22 -0
- data/spec/auth_spec.rb +37 -0
- data/spec/spec_helper.rb +34 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3636f14f64b0dcc8e9fa7b8b54a8f0f93cf4b0f6
|
4
|
+
data.tar.gz: dde899f25266ea6610350ab71bae36b6f272cee3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d05cddb7cb85bbfc9b74e1c05a280ac62952707d682279097af1c07a3447f53d6dd5fd3ac844fe9fb91a081f1fcb7fc4f38afc74f6c67e65138c1633c333a717
|
7
|
+
data.tar.gz: a6ca077e40c9ef7029f556c82e8f117b9c0786676a671bf2514fd1959b00c2ff0a50b58a5aecb7768b97dfb59a5d50999c5d0f366beeeddbcca5cdcb21471b17
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nathaniel Symer
|
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,84 @@
|
|
1
|
+
# Rack::Auth
|
2
|
+
|
3
|
+
Rackish authentication for Rack apps.
|
4
|
+
|
5
|
+
## Why
|
6
|
+
|
7
|
+
There is no simple authentication gem in existence. Current ones implement more than what's required, provide poor access to basic auth data, and have too many dependencies.
|
8
|
+
|
9
|
+
While I say this general thing about most software, it rings true for this gem. `rack-auth` provides a simple addition to `Rack::Request` that handles reading the `Authorization` header. Nothing more. `rack-auth` doesn't try to handle persistence, token generation, nor token granting.
|
10
|
+
|
11
|
+
`rack/auth` also beats its competitors on amount of code. There's ~60 SLOC in `rack/auth` and closer to 500 for other gems.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
`rack-auth` uses token handlers to allow a developer to write their own token lookup code.
|
16
|
+
|
17
|
+
Token handlers are **optional**, **defined by token type** and **return a hash** containing auth information:
|
18
|
+
|
19
|
+
# If a handler is not given
|
20
|
+
# Rack::Request#auth will return client-provided
|
21
|
+
# auth data in a hash
|
22
|
+
|
23
|
+
Rack::Request::AuthHandlers.bearer do |token|
|
24
|
+
# Look up `token`
|
25
|
+
end
|
26
|
+
|
27
|
+
Rack::Request::AuthHandlers.mac do |token|
|
28
|
+
# Look up `token`
|
29
|
+
end
|
30
|
+
|
31
|
+
# You probably don't need this handler.
|
32
|
+
Rack::Request::AuthHandlers.basic do |username, password|
|
33
|
+
# Look up username and password
|
34
|
+
end
|
35
|
+
|
36
|
+
You can put handlers *anywhere*, as long as the class variable is assigned before `Rack::Request#auth` is called. I'd put them inside a class definition like below. (You should put it anywhere global/semi-global)
|
37
|
+
|
38
|
+
class MyApp
|
39
|
+
### put handlers here
|
40
|
+
|
41
|
+
def call env
|
42
|
+
[200, {}, ["Hello world!"]]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Then you can access auth information on each `Rack::Request`:
|
47
|
+
|
48
|
+
r = Rack::Request.new env
|
49
|
+
r.auth # gets auth from `authenticator` block
|
50
|
+
r.authenticated! # raises TokenPresenceError if auth is nil (invalid)
|
51
|
+
r.authenticated?
|
52
|
+
|
53
|
+
`rack-auth` throws errors:
|
54
|
+
|
55
|
+
* `Rack::TokenPresenceError` - The request is unauthorized.
|
56
|
+
* `Rack::TokenValidityError` - The authorization is bad.
|
57
|
+
|
58
|
+
You can catch them and/or use things like Sansom's `Sansomable#error` method or Sinatra's error catching contraption
|
59
|
+
|
60
|
+
## Installation
|
61
|
+
|
62
|
+
Add this line to your application's Gemfile:
|
63
|
+
|
64
|
+
gem 'rack-auth'
|
65
|
+
|
66
|
+
And then execute:
|
67
|
+
|
68
|
+
$ bundle
|
69
|
+
|
70
|
+
Or install it yourself as:
|
71
|
+
|
72
|
+
$ gem install rack-auth
|
73
|
+
|
74
|
+
## Usage
|
75
|
+
|
76
|
+
TODO: Write usage instructions here
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
1. Fork it ( https://github.com/sansomrb/rack-auth/fork )
|
81
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
82
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
83
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
84
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/rack/auth.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
TokenPresenceError = Class.new StandardError
|
8
|
+
TokenValidityError = Class.new StandardError
|
9
|
+
class Request
|
10
|
+
class AuthHandlers
|
11
|
+
TOKENS = [:basic, :bearer, :mac].freeze
|
12
|
+
NIL_BLOCK = lambda { |*_| nil }.freeze
|
13
|
+
|
14
|
+
def self.blocks
|
15
|
+
@@blocks ||= nil
|
16
|
+
@@blocks = {} if @@blocks.nil?
|
17
|
+
@@blocks
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.method_missing meth, *args, &block
|
21
|
+
super unless TOKENS.include? meth
|
22
|
+
blocks[meth] = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.[] type
|
26
|
+
return NIL_BLOCK unless TOKENS.include? type
|
27
|
+
blocks[type] || NIL_BLOCK
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.reset!
|
31
|
+
blocks.clear
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.delete! type
|
35
|
+
blocks.delete type
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def auth
|
40
|
+
return @auth if @auth
|
41
|
+
return nil if @env["HTTP_AUTHORIZATION"].to_s.empty?
|
42
|
+
|
43
|
+
type, token = @env["HTTP_AUTHORIZATION"].split(" ", 2).map(&:strip)
|
44
|
+
type = type.strip.downcase.to_sym
|
45
|
+
|
46
|
+
raise TokenValidityError, "Invalid token type." unless AuthHandlers::TOKENS.include? type
|
47
|
+
raise TokenValidityError, "Authorization data cannot have a zero length." if token.empty?
|
48
|
+
|
49
|
+
args = case type
|
50
|
+
when :bearer, :mac then { "token" => token }
|
51
|
+
when :basic then Hash[["username","password"].zip(Base64.decode64(token).split(":"))]
|
52
|
+
end
|
53
|
+
|
54
|
+
@auth ||= AuthHandlers[type].call(*args.values) || args
|
55
|
+
end
|
56
|
+
|
57
|
+
def authenticated?
|
58
|
+
!auth.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
def authenticated!
|
62
|
+
raise TokenPresenceError, "No valid token provided." if auth.nil?
|
63
|
+
auth
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/rack-auth.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "rack-auth"
|
7
|
+
spec.version = "0.0.1"
|
8
|
+
spec.authors = ["Nathaniel Symer"]
|
9
|
+
spec.email = ["nate@natesymer.com"]
|
10
|
+
spec.summary = "Rackish authentication for Rack apps."
|
11
|
+
spec.description = spec.summary + " " + "Provides access to the `Authorization` HTTP header."
|
12
|
+
spec.homepage = "https://github.com/sansomrb/rack-auth"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
end
|
data/spec/auth_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "./spec_helper.rb"
|
4
|
+
|
5
|
+
describe Rack::Request do
|
6
|
+
context "when reading auth information" do
|
7
|
+
context "with a handler" do
|
8
|
+
it "reads basic auth headers" do
|
9
|
+
Rack::Request::AuthHandlers.basic { |username, password| { "this" => "that" } }
|
10
|
+
expect(@basic.authenticated?).to be_truthy
|
11
|
+
expect(@basic.auth).to_not be_empty
|
12
|
+
expect(@basic.auth["this"]).to eq("that")
|
13
|
+
Rack::Request::AuthHandlers.delete! :basic
|
14
|
+
end
|
15
|
+
|
16
|
+
it "reads OAuth 2 (bearer) auth headers" do
|
17
|
+
Rack::Request::AuthHandlers.bearer { |token| { "this" => "that" } }
|
18
|
+
expect(@bearer.authenticated?).to be_truthy
|
19
|
+
expect(@bearer.auth).to_not be_empty
|
20
|
+
expect(@bearer.auth["this"]).to eq("that")
|
21
|
+
Rack::Request::AuthHandlers.delete! :bearer
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "without a handler" do
|
26
|
+
it "reads basic auth headers" do
|
27
|
+
expect(@basic.authenticated?).to be_truthy
|
28
|
+
expect(@basic.auth).to_not be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it "reads OAuth 2 (bearer) auth headers" do
|
32
|
+
expect(@bearer.authenticated?).to be_truthy
|
33
|
+
expect(@bearer.auth).to_not be_empty
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rspec"
|
4
|
+
|
5
|
+
module Setup
|
6
|
+
require_relative File.dirname(File.dirname(__FILE__)) + "/lib/rack/auth.rb"
|
7
|
+
require "rack"
|
8
|
+
require "stringio"
|
9
|
+
|
10
|
+
def auth_env auth_str
|
11
|
+
@env = {
|
12
|
+
"HTTP_AUTHORIZATION" => auth_str,
|
13
|
+
"CONTENT_TYPE" => "text/plain",
|
14
|
+
"QUERY_STRING" => "",
|
15
|
+
"REQUEST_METHOD" => "GET",
|
16
|
+
"REQUEST_PATH" => "/",
|
17
|
+
"REQUEST_URI" => "/",
|
18
|
+
"HTTP_HOST" => "localhost:2000",
|
19
|
+
"SERVER_NAME" => "localhost",
|
20
|
+
"SERVER_PORT" => "2000",
|
21
|
+
"PATH_INFO" => "/",
|
22
|
+
"rack.url_scheme" => "http",
|
23
|
+
"rack.input" => StringIO.new
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |c|
|
29
|
+
c.include Setup
|
30
|
+
c.before :each do
|
31
|
+
@basic = Rack::Request.new auth_env("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")
|
32
|
+
@bearer = Rack::Request.new auth_env("Bearer d6503c9fdd3ee788cd749eee130f0927")
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathaniel Symer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-10 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: '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
|
+
description: Rackish authentication for Rack apps. Provides access to the `Authorization`
|
42
|
+
HTTP header.
|
43
|
+
email:
|
44
|
+
- nate@natesymer.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- ".rspec"
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- lib/rack/auth.rb
|
56
|
+
- rack-auth.gemspec
|
57
|
+
- spec/auth_spec.rb
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
homepage: https://github.com/sansomrb/rack-auth
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.2.2
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Rackish authentication for Rack apps.
|
83
|
+
test_files:
|
84
|
+
- spec/auth_spec.rb
|
85
|
+
- spec/spec_helper.rb
|