Add integration tests for implicit flow
Squashed commits: [d5001fe] Refactor [8d8a23f] Add test for when authorization is denied [659fc56] Adjust password flow integration test
This commit is contained in:
parent
ee9ac06e1a
commit
7b80a7408d
12 changed files with 82 additions and 42 deletions
|
|
@ -4,6 +4,7 @@ class OpenidConnect::Authorization < ActiveRecord::Base
|
||||||
|
|
||||||
validates :user, presence: true
|
validates :user, presence: true
|
||||||
validates :o_auth_application, presence: true
|
validates :o_auth_application, presence: true
|
||||||
|
validates :user, uniqueness: {scope: :o_auth_application}
|
||||||
|
|
||||||
has_many :scopes, through: :authorization_scopes
|
has_many :scopes, through: :authorization_scopes
|
||||||
has_many :o_auth_access_tokens, dependent: :destroy
|
has_many :o_auth_access_tokens, dependent: :destroy
|
||||||
|
|
|
||||||
|
|
@ -602,10 +602,6 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_authorization_by_client_id(client_id)
|
|
||||||
OpenidConnect::Authorization.find_by_client_id_and_user client_id, self
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def clearable_fields
|
def clearable_fields
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,4 @@ class CreateOAuthApplications < ActiveRecord::Migration
|
||||||
t.timestamps null: false
|
t.timestamps null: false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.down
|
|
||||||
drop_table :o_auth_applications
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
class CreateOAuthAccessTokens < ActiveRecord::Migration
|
class CreateOAuthAccessTokens < ActiveRecord::Migration
|
||||||
def self.up
|
def change
|
||||||
create_table :o_auth_access_tokens do |t|
|
create_table :o_auth_access_tokens do |t|
|
||||||
t.belongs_to :authorization, index: true
|
t.belongs_to :authorization, index: true
|
||||||
t.string :token
|
t.string :token
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ Feature: Access protected resources using password flow
|
||||||
|
|
||||||
Scenario: Invalid credentials to token endpoint
|
Scenario: Invalid credentials to token endpoint
|
||||||
When I register a new client
|
When I register a new client
|
||||||
And I send a post request from that client to the token endpoint using invalid credentials
|
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
|
Then I should receive an "invalid_grant" error
|
||||||
|
|
||||||
Scenario: Invalid bearer tokens sent
|
Scenario: Invalid bearer tokens sent
|
||||||
When I register a new client
|
When I register a new client
|
||||||
And I send a post request from that client to the token endpoint using "kent"'s credentials
|
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
|
And I use invalid bearer tokens to access user info
|
||||||
Then I should receive an "invalid_token" error
|
Then I should receive an "invalid_token" error
|
||||||
|
|
||||||
Scenario: Valid password flow
|
Scenario: Valid password flow
|
||||||
When I register a new client
|
When I register a new client
|
||||||
And I send a post request from that client to the token endpoint using "kent"'s credentials
|
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
|
And I use received valid bearer tokens to access user info
|
||||||
Then I should receive "kent"'s id, username, and email
|
Then I should receive "kent"'s id, username, and email
|
||||||
|
|
|
||||||
26
features/desktop/oidc_implicit_flow.feature
Normal file
26
features/desktop/oidc_implicit_flow.feature
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
@javascript
|
||||||
|
Feature: Access protected resources using implicit flow
|
||||||
|
Background:
|
||||||
|
Given a user with username "kent"
|
||||||
|
And the OpenID scope exists
|
||||||
|
|
||||||
|
Scenario: Invalid client id to auth endpoint
|
||||||
|
When I register a new client
|
||||||
|
And I send a post request from that client to the implicit flow authorization endpoint using a invalid client id
|
||||||
|
And I sign in as "kent@kent.kent"
|
||||||
|
Then I should see an "bad_request" error
|
||||||
|
|
||||||
|
Scenario: Application is denied authorization
|
||||||
|
When I register a new client
|
||||||
|
And I send a post request from that client to the implicit flow authorization endpoint
|
||||||
|
And I sign in as "kent@kent.kent"
|
||||||
|
And I deny authorization to the client
|
||||||
|
Then I should not see any tokens in the redirect url
|
||||||
|
|
||||||
|
Scenario: Application is authorized
|
||||||
|
When I register a new client
|
||||||
|
And I send a post request from that client to the implicit flow authorization endpoint
|
||||||
|
And I sign in as "kent@kent.kent"
|
||||||
|
And I give my consent and authorize the client
|
||||||
|
And I parse the bearer tokens and use it to access user info
|
||||||
|
Then I should receive "kent"'s id, username, and email
|
||||||
41
features/step_definitions/implicit_flow_steps.rb
Normal file
41
features/step_definitions/implicit_flow_steps.rb
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
Given(/^the OpenID scope exists$/) do
|
||||||
|
OpenidConnect::Scope.create(name: "openid")
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^I send a post request from that client to the implicit flow authorization endpoint$/ do
|
||||||
|
client_json = JSON.parse(last_response.body)
|
||||||
|
auth_endpoint_url = "/openid_connect/authorizations/new"
|
||||||
|
visit auth_endpoint_url + "?client_id=" + client_json["o_auth_application"]["client_id"] + "&redirect_uri=" + "http://localhost:3000" +
|
||||||
|
"&response_type=id_token token" + "&scope=openid" + "&nonce=hello" + "&state=hi"
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^I send a post request from that client to the implicit flow authorization endpoint using a invalid client id/ do
|
||||||
|
auth_endpoint_url = "/openid_connect/authorizations/new"
|
||||||
|
visit auth_endpoint_url + "?client_id=randomid" + "&redirect_uri=" + "http://localhost:3000" +
|
||||||
|
"&response_type=id_token token" + "&scope=openid" + "&nonce=hello" + "&state=hi"
|
||||||
|
end
|
||||||
|
|
||||||
|
When /^I give my consent and authorize the client$/ do
|
||||||
|
click_button "Approve"
|
||||||
|
end
|
||||||
|
|
||||||
|
When /^I deny authorization to the client$/ do
|
||||||
|
click_button "Deny"
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see any tokens in the redirect url$/ do
|
||||||
|
access_token = current_url[/(?<=access_token=)[^&]+/]
|
||||||
|
id_token = current_url[/(?<=access_token=)[^&]+/]
|
||||||
|
expect(access_token).to eq(nil)
|
||||||
|
expect(id_token).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
When /^I parse the bearer tokens and use it to access user info$/ do
|
||||||
|
access_token = current_url[/(?<=access_token=)[^&]+/]
|
||||||
|
user_info_endpoint_url = "/api/v0/user/"
|
||||||
|
get user_info_endpoint_url, access_token: access_token
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should see an "([^\"]*)" error$/ do |error_message|
|
||||||
|
expect(page).to have_content(error_message)
|
||||||
|
end
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
When /^I register a new client$/ do
|
When /^I register a new client$/ do
|
||||||
client_registration_url = "/openid_connect/clients"
|
client_registration_url = "/openid_connect/clients"
|
||||||
post client_registration_url, redirect_uris: ["http://localhost:3000"] # Not actually used
|
post client_registration_url, redirect_uris: ["http://localhost:3000"]
|
||||||
end
|
end
|
||||||
|
|
||||||
Given /^I send a post request from that client to the token endpoint using "([^\"]*)"'s credentials$/ do |username|
|
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)
|
client_json = JSON.parse(last_response.body)
|
||||||
user = User.find_by(username: username)
|
user = User.find_by(username: username)
|
||||||
token_endpoint_url = "/openid_connect/access_tokens"
|
token_endpoint_url = "/openid_connect/access_tokens"
|
||||||
|
|
@ -13,7 +13,7 @@ Given /^I send a post request from that client to the token endpoint using "([^\
|
||||||
client_secret: client_json["o_auth_application"]["client_secret"]
|
client_secret: client_json["o_auth_application"]["client_secret"]
|
||||||
end
|
end
|
||||||
|
|
||||||
Given /^I send a post request from that client to the token endpoint using invalid credentials$/ do
|
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)
|
client_json = JSON.parse(last_response.body)
|
||||||
token_endpoint_url = "/openid_connect/access_tokens"
|
token_endpoint_url = "/openid_connect/access_tokens"
|
||||||
post token_endpoint_url, grant_type: "password", username: "bob", password: "wrongpassword",
|
post token_endpoint_url, grant_type: "password", username: "bob", password: "wrongpassword",
|
||||||
|
|
@ -7,17 +7,17 @@ module OpenidConnect
|
||||||
@app = Rack::OAuth2::Server::Token.new do |req, res|
|
@app = Rack::OAuth2::Server::Token.new do |req, res|
|
||||||
o_auth_app = retrieve_client(req)
|
o_auth_app = retrieve_client(req)
|
||||||
if app_valid?(o_auth_app, req)
|
if app_valid?(o_auth_app, req)
|
||||||
handle_flows(req, res)
|
handle_flows(o_auth_app, req, res)
|
||||||
else
|
else
|
||||||
req.invalid_client!
|
req.invalid_client!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_flows(req, res)
|
def handle_flows(o_auth_app, req, res)
|
||||||
case req.grant_type
|
case req.grant_type
|
||||||
when :password
|
when :password
|
||||||
handle_password_flow(req, res)
|
handle_password_flow(o_auth_app, req, res)
|
||||||
when :refresh_token
|
when :refresh_token
|
||||||
handle_refresh_flow(req, res)
|
handle_refresh_flow(req, res)
|
||||||
else
|
else
|
||||||
|
|
@ -25,11 +25,11 @@ module OpenidConnect
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_password_flow(req, res)
|
def handle_password_flow(o_auth_app, req, res)
|
||||||
user = User.find_for_database_authentication(username: req.username)
|
user = User.find_for_database_authentication(username: req.username)
|
||||||
if user
|
if user
|
||||||
if user.valid_password?(req.password)
|
if user.valid_password?(req.password)
|
||||||
auth = OpenidConnect::Authorization.find_or_create(req.client_id, user)
|
auth = OpenidConnect::Authorization.find_or_create_by(o_auth_application: o_auth_app, user: user)
|
||||||
res.access_token = auth.create_access_token
|
res.access_token = auth.create_access_token
|
||||||
else
|
else
|
||||||
req.invalid_grant!
|
req.invalid_grant!
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en-US">
|
|
||||||
<head>
|
|
||||||
<title>Documentation for v0</title>
|
|
||||||
<link href="v2/style.css" media="screen" rel="stylesheet" type="text/css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container">
|
|
||||||
<div id="operations">
|
|
||||||
<h3>API Operations</h3>
|
|
||||||
</div>
|
|
||||||
<div id="content">
|
|
||||||
<h1>Documentation for v0</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
body {margin: 0; background-color: #fff; color: #000; font-family: Arial,sans-serif;}
|
|
||||||
content {margin-left: 200px;}
|
|
||||||
content h1 {text-align: center;}
|
|
||||||
operations {float: left; width: 200px; border-right: 1px solid #ccc;}
|
|
||||||
operations h3 {text-align: center;}
|
|
||||||
|
|
@ -7,6 +7,8 @@ describe OpenidConnect::AuthorizationsController, type: :controller do
|
||||||
name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/", "http://localhost/"])
|
name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/", "http://localhost/"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: jhass - "Might want to setup some factories in spec/factories.rb, see factory_girl's docs."
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in :user, alice
|
sign_in :user, alice
|
||||||
allow(@controller).to receive(:current_user).and_return(alice)
|
allow(@controller).to receive(:current_user).and_return(alice)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue