Skip to content

Commit

Permalink
Released v0.10.0
Browse files Browse the repository at this point in the history
  • Loading branch information
binarylogic committed Oct 27, 2008
1 parent ae1d3bb commit 35f14ba
Show file tree
Hide file tree
Showing 24 changed files with 624 additions and 174 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rdoc
@@ -1,3 +1,11 @@
== 0.10.0 released 2008-10-24

* Do not allow instantiation if the session has not been activated with a controller object. Just like ActiveRecord won't let you do anything without a DB connection.
* Abstracted controller implementation to allow for rails, merb, etc adapters. So this is not confined to the rails framework.
* Removed create and update methods and added save, like ActiveRecord.
* after_validation should be able to change the result if it adds errors on callbacks.
* Completed tests.

== 0.9.1 released 2008-10-24

* Changed scope to id. Makes more sense to call it an id and fits better with the ActiveRecord model.
Expand Down
6 changes: 4 additions & 2 deletions Manifest
@@ -1,7 +1,8 @@
CHANGELOG.rdoc
init.rb
lib/authgasm/acts_as_authentic.rb
lib/authgasm/controller.rb
lib/authgasm/controller_adapters/abstract_adapter.rb
lib/authgasm/controller_adapters/rails_adapter.rb
lib/authgasm/session/active_record_trickery.rb
lib/authgasm/session/base.rb
lib/authgasm/session/callbacks.rb
Expand Down Expand Up @@ -77,6 +78,7 @@ test_app/script/server
test_app/test/fixtures/users.yml
test_app/test/functional/user_sessions_controller_test.rb
test_app/test/functional/users_controller_test.rb
test_app/test/integration/user_sesion_stories_test.rb
test_app/test/integration/user_session_test.rb
test_app/test/test_helper.rb
test_app/test/unit/ass_test.rb
test_app/test/unit/user_test.rb
28 changes: 25 additions & 3 deletions README.rdoc
Expand Up @@ -19,7 +19,7 @@ What if your user sessions controller could look just like your other controller

def create
@user_session = UserSession.new(params[:user_session])
if @user_session.create
if @user_session.save
redirect_to account_url
else
render :action => :new
Expand Down Expand Up @@ -134,6 +134,8 @@ Authgasm tries to check the state of the record before creating the session. If

What's neat about this is that these are checked upon any type of login. When logging in explicitly, by cookie, session, or basic http auth. So if you mark a user inactive in the middle of their session they wont be logged back in next time they refresh the page. Giving you complete control.

Need Authgasm to check your own "state"? No problem, check out the hooks section below. Add in a before_validation or after_validation to do your own checking.

== Hooks / Callbacks

Just like ActiveRecord you can create your own hooks / callbacks so that you can do whatever you want when certain actions are performed. Here they are:
Expand All @@ -142,11 +144,27 @@ Just like ActiveRecord you can create your own hooks / callbacks so that you can
after_create
before_destroy
after_destroy
before_save
after_save
before_update
after_update
before_validation
after_validation

== Errors

The errors in Authgasm work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:

class UserSession
before_validation :check_if_awesome

private
def check_if_awesome
errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
errors.add_to_base("You must be awesome to log in") unless record.awesome?
end
end

== Automatic Session Updating

This is one of my favorite features that I think its pretty cool. It's things like this that make a library great and let you know you are on the right track.
Expand Down Expand Up @@ -183,7 +201,7 @@ When things come together like this I think its a sign that you are doing someth

You're asking: "why would I want multiple sessions?". Take this example:

You have an app where users login and then need to re-login to view / change their billing information. Similar to how Apples' me.com works, if you've ever used it. What you could do is have the user login with their normal session, then have an entirely new session that represents their "secure" session. But wait, this is 2 users sessions. No problem:
You have an app where users login and then need to re-login to view / change their billing information. Similar to how Apple's me.com works. What you could do is have the user login with their normal session, then have an entirely new session that represents their "secure" session. But wait, this is 2 users sessions. No problem:

# regular user session
@user_session = UserSession.new
Expand All @@ -202,9 +220,13 @@ This will keep everything separate. The :secure session will store its info in a

For more information on ids checkout Authgasm::Session::Base#initialize

== What about [insert framework here]?

