#1464 Digest authentication

This commit is contained in:
Karel Pičman 2024-05-16 14:54:11 +02:00
parent d9b9cb05f5
commit 8f7157ca19
30 changed files with 411 additions and 24 deletions

View File

@ -22,11 +22,12 @@
class DmsfController < ApplicationController class DmsfController < ApplicationController
include RedmineDmsf::DmsfZip include RedmineDmsf::DmsfZip
before_action :find_project, except: %i[expand_folder index] before_action :find_project, except: %i[expand_folder index digest reset_digest]
before_action :authorize, except: %i[expand_folder index] before_action :authorize, except: %i[expand_folder index digest reset_digest]
before_action :authorize_global, only: [:index] before_action :authorize_global, only: [:index]
before_action :find_folder, before_action :find_folder,
except: %i[new create edit_root save_root add_email append_email autocomplete_for_user] except: %i[new create edit_root save_root add_email append_email autocomplete_for_user digest
reset_digest]
before_action :find_parent, only: %i[new create delete] before_action :find_parent, only: %i[new create delete]
before_action :permissions before_action :permissions
# Also try to lookup folder by title if this is an API call # Also try to lookup folder by title if this is an API call
@ -35,6 +36,7 @@ class DmsfController < ApplicationController
before_action :project_roles, only: %i[new edit create save] before_action :project_roles, only: %i[new edit create save]
before_action :find_target_folder, only: %i[copymove entries_operation] before_action :find_target_folder, only: %i[copymove entries_operation]
before_action :check_target_folder, only: [:entries_operation] before_action :check_target_folder, only: [:entries_operation]
before_action :require_login, only: %i[digest reset_digest]
accept_api_auth :show, :create, :save, :delete, :entries_operation accept_api_auth :show, :create, :save, :delete, :entries_operation
@ -465,6 +467,27 @@ class DmsfController < ApplicationController
redirect_back_or_default trash_dmsf_path id: @project redirect_back_or_default trash_dmsf_path id: @project
end end
# Reset WebDAV digest
def digest; end
def reset_digest
if request.post?
raise StandardError, l(:notice_account_wrong_password) unless User.current.check_password?(params[:password])
# We have to create a token first to prevent an autogenerated token's value
token = Token.create!(user_id: User.current.id, action: 'dmsf-webdav-digest')
token.value = Digest::MD5.hexdigest(
"#{User.current.login}:#{RedmineDmsf::Webdav::AUTHENTICATION_REALM}:#{params[:password]}"
)
token.save
flash[:notice] = l(:notice_webdav_digest_reset)
end
rescue StandardError => e
flash[:error] = e.message
ensure
redirect_to my_account_path
end
private private
def users_for_new_users def users_for_new_users

View File

@ -0,0 +1,30 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<p>
<%= l(:text_dmsf_webdav_digest_reset) %>
</p>
<%= form_tag(dmsf_reset_digest_path) do %>
<label for="password">
<%= l(:field_password) %>
</label>
<%= password_field_tag 'password', nil, autofocus: true %>
<input type="submit" name="reset" value="<%= l(:button_reset) %>" onclick="hideModal(this);">
<% end %>

View File

@ -0,0 +1,22 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
$('#ajax-modal').html('<%= escape_javascript render partial: 'digest' %>');
showModal('ajax-modal', '30%', '<%= l(:label_dmsf_webdav_digest) %>');

View File

@ -0,0 +1,38 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render partial: "/#{File.dirname(__FILE__)}/../../../../../app/views/my/sidebar.html.erb" %>
<%# DMSF extension do %>
<% if Setting.plugin_redmine_dmsf['dmsf_webdav_authentication'] == 'Digest' %>
<h4><%= l(:label_dmsf_webdav_digest) %></h4>
<p>
<% token = Token.find_by(user_id: @user.id, action: 'dmsf-webdav-digest') %>
<% if token %>
<%= l(:label_dmsf_webdav_digest_created_on, distance_of_time_in_words(Time.now, token.created_on)) %>
<% else %>
<%= l(:label_missing_dmsf_webdav_digest) %>
<% end %>
(<%= link_to l(:button_reset), dmsf_digest_path, remote: true %>)
</p>
<% end %>
<%# end %>

View File

@ -277,6 +277,17 @@
<% visible_class = @settings['dmsf_webdav'].blank? ? 'dmsf-hidden' : '' %> <% visible_class = @settings['dmsf_webdav'].blank? ? 'dmsf-hidden' : '' %>
<div id="dmsf_webdav_block" class="<%= visible_class %>"> <div id="dmsf_webdav_block" class="<%= visible_class %>">
<p>
<%= content_tag :label, l(:label_webdav_authentication) %>
<% auth_types = [%w[Basic Basic], %w[Digest Digest]] %>
<% @settings['dmsf_webdav_authentication'] = 'Basic' if @settings['dmsf_webdav_authentication'].blank? %>
<%= select_tag 'settings[dmsf_webdav_authentication]',
options_for_select(auth_types, @settings['dmsf_webdav_authentication']) %>
<em class="<%= klass %>">
<%= l(:note_webdav_authentication) %> <br>
<%= l(:label_default)%>: <%= auth_types[0][0] %>
</em>
</p>
<p> <p>
<%= content_tag :label, l(:label_webdav_strategy) %> <%= content_tag :label, l(:label_webdav_strategy) %>
<%= select_tag'settings[dmsf_webdav_strategy]', <%= select_tag'settings[dmsf_webdav_strategy]',
@ -316,7 +327,6 @@
<%= l(:label_default) %>: ^\~\$|\.tmp$ <%= l(:label_default) %>: ^\~\$|\.tmp$
</em> </em>
</p> </p>
<p> <p>
<%= content_tag :label, l(:label_webdav_use_project_names) %> <%= content_tag :label, l(:label_webdav_use_project_names) %>
<%= check_box_tag 'settings[dmsf_webdav_use_project_names]', true, @settings['dmsf_webdav_use_project_names'] %> <%= check_box_tag 'settings[dmsf_webdav_use_project_names]', true, @settings['dmsf_webdav_use_project_names'] %>

View File

@ -479,6 +479,16 @@ cs:
error_not_supported_image_format: Nepodporovaný formát obrázku error_not_supported_image_format: Nepodporovaný formát obrázku
error_not_supported_video_format: Nepodporovaný formát videa error_not_supported_video_format: Nepodporovaný formát videa
label_webdav_authentication: WebDAV autentifikace
note_webdav_authentication: Autentifikační metoda Basic není považována za bezpečnou a z toho důvodu je blokována
některými klienty. Metoda Digest, na druhou stranu, vyžaduje od uživatelů vytvoření DMSF WebDAV digestu v jejich
profilu za použití hesla, které se pak používá při autentifikaci z WebDAV klienta.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Chybějící Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: Je vyžadováno vaše heslo pro vygenerování nového DMSF WebDAV digestu.
notice_webdav_digest_reset: Váš DMSF WebDAV digest byl resetován.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -474,6 +474,16 @@ de:
error_not_supported_image_format: Nicht unterstütztes Bildformat error_not_supported_image_format: Nicht unterstütztes Bildformat
error_not_supported_video_format: Nicht unterstütztes Videoformat error_not_supported_video_format: Nicht unterstütztes Videoformat
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: Von mir gesperrte Dokumente dmsf_locked_documents: Von mir gesperrte Dokumente

View File

@ -478,6 +478,16 @@ en:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -478,6 +478,16 @@ es:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -457,6 +457,16 @@ fa:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: اسناد قفل شده‌ی من dmsf_locked_documents: اسناد قفل شده‌ی من

View File

@ -479,6 +479,16 @@ fr:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -479,6 +479,16 @@ hu:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -478,6 +478,16 @@ it: # Italian strings thx 2 Matteo Arceci!
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -480,6 +480,16 @@ ja:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: 自分がロック中の文書 dmsf_locked_documents: 自分がロック中の文書

View File

@ -478,6 +478,16 @@ ko:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: 내 잠긴 파일 dmsf_locked_documents: 내 잠긴 파일

View File

@ -478,6 +478,16 @@ nl:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -477,6 +477,16 @@ pl:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -478,6 +478,16 @@ pt-BR:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -479,6 +479,16 @@ sl:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -480,6 +480,16 @@ uk:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: Мої заблоковані документи dmsf_locked_documents: Мої заблоковані документи

View File

@ -477,6 +477,16 @@ zh-TW:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -479,6 +479,16 @@ zh:
error_not_supported_image_format: Not supported image format error_not_supported_image_format: Not supported image format
error_not_supported_video_format: Not supported video format error_not_supported_video_format: Not supported video format
label_webdav_authentication: WebDAV Authentication
note_webdav_authentication: Basic authentication method is considered as unsecure and therefore blocked by some
clients. Digest authentication, on the other hand, requires users to create a DMSF WebDAV digest in their profiles
using a password that must by used for authentication in their WebDAV clients after that.
label_dmsf_webdav_digest_created_on: "Dmsf WebDAV digest created %{value} ago"
label_missing_dmsf_webdav_digest: Missing a Dmsf WebDAV digest
label_dmsf_webdav_digest: DMSF WebDAV digest
text_dmsf_webdav_digest_reset: You are supposed to enter your password to generate a new DMSF WebDAV digest.
notice_webdav_digest_reset: Your DMSF WebDAV digest was reset.
easy_pages: easy_pages:
modules: modules:
dmsf_locked_documents: My locked documents dmsf_locked_documents: My locked documents

