Remove old OpenNeo ID auth code

This removes login/logout/session logic for integrating with OpenNeo ID, replacing them with stubs that just redirect to `/?TODO` when you click login, and helpers that act as if you're not logged in.

This gives us a clean slate to plug in new Devise logic to integrate with the `openneo_id` database directly!
This commit is contained in:
Emi Matchu 2023-08-03 17:40:52 -07:00
parent 1d5af835a5
commit 700e26d7df
16 changed files with 14 additions and 462 deletions

View file

@ -43,10 +43,6 @@ gem 'sanitize', '~> 6.0', '>= 6.0.2'
# unstable version of RocketAMF interprets info registry as a hash instead of an array
gem 'RocketAMF', :git => 'https://github.com/rubyamf/rocketamf.git'
# For working with the OpenNeo ID service.
gem 'msgpack', '~> 1.7', '>= 1.7.2'
gem 'openneo-auth-signatory', '~> 0.1.0'
# For preventing too many modeling attempts.
gem 'rack-attack', '~> 6.7'

View file

@ -193,8 +193,6 @@ GEM
nokogiri (1.15.3)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
openneo-auth-signatory (0.1.0)
ruby-hmac
orm_adapter (0.5.0)
parallel (1.23.0)
public_suffix (5.0.3)
@ -270,7 +268,6 @@ GEM
rspec-expectations (~> 2.0.1)
rspec-rails (2.0.1)
rspec (~> 2.0.0)
ruby-hmac (0.4.0)
rvm-capistrano (1.5.6)
capistrano (~> 2.15.4)
sanitize (6.0.2)
@ -331,10 +328,8 @@ DEPENDENCIES
http_accept_language (~> 2.1, >= 2.1.1)
letter_opener (~> 1.8, >= 1.8.1)
memcache-client (~> 1.8.5)
msgpack (~> 1.7, >= 1.7.2)
mysql2 (~> 0.5.5)
nokogiri (~> 1.15, >= 1.15.3)
openneo-auth-signatory (~> 0.1.0)
parallel (~> 1.23)
rack-attack (~> 6.7)
rails (= 7.0.6)

View file

@ -5,12 +5,11 @@ class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :can_use_image_mode?, :user_is?
helper_method :current_user, :user_signed_in?
before_action :set_locale
before_action :login_as_test_user if Rails.env.development?
def authenticate_user! # too lazy to change references to login_path
def authenticate_user!
redirect_to(login_path) unless user_signed_in?
end
@ -18,8 +17,12 @@ class ApplicationController < ActionController::Base
raise AccessDenied unless user_signed_in? && current_user.id == params[:user_id].to_i
end
def can_use_image_mode?
true
def current_user
nil # TODO
end
def user_signed_in?
false # TODO
end
def infer_locale
@ -59,18 +62,9 @@ class ApplicationController < ActionController::Base
def set_locale
I18n.locale = infer_locale || I18n.default_locale
end
def user_is?(user)
user_signed_in? && user == current_user
end
def valid_locale?(locale)
locale && I18n.usable_locales.include?(locale.to_sym)
end
def login_as_test_user
test_user = User.find_by_name('test')
sign_in(:user, test_user, bypass: true)
end
end

View file

@ -29,7 +29,8 @@ class ClosetHangersController < ApplicationController
end
def index
@public_perspective = params.has_key?(:public) || !user_is?(@user)
is_user = user_signed_in? && current_user == @user
@public_perspective = params.has_key?(:public) || !is_user
@perspective_user = current_user unless @public_perspective
closet_lists = @user.closet_lists
unless @perspective_user == @user

View file

@ -1,38 +0,0 @@
class SessionsController < ApplicationController
rescue_from Openneo::Auth::Session::InvalidSignature, :with => :invalid_signature
rescue_from Openneo::Auth::Session::MissingParam, :with => :missing_param
before_action :initialize_session, :only => [new]
skip_before_action :verify_authenticity_token, :only => [:create]
def new
redirect_to Openneo::Auth.remote_auth_url(params, session)
end
def create
session = Openneo::Auth::Session.from_params(params)
session.save!
render :text => 'Success'
end
def destroy
sign_out(:user)
redirect_to (params[:return_to] || root_path)
end
protected
def initialize_session
session[:session_initialization_placeholder] = nil
end
def invalid_signature(exception)
render :text => "Signature did not match. Check secret.",
:status => :unprocessable_entity
end
def missing_param(exception)
render :text => exception.message, :status => :unprocessable_entity
end
end

View file

@ -1,7 +1,6 @@
class User < ApplicationRecord
include PrettyParam
DefaultAuthServerId = 1
PreviewTopContributorsCount = 3
has_many :closet_hangers
@ -23,8 +22,6 @@ class User < ApplicationRecord
scope :top_contributors, -> { order('points DESC').where('points > 0') }
devise :rememberable
def admin?
name == 'matchu' # you know that's right.
end
@ -159,18 +156,6 @@ class User < ApplicationRecord
contact_neopets_connection.try(:neopets_username)
end
def self.find_or_create_from_remote_auth_data(user_data)
user = find_or_initialize_by_remote_id_and_auth_server_id(
user_data['id'],
DefaultAuthServerId
)
if user.new_record?
user.name = user_data['name']
user.save
end
user
end
def self.points_required_to_pass_top_contributor(offset)
user = User.top_contributors.select(:points).limit(1).offset(offset).first
user ? user.points : 0

View file

@ -47,7 +47,7 @@
= userbar_contributions_summary(current_user)
= link_to t('.userbar.items'), user_closet_hangers_path(current_user), :id => 'userbar-items-link'
= link_to t('.userbar.outfits'), current_user_outfits_path
= link_to t('.userbar.settings'), Openneo::Auth.remote_settings_url
= link_to t('.userbar.settings'), auth_user_settings_path
= link_to t('.userbar.logout'), logout_path_with_return_to
- else
= link_to login_path_with_return_to, :id => 'userbar-log-in' do

View file

@ -1,146 +0,0 @@
# Use this hook to configure devise mailer, warden hooks and so forth. The first
# four configuration values can also be set straight in your models.
Devise.setup do |config|
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "matchu@openneo.net"
# Configure the class responsible to send e-mails.
# config.mailer = "Devise::Mailer"
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
# available as additional gems.
require 'devise/orm/active_record'
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating an user. By default is
# just :email. You can configure it to use [:username, :subdomain], so for
# authenticating an user, both parameters are required. Remember that those
# parameters are used only when authenticating and not when retrieving from
# session. If you need permissions, you should implement that in a before filter.
# config.authentication_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true
# Tell if authentication through HTTP Basic Auth is enabled. False by default.
# config.http_authenticatable = false
# Set this to true to use Basic Auth for AJAX requests. True by default.
# config.http_authenticatable_on_xhr = true
# The realm used in Http Basic Authentication
# config.http_authentication_realm = "Application"
# ==> Configuration for :database_authenticatable
# For bcrypt, this is the cost for hashing the password and defaults to 10. If
# using other encryptors, it sets how many times you want the password re-encrypted.
# config.stretches = 10
# Define which will be the encryption algorithm. Devise also supports encryptors
# from others authentication tools as :clearance_sha1, :authlogic_sha512 (then
# you should set stretches above to 20 for default behavior) and :restful_authentication_sha1
# (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
# config.encryptor = :bcrypt
# Setup a pepper to generate the encrypted password.
# config.pepper = "f6a7bb49e6d2348d529bf4c64c09af1491284e90087d282713825f09b8ac0d78be1d3e5fb65b4f95115da90a8b6be60a9d4da68ae60a6174a6c238976b52b848"
# ==> Configuration for :confirmable
# The time you want to give your user to confirm his account. During this time
# he will be able to access your application without confirming. Default is nil.
# When confirm_within is zero, the user won't be able to sign in without confirming.
# You can use this to let your user access some features of your application
# without confirming the account, but blocking it after a certain period
# (ie 2 days).
# config.confirm_within = 2.days
# ==> Configuration for :rememberable
# The time the user will be remembered without asking for credentials again.
# config.remember_for = 2.weeks
# If true, a valid remember token can be re-used between multiple browsers.
# config.remember_across_browsers = true
# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
# ==> Configuration for :validatable
# Range for password length
# config.password_length = 6..20
# Regex to use to validate the email address
# config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again.
# config.timeout_in = 10.minutes
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
# :failed_attempts = Locks an account after a number of failed attempts to sign in.
# :none = No lock strategy. You should handle locking by yourself.
# config.lock_strategy = :failed_attempts
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
# :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself.
# config.unlock_strategy = :both
# Number of authentication tries before locking an account if lock_strategy
# is failed attempts.
# config.maximum_attempts = 20
# Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour
# ==> Configuration for :token_authenticatable
# Defines name of the authentication token params key
# config.token_authentication_key = :auth_token
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "users/sessions/new". It's turned off by default because it's slower if you
# are using only default views.
# config.scoped_views = true
# Configure the default scope given to Warden. By default it's the first
# devise role declared in your routes.
# config.default_scope = :user
# Configure sign_out behavior.
# By default sign_out is scoped (i.e. /users/sign_out affects only :user scope).
# In case of sign_out_all_scopes set to true any logout action will sign out all active scopes.
# config.sign_out_all_scopes = false
# ==> Navigation configuration
# Lists the formats that should be treated as navigational. Formats like
# :html, should redirect to the sign in page when the user does not have
# access, but formats like :xml or :json, should return 401.
# If you have any extra navigational formats, like :iphone or :mobile, you
# should add them to the navigational formats lists. Default is [:html]
# config.navigational_formats = [:html, :iphone]
# ==> Warden configuration
# If you want to use other strategies, that are not (yet) supported by Devise,
# you can configure them inside the config.warden block. The example below
# allows you to setup OAuth, using http://github.com/roman/warden_oauth
#
# config.warden do |manager|
# manager.oauth(:twitter) do |twitter|
# twitter.consumer_secret = <YOUR CONSUMER SECRET>
# twitter.consumer_key = <YOUR CONSUMER KEY>
# twitter.options :site => 'http://twitter.com'
# end
# manager.default_strategies(:scope => :user).unshift :twitter_oauth
# end
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift(:openneo_auth_token)
end
end

View file

@ -1,15 +0,0 @@
require 'openneo-auth'
Openneo::Auth.configure do |config|
config.app = ENV.fetch('OPENNEO_AUTH_APP')
config.auth_server = ENV.fetch('OPENNEO_AUTH_SERVER')
config.secret = ENV.fetch('OPENNEO_AUTH_SECRET')
config.remote_auth_user_finder do |user_data|
User.find_or_create_from_remote_auth_data(user_data)
end
config.remember_user_finder do |id|
User.find_by_id(id)
end
end

View file

@ -1,39 +0,0 @@
en:
errors:
messages:
not_found: "not found"
already_confirmed: "was already confirmed"
not_locked: "was not locked"
devise:
failure:
unauthenticated: 'You need to sign in or sign up before continuing.'
unconfirmed: 'You have to confirm your account before continuing.'
locked: 'Your account is locked.'
invalid: 'Invalid email or password.'
invalid_token: 'Invalid authentication token.'
timeout: 'Your session expired, please sign in again to continue.'
inactive: 'Your account was not activated yet.'
sessions:
signed_in: 'Signed in successfully.'
signed_out: 'Signed out successfully.'
passwords:
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: 'Your password was changed successfully. You are now signed in.'
confirmations:
send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
confirmed: 'Your account was successfully confirmed. You are now signed in.'
registrations:
signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
updated: 'You updated your account successfully.'
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
unlocks:
send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
unlocked: 'Your account was successfully unlocked. You are now signed in.'
mailer:
confirmation_instructions:
subject: 'Confirmation instructions'
reset_password_instructions:
subject: 'Reset password instructions'
unlock_instructions:
subject: 'Unlock Instructions'

View file

@ -7,8 +7,6 @@ OpenneoImpressItems::Application.routes.draw do
root :to => 'outfits#new'
devise_for :users
# DEPRECATED
get '/bodies/:body_id/swf_assets.json' => 'swf_assets#index', :as => :body_swf_assets
@ -49,9 +47,9 @@ OpenneoImpressItems::Application.routes.draw do
post '/pets/submit' => 'pets#submit', :method => :post
get '/modeling' => 'pets#bulk', :as => :bulk_pets
get '/login' => 'sessions#new', :as => :login
get '/logout' => 'sessions#destroy', :as => :logout
post '/users/authorize' => 'sessions#create'
get '/login', to: redirect('/?TODO'), as: :login
get '/logout', to: redirect('/?TODO'), as: :logout
get '/auth-users/settings', to: redirect('/?TODO'), as: :auth_user_settings
post '/locales/choose' => 'locales#choose', :as => :choose_locale

