From 7b80a7408da614fd78f67da46a7e822271aab3cc Mon Sep 17 00:00:00 2001
From: theworldbright <kent@kentshikama.com>
Date: Thu, 16 Jul 2015 17:12:53 +0900
Subject: [PATCH] Add integration tests for implicit flow

Squashed commits:
[d5001fe] Refactor
[8d8a23f] Add test for when authorization is denied
[659fc56] Adjust password flow integration test
---
 app/models/openid_connect/authorization.rb    |  1 +
 app/models/user.rb                            |  4 --
 ...150613202109_create_o_auth_applications.rb |  4 --
 ...50614134031_create_o_auth_access_tokens.rb |  2 +-
 features/desktop/oauth_password_flow.feature  |  6 +--
 features/desktop/oidc_implicit_flow.feature   | 26 ++++++++++++
 .../step_definitions/implicit_flow_steps.rb   | 41 +++++++++++++++++++
 ...openid_steps.rb => password_flow_steps.rb} |  6 +--
 lib/openid_connect/token_endpoint.rb          | 10 ++---
 public/docs/v0/index.html                     | 17 --------
 public/docs/v0/style.css                      |  5 ---
 .../authorizations_controller_spec.rb         |  2 +
 12 files changed, 82 insertions(+), 42 deletions(-)
 create mode 100644 features/desktop/oidc_implicit_flow.feature
 create mode 100644 features/step_definitions/implicit_flow_steps.rb
 rename features/step_definitions/{openid_steps.rb => password_flow_steps.rb} (88%)
 delete mode 100644 public/docs/v0/index.html
 delete mode 100644 public/docs/v0/style.css

diff --git a/app/models/openid_connect/authorization.rb b/app/models/openid_connect/authorization.rb
index c91aa2cc66..abbe8c090e 100644
--- a/app/models/openid_connect/authorization.rb
+++ b/app/models/openid_connect/authorization.rb
@@ -4,6 +4,7 @@ class OpenidConnect::Authorization < ActiveRecord::Base
 
   validates :user, presence: true
   validates :o_auth_application, presence: true
+  validates :user, uniqueness: {scope: :o_auth_application}
 
   has_many :scopes, through: :authorization_scopes
   has_many :o_auth_access_tokens, dependent: :destroy
diff --git a/app/models/user.rb b/app/models/user.rb
index 28fa845a2d..3766456bca 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -602,10 +602,6 @@ class User < ActiveRecord::Base
     end
   end
 
-  def find_authorization_by_client_id(client_id)
-    OpenidConnect::Authorization.find_by_client_id_and_user client_id, self
-  end
-
   private
 
   def clearable_fields
diff --git a/db/migrate/20150613202109_create_o_auth_applications.rb b/db/migrate/20150613202109_create_o_auth_applications.rb
index c5f44bfef1..0e36a70062 100644
--- a/db/migrate/20150613202109_create_o_auth_applications.rb
+++ b/db/migrate/20150613202109_create_o_auth_applications.rb
@@ -10,8 +10,4 @@ class CreateOAuthApplications < ActiveRecord::Migration
       t.timestamps null: false
     end
   end
-
-  def self.down
-    drop_table :o_auth_applications
-  end
 end
diff --git a/db/migrate/20150614134031_create_o_auth_access_tokens.rb b/db/migrate/20150614134031_create_o_auth_access_tokens.rb
index 5084d61e5a..8bd619142b 100644
--- a/db/migrate/20150614134031_create_o_auth_access_tokens.rb
+++ b/db/migrate/20150614134031_create_o_auth_access_tokens.rb
@@ -1,5 +1,5 @@
 class CreateOAuthAccessTokens < ActiveRecord::Migration
-  def self.up
+  def change
     create_table :o_auth_access_tokens do |t|
       t.belongs_to :authorization, index: true
       t.string :token
