Skip to content

Commit

Permalink
#1464 Digest as the default authentication method
Browse files Browse the repository at this point in the history
  • Loading branch information
picman committed May 28, 2024
1 parent d18b557 commit 296e2e0
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
6 changes: 4 additions & 2 deletions lib/redmine_dmsf/webdav/dmsf_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def authenticate
nc = params['nc']
user = User.find_by(login: username)
unless user
Rails.logger.error 'Digest authentication: provided user name has no match in the DB'
Rails.logger.error "Digest authentication: #{username} not found"
raise Unauthorized
end
unless user.active?
Expand All @@ -85,7 +85,7 @@ def authenticate
ha1 = user.easy_digest_token
else
unless token
Rails.logger.error "Digest authentication: no digest found for #{user}"
Rails.logger.error "Digest authentication: no digest found for #{username}"
raise Unauthorized
end
ha1 = token.value
Expand All @@ -101,6 +101,8 @@ def authenticate
else
Rails.logger.error 'Digest authentication: digest response is incorrect'
end
else
Rails.logger.error "Digest authentication method expected got #{scheme}"
end
raise Unauthorized if User.current.anonymous?

Expand Down
23 changes: 23 additions & 0 deletions test/integration/webdav/dmsf_webdav_get_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ def test_should_deny_failed_authentication
assert_response :unauthorized
end

def test_digest_authentication
# Basic
with_settings plugin_redmine_dmsf: { 'dmsf_webdav_authentication' => 'Basic', 'dmsf_webdav' => '1' } do
get '/dmsf/webdav', params: nil, headers: credentials('jsmith', 'jsmith')
assert_response :success
end
# Wrong digest
with_settings plugin_redmine_dmsf: { 'dmsf_webdav_authentication' => 'Digest', 'dmsf_webdav' => '1' } do
get '/dmsf/webdav', params: nil, headers: credentials('jsmith', 'jsmith')
assert_response :unauthorized
end
# Right digest
digest = Digest::MD5.hexdigest("#{@jsmith_user.login}:#{RedmineDmsf::Webdav::AUTHENTICATION_REALM}:jsmith")
token ||= Token.create!(user_id: @jsmith_user.id, action: 'dmsf-webdav-digest')
token.value = digest
assert token.save
authorization = encode_credentials(username: 'jsmith', digest: digest, target: '/dmsf/webdav')
with_settings plugin_redmine_dmsf: { 'dmsf_webdav_authentication' => 'Digest', 'dmsf_webdav' => '1' } do
get '/dmsf/webdav', params: nil, headers: { HTTP_AUTHORIZATION: authorization }
assert_response :success
end
end

def test_should_permit_authenticated_user
get '/dmsf/webdav', params: nil, headers: @admin
assert_response :success
Expand Down
27 changes: 27 additions & 0 deletions test/integration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def setup
Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = nil
Setting.plugin_redmine_dmsf['dmsf_projects_as_subfolders'] = nil
Setting.plugin_redmine_dmsf['dmsf_storage_directory'] = File.join('files', ['dmsf'])
Setting.plugin_redmine_dmsf['dmsf_webdav_authentication'] = 'Basic'
FileUtils.cp_r File.join(File.expand_path('../fixtures/files', __FILE__), '.'), DmsfFile.storage_path
User.current = nil
end
Expand Down Expand Up @@ -115,6 +116,32 @@ def check_headers_dont_exist
assert val.blank?, "Expected header #{key} should be empty."
end
end

def encode_credentials(options)
options.reverse_merge!(nc: '00000001', cnonce: '0a4f113b', password_is_ha1: false)
# Perform unauthenticated request to retrieve digest parameters to use on subsequent request
target = options.delete(:target) || :index
get target
assert_response :unauthorized
# Credentials
credentials = {
uri: target,
realm: RedmineDmsf::Webdav::AUTHENTICATION_REALM,
username: options[:username],
nonce: ActionController::HttpAuthentication::Digest.nonce(Rails.configuration.secret_key_base),
opaque: ActionController::HttpAuthentication::Digest.opaque(Rails.configuration.secret_key_base)
}
credentials.merge!(options)
path_info = @request.env['PATH_INFO'].to_s
uri = options[:uri] || path_info
credentials[uri] = uri
@request.env['ORIGINAL_FULLPATH'] = path_info
ha2 = Digest::MD5.hexdigest("GET:#{target}")
nonce = ActionController::HttpAuthentication::Digest.nonce(Rails.configuration.secret_key_base)
ha1 = options.delete(:digest)
credentials[:response] = Digest::MD5.hexdigest("#{ha1}:#{nonce}:#{ha2}")
"Digest #{credentials.sort_by { |x| x[0].to_s }.map { |v| "#{v[0]}=#{v[1]}" }.join(',')}"
end
end
end
end

0 comments on commit 296e2e0

Please sign in to comment.