Add support for digest authentication

This commit is contained in:
Brandon Robins
2017-12-14 23:16:01 -06:00
parent 50becf8ae3
commit dde85d453c
8 changed files with 66 additions and 8 deletions

View File

@@ -38,6 +38,12 @@ module Calligraphy
options head get put delete copy move mkcol propfind proppatch lock unlock
)
mattr_accessor :digest_password_procedure
@@digest_password_procedure = Proc.new { |x| 'changeme!' }
mattr_accessor :enable_digest_authentication
@@enable_digest_authentication = false
mattr_accessor :lock_timeout_period
@@lock_timeout_period = 24 * 60 * 60
@@ -45,4 +51,8 @@ module Calligraphy
@@web_dav_actions = %i(
options get put delete copy move mkcol propfind proppatch lock unlock
)
def self.configure
yield self
end
end

View File

@@ -309,6 +309,7 @@ module Calligraphy
def create_lock(properties, depth)
@store.transaction do
@store[:lockcreator] = client_nonce
@store[:lockdiscovery] = [] unless @store[:lockdiscovery].is_a? Array
@store[:lockdepth] = depth
@@ -366,6 +367,7 @@ module Calligraphy
def locking_ancestor?(ancestor_path, ancestors, headers=nil)
ancestor_store_path = "#{ancestor_path}/#{ancestors[-1]}.pstore"
check_lock_creator = Calligraphy.enable_digest_authentication
blocking_lock = false
unlockable = true
@@ -381,6 +383,10 @@ module Calligraphy
ancestor_store[:lockdiscovery]
end
ancestor_lock_creator = ancestor_store.transaction(true) do
ancestor_store[:lockcreator]
end if check_lock_creator
blocking_lock = obj_exists_and_is_not_type? obj: ancestor_lock, type: []
if blocking_lock
@@ -392,7 +398,8 @@ module Calligraphy
.each { |x| x }
.map { |k, v| k[:locktoken].children[0].text }
unlockable = ancestor_lock_tokens.include? token
unlockable = ancestor_lock_tokens.include?(token) ||
(check_lock_creator && (ancestor_lock_creator == client_nonce))
end
end
@@ -463,6 +470,8 @@ module Calligraphy
def remove_lock(token)
@store.transaction do
@store.delete :lockcreator
if @store[:lockdiscovery].length == 1
@store.delete :lockdiscovery
else

View File

@@ -1,6 +1,7 @@
module Calligraphy::Rails
class WebDavRequestsController < ActionController::Base
before_action :verify_resource_scope
before_action :authenticate_with_digest_authentiation
before_action :set_resource
def invoke_method
@@ -10,6 +11,8 @@ module Calligraphy::Rails
if method == 'head'
status = get head: true
elsif Calligraphy.allowed_methods.include? method
set_resource_client_nonce(method) if Calligraphy.enable_digest_authentication
status, body = send method
else
status = :method_not_allowed
@@ -27,6 +30,14 @@ module Calligraphy::Rails
head :forbidden if params[:resource].include? '..'
end
def authenticate_with_digest_authentiation
if Calligraphy.enable_digest_authentication
authenticate_or_request_with_http_digest do |username|
Calligraphy.digest_password_procedure.call(username)
end
end
end
def set_resource
resource_id = if params[:format]
[params[:resource], params[:format]].join '.'
@@ -182,5 +193,16 @@ module Calligraphy::Rails
render body: body, status: status
end
end
def set_resource_client_nonce(method)
@resource.client_nonce = get_client_nonce
end
def get_client_nonce
auth_header = request.headers["HTTP_AUTHORIZATION"]
auth = ::ActionController::HttpAuthentication::Digest.decode_credentials auth_header
auth[:cnonce]
end
end
end

View File

@@ -1,6 +1,6 @@
module Calligraphy
class Resource
attr_accessor :contents, :updated_at
attr_accessor :client_nonce, :contents, :updated_at
attr_reader :full_request_path, :mount_point, :request_body, :request_path, :root_dir
def initialize(resource: nil, req: nil, mount: nil, root_dir: nil)

View File

@@ -1,3 +1,3 @@
module Calligraphy
VERSION = '0.1.0'
VERSION = '0.2.0'
end