diff --git a/features/desktop/oauth_password_flow.feature b/features/desktop/oauth_password_flow.feature
index 2829ac296a..7fa59c4fd7 100644
--- a/features/desktop/oauth_password_flow.feature
+++ b/features/desktop/oauth_password_flow.feature
@@ -4,17 +4,17 @@ Feature: Access protected resources using password flow
 
   Scenario: Invalid credentials to token endpoint
     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
 
   Scenario: Invalid bearer tokens sent
     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
     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 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
     Then I should receive "kent"'s id, username, and email
diff --git a/features/desktop/oidc_implicit_flow.feature b/features/desktop/oidc_implicit_flow.feature
new file mode 100644
index 0000000000..92bf59d5a9
--- /dev/null
+++ b/features/desktop/oidc_implicit_flow.feature
@@ -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
diff --git a/features/step_definitions/implicit_flow_steps.rb b/features/step_definitions/implicit_flow_steps.rb
new file mode 100644
index 0000000000..2ea9fdfa0b
--- /dev/null
+++ b/features/step_definitions/implicit_flow_steps.rb
@@ -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
diff --git a/features/step_definitions/openid_steps.rb b/features/step_definitions/password_flow_steps.rb
similarity index 88%
rename from features/step_definitions/openid_steps.rb
rename to features/step_definitions/password_flow_steps.rb
index 3aa5bdf36b..2dcbf7b3f1 100644
--- a/features/step_definitions/openid_steps.rb
+++ b/features/step_definitions/password_flow_steps.rb
@@ -1,9 +1,9 @@
 When /^I register a new client$/ do
   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
 
-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)
   user = User.find_by(username: username)
   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"]
 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)
   token_endpoint_url = "/openid_connect/access_tokens"
   post token_endpoint_url, grant_type: "password", username: "bob", password: "wrongpassword",
diff --git a/lib/openid_connect/token_endpoint.rb b/lib/openid_connect/token_endpoint.rb
index a19d7766c1..116a5c67b4 100644
--- a/lib/openid_connect/token_endpoint.rb
+++ b/lib/openid_connect/token_endpoint.rb
@@ -7,17 +7,17 @@ module OpenidConnect
       @app = Rack::OAuth2::Server::Token.new do |req, res|
         o_auth_app = retrieve_client(req)
         if app_valid?(o_auth_app, req)
-          handle_flows(req, res)
+          handle_flows(o_auth_app, req, res)
         else
           req.invalid_client!
         end
       end
     end
 
-    def handle_flows(req, res)
+    def handle_flows(o_auth_app, req, res)
       case req.grant_type
       when :password
-        handle_password_flow(req, res)
+        handle_password_flow(o_auth_app, req, res)
       when :refresh_token
         handle_refresh_flow(req, res)
       else
@@ -25,11 +25,11 @@ module OpenidConnect
       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)
       if user
         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
         else
           req.invalid_grant!
diff --git a/public/docs/v0/index.html b/public/docs/v0/index.html
deleted file mode 100644
index 08b6b913fe..0000000000
--- a/public/docs/v0/index.html
+++ /dev/null
@@ -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>
diff --git a/public/docs/v0/style.css b/public/docs/v0/style.css
deleted file mode 100644
index ea6e1ce9cb..0000000000
--- a/public/docs/v0/style.css
+++ /dev/null
@@ -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;}
diff --git a/spec/controllers/openid_connect/authorizations_controller_spec.rb b/spec/controllers/openid_connect/authorizations_controller_spec.rb
index bb597254db..1c8e3655b8 100644
--- a/spec/controllers/openid_connect/authorizations_controller_spec.rb
+++ b/spec/controllers/openid_connect/authorizations_controller_spec.rb
@@ -7,6 +7,8 @@ describe OpenidConnect::AuthorizationsController, type: :controller do
       name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/", "http://localhost/"])
   end
 
+  # TODO: jhass - "Might want to setup some factories in spec/factories.rb, see factory_girl's docs."
+
   before do
     sign_in :user, alice
     allow(@controller).to receive(:current_user).and_return(alice)
-- 
GitLab