Skip to content
Extraits de code Groupes Projets
Valider beae7710 rédigé par theworldbright's avatar theworldbright Validation de theworldbright
Parcourir les fichiers

Allow current user to be obtained from access token

parent 68d96a31
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de
avec 116 ajouts et 44 suppressions
class Api::V2::BaseController < ApplicationController class Api::V2::BaseController < ApplicationController
include Openid::Authentication include OpenidConnect::Authentication
before_action :authenticate_user!
before_filter :require_access_token before_filter :require_access_token
end end
class Api::V2::UsersController < Api::V2::BaseController class Api::V2::UsersController < Api::V2::BaseController
def show def show
render json: current_user render json: user
end
private
def user
current_token.o_auth_application.user
end end
end end
class OAuthApplication < ActiveRecord::Base class OAuthApplication < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
validates :client_id, presence: true, uniqueness: true validates :client_id, presence: true, uniqueness: true
validates :client_secret, presence: true validates :client_secret, presence: true
......
...@@ -246,7 +246,7 @@ Diaspora::Application.routes.draw do ...@@ -246,7 +246,7 @@ Diaspora::Application.routes.draw do
resources :authorizations, only: [:new, :create] resources :authorizations, only: [:new, :create]
match 'connect', to: 'connect#show', via: [:get, :post] match 'connect', to: 'connect#show', via: [:get, :post]
match '.well-known/:id', to: 'discovery#show' , via: [:get, :post] match '.well-known/:id', to: 'discovery#show' , via: [:get, :post]
post 'access_tokens', to: proc { |env| Openid::TokenEndpoint.new.call(env) } post 'access_tokens', to: proc { |env| OpenidConnect::TokenEndpoint.new.call(env) }
end end
api_version(:module => "Api::V2", path: {value: "api/v2"}, default: true) do api_version(:module => "Api::V2", path: {value: "api/v2"}, default: true) do
......
class CreateOAuthApplications < ActiveRecord::Migration class CreateOAuthApplications < ActiveRecord::Migration
def change def self.up
create_table :o_auth_applications do |t| create_table :o_auth_applications do |t|
t.belongs_to :user, index: true
t.string :client_id t.string :client_id
t.string :client_secret t.string :client_secret
t.timestamps null: false t.timestamps null: false
end end
end end
def self.down
drop_table :o_auth_applications
end
end end
class CreateTokens < ActiveRecord::Migration class CreateTokens < ActiveRecord::Migration
def self.up def self.up
create_table :tokens do |t| create_table :tokens do |t|
t.belongs_to :o_auth_application t.belongs_to :o_auth_application, index: true
t.string :token t.string :token
t.datetime :expires_at t.datetime :expires_at
t.timestamps null: false t.timestamps null: false
......
...@@ -237,12 +237,15 @@ ActiveRecord::Schema.define(version: 20151003142048) do ...@@ -237,12 +237,15 @@ ActiveRecord::Schema.define(version: 20151003142048) do
add_index "notifications", ["target_type", "target_id"], name: "index_notifications_on_target_type_and_target_id", length: {"target_type"=>190, "target_id"=>nil}, using: :btree add_index "notifications", ["target_type", "target_id"], name: "index_notifications_on_target_type_and_target_id", length: {"target_type"=>190, "target_id"=>nil}, using: :btree
create_table "o_auth_applications", force: :cascade do |t| create_table "o_auth_applications", force: :cascade do |t|
t.integer "user_id", limit: 4
t.string "client_id", limit: 255 t.string "client_id", limit: 255
t.string "client_secret", limit: 255 t.string "client_secret", limit: 255
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "o_auth_applications", ["user_id"], name: "index_o_auth_applications_on_user_id", using: :btree
create_table "o_embed_caches", force: :cascade do |t| create_table "o_embed_caches", force: :cascade do |t|
t.string "url", limit: 1024, null: false t.string "url", limit: 1024, null: false
t.text "data", limit: 65535, null: false t.text "data", limit: 65535, null: false
...@@ -543,6 +546,8 @@ ActiveRecord::Schema.define(version: 20151003142048) do ...@@ -543,6 +546,8 @@ ActiveRecord::Schema.define(version: 20151003142048) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "tokens", ["o_auth_application_id"], name: "index_tokens_on_o_auth_application_id", using: :btree
create_table "user_preferences", force: :cascade do |t| create_table "user_preferences", force: :cascade do |t|
t.string "email_type", limit: 255 t.string "email_type", limit: 255
t.integer "user_id", limit: 4 t.integer "user_id", limit: 4
......
@javascript
Feature: Access protected resources using password flow
# TODO: Add tests for expired access tokens
Background:
Given a user with username "kent"
Scenario: Valid bearer tokens sent via Authorization Request Header Field
Scenario: Valid bearer tokens sent via Form Encoded Parameter
Scenario: Valid bearer tokens sent via URI query parameter
When I send a post request to the token endpoint using "kent"'s credentials
And I use received valid bearer tokens to access user info via URI query parameter
Then I should receive "kent"'s id, username, and email
Scenario: Invalid bearer tokens sent via URI query parameter
When I send a post request to the token endpoint using "kent"'s credentials
And I use invalid bearer tokens to access user info via URI query parameter
Then I should receive an "invalid_token" error
@javascript
# TODO: Add tests for expired access tokens
# TODO: Add tests to check for WWW-Authenticate response header field as according to RFC 6750
Feature: Access protected resources using bearer access token
Background:
Given a user with username "bob"
And I log in manually as "bob" with password "password"
And I send a post request to the token endpoint using "bob"'s credentials
Scenario: Valid bearer tokens sent via Authorization Request Header Field
# TODO: Add tests
Scenario: Valid bearer tokens sent via Form Encoded Parameter
# TODO: Add tests
Scenario: Valid bearer tokens sent via URI query parameter
When I use received valid bearer tokens to access user info via URI query parameter
Then I should receive "bob"'s id, username, and email
# TODO: I want to confirm that the cache-control header in the response is private as according to RFC 6750
# Unfortunately, selenium doesn't allow access to response headers
Scenario: Invalid bearer tokens sent via URI query parameter
When I use invalid bearer tokens to access user info via URI query parameter
Then I should receive an "invalid_token" error
Scenario: Valid bearer tokens sent via URI query parameter but user is logged out
When I log out manually
And I use received valid bearer tokens to access user info via URI query parameter
Then I should see "Sign in" in the content
When I log in manually as "bob" with password "password"
Then I should receive "bob"'s id, username, and email
...@@ -10,13 +10,13 @@ end ...@@ -10,13 +10,13 @@ end
When /^I use received valid bearer tokens to access user info via URI query parameter$/ do When /^I use received valid bearer tokens to access user info via URI query parameter$/ do
accessTokenJson = JSON.parse(last_response.body) accessTokenJson = JSON.parse(last_response.body)
userInfoEndPointURL = "/openid/user_info/" userInfoEndPointURL = "/api/v2/user/"
userInfoEndPointURLQuery = "?access_token=" + accessTokenJson["access_token"] userInfoEndPointURLQuery = "?access_token=" + accessTokenJson["access_token"]
visit userInfoEndPointURL + userInfoEndPointURLQuery visit userInfoEndPointURL + userInfoEndPointURLQuery
end end
When /^I use invalid bearer tokens to access user info via URI query parameter$/ do When /^I use invalid bearer tokens to access user info via URI query parameter$/ do
userInfoEndPointURL = "/openid/user_info/" userInfoEndPointURL = "/api/v2/user/"
userInfoEndPointURLQuery = "?access_token=" + SecureRandom.hex(32) userInfoEndPointURLQuery = "?access_token=" + SecureRandom.hex(32)
visit userInfoEndPointURL + userInfoEndPointURLQuery visit userInfoEndPointURL + userInfoEndPointURLQuery
end end
......
Fichier déplacé
module Openid module OpenidConnect
module Authentication module Authentication
def self.included(klass) def self.included(klass)
...@@ -22,9 +22,9 @@ module Openid ...@@ -22,9 +22,9 @@ module Openid
end end
end end
# Scopes should be implemented here # TODO: Scopes should be implemented here
def required_scopes def required_scopes
nil # as default nil
end end
end end
end end
module Openid module OpenidConnect
class AuthorizationEndpoint class AuthorizationEndpoint
attr_accessor :app, :account, :client, :redirect_uri, :response_type, :scopes, :_request_, :request_uri, :request_object attr_accessor :app, :account, :client, :redirect_uri, :response_type, :scopes, :_request_, :request_uri, :request_object
delegate :call, to: :app delegate :call, to: :app
......
module Openid module OpenidConnect
class TokenEndpoint class TokenEndpoint
attr_accessor :app attr_accessor :app
delegate :call, to: :app delegate :call, to: :app
...@@ -7,12 +7,16 @@ module Openid ...@@ -7,12 +7,16 @@ module Openid
@app = Rack::OAuth2::Server::Token.new do |req, res| @app = Rack::OAuth2::Server::Token.new do |req, res|
case req.grant_type case req.grant_type
when :password when :password
o_auth_app = retrieveOrCreateNewClientApplication(req)
user = User.find_for_database_authentication(username: req.username) user = User.find_for_database_authentication(username: req.username)
if o_auth_app && user && user.valid_password?(req.password) if user
res.access_token = o_auth_app.tokens.create!.bearer_token o_auth_app = retrieveOrCreateNewClientApplication(req, user)
if o_auth_app && user.valid_password?(req.password)
res.access_token = o_auth_app.tokens.create!.bearer_token
else
req.invalid_grant!
end
else else
req.invalid_grant! req.invalid_grant! # TODO: Change to user login
end end
else else
res.unsupported_grant_type! res.unsupported_grant_type!
...@@ -20,16 +24,16 @@ module Openid ...@@ -20,16 +24,16 @@ module Openid
end end
end end
def retrieveOrCreateNewClientApplication(req) def retrieveOrCreateNewClientApplication(req, user)
retrieveClient(req) || createClient(req) retrieveClient(req, user) || createClient(req, user)
end end
def retrieveClient(req) def retrieveClient(req, user)
OAuthApplication.find_by_client_id req.client_id user.o_auth_applications.find_by_client_id req.client_id
end end
def createClient(req) def createClient(req, user)
OAuthApplication.create!(client_id: req.client_id, client_secret: req.client_secret) user.o_auth_applications.create!(client_id: req.client_id, client_secret: req.client_secret)
end end
end end
end end
require 'spec_helper'
# TODO: Confirm that the cache-control header in the response is private as according to RFC 6750
# TODO: Check for WWW-Authenticate response header field as according to RFC 6750
describe Api::V2::UsersController, type: :request do
describe "#show" do
let!(:application) { bob.o_auth_applications.create!(client_id: 1, client_secret: "secret") }
let!(:token) { application.tokens.create!.bearer_token.to_s }
context "when valid" do
it "shows the user's info" do
get "/api/v2/user/?access_token=" + token
jsonBody = JSON.parse(response.body)
expect(jsonBody["username"]).to eq(bob.username)
expect(jsonBody["email"]).to eq(bob.email)
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe "Token Endpoint", type: :request do describe OpenidConnect::TokenEndpoint, type: :request do
describe "password grant type" do describe "password grant type" do
context "when the username field is missing" do context "when the username field is missing" do
it "should return an invalid request error" do it "should return an invalid request error" do
......
...@@ -59,6 +59,14 @@ def photo_fixture_name ...@@ -59,6 +59,14 @@ def photo_fixture_name
@photo_fixture_name = File.join(File.dirname(__FILE__), "fixtures", "button.png") @photo_fixture_name = File.join(File.dirname(__FILE__), "fixtures", "button.png")
end end
def retrieveAccessToken(user)
o_auth_app = OAuthApplication.create!(client_id: 4, client_secret: "azerty")
user = User.find_for_database_authentication(username: user.username)
if o_auth_app && user && user.valid_password?("bluepin7") # Hard coded password for bob
o_auth_app.tokens.create!.bearer_token.to_s
end
end
# Force fixture rebuild # Force fixture rebuild
FileUtils.rm_f(Rails.root.join("tmp", "fixture_builder.yml")) FileUtils.rm_f(Rails.root.join("tmp", "fixture_builder.yml"))
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter