require 'rails_helper' RSpec.describe Rs::OauthController, type: :controller do let(:user) { create :user } describe "GET /rs/oauth/:useraddress" do context "when user is signed in" do before do sign_in user end context "when username is different than current user" do let(:other_user) { create :user, id: 23, cn: "jomokenyatta", email: "jomo@hotmail.com" } before do get :new, params: { useraddress: other_user.address, redirect_uri: "https://example.com", client_id: "example.com", scope: "examples" } end it "logs out the users and repeats the request" do url = new_rs_oauth_url other_user.address, redirect_uri: "https://example.com", client_id: "example.com", scope: "examples" expect(response).to redirect_to(url) end end context "when no valid token exists" do before do get :new, params: { useraddress: user.address, redirect_uri: "https://example.com", client_id: "example.com", scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", state: "foobar123" } end it "returns a 200" do expect(response.response_code).to eq(200) end it "sets the instance variables" do expected_scopes = %w(documents photos contacts:rw videos:r tasks/work:r) expect(assigns["user"]).to eq(user) expect(assigns["redirect_uri"]).to eq("https://example.com") expect(assigns["scopes"]).to eq(expected_scopes) expect(assigns["client_id"]).to eq("example.com") expect(assigns["root_access_requested"]).to eq(false) expect(assigns["state"]).to eq("foobar123") expect(assigns["denial_url"]).to eq("https://example.com#error=access_denied&state=foobar123") end context "no redirect_uri" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", client_id: "https://example.com" } end it "returns a 400" do expect(response.response_code).to eq(400) end end context "no client_id" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com" } end it "redirects with invalid_request error" do expect(response).to redirect_to("https://example.com#error=invalid_request") end end context "different host for client_id and redirect_uri" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com/foobar", client_id: "https://google.com" } end it "redirects with invalid_client error" do expect(response).to redirect_to("https://example.com/foobar#error=invalid_client") end end end context "when valid token already exists" do before do @auth = user.remote_storage_authorizations.create!( permissions: %w(documents photos contacts:rw videos:r tasks/work:r), client_id: "example.com", redirect_uri: "https://example.com", expire_at: 1.day.from_now ) end after { @auth.destroy } context "with same host for client_id and redirect_uri" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com", client_id: "https://example.com" } end it "redirects to the redirect_uri with the existing token" do expect(response).to redirect_to("https://example.com#access_token=#{@auth.token}") end end context "with different host for client_id and redirect_uri" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://app.example.com", client_id: "https://example.com" } end it "redirects with invalid_client error" do expect(response).to redirect_to("https://app.example.com#error=invalid_client") end end context "with different redirect_uri" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com/a_new_route", client_id: "https://example.com" } end it "redirects to the new redirect_uri" do expect(response).to redirect_to("https://example.com/a_new_route#access_token=#{@auth.token}") end end context "with state param given" do before do get :new, params: { useraddress: user.address, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com", client_id: "https://example.com", state: "foobar123" } end it "redirects to the redirect_uri with token and state" do expect(response).to redirect_to("https://example.com#access_token=#{@auth.token}&state=foobar123") end end end context "no scope" do before do get :new, params: { useraddress: user.address, redirect_uri: "https://example.com", client_id: "https://example.com", state: "foobar123" } end it "redirects to the redirect_uri with an error code" do expect(response).to redirect_to("https://example.com#error=invalid_scope&state=foobar123") end end context "empty scope" do before do get :new, params: { useraddress: user.address, scope: "", redirect_uri: "https://example.com", client_id: "https://example.com", state: "foobar123" } end it "redirects to the redirect_uri with an error code" do expect(response).to redirect_to("https://example.com#error=invalid_scope&state=foobar123") end end end context "when user is not signed in" do it "redirects to the signin page with username pre-filled" do get :new, params: { useraddress: user.address, scope: "documents,photos", redirect_uri: "https://example.com" } expect(response).to redirect_to(new_user_session_path(cn: user.cn, ou: user.ou)) end end describe "root access" do before do sign_in user end describe "full" do before do get :new, params: { useraddress: user.address, scope: "*:rw", redirect_uri: "https://example.com", client_id: "example.com" } end it "sets the instance variables" do expect(assigns["scopes"]).to eq([":rw"]) expect(assigns["root_access_requested"]).to be(true) end end describe "read-only" do before do get :new, params: { useraddress: user.address, scope: "*:r", redirect_uri: "https://example.com", client_id: "example.com" } end it "sets the instance variables" do expect(assigns["scopes"]).to eq([":r"]) expect(assigns["root_access_requested"]).to be(true) end end end end describe "POST /rs/oauth/:useraddress" do context "when user is signed in" do before do sign_in user end after do user.remote_storage_authorizations.destroy_all end context "when no valid token exists" do before do post :create, params: { user_id: user.id, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com", client_id: "example.com", state: "foobar123", expire_at: 1.day.from_now } @auth = user.reload.remote_storage_authorizations.first end it "creates a new token" do expect(@auth.permissions).to eq(%w(documents photos contacts:rw videos:r tasks/work:r)) end it "redirects to the redirect_uri" do expect(response).to redirect_to("https://example.com#access_token=#{@auth.token}&state=foobar123") end end context "when token is expired" do before do @auth = user.remote_storage_authorizations.create!( permissions: %w(documents), client_id: "example.com", redirect_uri: "https://example.com", expire_at: 1.day.ago, token: nil ) post :create, params: { user_id: user.id, scope: "documents", redirect_uri: "https://example.com", client_id: "example.com", state: "foobar123", expire_at: 1.month.from_now } end it "updates the token" do expect(@auth.reload.token).not_to be_nil end end context "root access with several scopes" do before do post :create, params: { user_id: user.id, scope: "*:rw contacts:r", redirect_uri: "https://example.com", client_id: "example.com", expire_at: 1.month.from_now } @auth = user.reload.remote_storage_authorizations.first end it "removes all scopes except for the root permission" do expect(@auth.permissions).to eq(%w(:rw)) end end context "no redirect_uri" do before do post :create, params: { user_id: user.id, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", client_id: "example.com", expire_at: 1.month.from_now } end it "returns a 400" do expect(response.response_code).to eq(400) end end context "no client_id" do before do post :create, params: { user_id: user.id, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", redirect_uri: "https://example.com", expire_at: 1.month.from_now } end it "redirects with invalid_request error" do expect(response).to redirect_to("https://example.com#error=invalid_request") end end context "hostnames of client_id and redirect_uri do not match" do before do post :create, params: { user_id: user.id, scope: "documents,[photos], contacts:rw videos:r tasks/work/:r", client_id: "fishing.com", redirect_uri: "https://example.com", expire_at: 1.month.from_now } end it "redirects with invalid_client error" do expect(response).to redirect_to("https://example.com#error=invalid_client") end end context "empty scope" do before do post :create, params: { user_id: user.id, scope: "", redirect_uri: "https://example.com", client_id: "example.com", state: "foobar123", expire_at: 1.month.from_now } end it "redirects to the redirect_uri with an error code" do expect(response).to redirect_to("https://example.com#error=invalid_scope&state=foobar123") end end context "when the user_id is different from the signed in user" do before do post :create, params: { user_id: user.id, scope: "documents,photos", redirect_uri: "https://example.com", client_id: "example.com", expire_at: 1.month.from_now } end it "returns a 403" do post :create, params: { user_id: "69", scope: "documents,photos", redirect_uri: "https://example.com", client_id: "example.com", expire_at: 1.month.from_now } expect(response.response_code).to eq(403) end end end context "when user is not signed in" do it "redirects to the signin page" do post :create, params: { user_id: user.id, scope: "documents,photos", redirect_uri: "https://example.com", client_id: "example.com", expire_at: 1.month.from_now } expect(response).to redirect_to(new_user_session_path) end end end describe "GET /rs/oauth/token/:id/launch_app" do context "when user is signed in" do before do sign_in user end context "token exists" do before do @auth = user.remote_storage_authorizations.create!( permissions: %w(documents), client_id: "app.example.com", redirect_uri: "https://app.example.com", expire_at: 2.days.from_now ) get :launch_app, params: { id: @auth.id } end after do @auth.destroy end it "redirects to the given URL with the correct RS URL fragment params" do launch_url = "https://app.example.com#remotestorage=#{user.address}&access_token=#{@auth.token}" expect(response).to redirect_to(launch_url) end end end end end