Skip to content

Commit c15d9bb

Browse files
author
Ted Kulp
committed
Merge branch 'master' into fix_params_in_post
Conflicts: lib/grape/middleware/formatter.rb
2 parents 11f7163 + 5d7e4a3 commit c15d9bb

File tree

12 files changed

+246
-101
lines changed

12 files changed

+246
-101
lines changed

Gemfile.lock

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
PATH
2+
remote: .
3+
specs:
4+
grape (0.1.4)
5+
multi_json
6+
multi_xml
7+
rack
8+
rack-jsonp
9+
rack-mount
10+
11+
GEM
12+
remote: http://rubygems.org/
13+
specs:
14+
ZenTest (4.5.0)
15+
diff-lcs (1.1.2)
16+
json_pure (1.5.2)
17+
maruku (0.6.0)
18+
syntax (>= 1.0.0)
19+
multi_json (1.0.3)
20+
multi_xml (0.2.2)
21+
rack (1.3.0)
22+
rack-jsonp (1.2.0)
23+
rack
24+
rack-mount (0.8.1)
25+
rack (>= 1.0.0)
26+
rack-test (0.6.0)
27+
rack (>= 1.0)
28+
rake (0.9.2)
29+
rspec (2.6.0)
30+
rspec-core (~> 2.6.0)
31+
rspec-expectations (~> 2.6.0)
32+
rspec-mocks (~> 2.6.0)
33+
rspec-core (2.6.4)
34+
rspec-expectations (2.6.0)
35+
diff-lcs (~> 1.1.2)
36+
rspec-mocks (2.6.0)
37+
syntax (1.0.0)
38+
yard (0.7.1)
39+
40+
PLATFORMS
41+
ruby
42+
43+
DEPENDENCIES
44+
ZenTest
45+
bundler
46+
grape!
47+
json_pure
48+
maruku
49+
rack-test
50+
rake
51+
rspec (~> 2.6.0)
52+
yard

lib/grape.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Middleware
1717
module Auth
1818
autoload :OAuth2, 'grape/middleware/auth/oauth2'
1919
autoload :Basic, 'grape/middleware/auth/basic'
20+
autoload :Digest, 'grape/middleware/auth/digest'
2021
end
2122
end
2223
end

lib/grape/api.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'rack/mount'
22
require 'rack/auth/basic'
3+
require 'rack/auth/digest/md5'
34
require 'logger'
45

56
module Grape
@@ -138,7 +139,7 @@ def helpers(&block)
138139
end
139140

140141
# Add an authentication type to the API. Currently
141-
# only `:http_basic` is supported.
142+
# only `:http_basic`, `:http_digest` and `:oauth2` are supported.
142143
def auth(type = nil, options = {}, &block)
143144
if type
144145
set(:auth, {:type => type.to_sym, :proc => block}.merge(options))
@@ -155,6 +156,12 @@ def http_basic(options = {}, &block)
155156
options[:realm] ||= "API Authorization"
156157
auth :http_basic, options, &block
157158
end
159+
160+
def http_digest(options = {}, &block)
161+
options[:realm] ||= "API Authorization"
162+
options[:opaque] ||= "secret"
163+
auth :http_digest, options, &block
164+
end
158165

159166
# Defines a route that will be recognized
160167
# by the Grape API.
@@ -257,6 +264,7 @@ def build_endpoint(&block)
257264
:format => settings[:error_format] || :txt,
258265
:rescue_options => settings[:rescue_options]
259266
b.use Rack::Auth::Basic, settings[:auth][:realm], &settings[:auth][:proc] if settings[:auth] && settings[:auth][:type] == :http_basic
267+
b.use Rack::Auth::Digest::MD5, settings[:auth][:realm], settings[:auth][:opaque], &settings[:auth][:proc] if settings[:auth] && settings[:auth][:type] == :http_digest
260268
b.use Grape::Middleware::Prefixer, :prefix => prefix if prefix
261269
b.use Grape::Middleware::Versioner, :versions => (version if version.is_a?(Array)) if version
262270
b.use Grape::Middleware::Formatter, :default_format => default_format || :json
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require 'rack/auth/digest/md5'
2+
3+
module Grape
4+
module Middleware
5+
module Auth
6+
class Digest < Grape::Middleware::Base
7+
attr_reader :authenticator
8+
9+
def initialize(app, options = {}, &authenticator)
10+
super(app, options)
11+
@authenticator = authenticator
12+
end
13+
14+
def digest_request
15+
Rack::Auth::Digest::Request.new(env)
16+
end
17+
18+
def credentials
19+
digest_request.provided?? digest_request.credentials : [nil, nil]
20+
end
21+
22+
def before
23+
unless authenticator.call(*credentials)
24+
throw :error, :status => 401, :message => "API Authorization Failed."
25+
end
26+
end
27+
end
28+
end
29+
end
30+
end

