Redesign the models

This commit is contained in:
augier 2015-09-13 14:44:22 -07:00 committed by theworldbright
parent 9140c8244b
commit 031679762a
28 changed files with 181 additions and 147 deletions

View file

@ -17,7 +17,7 @@ class OpenidConnect::AuthorizationsController < ApplicationController
private
def request_authorization_consent_form
endpoint = OpenidConnect::Authorization::EndpointStartPoint.new(current_user)
endpoint = OpenidConnect::Endpoints::EndpointStartPoint.new(current_user)
handle_startpoint_response(endpoint)
end
@ -35,7 +35,7 @@ class OpenidConnect::AuthorizationsController < ApplicationController
end
def process_authorization_consent(approvedString)
endpoint = OpenidConnect::Authorization::EndpointConfirmationPoint.new(current_user, to_boolean(approvedString))
endpoint = OpenidConnect::Endpoints::EndpointConfirmationPoint.new(current_user, to_boolean(approvedString))
restore_request_parameters(endpoint)
handle_confirmation_endpoint_response(endpoint)
end
@ -56,7 +56,7 @@ class OpenidConnect::AuthorizationsController < ApplicationController
req.update_param("redirect_uri", session[:redirect_uri])
req.update_param("response_type", session[:response_type])
endpoint.scopes, endpoint.request_object =
session[:scopes].map {|scope| Scope.find_by_name(scope) }, session[:request_object]
session[:scopes].map {|scope| OpenidConnect::Scope.find_by_name(scope) }, session[:request_object]
end
def to_boolean(str)

View file

@ -9,7 +9,7 @@ class OpenidConnect::ClientsController < ApplicationController
def create
registrar = OpenIDConnect::Client::Registrar.new(request.url, params)
client = OAuthApplication.register! registrar
client = OpenidConnect::OAuthApplication.register! registrar
render json: client
end

View file

@ -1,32 +1,30 @@
module OpenidConnect
class DiscoveryController < ApplicationController
def webfinger
jrd = {
links: [{
rel: OpenIDConnect::Discovery::Provider::Issuer::REL_VALUE,
href: File.join(root_url, "openid_connect")
}]
}
jrd[:subject] = params[:resource] if params[:resource].present?
render json: jrd, content_type: "application/jrd+json"
end
class OpenidConnect::DiscoveryController < ApplicationController
def webfinger
jrd = {
links: [{
rel: OpenIDConnect::Discovery::Provider::Issuer::REL_VALUE,
href: File.join(root_url, "openid_connect")
}]
}
jrd[:subject] = params[:resource] if params[:resource].present?
render json: jrd, content_type: "application/jrd+json"
end
def configuration
render json: OpenIDConnect::Discovery::Provider::Config::Response.new(
issuer: root_url,
registration_endpoint: openid_connect_clients_url,
authorization_endpoint: new_openid_connect_authorization_url,
token_endpoint: openid_connect_access_tokens_url,
userinfo_endpoint: api_v0_user_url,
jwks_uri: "https://not_configured_yet.com", # TODO: File.join({new_openid_connect_authorization_path} + "/jwks.json"),
scopes_supported: Scope.pluck(:name),
response_types_supported: OAuthApplication.available_response_types,
request_object_signing_alg_values_supported: %i(HS256 HS384 HS512),
subject_types_supported: %w(public pairwise),
id_token_signing_alg_values_supported: %i(RS256),
token_endpoint_auth_methods_supported: %w(client_secret_basic client_secret_post),
# TODO: claims_supported: ["sub", "iss", "name", "email"]
)
end
def configuration
render json: OpenIDConnect::Discovery::Provider::Config::Response.new(
issuer: root_url,
registration_endpoint: openid_connect_clients_url,
authorization_endpoint: new_openid_connect_authorization_url,
token_endpoint: openid_connect_access_tokens_url,
userinfo_endpoint: api_v0_user_url,
jwks_uri: "https://not_configured_yet.com", # TODO: File.join({new_openid_connect_authorization_path} + "/jwks.json"),
scopes_supported: Scope.pluck(:name),
response_types_supported: OAuthApplication.available_response_types,
request_object_signing_alg_values_supported: %i(HS256 HS384 HS512),
subject_types_supported: %w(public pairwise),
id_token_signing_alg_values_supported: %i(RS256),
token_endpoint_auth_methods_supported: %w(client_secret_basic client_secret_post),
# TODO: claims_supported: ["sub", "iss", "name", "email"]
)
end
end