As of now, authgasm supports rails right out of the box. But I designed authgasm to be framework agnostic. The only thing stopping Authgasm from being implemented in merb, or any other framework, is a simple adapter. I have not had the opportunity to use Authgasm in anything other than rails. If you want to use this in merb or any other framework take a look at authgasm/controller/rails_adapter.rb.

== How it works

Interested in how all of this all works? Basically a before_filter is automatically set in your controller which lets Authgasm know about the current controller object. This allows Authgasm to set sessions, cookies, login via basic http auth, etc. If you are using rails in a multiple thread environment, don't worry. I kept that in mind and made this is thread safe.
Interested in how all of this all works? Basically a before_filter is automatically set in your controller which lets Authgasm know about the current controller object. This allows Authgasm to set sessions, cookies, login via basic http auth, etc. If you are using rails in a multiple thread environment, don't worry. I kept that in mind and made this thread safe.

From there it is pretty simple. When you try to create a new session the record is authenticated and then all of the session / cookie magic is done for you. The sky is the limit.

Expand Down
1 change: 0 additions & 1 deletion init.rb
@@ -1,2 +1 @@
require "digest/sha2"
require "authgasm"
5 changes: 4 additions & 1 deletion lib/authgasm.rb
@@ -1,5 +1,8 @@
require "digest/sha2"
require File.dirname(__FILE__) + "/authgasm/version"
require File.dirname(__FILE__) + "/authgasm/controller"

require File.dirname(__FILE__) + "/authgasm/controller_adapters/rails_adapter" if defined?(Rails)

