spec/requests/flows/password_spec.rb in doorkeeper-mongodb-5.2.1 vs spec/requests/flows/password_spec.rb in doorkeeper-mongodb-5.2.2

- old
+ new

@@ -1,316 +1,356 @@ # frozen_string_literal: true require "spec_helper" -describe "Resource Owner Password Credentials Flow not set up" do - before do - client_exists - create_resource_owner - end +RSpec.describe "Resource Owner Password Credentials Flow" do + context "when not setup properly" do + before do + client_exists + create_resource_owner + end - context "with valid user credentials" do - it "does not issue new token" do - expect do - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - end.to_not(change { Doorkeeper::AccessToken.count }) + context "with valid user credentials" do + it "does not issue new token" do + expect do + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) + end.not_to(change { Doorkeeper::AccessToken.count }) + end end end -end -describe "Resource Owner Password Credentials Flow" do - let(:client_attributes) { { redirect_uri: nil } } + context "when grant type configured" do + let(:client_attributes) { { redirect_uri: nil } } - before do - config_is_set(:grant_flows, ["password"]) - config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] } - client_exists(client_attributes) - create_resource_owner - end + before do + config_is_set(:grant_flows, ["password"]) + config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] } + client_exists(client_attributes) + create_resource_owner + end - context "with valid user credentials" do - context "with non-confidential/public client" do - let(:client_attributes) { { confidential: false } } + context "with valid user credentials" do + context "with confidential client authorized using Basic auth" do + it "issues a new token" do + expect do + post password_token_endpoint_url( + resource_owner: @resource_owner, + ), headers: { "HTTP_AUTHORIZATION" => basic_auth_header_for_client(@client) } + end.to(change { Doorkeeper::AccessToken.count }) - context "when configured to check application supported grant flow" do - before do - Doorkeeper.configuration.instance_variable_set( - :@allow_grant_flow_for_client, - ->(_grant_flow, client) { client.name == "admin" }, + token = Doorkeeper::AccessToken.first + expect(token.application_id).to eq(@client.id) + + expect(json_response).to match( + "access_token" => token.token, + "expires_in" => an_instance_of(Integer), + "token_type" => "Bearer", + "created_at" => an_instance_of(Integer), ) end + end - scenario "forbids the request when doesn't satisfy condition" do - @client.update(name: "sample app") + context "with non-confidential/public client" do + let(:client_attributes) { { confidential: false } } - expect do - post password_token_endpoint_url( - client_id: @client.uid, - client_secret: "foobar", - resource_owner: @resource_owner, + context "when configured to check application supported grant flow" do + before do + Doorkeeper.configuration.instance_variable_set( + :@allow_grant_flow_for_client, + ->(_grant_flow, client) { client.name == "admin" }, ) - end.not_to(change { Doorkeeper::AccessToken.count }) + end - expect(response.status).to eq(401) - should_have_json "error", "invalid_client" - end + scenario "forbids the request when doesn't satisfy condition" do + @client.update(name: "sample app") - scenario "allows the request when satisfies condition" do - @client.update(name: "admin") + expect do + post password_token_endpoint_url( + client_id: @client.uid, + client_secret: "foobar", + resource_owner: @resource_owner, + ) + end.not_to(change { Doorkeeper::AccessToken.count }) - expect do - post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner) - end.to change { Doorkeeper::AccessToken.count }.by(1) + expect(response.status).to eq(401) + expect(json_response).to match( + "error" => "invalid_client", + "error_description" => an_instance_of(String), + ) + end - token = Doorkeeper::AccessToken.first + scenario "allows the request when satisfies condition" do + @client.update(name: "admin") - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token + expect do + post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner) + end.to change { Doorkeeper::AccessToken.count }.by(1) + + token = Doorkeeper::AccessToken.first + expect(token.application_id).to eq(@client.id) + + expect(json_response).to include("access_token" => token.token) + end end - end - context "when client_secret absent" do - it "should issue new token" do - expect do - post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner) - end.to change { Doorkeeper::AccessToken.count }.by(1) + context "when client_secret absent" do + it "issues a new token" do + expect do + post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner) + end.to change { Doorkeeper::AccessToken.count }.by(1) - token = Doorkeeper::AccessToken.first + token = Doorkeeper::AccessToken.first - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token + expect(token.application_id).to eq(@client.id) + expect(json_response).to include("access_token" => token.token) + end end + + context "when client_secret present" do + it "issues a new token" do + expect do + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) + end.to change { Doorkeeper::AccessToken.count }.by(1) + + token = Doorkeeper::AccessToken.first + + expect(token.application_id).to eq(@client.id) + expect(json_response).to include("access_token" => token.token) + end + + context "when client_secret incorrect" do + it "doesn't issue new token" do + expect do + post password_token_endpoint_url( + client_id: @client.uid, + client_secret: "foobar", + resource_owner: @resource_owner, + ) + end.not_to(change { Doorkeeper::AccessToken.count }) + + expect(response.status).to eq(401) + expect(json_response).to include( + "error" => "invalid_client", + "error_description" => an_instance_of(String), + ) + end + end + end end - context "when client_secret present" do - it "should issue new token" do + context "with confidential/private client" do + it "issues a new token" do expect do post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) end.to change { Doorkeeper::AccessToken.count }.by(1) token = Doorkeeper::AccessToken.first - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token + expect(token.application_id).to eq(@client.id) + expect(json_response).to include("access_token" => token.token) end - context "when client_secret incorrect" do - it "should not issue new token" do + context "when client_secret absent" do + it "doesn't issue new token" do expect do - post password_token_endpoint_url( - client_id: @client.uid, - client_secret: "foobar", - resource_owner: @resource_owner, - ) + post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner) end.not_to(change { Doorkeeper::AccessToken.count }) expect(response.status).to eq(401) - should_have_json "error", "invalid_client" + expect(json_response).to match( + "error" => "invalid_client", + "error_description" => an_instance_of(String), + ) end end end - end - context "with confidential/private client" do - it "should issue new token" do + it "issues new token without client credentials" do expect do - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - end.to change { Doorkeeper::AccessToken.count }.by(1) + post password_token_endpoint_url(resource_owner: @resource_owner) + end.to(change { Doorkeeper::AccessToken.count }.by(1)) token = Doorkeeper::AccessToken.first - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token + expect(token.application_id).to be_nil + expect(json_response).to include("access_token" => token.token) end - context "when client_secret absent" do - it "should not issue new token" do - expect do - post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner) - end.not_to(change { Doorkeeper::AccessToken.count }) + it "issues a refresh token if enabled" do + config_is_set(:refresh_token_enabled, true) - expect(response.status).to eq(401) - should_have_json "error", "invalid_client" - end + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) + + token = Doorkeeper::AccessToken.first + expect(json_response).to include("refresh_token" => token.refresh_token) end - end - it "should issue new token without client credentials" do - expect do - post password_token_endpoint_url(resource_owner: @resource_owner) - end.to(change { Doorkeeper::AccessToken.count }.by(1)) + it "returns the same token if it is still accessible" do + allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) - token = Doorkeeper::AccessToken.first + client_is_authorized(@client, @resource_owner) - expect(token.application_id).to be_nil - should_have_json "access_token", token.token - end + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - it "should issue a refresh token if enabled" do - config_is_set(:refresh_token_enabled, true) + expect(Doorkeeper::AccessToken.count).to be(1) + expect(json_response).to include("access_token" => Doorkeeper::AccessToken.first.token) + end - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) + context "with valid, default scope" do + before do + default_scopes_exist :public + end - token = Doorkeeper::AccessToken.first + it "issues new token" do + expect do + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner, scope: "public") + end.to change { Doorkeeper::AccessToken.count }.by(1) - should_have_json "refresh_token", token.refresh_token - end + token = Doorkeeper::AccessToken.first - it "should return the same token if it is still accessible" do - allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) - - client_is_authorized(@client, @resource_owner) - - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - - expect(Doorkeeper::AccessToken.count).to be(1) - should_have_json "access_token", Doorkeeper::AccessToken.first.token + expect(token.application_id).to eq(@client.id) + expect(json_response).to include( + "access_token" => token.token, + "scope" => "public", + ) + end + end end - context "with valid, default scope" do + context "when application scopes are present and differs from configured default scopes and no scope is passed" do before do default_scopes_exist :public + @client.update(scopes: "abc") end - it "should issue new token" do + it "issues new token without any scope" do expect do - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner, scope: "public") + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) end.to change { Doorkeeper::AccessToken.count }.by(1) token = Doorkeeper::AccessToken.first - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token - should_have_json "scope", "public" + expect(token.application_id).to eq(@client.id) + expect(token.scopes).to be_empty + expect(json_response).to include("access_token" => token.token) + expect(json_response).not_to include("scope") end end - end - context "when application scopes are present and differs from configured default scopes and no scope is passed" do - before do - default_scopes_exist :public - @client.update(scopes: "abc") - end + context "when application scopes contain some of the default scopes and no scope is passed" do + before do + @client.update(scopes: "read write public") + end - it "issues new token without any scope" do - expect do - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - end.to change { Doorkeeper::AccessToken.count }.by(1) + it "issues new token with one default scope that are present in application scopes" do + default_scopes_exist :public, :admin - token = Doorkeeper::AccessToken.first + expect do + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) + end.to change { Doorkeeper::AccessToken.count }.by(1) - expect(token.application_id).to eq @client.id - expect(token.scopes).to be_empty - should_have_json "access_token", token.token - should_not_have_json "scope" - end - end + token = Doorkeeper::AccessToken.first - context "when application scopes contain some of the default scopes and no scope is passed" do - before do - @client.update(scopes: "read write public") - end + expect(token.application_id).to eq(@client.id) + expect(json_response).to include( + "access_token" => token.token, + "scope" => "public", + ) + end - it "issues new token with one default scope that are present in application scopes" do - default_scopes_exist :public, :admin + it "issues new token with multiple default scopes that are present in application scopes" do + default_scopes_exist :public, :read, :update - expect do - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - end.to change { Doorkeeper::AccessToken.count }.by(1) + expect do + post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) + end.to change { Doorkeeper::AccessToken.count }.by(1) - token = Doorkeeper::AccessToken.first + token = Doorkeeper::AccessToken.first - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token - should_have_json "scope", "public" + expect(token.application_id).to eq(@client.id) + expect(json_response).to include( + "access_token" => token.token, + "scope" => "public read", + ) + end end - it "issues new token with multiple default scopes that are present in application scopes" do - default_scopes_exist :public, :read, :update + context "with invalid scopes" do + subject do + post password_token_endpoint_url( + client: @client, + resource_owner: @resource_owner, + scope: "random", + ) + end - expect do - post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) - end.to change { Doorkeeper::AccessToken.count }.by(1) + it "doesn't issue new token" do + expect { subject }.not_to(change { Doorkeeper::AccessToken.count }) + end - token = Doorkeeper::AccessToken.first + it "returns invalid_scope error" do + subject - expect(token.application_id).to eq @client.id - should_have_json "access_token", token.token - should_have_json "scope", "public read" - end - end + expect(json_response).to include( + "error" => "invalid_scope", + "error_description" => translated_error_message(:invalid_scope), + ) - context "with invalid scopes" do - subject do - post password_token_endpoint_url( - client: @client, - resource_owner: @resource_owner, - scope: "random", - ) - end + expect(json_response).not_to include("access_token") - it "should not issue new token" do - expect { subject }.to_not(change { Doorkeeper::AccessToken.count }) + expect(response.status).to eq(400) + end end - it "should return invalid_scope error" do - subject - should_have_json "error", "invalid_scope" - should_have_json "error_description", translated_error_message(:invalid_scope) - should_not_have_json "access_token" + context "with invalid user credentials" do + it "doesn't issue new token with bad password" do + expect do + post password_token_endpoint_url( + client: @client, + resource_owner_username: @resource_owner.name, + resource_owner_password: "wrongpassword", + ) + end.not_to(change { Doorkeeper::AccessToken.count }) + end - expect(response.status).to eq(400) - end - end + it "doesn't issue new token without credentials" do + expect do + post password_token_endpoint_url(client: @client) + end.not_to(change { Doorkeeper::AccessToken.count }) + end - context "with invalid user credentials" do - it "should not issue new token with bad password" do - expect do - post password_token_endpoint_url( - client: @client, - resource_owner_username: @resource_owner.name, - resource_owner_password: "wrongpassword", - ) - end.to_not(change { Doorkeeper::AccessToken.count }) - end + it "doesn't issue new token if resource_owner_from_credentials returned false or nil" do + config_is_set(:resource_owner_from_credentials) { false } - it "should not issue new token without credentials" do - expect do - post password_token_endpoint_url(client: @client) - end.to_not(change { Doorkeeper::AccessToken.count }) - end + expect do + post password_token_endpoint_url(client: @client) + end.not_to(change { Doorkeeper::AccessToken.count }) - it "should not issue new token if resource_owner_from_credentials returned false or nil" do - config_is_set(:resource_owner_from_credentials) { false } + config_is_set(:resource_owner_from_credentials) { nil } - expect do - post password_token_endpoint_url(client: @client) - end.to_not(change { Doorkeeper::AccessToken.count }) - - config_is_set(:resource_owner_from_credentials) { nil } - - expect do - post password_token_endpoint_url(client: @client) - end.to_not(change { Doorkeeper::AccessToken.count }) + expect do + post password_token_endpoint_url(client: @client) + end.not_to(change { Doorkeeper::AccessToken.count }) + end end - end - context "with invalid confidential client credentials" do - it "should not issue new token with bad client credentials" do - expect do - post password_token_endpoint_url( - client_id: @client.uid, - client_secret: "bad_secret", - resource_owner: @resource_owner, - ) - end.to_not(change { Doorkeeper::AccessToken.count }) + context "with invalid confidential client credentials" do + it "doesn't issue new token with bad client credentials" do + expect do + post password_token_endpoint_url( + client_id: @client.uid, + client_secret: "bad_secret", + resource_owner: @resource_owner, + ) + end.not_to(change { Doorkeeper::AccessToken.count }) + end end - end - context "with invalid public client id" do - it "should not issue new token with bad client id" do - expect do - post password_token_endpoint_url(client_id: "bad_id", resource_owner: @resource_owner) - end.to_not(change { Doorkeeper::AccessToken.count }) + context "with invalid public client id" do + it "doesn't issue new token with bad client id" do + expect do + post password_token_endpoint_url(client_id: "bad_id", resource_owner: @resource_owner) + end.not_to(change { Doorkeeper::AccessToken.count }) + end end end end