View file

@ -1,7 +0,0 @@
class Authorization < ActiveRecord::Base
belongs_to :user
belongs_to :o_auth_application
has_many :scopes, through: :authorization_scopes
# TODO: Incomplete class
end

View file

@ -0,0 +1,43 @@
class OpenidConnect::Authorization < ActiveRecord::Base
belongs_to :user
belongs_to :o_auth_application
has_many :scopes, through: :authorization_scopes
has_many :o_auth_access_tokens
before_validation :setup, on: :create
validates :refresh_token, uniqueness: true
validates :user, :o_auth_application, uniqueness: true
# TODO: Incomplete class
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)
end
def create_token
o_auth_access_tokens.create!.bearer_token
end
def self.find_by_client_id_and_user(client_id, user)
app = OpenidConnect::OAuthApplication.find_by(client_id: client_id)
find_by(o_auth_application: app, user: user)
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
auth = create! user: user, o_auth_application: OpenidConnect::OAuthApplication.find_by(client_id: client_id)
end
auth
end
end

View file

@ -1,7 +1,7 @@
class Token < ActiveRecord::Base
class OpenidConnect::OAuthAccessToken < ActiveRecord::Base
belongs_to :user
belongs_to :authorization
has_many :scopes, through: :scope_tokens
has_one :refresh_token
before_validation :setup, on: :create
@ -11,7 +11,6 @@ class Token < ActiveRecord::Base
def setup
self.token = SecureRandom.hex(32)
self.refresh_token = RefreshToken.create!
self.expires_at = 24.hours.from_now
end

View file

@ -1,7 +1,8 @@
class OAuthApplication < ActiveRecord::Base
class OpenidConnect::OAuthApplication < ActiveRecord::Base
belongs_to :user
has_many :authorizations
has_many :user, through: :authorizations
validates :client_id, presence: true, uniqueness: true
validates :client_secret, presence: true
@ -9,6 +10,7 @@ class OAuthApplication < ActiveRecord::Base
serialize :redirect_uris, JSON
before_validation :setup, on: :create
def setup
self.client_id = SecureRandom.hex(16)
self.client_secret = SecureRandom.hex(32)

View file

@ -1,4 +1,4 @@
class Scope < ActiveRecord::Base
class OpenidConnect::Scope < ActiveRecord::Base
has_many :tokens, through: :scope_tokens
has_many :authorizations, through: :authorization_scopes

View file

@ -1,4 +1,4 @@
class ScopeToken < ActiveRecord::Base
class OpenidConnect::ScopeToken < ActiveRecord::Base
belongs_to :scope
belongs_to :token

View file

@ -1,26 +0,0 @@
class RefreshToken < ActiveRecord::Base
belongs_to :token
before_validation :setup, on: :create
validates :refresh_token, presence: true, uniqueness: true
attr_reader :refresh_token
def setup
self.refresh_token = SecureRandom.hex(32)
# No expipration date for now
end
# Finds the requested refresh token and destroys it if found; returns true if found, false otherwise
def valid?(token)
the_token = RefreshToken.find_by_refresh_token token
if the_token
RefreshToken.destroy_all refresh_token: the_token.refresh_token
Token.destroy_all refresh_token: the_token.refresh_token
true
else
false
end
end
end

View file