require File.dirname(__FILE__) + "/authgasm/sha256_crypto_provider"
require File.dirname(__FILE__) + "/authgasm/acts_as_authentic"
require File.dirname(__FILE__) + "/authgasm/session/active_record_trickery"
Expand Down
38 changes: 32 additions & 6 deletions lib/authgasm/acts_as_authentic.rb
@@ -1,5 +1,5 @@
module Authgasm
module ActsAsAuthenticated # :nodoc:
module ActsAsAuthentic # :nodoc:
def self.included(base)
base.extend(ClassMethods)
end
Expand All @@ -20,6 +20,7 @@ module ClassMethods
# Class method name Description
# User.unique_token returns unique token generated by your :crypto_provider
# User.crypto_provider The class that you set in your :crypto_provider option
# User.forget_all! Resets all records so they will not be remembered on their next visit. Basically makes their cookies invalid
#
# Named Scopes
# User.logged_in Find all users who are logged in, based on your :logged_in_timeout option
Expand All @@ -31,6 +32,7 @@ module ClassMethods
# user.valid_password?(pass) Based on the valid of :password_field. Determines if the password passed is valid. The password could be encrypted or raw.
# user.randomize_password! Basically resets the password to a random password using only letters and numbers
# user.logged_in? Based on the :logged_in_timeout option. Tells you if the user is logged in or not
# user.forget! Changes their remember token, making their cookie invalid.
#
# === Options
# * <tt>session_class:</tt> default: "#{name}Session", the related session class. Used so that you don't have to repeat yourself here. A lot of the configuration will be based off of the configuration values of this class.
Expand Down Expand Up @@ -107,6 +109,17 @@ def self.unique_token
def self.crypto_provider
#{options[:crypto_provider]}
end
def self.forget_all!
# Paginate these to save on memory
records = nil
i = 0
begin
records = find(:all, :limit => 50, :offset => i)
records.each { |record| records.update_attribute(:#{options[:remember_token_field]}, unique_token) }
i += 50
end while !records.blank?
end
end_eval

# Instance methods
Expand All @@ -125,12 +138,13 @@ def #{options[:password_field]}=(pass)
return if pass.blank?
self.tried_to_set_#{options[:password_field]} = true
@#{options[:password_field]} = pass
salt = [Array.new(6) {rand(256).chr}.join].pack("m").chomp
self.#{options[:remember_token_field]} = self.class.unique_token
self.#{options[:password_salt_field]}, self.#{options[:crypted_password_field]} = salt, crypto_provider.encrypt(@#{options[:password_field]} + salt)
self.#{options[:password_salt_field]} = self.class.unique_token
self.#{options[:crypted_password_field]} = crypto_provider.encrypt(@#{options[:password_field]} + #{options[:password_salt_field]})
end
def valid_#{options[:password_field]}?(attempted_password)
return false if attempted_password.blank?
attempted_password == #{options[:crypted_password_field]} || #{options[:crypted_password_field]} == crypto_provider.encrypt(attempted_password + #{options[:password_salt_field]})
end
end_eval
Expand All @@ -145,6 +159,7 @@ def #{options[:password_field]}=(pass)
end
def valid_#{options[:password_field]}?(attemtped_password)
return false if attempted_password.blank?
attempted_password == #{options[:crypted_password_field]} || #{options[:crypted_password_field]} = crypto_provider.decrypt(attempted_password)
end
end_eval
Expand All @@ -158,6 +173,10 @@ def crypto_provider
self.class.crypto_provider
end
def forget!
update_attribute(:#{options[:remember_token_field]}, self.class.unique_token)
end
def randomize_#{options[:password_field]}!
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
newpass = ""
Expand All @@ -166,6 +185,13 @@ def randomize_#{options[:password_field]}!
self.confirm_#{options[:password_field]} = newpass
end
def save_from_session(*args)
@saving_from_session = true
result = save(*args)
@saving_from_session = false
result
end
protected
def create_sessions!
return if !#{options[:session_class]}.activated? || #{options[:session_ids].inspect}.blank?
Expand All @@ -183,7 +209,7 @@ def create_sessions!
end
def update_sessions!
return if !#{options[:session_class]}.activated?
return if @saving_from_session || !#{options[:session_class]}.activated?
#{options[:session_ids].inspect}.each do |session_id|
session = #{options[:session_class]}.find(*[session_id].compact)
Expand All @@ -192,7 +218,7 @@ def update_sessions!
next if !session || session.record != self
# We know we are logged in and this is our record, update the session
session.update
session.save
end
end
Expand All @@ -215,4 +241,4 @@ def validate_password
end
end

ActiveRecord::Base.send(:include, Authgasm::ActsAsAuthenticated)
ActiveRecord::Base.send(:include, Authgasm::ActsAsAuthentic)
16 changes: 0 additions & 16 deletions lib/authgasm/controller.rb

This file was deleted.

25 changes: 25 additions & 0 deletions lib/authgasm/controller_adapters/abstract_adapter.rb
@@ -0,0 +1,25 @@
module Authgasm
module ControllerAdapters # :nodoc:
# = Abstract Adapter
# Allows you to use Authgasm in any framework you want, not just rails. See tha RailsAdapter for an example of how to adapter Authgasm to work with your framework.
class AbstractAdapter
attr_accessor :controller

def initialize(controller)
self.controller = controller
end

def authenticate_with_http_basic(*args, &block)
end

def cookies
end

def request
end

def session
end
end
end
end
39 changes: 39 additions & 0 deletions lib/authgasm/controller_adapters/rails_adapter.rb
@@ -0,0 +1,39 @@
module Authgasm
module ControllerAdapters
# = Rails Adapter
# Adapts authgasm to work with rails. The point is to close the gap between what authgasm expects and what the rails controller object
# provides. Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite, etc.
class RailsAdapter < AbstractAdapter
def authenticate_with_http_basic(*args, &block)
controller.authenticate_with_http_basic(*args, &block)
end

def cookies
controller.send(:cookies)
end

def request
controller.request
end

def session
controller.session
end
end

# = Rails Implementation
# Lets Authgasm know about the controller object, AKA "activates" authgasm.
module RailsImplementation
def self.included(klass) # :nodoc:
klass.prepend_before_filter :set_controller
end

private
def set_controller
Authgasm::Session::Base.controller = RailsAdapter.new(self)
end
end
end
end

ActionController::Base.send(:include, Authgasm::ControllerAdapters::RailsImplementation)
2 changes: 1 addition & 1 deletion lib/authgasm/session/active_record_trickery.rb
Expand Up @@ -18,7 +18,7 @@ def human_attribute_name(attribute_key_name, options = {})

module InstanceMethods # :nodoc:
def new_record?
true
new_session?
end
end
end
Expand Down

0 comments on commit 35f14ba

Please sign in to comment.