Skip to content

Commit

Permalink
Merge pull request #2196 from lHydra/allow_set_passwords_hashed_optio…
Browse files Browse the repository at this point in the history
…n_for_digest_auth

allow set passwords_hashed option for digest auth
  • Loading branch information
dblock authored Nov 10, 2021
2 parents 43936ac + 68d62d5 commit 71b8211
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### Features

* [#2196](https://github.com/ruby-grape/grape/pull/2196): Add support for `passwords_hashed` param for `digest_auth` - [@lHydra](https://github.com/lhydra).
* Your contribution here.

#### Fixes
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3297,12 +3297,20 @@ http_basic do |username, password|
end
```

Digest auth supports clear-text passwords and password hashes.

```ruby
http_digest({ realm: 'Test Api', opaque: 'app secret' }) do |username|
# lookup the user's password here
end
```

```ruby
http_digest(realm: { realm: 'Test Api', opaque: 'app secret', passwords_hashed: true }) do |username|
# lookup the user's password hash here
end
```

### Register custom middleware for authentication

Grape can use custom Middleware for authentication. How to implement these
Expand Down
8 changes: 7 additions & 1 deletion lib/grape/middleware/auth/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ def http_basic(options = {}, &block)

def http_digest(options = {}, &block)
options[:realm] ||= 'API Authorization'
options[:opaque] ||= 'secret'

if options[:realm].respond_to?(:values_at)
options[:realm][:opaque] ||= 'secret'
else
options[:opaque] ||= 'secret'
end

auth :http_digest, options, &block
end
end
Expand Down
19 changes: 14 additions & 5 deletions spec/grape/middleware/auth/dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
end

describe '.auth' do
it 'stets auth parameters' do
it 'sets auth parameters' do
expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings)

subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
Expand All @@ -38,16 +38,25 @@
end

describe '.http_basic' do
it 'stets auth parameters' do
it 'sets auth parameters' do
subject.http_basic realm: 'my_realm', &settings[:proc]
expect(subject.auth).to eq(realm: 'my_realm', type: :http_basic, proc: block)
end
end

describe '.http_digest' do
it 'stets auth parameters' do
subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
context 'when realm is a hash' do
it 'sets auth parameters' do
subject.http_digest realm: { realm: 'my_realm', opaque: 'my_opaque' }, &settings[:proc]
expect(subject.auth).to eq(realm: { realm: 'my_realm', opaque: 'my_opaque' }, type: :http_digest, proc: block)
end
end

context 'when realm is not hash' do
it 'sets auth parameters' do
subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
end
end
end
end
80 changes: 60 additions & 20 deletions spec/grape/middleware/auth/strategies_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,17 @@ def app
end

module StrategiesSpec
class Test < Grape::API
class PasswordHashed < Grape::API
http_digest(realm: { realm: 'Test Api', opaque: 'secret', passwords_hashed: true }) do |username|
{ 'foo' => Digest::MD5.hexdigest(['foo', 'Test Api', 'bar'].join(':')) }[username]
end

get '/test' do
[{ hey: 'you' }, { there: 'bar' }, { foo: 'baz' }]
end
end

class PasswordIsNotHashed < Grape::API
http_digest(realm: 'Test Api', opaque: 'secret') do |username|
{ 'foo' => 'bar' }[username]
end
Expand All @@ -53,30 +63,60 @@ class Test < Grape::API
end
end

def app
StrategiesSpec::Test
end
context 'when password is hashed' do
def app
StrategiesSpec::PasswordHashed
end

it 'is a digest authentication challenge' do
get '/test'
expect(last_response).to be_challenge
end
it 'is a digest authentication challenge' do
get '/test'
expect(last_response).to be_challenge
end

it 'throws a 401 if no auth is given' do
get '/test'
expect(last_response.status).to eq(401)
end
it 'throws a 401 if no auth is given' do
get '/test'
expect(last_response.status).to eq(401)
end

it 'authenticates if given valid creds' do
digest_authorize 'foo', 'bar'
get '/test'
expect(last_response.status).to eq(200)
it 'authenticates if given valid creds' do
digest_authorize 'foo', 'bar'
get '/test'
expect(last_response.status).to eq(200)
end

it 'throws a 401 if given invalid creds' do
digest_authorize 'bar', 'foo'
get '/test'
expect(last_response.status).to eq(401)
end
end

it 'throws a 401 if given invalid creds' do
digest_authorize 'bar', 'foo'
get '/test'
expect(last_response.status).to eq(401)
context 'when password is not hashed' do
def app
StrategiesSpec::PasswordIsNotHashed
end

it 'is a digest authentication challenge' do
get '/test'
expect(last_response).to be_challenge
end

it 'throws a 401 if no auth is given' do
get '/test'
expect(last_response.status).to eq(401)
end

it 'authenticates if given valid creds' do
digest_authorize 'foo', 'bar'
get '/test'
expect(last_response.status).to eq(200)
end

it 'throws a 401 if given invalid creds' do
digest_authorize 'bar', 'foo'
get '/test'
expect(last_response.status).to eq(401)
end
end
end
end

0 comments on commit 71b8211

Please sign in to comment.