Fix authorization and related models

Squashed commits:
[a844d37] Remove unnecessary class_name's from models
[529a30c] Further adjust authorization and related models
This commit is contained in:
theworldbright 2015-07-15 16:16:50 +09:00
parent 031679762a
commit 1475672d72
14 changed files with 46 additions and 52 deletions

View file

@ -2,4 +2,8 @@ class Api::V0::BaseController < ApplicationController
include OpenidConnect::ProtectedResourceEndpoint include OpenidConnect::ProtectedResourceEndpoint
before_filter :require_access_token before_filter :require_access_token
def authorization
current_token.authorization
end
end end

View file

@ -6,6 +6,6 @@ class Api::V0::UsersController < Api::V0::BaseController
private private
def user def user
current_token.user authorization.user
end end
end end

View file

@ -1,43 +1,38 @@
class OpenidConnect::Authorization < ActiveRecord::Base class OpenidConnect::Authorization < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :o_auth_application belongs_to :o_auth_application
has_many :scopes, through: :authorization_scopes has_many :scopes, through: :authorization_scopes
has_many :o_auth_access_tokens has_many :o_auth_access_tokens
before_validation :setup, on: :create before_validation :setup, on: :create
validates :refresh_token, uniqueness: true validates :refresh_token, presence: true, uniqueness: true
validates :user, :o_auth_application, uniqueness: true validates :user, presence: true, uniqueness: true
validates :o_auth_application, presence: true, uniqueness: true
# TODO: Incomplete class
def setup def setup
self.refresh_token = nil
end
def self.valid?(token)
OpenidConnect::Authorization.exists? refresh_token: token
end
def create_refresh_token
self.refresh_token = SecureRandom.hex(32) self.refresh_token = SecureRandom.hex(32)
end end
def create_token def create_access_token
o_auth_access_tokens.create!.bearer_token OpenidConnect::OAuthAccessToken.create!(authorization: self).bearer_token
end end
def self.find_by_client_id_and_user(client_id, user) # TODO: Actually call this method from token endpoint
app = OpenidConnect::OAuthApplication.find_by(client_id: client_id) def regenerate_refresh_token
self.refresh_token = SecureRandom.hex(32)
end
def self.find_by_client_id_and_user(app, user)
find_by(o_auth_application: app, user: user) find_by(o_auth_application: app, user: user)
end end
def self.find_or_create(client_id, user)
auth = find_by_client_id_and_user client_id, user
unless auth
# TODO: Handle creation error # TODO: Handle creation error
auth = create! user: user, o_auth_application: OpenidConnect::OAuthApplication.find_by(client_id: client_id) def self.find_or_create(client_id, user)
end app = OpenidConnect::OAuthApplication.find_by(client_id: client_id)
auth find_by_client_id_and_user(app, user) || create!(user: user, o_auth_application: app)
end end
# TODO: Incomplete class
end end

View file

@ -1,7 +1,7 @@
class AuthorizationScope < ActiveRecord::Base class OpenidConnect::AuthorizationScope < ActiveRecord::Base
belongs_to authorization belongs_to :authorization
belongs_to scope belongs_to :scope
validates authorization, presence: true validates :authorization, presence: true
validates scope, presence: true validates :scope, presence: true
end end

View file

@ -1,11 +1,11 @@
class OpenidConnect::OAuthAccessToken < ActiveRecord::Base class OpenidConnect::OAuthAccessToken < ActiveRecord::Base
belongs_to :user belongs_to :authorization, dependent: :delete
belongs_to :authorization
has_many :scopes, through: :scope_tokens has_many :scopes, through: :scope_tokens
before_validation :setup, on: :create before_validation :setup, on: :create
validates :token, presence: true, uniqueness: true validates :token, presence: true, uniqueness: true
validates :authorization, presence: true, uniqueness: true
scope :valid, ->(time) { where("expires_at >= ?", time) } scope :valid, ->(time) { where("expires_at >= ?", time) }

View file

@ -1,6 +1,4 @@
class OpenidConnect::OAuthApplication < ActiveRecord::Base class OpenidConnect::OAuthApplication < ActiveRecord::Base
belongs_to :user
has_many :authorizations has_many :authorizations
has_many :user, through: :authorizations has_many :user, through: :authorizations

View file

@ -1,5 +1,5 @@
class OpenidConnect::Scope < ActiveRecord::Base class OpenidConnect::Scope < ActiveRecord::Base
has_many :tokens, through: :scope_tokens has_many :o_auth_access_token, through: :scope_tokens
has_many :authorizations, through: :authorization_scopes has_many :authorizations, through: :authorization_scopes
validates :name, presence: true, uniqueness: true validates :name, presence: true, uniqueness: true

View file

@ -1,6 +1,6 @@
class OpenidConnect::ScopeToken < ActiveRecord::Base class OpenidConnect::ScopeToken < ActiveRecord::Base
belongs_to :scope belongs_to :scope
belongs_to :token belongs_to :o_auth_access_token
validates :scope, presence: true validates :scope, presence: true
validates :token, presence: true validates :token, presence: true