View File

@ -56,6 +56,8 @@ if Redmine::Plugin.installed? 'redmine_dmsf'
put '/projects/:id/dmsf', controller: 'dmsf', action: 'drop' put '/projects/:id/dmsf', controller: 'dmsf', action: 'drop'
get '/projects/:id/dmsf/empty_trash', to: 'dmsf#empty_trash', as: 'empty_trash' get '/projects/:id/dmsf/empty_trash', to: 'dmsf#empty_trash', as: 'empty_trash'
get '/dmsf', to: 'dmsf#index', as: 'dmsf_index' get '/dmsf', to: 'dmsf#index', as: 'dmsf_index'
get '/dmsf/digest', to: 'dmsf#digest', as: 'dmsf_digest'
post '/dmsf/digest', to: 'dmsf#reset_digest', as: 'dmsf_reset_digest'
# dmsf_context_menu_controller # dmsf_context_menu_controller
match '/projects/dmsf/context_menu', to: 'dmsf_context_menus#dmsf', as: 'dmsf_context_menu', via: %i[get post] match '/projects/dmsf/context_menu', to: 'dmsf_context_menus#dmsf', as: 'dmsf_context_menu', via: %i[get post]
@ -98,22 +100,6 @@ if Redmine::Plugin.installed? 'redmine_dmsf'
get '/dmsf_files/:id', controller: 'dmsf_files', action: 'show' get '/dmsf_files/:id', controller: 'dmsf_files', action: 'show'
get '/dmsf_files/:id/download', controller: 'dmsf_files', action: 'show', download: '' get '/dmsf_files/:id/download', controller: 'dmsf_files', action: 'show', download: ''
#
# files_copy controller
# /dmsf/files/<file id>/copy
##
post '/dmsf/files/:id/copy/copy', controller: 'dmsf_files_copy', action: 'copy'
post '/dmsf/files/:id/copy/move', controller: 'dmsf_files_copy', action: 'move'
get '/dmsf/files/:id/copy', controller: 'dmsf_files_copy', action: 'new', as: 'copy_file'
#
# folders_copy controller
# /dmsf/folders/<folder id>/copy
##
post '/dmsf/folders/:id/copy/copy', controller: 'dmsf_folders_copy', action: 'copy'
post '/dmsf/folders/:id/copy/move', controller: 'dmsf_folders_copy', action: 'move'
get '/dmsf/folders/:id/copy', controller: 'dmsf_folders_copy', action: 'new', as: 'copy_folder'
# #
# dmsf_files controller # dmsf_files controller
# /dmsf/files/<file id> # /dmsf/files/<file id>

View File

@ -62,7 +62,8 @@ Redmine::Plugin.register :redmine_dmsf do
'dmsf_global_menu_disabled' => nil, 'dmsf_global_menu_disabled' => nil,
'dmsf_default_query' => nil, 'dmsf_default_query' => nil,
'empty_minor_version_by_default' => nil, 'empty_minor_version_by_default' => nil,
'remove_original_documents_module' => nil 'remove_original_documents_module' => nil,
'dmsf_webdav_authentication' => 'Basic'
} }
end end

View File

@ -25,7 +25,10 @@ module Dav4rack
end end
def authorization def authorization
get_header 'HTTP_AUTHORIZATION' get_header('HTTP_AUTHORIZATION') ||
get_header('X-HTTP_AUTHORIZATION') ||
get_header('X_HTTP_AUTHORIZATION') ||
get_header('REDIRECT_X_HTTP_AUTHORIZATION')
end end
# path relative to root uri # path relative to root uri

View File

@ -505,7 +505,7 @@ module Dav4rack
def propnames_xml def propnames_xml
response = Ox::Element.new(D_RESPONSE) response = Ox::Element.new(D_RESPONSE)
response << ox_element(D_HREF, href) response << ox_element(D_HREF, href)
propstats response, { OK => [propname_properties.map { |p| [p, nil] }].to_h } propstats response, { OK => propname_properties.index_with { |p| [p, nil] } }
response response
end end

View File

