Delete password flow

This commit is contained in:
theworldbright 2015-07-31 01:46:14 +09:00
parent e5932968fd
commit 2be932ceff
5 changed files with 30 additions and 158 deletions

View file

@ -1,21 +0,0 @@
Feature: Access protected resources using password flow
Background:
Given a user with username "kent"
And all scopes exist
Scenario: Invalid credentials to token endpoint
When I register a new client
And I send a post request from that client to the password flow token endpoint using invalid credentials
Then I should receive an "invalid_grant" error
Scenario: Invalid bearer tokens sent
When I register a new client
And I send a post request from that client to the password flow token endpoint using "kent"'s credentials
And I use invalid bearer tokens to access user info
Then I should receive an "invalid_token" error
Scenario: Valid password flow
When I register a new client
And I send a post request from that client to the password flow token endpoint using "kent"'s credentials
And I use received valid bearer tokens to access user info
Then I should receive "kent"'s id, username, and email

View file

@ -0,0 +1,30 @@
Given(/^all scopes exist$/) do
Api::OpenidConnect::Scope.find_or_create_by(name: "openid")
Api::OpenidConnect::Scope.find_or_create_by(name: "read")
end
When /^I register a new client$/ do
post api_openid_connect_clients_path, redirect_uris: ["http://localhost:3000"], client_name: "diaspora client"
end
When /^I use received valid bearer tokens to access user info$/ do
access_token_json = JSON.parse(last_response.body)
get api_v0_user_path, access_token: access_token_json["access_token"]
end
When /^I use invalid bearer tokens to access user info$/ do
get api_v0_user_path, access_token: SecureRandom.hex(32)
end
Then /^I should receive "([^\"]*)"'s id, username, and email$/ do |username|
user_info_json = JSON.parse(last_response.body)
user = User.find_by_username(username)
expect(user_info_json["username"]).to have_content(user.username)
expect(user_info_json["language"]).to have_content(user.language)
expect(user_info_json["email"]).to have_content(user.email)
end
Then /^I should receive an "([^\"]*)" error$/ do |error_message|
user_info_json = JSON.parse(last_response.body)
expect(user_info_json["error"]).to have_content(error_message)
end

View file

@ -1,48 +0,0 @@
Given(/^all scopes exist$/) do
Api::OpenidConnect::Scope.find_or_create_by(name: "openid")
Api::OpenidConnect::Scope.find_or_create_by(name: "read")
end
When /^I register a new client$/ do
post api_openid_connect_clients_path, redirect_uris: ["http://localhost:3000"], client_name: "diaspora client"
end
Given /^I send a post request from that client to the password flow token endpoint using "([^\"]*)"'s credentials$/ do |username|
client_json = JSON.parse(last_response.body)
user = User.find_by(username: username)
post api_openid_connect_access_tokens_path, grant_type: "password", username: user.username,
password: "password", # Password has been hard coded as all test accounts seem to have a password of "password"
client_id: client_json["o_auth_application"]["client_id"],
client_secret: client_json["o_auth_application"]["client_secret"],
scope: "read"
end
Given /^I send a post request from that client to the password flow token endpoint using invalid credentials$/ do
client_json = JSON.parse(last_response.body)
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob", password: "wrongpassword",
client_id: client_json["o_auth_application"]["client_id"],
client_secret: client_json["o_auth_application"]["client_secret"],
scope: "read"
end
When /^I use received valid bearer tokens to access user info$/ do
access_token_json = JSON.parse(last_response.body)
get api_v0_user_path, access_token: access_token_json["access_token"]
end
When /^I use invalid bearer tokens to access user info$/ do
get api_v0_user_path, access_token: SecureRandom.hex(32)
end
Then /^I should receive "([^\"]*)"'s id, username, and email$/ do |username|
user_info_json = JSON.parse(last_response.body)
user = User.find_by_username(username)
expect(user_info_json["username"]).to have_content(user.username)
expect(user_info_json["language"]).to have_content(user.language)
expect(user_info_json["email"]).to have_content(user.email)
end
Then /^I should receive an "([^\"]*)" error$/ do |error_message|
user_info_json = JSON.parse(last_response.body)
expect(user_info_json["error"]).to have_content(error_message)
end

View file

@ -17,8 +17,6 @@ module Api
def handle_flows(o_auth_app, req, res) def handle_flows(o_auth_app, req, res)
case req.grant_type case req.grant_type
when :password
handle_password_flow(o_auth_app, req, res)
when :refresh_token when :refresh_token
handle_refresh_flow(req, res) handle_refresh_flow(req, res)
when :authorization_code when :authorization_code
@ -34,20 +32,6 @@ module Api
end end
end end
def handle_password_flow(o_auth_app, req, res)
user = User.find_for_database_authentication(username: req.username)
if user
if user.valid_password?(req.password)
auth = OpenidConnect::Authorization.find_or_create_by(o_auth_application: o_auth_app, user: user)
build_auth_and_access_token(auth, req, res)
else
req.invalid_grant!
end
else
req.invalid_grant! # TODO: Change to user login: Perhaps redirect_to login_path?
end
end
def build_auth_and_access_token(auth, req, res) def build_auth_and_access_token(auth, req, res)
scope_list = req.scope.map { |scope_name| scope_list = req.scope.map { |scope_name|
OpenidConnect::Scope.find_by(name: scope_name).tap do |scope| OpenidConnect::Scope.find_by(name: scope_name).tap do |scope|

View file

@ -75,79 +75,6 @@ describe Api::OpenidConnect::TokenEndpoint, type: :request do
end end
end end
describe "the password grant type" do
context "when the username field is missing" do
it "should return an invalid request error" do
post api_openid_connect_access_tokens_path, grant_type: "password", password: "bluepin7",
client_id: client.client_id, client_secret: client.client_secret, scope: "read"
expect(response.body).to include "'username' required"
end
end
context "when the password field is missing" do
it "should return an invalid request error" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob",
client_id: client.client_id, client_secret: client.client_secret, scope: "read"
expect(response.body).to include "'password' required"
end
end
context "when the username does not match an existing user" do
it "should return an invalid request error" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "randomnoexist",
password: "bluepin7", client_id: client.client_id, client_secret: client.client_secret, scope: "read"
expect(response.body).to include "invalid_grant"
end
end
context "when the password is invalid" do
it "should return an invalid request error" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob",
password: "wrongpassword", client_id: client.client_id, client_secret: client.client_secret, scope: "read"
expect(response.body).to include "invalid_grant"
end
end
context "when the client_secret doesn't match" do
it "should return an invalid client error" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob",
password: "bluepin7", client_id: client.client_id, client_secret: "client.client_secret", scope: "read"
expect(response.body).to include "invalid_client"
end
end
context "when the request is valid" do
it "should return an access token" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob",
password: "bluepin7", client_id: client.client_id, client_secret: client.client_secret, scope: "read"
json = JSON.parse(response.body)
expect(json.keys).to include "expires_in"
expect(json["access_token"].length).to eq(64)
expect(json["token_type"]).to eq("bearer")
end
end
context "when there are duplicate fields" do
it "should return an invalid request error" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob", password: "bluepin7",
username: "bob", password: "bluepin6", client_id: client.client_id, client_secret: client.client_secret,
scope: "read"
expect(response.body).to include "invalid_grant"
end
end
context "when the client is unregistered" do
it "should return an error" do
post api_openid_connect_access_tokens_path, grant_type: "password", username: "bob",
password: "bluepin7", client_id: SecureRandom.hex(16).to_s, client_secret: client.client_secret,
scope: "read"
expect(response.body).to include "invalid_client"
end
end
# TODO: Support a way to prevent brute force attacks using rate-limitation
# as specified by RFC 6749 4.3.2 Access Token Request
end
describe "an unsupported grant type" do describe "an unsupported grant type" do
it "should return an unsupported grant type error" do it "should return an unsupported grant type error" do
post api_openid_connect_access_tokens_path, grant_type: "noexistgrant", username: "bob", post api_openid_connect_access_tokens_path, grant_type: "noexistgrant", username: "bob",