View file

@ -76,9 +76,9 @@ class User < ActiveRecord::Base
has_many :reports has_many :reports
has_many :authorizations, class_name: 'OpenidConnect::Authorization' has_many :authorizations, class_name: "OpenidConnect::Authorization"
has_many :o_auth_applications, through: :authorizations, class_name: 'OpenidConnect::OAuthApplication' has_many :o_auth_applications, through: :authorizations, class_name: "OpenidConnect::OAuthApplication"
has_many :o_auth_access_tokens, through: :authorizations, class_name: 'OpenidConnect::OAuthAccessToken' has_many :o_auth_access_tokens, through: :authorizations, class_name: "OpenidConnect::OAuthAccessToken"
before_save :guard_unconfirmed_email, before_save :guard_unconfirmed_email,
:save_person! :save_person!

View file

@ -1,9 +1,7 @@
class CreateOAuthAccessTokens < ActiveRecord::Migration class CreateOAuthAccessTokens < ActiveRecord::Migration
def self.up def self.up
create_table :o_auth_access_tokens do |t| create_table :o_auth_access_tokens do |t|
t.belongs_to :user, index: true t.belongs_to :authorization, index: true
t.belongs_to :authorizations
t.belongs_to :endpoints
t.string :token t.string :token
t.datetime :expires_at t.datetime :expires_at

View file

@ -1,7 +1,7 @@
class CreateAuthorizationsScopesJoinTable < ActiveRecord::Migration class CreateAuthorizationsScopesJoinTable < ActiveRecord::Migration
def change def change
create_table :authorizations_scopes, id: false do |t| create_table :authorizations_scopes, id: false do |t|
t.belongs_to :endpoints, index: true t.belongs_to :authorization, index: true
t.belongs_to :scope, index: true t.belongs_to :scope, index: true
end end
end end

View file

@ -256,7 +256,6 @@ ActiveRecord::Schema.define(version: 20150708155747) 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_access_tokens", force: :cascade do |t| create_table "o_auth_access_tokens", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "authorization_id", limit: 4 t.integer "authorization_id", limit: 4
t.string "token", limit: 255 t.string "token", limit: 255
t.datetime "expires_at" t.datetime "expires_at"
@ -264,7 +263,7 @@ ActiveRecord::Schema.define(version: 20150708155747) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "o_auth_access_tokens", ["user_id"], name: "index_o_auth_access_tokens_on_user_id", using: :btree add_index "o_auth_access_tokens", ["authorization_id"], name: "index_o_auth_access_tokens_on_authorization_id", 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.integer "user_id", limit: 4

View file

@ -30,7 +30,7 @@ module OpenidConnect
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(req.client_id, user)
res.access_token = auth.create_token res.access_token = auth.create_access_token
else else
req.invalid_grant! req.invalid_grant!
end end
@ -40,9 +40,9 @@ module OpenidConnect
end end
def handle_refresh_flow(req, res) def handle_refresh_flow(req, res)
auth = OpenidConnect::Authorization.find_by_client_id req.client_id auth = OpenidConnect::Authorization.where(client_id: req.client_id).where(refresh_token: req.refresh_token).first
if OpenidConnect::Authorization.valid? req.refresh_token if auth
res.access_token = auth.create_token res.access_token = auth.create_access_token
else else
req.invalid_grant! req.invalid_grant!
end end

View file

@ -5,20 +5,20 @@ describe OpenidConnect::ProtectedResourceEndpoint, type: :request do
let!(:client) do let!(:client) do
OpenidConnect::OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"]) OpenidConnect::OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"])
end end
let(:auth) { OpenidConnect::Authorization.find_or_create(client.client_id, bob) } let!(:auth) { OpenidConnect::Authorization.find_or_create(client.client_id, bob) }
let!(:token) { auth.create_token.to_s } let!(:access_token) { auth.create_access_token.to_s }
let(:invalid_token) { SecureRandom.hex(32).to_s } let!(:invalid_token) { SecureRandom.hex(32).to_s }
# TODO: Add tests for expired access tokens # TODO: Add tests for expired access tokens
context "when access token is valid" do context "when access token is valid" do
it "shows the user's username and email" do it "shows the user's username and email" do
get "/api/v0/user/", access_token: token get "/api/v0/user/", access_token: access_token
json_body = JSON.parse(response.body) json_body = JSON.parse(response.body)
expect(json_body["username"]).to eq(bob.username) expect(json_body["username"]).to eq(bob.username)
expect(json_body["email"]).to eq(bob.email) expect(json_body["email"]).to eq(bob.email)
end end
it "should include private in the cache-control header" do it "should include private in the cache-control header" do
get "/api/v0/user/", access_token: token get "/api/v0/user/", access_token: access_token
expect(response.headers["Cache-Control"]).to include("private") expect(response.headers["Cache-Control"]).to include("private")
end end
end end