@ -23,6 +23,7 @@ require "#{File.dirname(__FILE__)}/resource_proxy"
module RedmineDmsf module RedmineDmsf
module Webdav module Webdav
AUTHENTICATION_REALM = 'DMSF content'
# Custom middleware # Custom middleware
class CustomMiddleware class CustomMiddleware
def initialize(app) def initialize(app)

View File

@ -31,6 +31,78 @@ module RedmineDmsf
# Switch the locale to English for WebDAV requests in order to have log messages in English # Switch the locale to English for WebDAV requests in order to have log messages in English
I18n.with_locale(:en, &action) I18n.with_locale(:en, &action)
end end
def process
return super unless Setting.plugin_redmine_dmsf['dmsf_webdav_authentication'] == 'Digest'
status = skip_authorization? || authenticate ? process_action || OK : Dav4rack::HttpStatus::Unauthorized
rescue Dav4rack::HttpStatus::Status => e
status = e
ensure
if status
response.status = status.code
if status.code == 401
time_stamp = Time.now.to_i
h_once = Digest::MD5.hexdigest("#{time_stamp}:#{SecureRandom.hex(32)}")
nonce = Base64.strict_encode64("#{time_stamp}#{h_once}")
response['WWW-Authenticate'] =
%(Digest realm="#{authentication_realm}", nonce="#{nonce}", algorithm="MD5", qop="auth")
end
end
end
def authenticate
return super unless Setting.plugin_redmine_dmsf['dmsf_webdav_authentication'] == 'Digest'
auth_header = request.authorization.to_s
scheme = auth_header.split(' ', 2).first&.downcase
if scheme == 'digest'
Rails.logger.info 'Authentication: digest'
auth = Rack::Auth::Digest::Request.new(request.env)
params = auth.params
username = params['username']
response = params['response']
cnonce = params['cnonce']
nonce = params['nonce']
uri = params['uri']
qop = params['qop']
nc = params['nc']
user = User.find_by(login: username)
unless user
log_error('Digest authentication: provided user name has no match in the DB')
raise Unauthorized
end
token = Token.find_by(user_id: user.id, action: 'dmsf-webdav-digest')
if token.nil? && defined?(EasyExtensions)
if user.easy_digest_token_expired?
log_error('Digest authentication: digest token expired')
raise Unauthorized
end
ha1 = user.easy_digest_token
else
unless token
log_error("Digest authentication: no digest found for #{user}")
raise Unauthorized
end
ha1 = token.value
end
ha2 = Digest::MD5.hexdigest("#{request.env['REQUEST_METHOD']}:#{uri}")
required_response = if qop
Digest::MD5.hexdigest("#{ha1}:#{nonce}:#{nc}:#{cnonce}:#{qop}:#{ha2}")
else
Digest::MD5.hexdigest("#{ha1}:#{nonce}:#{ha2}")
end
if required_response == response
User.current = user
else
Rails.logger.error 'Digest authentication: digest response is incorrect'
end
end
raise Unauthorized if User.current.anonymous?
Rails.logger.info "Current user: #{User.current}, User-Agent: #{request.user_agent}"
User.current
end
end end
end end
end end

View File

@ -199,6 +199,10 @@ module RedmineDmsf
namespaces[ns_href] || add_namespace(ns_href) namespaces[ns_href] || add_namespace(ns_href)
end end
def authentication_realm
RedmineDmsf::Webdav::AUTHENTICATION_REALM
end
private private
def get_resource_class(path) def get_resource_class(path)

View File

@ -648,4 +648,31 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
assert_response :redirect assert_response :redirect
assert_nil flash[:error] assert_nil flash[:error]
end end
def test_digest
post '/login', params: { username: 'jsmith', password: 'jsmith' }
get '/dmsf/digest', xhr: true
assert_response :success
end
def test_digest_unauthorized
get '/dmsf/digest', xhr: true
assert_response :unauthorized
end
def test_reset_digest
post '/login', params: { username: 'jsmith', password: 'jsmith' }
post '/dmsf/digest', params: { password: 'jsmith' }
assert_response :redirect
assert_redirected_to my_account_path
token = Token.find_by(user_id: @jsmith.id, action: 'dmsf-webdav-digest')
assert token
assert_equal Digest::MD5.hexdigest("jsmith:#{RedmineDmsf::Webdav::AUTHENTICATION_REALM}:jsmith"), token.value
end
def test_reset_digest_unauthorized
post '/dmsf/digest', params: { password: 'jsmith' }
assert_response :redirect
assert_redirected_to 'http://www.example.com/login?back_url=http%3A%2F%2Fwww.example.com%2Fdmsf%2Fdigest'
end
end end