@ -76,9 +76,9 @@ class User < ActiveRecord::Base
has_many :reports
has_many :o_auth_applications
has_many :authorizations
has_many :tokens
has_many :authorizations, class_name: 'OpenidConnect::Authorization'
has_many :o_auth_applications, through: :authorizations, class_name: 'OpenidConnect::OAuthApplication'
has_many :o_auth_access_tokens, through: :authorizations, class_name: 'OpenidConnect::OAuthAccessToken'
before_save :guard_unconfirmed_email,
:save_person!
@ -602,15 +602,17 @@ 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
self.attributes.keys - ["id", "username", "encrypted_password",
"created_at", "updated_at", "locked_at",
"serialized_private_key", "getting_started",
"disable_mail", "show_community_spotlight_in_stream",
"strip_exif", "email", "remove_after",
"export", "exporting", "exported_at",
"exported_photos_file", "exporting_photos", "exported_photos_at"]
self.attributes.keys - %w(id username encrypted_password created_at updated_at locked_at
serialized_private_key getting_started
disable_mail show_community_spotlight_in_stream
strip_exif email remove_after export exporting exported_at
exported_photos_file exporting_photos exported_photos_at)
end
end

View file

@ -109,7 +109,7 @@ module Diaspora
config.action_mailer.asset_host = AppConfig.pod_uri.to_s
config.middleware.use Rack::OAuth2::Server::Resource::Bearer, "OpenID Connect" do |req|
Token.valid(Time.now.utc).find_by(token: req.access_token) || req.invalid_token!
OpenidConnect::OAuthAccessToken.valid(Time.now.utc).find_by(token: req.access_token) || req.invalid_token!
end
end
end

View file

@ -0,0 +1,13 @@
class CreateOAuthAccessTokens < ActiveRecord::Migration
def self.up
create_table :o_auth_access_tokens do |t|
t.belongs_to :user, index: true
t.belongs_to :authorizations
t.belongs_to :endpoints
t.string :token
t.datetime :expires_at
t.timestamps null: false
end
end
end

View file

@ -1,15 +0,0 @@
class CreateTokens < ActiveRecord::Migration
def self.up
create_table :tokens do |t|
t.belongs_to :user, index: true
t.string :token
t.datetime :expires_at
t.timestamps null: false
end
end
def self.down
drop_table :tokens
end
end

View file

@ -3,6 +3,7 @@ class CreateAuthorizations < ActiveRecord::Migration
create_table :authorizations do |t|
t.belongs_to :user, index: true
t.belongs_to :o_auth_application, index: true
t.string :refresh_token
t.timestamps null: false
end

View file

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

View file

@ -2,7 +2,7 @@ class CreateScopesTokensJoinTable < ActiveRecord::Migration
def change
create_table :scopes_tokens, id: false do |t|
t.belongs_to :scope, index: true
t.belongs_to :token, index: true
t.belongs_to :o_auth_access_token, index: true
end
end
end

View file

@ -1,14 +0,0 @@
class RefreshToken < ActiveRecord::Migration
def change
create_table :refresh_token do
t.belongs_to :token
t.string :refresh_token
t.timestamps null: false
end
end
def self.down
drop_table :refresh_token
end
end

