#1464 Digest as the default authentication method

This commit is contained in:
Karel Pičman 2024-05-28 11:53:15 +02:00
parent d18b557355
commit 296e2e06f8
3 changed files with 54 additions and 2 deletions

View File

@ -69,7 +69,7 @@ module RedmineDmsf
nc = params['nc'] nc = params['nc']
user = User.find_by(login: username) user = User.find_by(login: username)
unless user 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 raise Unauthorized
end end
unless user.active? unless user.active?
@ -85,7 +85,7 @@ module RedmineDmsf
ha1 = user.easy_digest_token ha1 = user.easy_digest_token
else else
unless token unless token
Rails.logger.error "Digest authentication: no digest found for #{user}" Rails.logger.error "Digest authentication: no digest found for #{username}"
raise Unauthorized raise Unauthorized
end end
ha1 = token.value ha1 = token.value
@ -101,6 +101,8 @@ module RedmineDmsf
else else
Rails.logger.error 'Digest authentication: digest response is incorrect' Rails.logger.error 'Digest authentication: digest response is incorrect'
end end
else
Rails.logger.error "Digest authentication method expected got #{scheme}"
end end
raise Unauthorized if User.current.anonymous? raise Unauthorized if User.current.anonymous?

View File

@ -34,6 +34,29 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest
assert_response :unauthorized assert_response :unauthorized
end 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 def test_should_permit_authenticated_user
get '/dmsf/webdav', params: nil, headers: @admin get '/dmsf/webdav', params: nil, headers: @admin
assert_response :success assert_response :success

View File

@ -60,6 +60,7 @@ module RedmineDmsf
Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = nil Setting.plugin_redmine_dmsf['dmsf_webdav_use_project_names'] = nil
Setting.plugin_redmine_dmsf['dmsf_projects_as_subfolders'] = 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_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 FileUtils.cp_r File.join(File.expand_path('../fixtures/files', __FILE__), '.'), DmsfFile.storage_path
User.current = nil User.current = nil
end end
@ -115,6 +116,32 @@ module RedmineDmsf
assert val.blank?, "Expected header #{key} should be empty." assert val.blank?, "Expected header #{key} should be empty."
end end
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 end
end end