diff --git a/.watchr.rb b/.watchr.rb index 1cfaa9c..9d7fca5 100644 --- a/.watchr.rb +++ b/.watchr.rb @@ -53,11 +53,10 @@ def run_spec_cmd(cmd) # Run all tests (Ctrl-c) Signal.trap 'INT' do check_exit # exit (double Ctrl-c) - @second_int = true + #@second_int = true run_spec "spec/" end def check_exit exit if @second_int - @second_int = false end diff --git a/app/controllers/oauth/oauth_authorize_controller.rb b/app/controllers/oauth/oauth_authorize_controller.rb index d1f7df1..8cc2d2a 100644 --- a/app/controllers/oauth/oauth_authorize_controller.rb +++ b/app/controllers/oauth/oauth_authorize_controller.rb @@ -41,7 +41,7 @@ def destroy def normalize_scope params[:scope] ||= "" - params[:scope] = Lelylan::Oauth::Scope.normalize(params[:scope].split(" ")) + params[:scope] = Oauth.normalize_scope(params[:scope]) end diff --git a/app/controllers/oauth/oauth_token_controller.rb b/app/controllers/oauth/oauth_token_controller.rb index 1e3a7ed..ca23481 100644 --- a/app/controllers/oauth/oauth_token_controller.rb +++ b/app/controllers/oauth/oauth_token_controller.rb @@ -83,7 +83,7 @@ def find_authorization_expired def normalize_scope if @body[:grant_type] == "password" @body[:scope] ||= "" - @body[:scope] = Lelylan::Oauth::Scope.normalize(@body[:scope].split(" ")) + @body[:scope] = Oauth.normalize_scope(@body[:scope]) end end diff --git a/app/controllers/pizzas_controller.rb b/app/controllers/pizzas_controller.rb index 4f1a357..8b5db78 100644 --- a/app/controllers/pizzas_controller.rb +++ b/app/controllers/pizzas_controller.rb @@ -1,2 +1,29 @@ class PizzasController < ApplicationController + before_filter :oauth_authorized + + def index + render json: {action: :index} + end + + def show + render json: {action: :show} + end + + def create + render json: {action: :create} + end + + def update + render json: {action: :update} + end + + def destroy + render json: {action: :destroy} + end + + private + + def oauth_authorized + end + end diff --git a/config/initializers/oauth_scope.rb b/config/initializers/oauth_scope.rb index c983888..efc5663 100644 --- a/config/initializers/oauth_scope.rb +++ b/config/initializers/oauth_scope.rb @@ -1,34 +1,14 @@ -# TODO: organize this in a Lelylan::Oauth::Scope class so -# that you can give it a more modular structure - -module Lelylan - module Oauth - module Scope - - SCOPE = %w( - type.read type.write - property.read property.write - function.read function.write - status.read status.write - ) - - MATCHES = { - write: SCOPE, - read: %w(type.read property.read function.read status.read), - type: %w(type.read type.write), - property: %w(property.read property.write), - function: %w(function.read function.write), - status: %w(status.read status.write) - } - - def self.normalize(scope = []) - normalized = scope.clone - scope.each { |key| normalized << MATCHES[key.to_sym] } - normalized.flatten! - intersection = normalized & SCOPE - return intersection - end - +module Oauth + + def self.normalize_scope(scope) + scope = scope.split(" ") if scope.kind_of? String + normalized = Scope.any_in(name: scope) + normalized = normalized.map(&:values).flatten + if normalized.empty? + return scope + else + return scope + self.normalize_scope(normalized) end end + end diff --git a/config/oauth.yml b/config/oauth.yml index 2aa73f2..86ba95d 100644 --- a/config/oauth.yml +++ b/config/oauth.yml @@ -1,3 +1,4 @@ token_expires_in: "1800" authorization_expires_in: "150" random_length: 32 +scope_separator: " " diff --git a/config/routes.rb b/config/routes.rb index ab24901..8c5735c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,4 +16,9 @@ resources :scopes root :to => "users#new" + + # sample resources + resources :pizzas, defaults: { format: "json" } + resources :pastas, defaults: { format: "json" } + end diff --git a/spec/acceptance/scopes_controller_spec.rb b/spec/acceptance/scopes_controller_spec.rb index d57e8a9..edd1e81 100644 --- a/spec/acceptance/scopes_controller_spec.rb +++ b/spec/acceptance/scopes_controller_spec.rb @@ -3,7 +3,7 @@ feature "ScopesController" do before { host! "http://" + host } before { @user = Factory(:user) } - before { @scope = Factory(:scope, values: WRITE_SCOPE) } + before { @scope = Factory(:scope, values: ALL_SCOPE) } context ".index" do diff --git a/spec/extras/scope_spec.rb b/spec/extras/scope_spec.rb index 156c09c..37d38d9 100644 --- a/spec/extras/scope_spec.rb +++ b/spec/extras/scope_spec.rb @@ -1,47 +1,138 @@ require 'spec_helper' -describe "Lelylan::Oauth::Scope" do +describe "Oauth" do + before { Scope.destroy_all } - context "when normalizing key" do - context "#write" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["write"]) } - it { scope.should == Lelylan::Oauth::Scope::MATCHES[:write] } - end + before { @scope = Factory(:scope_pizzas_read) } + before { @scope = Factory(:scope_pizzas_all) } + before { @scope = Factory(:scope_pastas_read) } + before { @scope = Factory(:scope_pastas_all) } + before { @scope = Factory(:scope_read) } + before { @scope = Factory(:scope_all) } - context "#read" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["read"]) } - it { scope.should == Lelylan::Oauth::Scope::MATCHES[:read] } - end + context "#normalize_scope" do + context "single resource" do + context "single action" do + let(:normalized) { Oauth.normalize_scope("pizzas/index") } + subject { normalized } + it { should include "pizzas/index" } + end - context "#type" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["type"]) } - it { scope.should == ["type.read", "type.write"] } - end + context "read actions" do + let(:normalized) { Oauth.normalize_scope("pizzas/read") } + subject { normalized } - context "#property" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["property"]) } - it { scope.should == ["property.read", "property.write"] } - end + it { should include "pizzas/index" } + it { should include "pizzas/show" } + it { should_not include "pizzas/create"} + end + + context "read actions and create action" do + let(:normalized) { Oauth.normalize_scope("pizzas/read pizzas/create") } + subject { normalized } + + it { should include "pizzas/index" } + it { should include "pizzas/show" } + it { should include "pizzas/create"} + end + + context "all rest actions" do + let(:normalized) { Oauth.normalize_scope("pizzas") } + subject { normalized } - context "#function" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["function"]) } - it { scope.should == ["function.read", "function.write"] } + it { should include "pizzas/index" } + it { should include "pizzas/show" } + it { should include "pizzas/create" } + it { should include "pizzas/update" } + it { should include "pizzas/destroy"} + it { should_not include "pastas/index" } + end end - context "#status" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["status"]) } - it { scope.should == ["status.read", "status.write"] } + context "all resources" do + context "single actions" do + let(:normalized) { Oauth.normalize_scope("pizzas/index pastas/index") } + subject { normalized } + it { should include "pizzas/index" } + it { should_not include "pizzas/show" } + it { should include "pastas/index" } + it { should_not include "pastas/show" } + end + + context "read actions" do + let(:normalized) { Oauth.normalize_scope("read") } + subject { normalized } + + it { should include "pizzas/index" } + it { should include "pizzas/show" } + it { should_not include "pizzas/create"} + it { should include "pastas/index" } + it { should include "pastas/show" } + it { should_not include "pastas/create"} + end + + context "all rest actions" do + let(:normalized) { Oauth.normalize_scope("all") } + subject { normalized } + + it { should include "pizzas/index" } + it { should include "pizzas/show" } + it { should include "pizzas/create" } + it { should include "pizzas/update" } + it { should include "pizzas/destroy"} + + it { should include "pastas/index" } + it { should include "pastas/show" } + it { should include "pastas/create" } + it { should include "pastas/update" } + it { should include "pastas/destroy"} + end end - end - context "when normalizing bases" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["status.read", "property.write"]) } - it { scope.should == ["status.read", "property.write"]} end +end - context "when normalizing not existing keys" do - let(:scope) { Lelylan::Oauth::Scope.normalize(["status.read", "resource.not_existing"]) } - it { scope.should == ["status.read"]} - end -end + + + #context "when normalizing key" do + #context "#write" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["write"]) } + #it { scope.should == Lelylan::Oauth::Scope::MATCHES[:write] } + #end + + #context "#read" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["read"]) } + #it { scope.should == Lelylan::Oauth::Scope::MATCHES[:read] } + #end + + #context "#type" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["type"]) } + #it { scope.should == ["type.read", "type.write"] } + #end + + #context "#property" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["property"]) } + #it { scope.should == ["property.read", "property.write"] } + #end + + #context "#function" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["function"]) } + #it { scope.should == ["function.read", "function.write"] } + #end + + #context "#status" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["status"]) } + #it { scope.should == ["status.read", "status.write"] } + #end + #end + + #context "when normalizing bases" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["status.read", "property.write"]) } + #it { scope.should == ["status.read", "property.write"]} + #end + + #context "when normalizing not existing keys" do + #let(:scope) { Lelylan::Oauth::Scope.normalize(["status.read", "resource.not_existing"]) } + #it { scope.should == ["status.read"]} + #end diff --git a/spec/factories/oauth.rb b/spec/factories/oauth.rb index decfee0..39feea9 100644 --- a/spec/factories/oauth.rb +++ b/spec/factories/oauth.rb @@ -17,13 +17,13 @@ factory :oauth_authorization do client_uri CLIENT_URI resource_owner_uri USER_URI - scope Lelylan::Oauth::Scope::SCOPE + scope ALL_SCOPE end factory :oauth_token do client_uri CLIENT_URI resource_owner_uri USER_URI - scope Lelylan::Oauth::Scope::SCOPE + scope ALL_SCOPE end factory :oauth_client do @@ -31,19 +31,50 @@ name "the client" created_from USER_URI redirect_uri REDIRECT_URI - scope Lelylan::Oauth::Scope::SCOPE + scope ALL_SCOPE end factory :oauth_client_read, parent: :oauth_client do uri ANOTHER_CLIENT_URI - scope Lelylan::Oauth::Scope::MATCHES[:read] + scope READ_SCOPE end + # TODO: make a factory file just for scopes factory :scope do uri SCOPE_URI name "write" end + factory :scope_pizzas_read, parent: :scope do + name "pizzas/read" + values ["pizzas/index", "pizzas/show"] + end + + factory :scope_pizzas_all, parent: :scope do + name "pizzas" + values ["pizzas/create", "pizzas/update", "pizzas/destroy", "pizzas/read"] + end + + factory :scope_pastas_read, parent: :scope do + name "pastas/read" + values ["pastas/index", "pastas/show"] + end + + factory :scope_pastas_all, parent: :scope do + name "pastas" + values ["pastas/create", "pastas/update", "pastas/destroy", "pastas/read"] + end + + factory :scope_read, parent: :scope do + name "read" + values ["pizzas/read", "pastas/read"] + end + + factory :scope_all, parent: :scope do + name "all" + values ["pizzas", "pastas"] + end + end diff --git a/spec/models/scope_spec.rb b/spec/models/scope_spec.rb index d135e71..ea8369b 100644 --- a/spec/models/scope_spec.rb +++ b/spec/models/scope_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Scope do - before { @scope = Factory(:scope, values: WRITE_SCOPE) } + before { @scope = Factory(:scope, values: ALL_SCOPE) } subject { @scope } it { should validate_presence_of(:name) } diff --git a/spec/support/settings_helper.rb b/spec/support/settings_helper.rb index cb85800..2ea1ac9 100644 --- a/spec/support/settings_helper.rb +++ b/spec/support/settings_helper.rb @@ -14,7 +14,7 @@ module SettingsHelper # scopes SCOPE_URI = HOST + "/scopes/write" - WRITE_SCOPE = ["pizza/read", "pizza/write", "pasta/read", "pasta/write"] + ALL_SCOPE = ["pizza/read", "pizza/write", "pasta/read", "pasta/write"] READ_SCOPE = ["pizza/read", "pasta/read"]