lib/grape/middleware/auth/oauth2.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
module Grape::Middleware::Auth
2+
# OAuth 2.0 authorization for Grape APIs.
23
class OAuth2 < Grape::Middleware::Base
34
def default_options
45
{
56
:token_class => 'AccessToken',
67
:realm => 'OAuth API',
78
:parameter => %w(bearer_token oauth_token),
9+
:accepted_headers => %w(HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION),
810
:header => [/Bearer (.*)/i, /OAuth (.*)/i]
911
}
1012
end
@@ -21,14 +23,21 @@ def token_parameter
2123
end
2224

2325
def token_header
24-
return false unless env['Authorization']
26+
return false unless authorization_header
2527
Array(options[:header]).each do |regexp|
26-
if env['Authorization'] =~ regexp
28+
if authorization_header =~ regexp
2729
return $1
2830
end
2931
end
3032
nil
3133
end
34+
35+
def authorization_header
36+
options[:accepted_headers].each do |head|
37+
return env[head] if env[head]
38+
end
39+
nil
40+
end
3241

3342
def token_class
3443
@klass ||= eval(options[:token_class])
@@ -39,7 +48,7 @@ def verify_token(token)
3948
if token.respond_to?(:expired?) && token.expired?
4049
error_out(401, 'expired_token')
4150
else
42-
if token.permission_for?(env)
51+
if !token.respond_to?(:permission_for?) || token.permission_for?(env)
4352
env['api.token'] = token
4453
else
4554
error_out(403, 'insufficient_scope')
@@ -50,12 +59,6 @@ def verify_token(token)
5059
end
5160
end
5261

53-
def parse_authorization_header
54-
if env['Authorization'] =~ /oauth (.*)/i
55-
$1
56-
end
57-
end
58-
5962
def error_out(status, error)
6063
throw :error, {
6164
:message => error,

lib/grape/middleware/base.rb

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Grape
22
module Middleware
33
class Base
44
attr_reader :app, :env, :options
5-
5+
66
# @param [Rack Application] app The standard argument for a Rack middleware.
77
# @param [Hash] options A hash of options, simply stored for use by subclasses.
88
def initialize(app, options = {})
@@ -38,6 +38,52 @@ def request
3838
def response
3939
Rack::Response.new(@app_response)
4040
end
41+
42+
43+
module Formats
44+
45+
CONTENT_TYPES = {
46+
:xml => 'application/xml',
47+
:json => 'application/json',
48+
:atom => 'application/atom+xml',
49+
:rss => 'application/rss+xml',
50+
:txt => 'text/plain'
51+
}
52+
FORMATTERS = {
53+
:json => :encode_json,
54+
:txt => :encode_txt,
55+
}
56+
57+
def formatters
58+
FORMATTERS.merge(options[:formatters] || {})
59+
end
60+
61+
def content_types
62+
CONTENT_TYPES.merge(options[:content_types] || {})
63+
end
64+
65+
def content_type
66+
content_types[options[:format]] || 'text/html'
67+
end
68+
69+
def mime_types
70+
content_types.invert
71+
end
72+
73+
def formatter_for(api_format)
74+
spec = formatters[api_format]
75+
case spec
76+
when nil
77+
lambda { |obj| obj }
78+
when Symbol
79+
method(spec)
80+
else
81+
spec
82+
end
83+
end
84+
85+
end
86+
4187
end
4288
end
43-
end
89+
end

lib/grape/middleware/error.rb

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
module Grape
55
module Middleware
66
class Error < Base
7-
7+
include Formats
8+
89
def default_options
910
{
1011
:default_status => 403, # default status returned on error
@@ -18,36 +19,15 @@ def default_options
1819
}
1920
end
2021

21-
FORMATTERS = {
22-
:json => :format_json,
23-
:txt => :format_txt,
24-
}
25-
26-
def formatters
27-
FORMATTERS.merge(options[:formatters])
28-
end
29-
30-
def formatter_for(api_format)
31-
spec = formatters[api_format]
32-
case spec
33-
when nil
34-
lambda { |obj| obj }
35-
when Symbol
36-
method(spec)
37-
else
38-
spec
39-
end
40-
end
41-
42-
def format_json(message, backtrace)
22+
def encode_json(message, backtrace)
4323
result = message.is_a?(Hash) ? message : { :error => message }
4424
if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
4525
result = result.merge({ :backtrace => backtrace })
4626
end
4727
MultiJson.encode(result)
4828
end
4929

50-
def format_txt(message, backtrace)
30+
def encode_txt(message, backtrace)
5131
result = message.is_a?(Hash) ? MultiJson.encode(message) : message
5232
if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
5333
result += "\r\n "
@@ -73,7 +53,8 @@ def call!(env)
7353
def error_response(error = {})
7454
status = error[:status] || options[:default_status]
7555
message = error[:message] || options[:default_message]
76-
headers = error[:headers] || {}
56+
headers = {'Content-Type' => content_type}
57+
headers.merge!(error[:headers]) if error[:headers].is_a?(Hash)
7758
backtrace = error[:backtrace] || []
7859
Rack::Response.new([format_message(message, backtrace, status)], status, headers).finish
7960
end

lib/grape/middleware/formatter.rb

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,8 @@
44
module Grape
55
module Middleware
66
class Formatter < Base
7-
CONTENT_TYPES = {
8-
:xml => 'application/xml',
9-
:json => 'application/json',
10-
:atom => 'application/atom+xml',
11-
:rss => 'application/rss+xml',
12-
:txt => 'text/plain'
13-
}
14-
FORMATTERS = {
15-
:json => :encode_json,
16-
:txt => :encode_txt,
17-
}
18-
PARSERS = {
19-
:json => :decode_json
20-
}
21-
7+
include Formats
8+
229
def default_options
2310
{
2411
:default_format => :txt,
@@ -28,22 +15,6 @@ def default_options
2815
}
2916
end
3017

31-
def content_types
32-
CONTENT_TYPES.merge(options[:content_types])
33-
end
34-
35-
def formatters
36-
FORMATTERS.merge(options[:formatters])
37-
end
38-
39-
def parsers
40-
PARSERS.merge(options[:parsers])
41-
end
42-
43-
def mime_types
44-
content_types.invert
45-
end
46-
4718
def headers
4819
env.dup.inject({}){|h,(k,v)| h[k.downcase] = v; h}
4920
end
@@ -113,34 +84,6 @@ def after
11384
Rack::Response.new(bodymap, status, headers).to_a
11485
end
11586

116-
def formatter_for(api_format)
117-
spec = formatters[api_format]
118-
case spec
119-
when nil
120-
lambda { |obj| obj }
121-
when Symbol
122-
method(spec)
123-
else
124-
spec
125-
end
126-
end
127-
128-
def parser_for(api_format)
129-
spec = parsers[api_format]
130-
case spec
131-
when nil
132-
nil
133-
when Symbol
134-
method(spec)
135-
else
136-
spec
137-
end
138-
end
139-
140-
def decode_json(object)
141-
MultiJson.decode(object)
142-
end
143-
14487
def encode_json(object)
14588
if object.respond_to? :serializable_hash
14689
MultiJson.encode(object.serializable_hash)

0 commit comments

Comments
 (0)