View file

@ -1,64 +0,0 @@
require 'openneo-auth/session'
require 'openneo-auth/strategy'
Warden::Strategies.add :openneo_auth_token, Openneo::Auth::Strategies::Token
module Openneo
module Auth
class Config
attr_accessor :app, :auth_server, :secret
def find_user_with_remote_auth(data)
raise "Must set a remote user finder for Openneo Auth to find a user" unless @remote_auth_user_finder
@remote_auth_user_finder.call(data)
end
def find_user_by_remembering(id)
raise "Must set a remember user finder for Openneo Auth to find a user" unless @remember_user_finder
@remember_user_finder.call(id)
end
def remote_auth_user_finder(&block)
@remote_auth_user_finder = block
end
def remember_user_finder(&block)
@remember_user_finder = block
end
end
class << self
def config
@@config ||= Config.new
end
def configure(&block)
block.call(config)
end
def remote_auth_url(params, session)
raise "Must set config.app to this app's subdomain" unless config.app
raise "Must set config.auth_server to remote server's hostname" unless config.auth_server
query = {
:app => config.app,
:session_id => session[:session_id],
:path => params[:return_to] || '/',
:from => params[:from]
}.to_query
uri = URI::HTTP.build({
:host => config.auth_server,
:path => '/',
:query => query
})
uri.to_s
end
def remote_settings_url
URI::HTTP.build({
:host => config.auth_server,
:path => '/users/edit'
}).to_s
end
end
end
end

View file

@ -1,87 +0,0 @@
require 'active_support/core_ext/hash'
require 'msgpack'
require 'openneo-auth-signatory'
module Openneo
module Auth
class Session
REMOTE_MSG_KEYS = %w(session_id source user)
TMP_STORAGE_DIR = Rails.root.join('tmp', 'openneo-auth-sessions')
attr_writer :id
def save!
content = +MessagePack.pack(@message)
FileUtils.mkdir_p TMP_STORAGE_DIR
File.open(tmp_storage_path, 'w') do |file|
file.write content
end
end
def destroy!
File.delete(tmp_storage_path)
end
def load_message!
raise NotFound, "Session #{id} not found" unless File.exists?(tmp_storage_path)
@message = File.open(tmp_storage_path, 'r') do |file|
MessagePack.unpack file.read
end
end
def params=(params)
unless Auth.config.secret
raise "Must set config.secret to the remote auth server's secret"
end
given_signature = params['signature']
secret = +Auth.config.secret
signatory = Auth::Signatory.new(secret)
REMOTE_MSG_KEYS.each do |key|
unless params.include?(key)
raise MissingParam, "Missing required param #{key.inspect}"
end
end
@message = params.slice(*REMOTE_MSG_KEYS)
correct_signature = signatory.sign(@message)
unless given_signature == correct_signature
raise InvalidSignature, "Signature (#{given_signature}) " +
"did not match message #{@message.inspect} (#{correct_signature})"
end
end
def user
Auth.config.find_user_with_remote_auth(@message['user'])
end
def self.from_params(params)
session = new
session.params = params
session
end
def self.find(id)
session = new
session.id = id
session.load_message!
session
end
private
def id
@id ||= @message[:session_id]
end
def tmp_storage_path
name = "#{id}.mpac"
File.join TMP_STORAGE_DIR, name
end
class InvalidSession < ArgumentError;end
class InvalidSignature < InvalidSession;end
class MissingParam < InvalidSession;end
class NotFound < StandardError;end
end
end
end

View file

@ -1,28 +0,0 @@
require 'devise'
module Openneo
module Auth
module Strategies
class Token < Devise::Strategies::Authenticatable
def valid?
session && session[:session_id]
end
def authenticate!
begin
auth_session = Session.find session[:session_id]
rescue Session::NotFound => e
pass
else
auth_session.destroy!
success! auth_session.user
end
end
def remember_me?
true
end
end
end
end
end

Binary file not shown.

Binary file not shown.