roda-http-auth 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0219bd5bc76baaeaf48e1e31d6a951dca87af4fa906af38c00099b5b8150871c'
4
- data.tar.gz: '0748fa0ac12041e995e2ee96baa02ef433d981c29be9f732eb3b0eb7222a879f'
3
+ metadata.gz: 1ff92568175fbe77129586e375501c1ef08a420b766a6f841d51f46c86c70db6
4
+ data.tar.gz: 893b85397675601e3521ab339a9fd047c76c0d8ebdcaee7e8290bffc6ec62618
5
5
  SHA512:
6
- metadata.gz: c365f2fbbf94606c0995f7b1138f4a566f44e2340d304998132671cbde59974e50fac5fb9ecc4ec54c4e1a53320902c3207f1066c09443bf794eb52311d896f7
7
- data.tar.gz: be1d27037cc49e10b867acdba4ee8d7307cceb7447748fc2625afdec779a1c36a44ef877bac9ab86e6835f15f5c66202f98bba5475e5f660c6c78a2381117c1e
6
+ metadata.gz: 1271d1c2d504363e7db7e067e2510eb4b61a2c544126b15ae5047a5135463e43b7aa35aa29db4377622aefdeea7f7b01ec8be32c1ec198500bbc937d9d98cc9c
7
+ data.tar.gz: cdc56c9d35aca78604ee22731443c5abd375401e324cec44a0d036cad3f576cfeb09ce20ac927771d8cd61dc5bdf4c2d9a96b16282d9949994db0730c688781f
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Roda Http Authorization
2
2
 
3
- [![Build Status](https://travis-ci.org/badosu/roda-basic-auth.png)](https://travis-ci.org/badosu/roda-basic-auth)
3
+ [![Build Status](https://travis-ci.org/badosu/roda-http-auth.png)](https://travis-ci.org/badosu/roda-http-auth)
4
4
 
5
5
  Add http authorization methods to Roda.
6
6
 
@@ -13,49 +13,42 @@ plugin :http_auth
13
13
  ```
14
14
 
15
15
  You can pass global options, in this context they'll be shared between all
16
- `r.http_auth` calls.
16
+ `http_auth` calls.
17
17
 
18
18
  ```ruby
19
- plugin :http_auth, authenticator: proc {|user, pass| [user, pass] == %w[foo bar]},
19
+ plugin :http_auth, authenticator: ->(user, pass) { [user, pass] == %w[foo bar] },
20
20
  realm: 'Restricted Area', # default
21
21
  schemes: %w[basic] # default
22
22
  ```
23
23
 
24
- ### Additional Configuration
24
+ ## Usage
25
25
 
26
- The header sent when the user is unauthorized can be configured via
27
- `unauthorized_headers` option, globally or locally:
26
+ Call `http_auth` inside the routes you want to authenticate the user, it will halt
27
+ the request with an empty response with status 401 if the authenticator is false.
28
28
 
29
- ```ruby
30
- unauthorized_headers: proc do |opts|
31
- {'Content-Type' => 'text/plain',
32
- 'Content-Length' => '0',
33
- 'WWW-Authenticate' => ('Basic realm="%s"' % opts[:realm])}
34
- end, # default
35
- ```
36
-
37
- The `unauthorized` option can receive a block to be invoked whenever the user
38
- is unathorized:
29
+ You can provide an `unauthorized` block to be invoked whenever the user is
30
+ unathorized, it's executed in the context of the instance:
39
31
 
40
32
  ```ruby
41
- plugin :http_auth, unauthorized: proc do |r|
42
- logger.warn("Unathorized attempt to access #{r.path}!!")
43
- end
44
- ```
33
+ plugin :http_auth, unauthorized: -> { view('401.html') }
45
34
 
46
- ## Usage
35
+ # ...
47
36
 
48
- Call `r.http_auth` inside the routes you want to authenticate the user, it will halt
49
- the request with 401 response code if the authenticator is false.
37
+ r.root do
38
+ http_auth {|u, p| [u, p] == %w[foo bar] }
50
39
 
51
- An additional `WWW-Authenticate` header is sent as specified on [rfc7235](https://tools.ietf.org/html/rfc7235#section-4.1) and it's realm can be configured.
40
+ "If you can see this you were authorized! \
41
+ Otherwise you'll be served with the 401.html.erb template"
42
+ end
43
+ ```
52
44
 
53
45
  ### Basic Auth
54
46
 
55
47
  Basic authorization is the default method:
56
48
 
57
49
  ```ruby
58
- r.http_auth { |user, pass| [user, pass] == %w[foo bar] }
50
+ # Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
51
+ http_auth { |user, pass| [user, pass] == ['Aladdin', 'open sesame'] }
59
52
  ```
60
53
 
61
54
  ### Schemes
@@ -70,19 +63,20 @@ plugin :http_auth, schemes: %w[bearer]
70
63
  You can also whitelist schemes for a specific route:
71
64
 
72
65
  ```ruby
73
- r.http_auth(schemes: %w[bearer]) { |token| token == '4t0k3n' }
66
+ http_auth(schemes: %w[bearer]) { |token| token == '4t0k3n' }
74
67
  ```
75
68
 
76
69
  ### Scheme: Bearer
77
70
 
78
- When the `Bearer` authorization is scheme is passed, if whitelisted, the token
79
- is passed to the authenticator:
71
+ When the `Bearer` scheme is passed, if whitelisted, the token is passed to
72
+ the authenticator:
80
73
 
81
74
  ```ruby
82
- r.http_auth { |token| token == '4t0k3n' }
75
+ # Authorization: Bearer 4t0k3n
76
+ http_auth { |token| token == '4t0k3n' }
83
77
  ```
84
78
 
85
- ### Formatted parameters schemes
79
+ ### Schemes with formatted parameters
86
80
 
87
81
  For schemes that require formatted params authorization header, like `Digest`,
88
82
  the scheme and the parsed params are passed to the authenticator:
@@ -102,13 +96,7 @@ Authorization: Digest username="Mufasa",
102
96
  ```
103
97
 
104
98
  ```ruby
105
- r.http_auth { |s, p| [s, p['username']] == ['digest', 'Mufasa'] }
106
- ```
107
-
108
- ## Test
109
-
110
- ```sh
111
- bundle exec ruby test/*.rb
99
+ http_auth { |s, p| [s, p['username']] == ['digest', 'Mufasa'] }
112
100
  ```
113
101
 
114
102
  ## Warden
@@ -117,12 +105,30 @@ To avoid having your 401 responses intercepted by warden, you need to configure
117
105
  the unauthenticated callback that is called just before the request is halted:
118
106
 
119
107
  ```ruby
120
- plugin :http_auth, unauthorized: proc {|r| r.env['warden'].custom_failure! }
108
+ plugin :http_auth, unauthorized: -> { env['warden'].custom_failure! }
109
+ ```
110
+
111
+ ## Additional Configuration
112
+
113
+ The header sent when the user is unauthorized can be configured via
114
+ `unauthorized_headers` and `realm` options, globally or locally:
115
+
116
+ ```ruby
117
+ unauthorized_headers: ->(opts) do
118
+ { 'WWW-Authenticate' => ('Basic realm="%s"' % opts[:realm]) }
119
+ end, # default
120
+ realm: "Restricted Area", # default
121
+ ```
122
+
123
+ ## Test
124
+
125
+ ```sh
126
+ bundle exec ruby spec/*_spec.rb
121
127
  ```
122
128
 
123
129
  ## Contributing
124
130
 
125
- Bug reports and pull requests are welcome on GitHub at https://github.com/badosu/roda-basic-auth.
131
+ Bug reports and pull requests are welcome on GitHub at https://github.com/badosu/roda-http-auth.
126
132
 
127
133
  ## License
128
134
 
@@ -5,14 +5,10 @@ module Roda::RodaPlugins
5
5
  module HttpAuth
6
6
  DEFAULTS = {
7
7
  realm: "Restricted Area",
8
- unauthorized_headers: proc do |opts|
9
- {'Content-Type' => 'text/plain',
10
- 'Content-Length' => '0',
11
- 'WWW-Authenticate' => ('Basic realm="%s"' % opts[:realm])}
12
- end,
13
- bad_request_headers: proc do |opts|
14
- {'Content-Type' => 'text/plain', 'Content-Length' => '0'}
8
+ unauthorized_headers: ->(opts) do
9
+ { 'WWW-Authenticate' => ('Basic realm="%s"' % opts[:realm]) }
15
10
  end,
11
+ unauthorized: ->(r) {},
16
12
  schemes: %w[basic]
17
13
  }
18
14
 
@@ -22,50 +18,48 @@ module Roda::RodaPlugins
22
18
  app.opts[:http_auth].freeze
23
19
  end
24
20
 
25
- module RequestMethods
21
+ module InstanceMethods
26
22
  def http_auth(opts={}, &authenticator)
27
- auth_opts = roda_class.opts[:http_auth].merge(opts)
23
+ auth_opts = request.roda_class.opts[:http_auth].merge(opts)
28
24
  authenticator ||= auth_opts[:authenticator]
29
25
 
30
26
  raise "Must provide an authenticator block" if authenticator.nil?
31
27
 
32
- begin
33
- auth = Rack::Auth::Basic::Request.new(env)
28
+ auth = Rack::Auth::Basic::Request.new(env)
29
+
30
+ unless auth.provided? && auth_opts[:schemes].include?(auth.scheme)
31
+ unauthorized(auth_opts)
32
+ end
34
33
 
35
- unless auth.provided? && auth_opts[:schemes].include?(auth.scheme)
36
- auth_opts[:unauthorized].call(self) if auth_opts[:unauthorized]
37
- halt [401, auth_opts[:unauthorized_headers].call(auth_opts), []]
38
- end
34
+ credentials = if auth.basic?
35
+ auth.credentials
36
+ elsif auth.scheme == 'bearer'
37
+ [env['HTTP_AUTHORIZATION'].split(' ', 2).last]
38
+ else
39
+ http_auth = env['HTTP_AUTHORIZATION'].split(' ', 2)
40
+ .last
39
41
 
40
- credentials = if auth.basic?
41
- auth.credentials
42
- elsif auth.scheme == 'bearer'
43
- [env['HTTP_AUTHORIZATION'].strip.split(' ').last]
44
- else
45
- [auth.scheme, _extract_credentials]
46
- end
42
+ creds = !http_auth.include?('=') ? http_auth :
43
+ Rack::Auth::Digest::Params.parse(http_auth)
47
44
 
48
- if authenticator.call(*credentials)
49
- env['REMOTE_USER'] = auth.username
50
- else
51
- opts[:unauthorized].call(self) if auth_opts[:unauthorized]
52
- halt [401, auth_opts[:unauthorized_headers].call(auth_opts), []]
53
- end
54
- rescue StandardError
55
- halt [400, auth_opts[:bad_request_headers].call(auth_opts), []]
45
+ [auth.scheme, creds]
46
+ end
47
+
48
+ if authenticator.call(*credentials)
49
+ env['REMOTE_USER'] = auth.username
50
+ else
51
+ unauthorized(auth_opts)
56
52
  end
57
53
  end
58
54
 
59
- def _extract_credentials
60
- authorization = env['HTTP_AUTHORIZATION'].split(' ', 2).last
61
- parts = authorization.split(',')
62
-
63
- return parts.first if parts.one? && !parts.first.include?('=')
55
+ private
64
56
 
65
- key_values = parts.map {|p| p.strip.split(/\=\"?/) }
66
- .map {|k, v| [k, v.chomp('"').gsub(/\\\"/, '"')] }
57
+ def unauthorized(opts)
58
+ response.status = 401
59
+ response.headers.merge!(opts[:unauthorized_headers].call(opts))
67
60
 
68
- Hash[key_values]
61
+ request.block_result(instance_exec(request, &opts[:unauthorized]))
62
+ request.halt response.finish
69
63
  end
70
64
  end
71
65
  end
@@ -1,7 +1,7 @@
1
1
  class Roda
2
2
  module RodaPlugins
3
3
  module HttpAuth
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -24,4 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rake", "~> 12.3"
25
25
  spec.add_development_dependency "minitest"
26
26
  spec.add_development_dependency "rack-test"
27
+ spec.add_development_dependency "tilt"
27
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda-http-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amadeus Folego
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-02 00:00:00.000000000 Z
11
+ date: 2018-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: roda
@@ -100,6 +100,20 @@ dependencies:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: tilt
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
103
117
  description: Add http authorization methods to Roda
104
118
  email:
105
119
  - amadeusfolego@gmail.com