diff --git a/lib/remote_storage/riak.rb b/lib/remote_storage/riak.rb index 5f19c9e..2df0b01 100644 --- a/lib/remote_storage/riak.rb +++ b/lib/remote_storage/riak.rb @@ -23,9 +23,12 @@ module RemoteStorage @auth_bucket ||= client.bucket(LiquorCabinet.config['buckets']['authorizations']) end - def authorize_request(user, directory, token) + def authorize_request(user, directory, token, listing=false) request_method = env["REQUEST_METHOD"] - return true if directory.split("/").first == "public" && request_method == "GET" + + if directory.split("/").first == "public" + return true if request_method == "GET" && !listing + end authorizations = auth_bucket.get("#{user}:#{token}").data permission = directory_permission(authorizations, directory) @@ -125,10 +128,11 @@ module RemoteStorage permission = authorizations[""] authorizations.each do |key, value| - if directory.match key + if directory.match /^(public\/)?#{key}(\/|$)/ if permission.nil? || permission == "r" permission = value end + return permission if permission == "rw" end end diff --git a/liquor-cabinet.rb b/liquor-cabinet.rb index 710cc70..3216c2e 100644 --- a/liquor-cabinet.rb +++ b/liquor-cabinet.rb @@ -49,7 +49,7 @@ class LiquorCabinet < Sinatra::Base token = env["HTTP_AUTHORIZATION"] ? env["HTTP_AUTHORIZATION"].split(" ")[1] : "" - authorize_request(@user, @directory, token) unless request.options? + authorize_request(@user, @directory, token, @key.blank?) unless request.options? end end diff --git a/spec/directories_spec.rb b/spec/directories_spec.rb index 752aa93..2bdf549 100644 --- a/spec/directories_spec.rb +++ b/spec/directories_spec.rb @@ -15,7 +15,6 @@ describe "Directories" do end describe "GET listing" do - before do put "/jimmy/tasks/foo", "do the laundry" put "/jimmy/tasks/http%3A%2F%2F5apps.com", "prettify design" @@ -175,6 +174,62 @@ describe "Directories" do content["tasks/"].to_s.length.must_equal 13 end end + + context "for the public directory" do + before do + auth = auth_bucket.new("jimmy:123") + auth.data = ["documents:r", "bookmarks:rw"] + auth.store + + put "/jimmy/public/bookmarks/5apps", "http://5apps.com" + end + + context "when authorized for the category" do + it "lists the files" do + get "/jimmy/public/bookmarks/" + + last_response.status.must_equal 200 + + content = JSON.parse(last_response.body) + content.must_include "5apps" + end + end + + context "when directly authorized for the public directory" do + before do + auth = auth_bucket.new("jimmy:123") + auth.data = ["documents:r", "public/bookmarks:rw"] + auth.store + end + + it "lists the files" do + get "/jimmy/public/bookmarks/" + + last_response.status.must_equal 200 + + content = JSON.parse(last_response.body) + content.must_include "5apps" + end + end + + context "when not authorized" do + before do + auth_bucket.delete("jimmy:123") + end + + it "does not allow a directory listing of the public root" do + get "/jimmy/public/" + + last_response.status.must_equal 403 + end + + it "does not allow a directory listing of a sub-directory" do + get "/jimmy/public/bookmarks/" + + last_response.status.must_equal 403 + end + end + end end describe "directory object" do diff --git a/spec/permissions_spec.rb b/spec/permissions_spec.rb index aa4929e..22720c7 100644 --- a/spec/permissions_spec.rb +++ b/spec/permissions_spec.rb @@ -134,6 +134,32 @@ describe "Permissions" do last_response.status.must_equal 403 end end + + context "to the public directory" do + context "when authorized for the corresponding category" do + it "saves the value" do + put "/jimmy/public/contacts/foo", "Foo Bar" + + last_response.status.must_equal 200 + data_bucket.get("jimmy:public/contacts:foo").data.must_equal "Foo Bar" + end + + it "saves the value to a sub-directory" do + put "/jimmy/public/contacts/family/foo", "Foo Bar" + + last_response.status.must_equal 200 + data_bucket.get("jimmy:public/contacts/family:foo").data.must_equal "Foo Bar" + end + end + + context "when not authorized for the corresponding category" do + it "returns a 403" do + put "/jimmy/public/documents/foo", "Foo Bar" + + last_response.status.must_equal 403 + end + end + end end describe "DELETE" do @@ -175,6 +201,24 @@ describe "Permissions" do data_bucket.get("jimmy:tasks/home:1") }.must_raise Riak::HTTPFailedRequest end + + context "public directory" do + before do + object = data_bucket.new("jimmy:public/tasks:open") + object.content_type = "text/plain" + object.data = "hello world" + object.store + end + + it "removes the key" do + delete "/jimmy/public/tasks/open" + + last_response.status.must_equal 204 + lambda { + data_bucket.get("jimmy:public/tasks:open") + }.must_raise Riak::HTTPFailedRequest + end + end end context "when not authorized" do @@ -201,6 +245,21 @@ describe "Permissions" do last_response.status.must_equal 403 end + + context "public directory" do + before do + object = data_bucket.new("jimmy:public/documents:foo") + object.content_type = "text/plain" + object.data = "some private, authorized text data" + object.store + end + + it "returns a 403" do + delete "/jimmy/public/documents/foo" + + last_response.status.must_equal 403 + end + end end end @@ -275,6 +334,37 @@ describe "Permissions" do }.must_raise Riak::HTTPFailedRequest end end + + context "public directory" do + before do + object = data_bucket.new("jimmy:public/tasks:hello") + object.content_type = "text/plain" + object.data = "Hello World" + object.store + end + + it "allows GET requests" do + get "/jimmy/public/tasks/" + + last_response.status.must_equal 200 + end + + it "allows PUT requests" do + put "/jimmy/public/1", "Hello World" + + last_response.status.must_equal 200 + data_bucket.get("jimmy:public:1").data.must_equal "Hello World" + end + + it "allows DELETE requests" do + delete "/jimmy/public/tasks/hello" + + last_response.status.must_equal 204 + lambda { + data_bucket.get("jimmy:public/tasks:hello") + }.must_raise Riak::HTTPFailedRequest + end + end end context "read all" do @@ -304,6 +394,33 @@ describe "Permissions" do last_response.status.must_equal 403 end + + context "public directory" do + before do + object = data_bucket.new("jimmy:public/tasks:hello") + object.content_type = "text/plain" + object.data = "Hello World" + object.store + end + + it "allows GET requests" do + get "/jimmy/tasks/" + + last_response.status.must_equal 200 + end + + it "disallows PUT requests" do + put "/jimmy/tasks/foo", "some text" + + last_response.status.must_equal 403 + end + + it "disallows DELETE requests" do + delete "/jimmy/tasks/hello" + + last_response.status.must_equal 403 + end + end end end