View file

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151003142048) do
ActiveRecord::Schema.define(version: 20150708155747) do
create_table "account_deletions", force: :cascade do |t|
t.string "diaspora_handle", limit: 255
@ -55,6 +55,25 @@ ActiveRecord::Schema.define(version: 20151003142048) do
add_index "aspects", ["user_id", "contacts_visible"], name: "index_aspects_on_user_id_and_contacts_visible", using: :btree
add_index "aspects", ["user_id"], name: "index_aspects_on_user_id", using: :btree
create_table "authorizations", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "o_auth_application_id", limit: 4
t.string "refresh_token", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "authorizations", ["o_auth_application_id"], name: "index_authorizations_on_o_auth_application_id", using: :btree
add_index "authorizations", ["user_id"], name: "index_authorizations_on_user_id", using: :btree
create_table "authorizations_scopes", id: false, force: :cascade do |t|
t.integer "authorization_id", limit: 4
t.integer "scope_id", limit: 4
end
add_index "authorizations_scopes", ["authorization_id"], name: "index_authorizations_scopes_on_authorization_id", using: :btree
add_index "authorizations_scopes", ["scope_id"], name: "index_authorizations_scopes_on_scope_id", using: :btree
create_table "blocks", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "person_id", limit: 4
@ -236,6 +255,17 @@ ActiveRecord::Schema.define(version: 20151003142048) do
add_index "notifications", ["target_id"], name: "index_notifications_on_target_id", 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|
t.integer "user_id", limit: 4
t.integer "authorization_id", limit: 4
t.string "token", limit: 255
t.datetime "expires_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "o_auth_access_tokens", ["user_id"], name: "index_o_auth_access_tokens_on_user_id", using: :btree
create_table "o_auth_applications", force: :cascade do |t|
t.integer "user_id", limit: 4
t.string "client_id", limit: 255
@ -470,6 +500,20 @@ ActiveRecord::Schema.define(version: 20151003142048) do
t.datetime "updated_at", null: false
end
create_table "scopes", force: :cascade do |t|
t.string "name", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "scopes_tokens", id: false, force: :cascade do |t|
t.integer "scope_id", limit: 4
t.integer "o_auth_access_token_id", limit: 4
end
add_index "scopes_tokens", ["o_auth_access_token_id"], name: "index_scopes_tokens_on_o_auth_access_token_id", using: :btree
add_index "scopes_tokens", ["scope_id"], name: "index_scopes_tokens_on_scope_id", using: :btree
create_table "services", force: :cascade do |t|
t.string "type", limit: 127, null: false
t.integer "user_id", limit: 4, null: false
@ -540,16 +584,6 @@ ActiveRecord::Schema.define(version: 20151003142048) do
add_index "tags", ["name"], name: "index_tags_on_name", unique: true, length: {"name"=>191}, using: :btree
create_table "tokens", force: :cascade do |t|
t.integer "user_id", limit: 4
t.string "token", limit: 255
t.datetime "expires_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "tokens", ["user_id"], name: "index_tokens_on_user_id", using: :btree
create_table "user_preferences", force: :cascade do |t|
t.string "email_type", limit: 255
t.integer "user_id", limit: 4

View file

@ -47,15 +47,16 @@ class AccountDeleter
#user deletions
def normal_ar_user_associates_to_delete
%i(tag_followings invitations_to_me services aspects user_preferences
notifications blocks authorizations o_auth_applications tokens)
notifications blocks authorizations o_auth_applications o_auth_access_tokens)
end
def special_ar_user_associations
[:invitations_from_me, :person, :profile, :contacts, :auto_follow_back_aspect]
%i(invitations_from_me person profile contacts auto_follow_back_aspect)
end
def ignored_ar_user_associations
[:followed_tags, :invited_by, :contact_people, :aspect_memberships, :ignored_people, :conversation_visibilities, :conversations, :reports]
%i(followed_tags invited_by contact_people aspect_memberships
ignored_people conversation_visibilities conversations reports)
end
def delete_standard_user_associations

View file

@ -1,5 +1,5 @@
module OpenidConnect
module Authorization
module Endpoints
class Endpoint
attr_accessor :app, :user, :client, :redirect_uri, :response_type,
:scopes, :_request_, :request_uri, :request_object
@ -9,7 +9,8 @@ module OpenidConnect
@user = current_user
@app = Rack::OAuth2::Server::Authorize.new do |req, res|
build_attributes(req, res)
if OAuthApplication.available_response_types.include? Array(req.response_type).map(&:to_s).join(" ")
if OpenidConnect::OAuthApplication.available_response_types.include?(
Array(req.response_type).map(&:to_s).join(" "))
handle_response_type(req, res)
else
req.unsupported_response_type!
@ -29,7 +30,7 @@ module OpenidConnect
private
def build_client(req)
@client = OAuthApplication.find_by_client_id(req.client_id) || req.bad_request!
@client = OpenidConnect::OAuthApplication.find_by_client_id(req.client_id) || req.bad_request!
end
def build_redirect_uri(req, res)

