Skip to content

Commit 5d7e4a3

Browse files
author
Michael Bleigh
committed
Merge pull request ruby-grape#40 from daddz/digest-auth
added http digest auth
2 parents 8294f7f + 063ebd1 commit 5d7e4a3

File tree

4 files changed

+89
-1
lines changed

4 files changed

+89
-1
lines changed

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` and `:oauth2` are 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
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require 'spec_helper'
2+
3+
RSpec::Matchers.define :be_challenge do
4+
match do |actual_response|
5+
actual_response.status == 401 &&
6+
actual_response['WWW-Authenticate'] =~ /^Digest / &&
7+
actual_response.body.empty?
8+
end
9+
end
10+
11+
class Test < Grape::API
12+
version '1'
13+
14+
http_digest({:realm => 'Test Api', :opaque => 'secret'}) do |username|
15+
{'foo' => 'bar'}[username]
16+
end
17+
18+
get '/test' do
19+
[{:hey => 'you'},{:there => 'bar'},{:foo => 'baz'}]
20+
end
21+
end
22+
23+
describe Grape::Middleware::Auth::Digest do
24+
def app
25+
Test
26+
end
27+
28+
it 'should be a digest authentication challenge' do
29+
get '/1/test'
30+
last_response.should be_challenge
31+
end
32+
33+
it 'should throw a 401 if no auth is given' do
34+
get '/1/test'
35+
last_response.status.should == 401
36+
end
37+
38+
it 'should authenticate if given valid creds' do
39+
digest_authorize "foo", "bar"
40+
get '/1/test'
41+
last_response.status.should == 200
42+
end
43+
44+
it 'should throw a 401 if given invalid creds' do
45+
digest_authorize "bar", "foo"
46+
get '/1/test'
47+
last_response.status.should == 401
48+
end
49+
end

0 commit comments

Comments
 (0)