View file

@ -1,5 +1,5 @@
module OpenidConnect
module Authorization
module Endpoints
class EndpointConfirmationPoint < Endpoint
def initialize(current_user, approved=false)
super(current_user)

View file

@ -1,5 +1,5 @@
module OpenidConnect
module Authorization
module Endpoints
class EndpointStartPoint < Endpoint
def initialize(current_user)
super(current_user)
@ -24,7 +24,7 @@ module OpenidConnect
def build_scopes(req)
@scopes = req.scope.map {|scope|
Scope.where(name: scope).first.tap do |scope|
OpenidConnect::Scope.where(name: scope).first.tap do |scope|
req.invalid_scope! "Unknown scope: #{scope}" unless scope
end
}

View file

@ -29,7 +29,8 @@ module OpenidConnect
user = User.find_for_database_authentication(username: req.username)
if user
if user.valid_password?(req.password)
res.access_token = token! user
auth = OpenidConnect::Authorization.find_or_create(req.client_id, user)
res.access_token = auth.create_token
else
req.invalid_grant!
end
@ -39,24 +40,21 @@ module OpenidConnect
end
def handle_refresh_flow(req, res)
user = OAuthApplication.find_by_client_id(req.client_id).user
if RefreshToken.valid?(req.refresh_token)
res.access_token = token! user
auth = OpenidConnect::Authorization.find_by_client_id req.client_id
if OpenidConnect::Authorization.valid? req.refresh_token
res.access_token = auth.create_token
else
req.invalid_grant!
end
end
def retrieve_client(req)
OAuthApplication.find_by_client_id req.client_id
OpenidConnect::OAuthApplication.find_by client_id: req.client_id
end
def app_valid?(o_auth_app, req)
o_auth_app.client_secret == req.client_secret
end
def token!(user)
user.tokens.create!.bearer_token
end
end
end

View file

@ -1,16 +1,16 @@
require "spec_helper"
describe OpenidConnect::AuthorizationsController, type: :controller do
let!(:client) { OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"]) }
let!(:client) { OpenidConnect::OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"]) }
let!(:client_with_multiple_redirects) do
OAuthApplication.create!(
OpenidConnect::OAuthApplication.create!(
name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/", "http://localhost/"])
end
before do
sign_in :user, alice
allow(@controller).to receive(:current_user).and_return(alice)
Scope.create!(name: "openid")
OpenidConnect::Scope.create!(name: "openid")
end
describe "#new" do

View file

@ -2,7 +2,11 @@ require "spec_helper"
describe OpenidConnect::ProtectedResourceEndpoint, type: :request do
describe "getting the user info" do
let!(:token) { bob.tokens.create!.bearer_token.to_s }
let!(:client) do
OpenidConnect::OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"])
end
let(:auth) { OpenidConnect::Authorization.find_or_create(client.client_id, bob) }
let!(:token) { auth.create_token.to_s }
let(:invalid_token) { SecureRandom.hex(32).to_s }
# TODO: Add tests for expired access tokens

View file

@ -1,7 +1,7 @@
require "spec_helper"
describe OpenidConnect::TokenEndpoint, type: :request do
let!(:client) { OAuthApplication.create!(redirect_uris: ["http://localhost"]) }
let!(:client) { OpenidConnect::OAuthApplication.create!(redirect_uris: ["http://localhost"]) }
describe "the password grant type" do
context "when the username field is missing" do
it "should return an invalid request error" do