Browse Source

Added password system

master
Adrian Short 12 years ago
parent
commit
19954ca048
28 changed files with 750 additions and 2 deletions
  1. +1
    -0
      Gemfile
  2. +13
    -0
      Gemfile.lock
  3. +3
    -0
      app/assets/javascripts/sessions.js.coffee
  4. +3
    -0
      app/assets/javascripts/users.js.coffee
  5. +3
    -0
      app/assets/stylesheets/sessions.css.scss
  6. +3
    -0
      app/assets/stylesheets/users.css.scss
  7. +6
    -0
      app/controllers/application_controller.rb
  8. +2
    -2
      app/controllers/feeds_controller.rb
  9. +19
    -0
      app/controllers/sessions_controller.rb
  10. +83
    -0
      app/controllers/users_controller.rb
  11. +2
    -0
      app/helpers/sessions_helper.rb
  12. +2
    -0
      app/helpers/users_helper.rb
  13. +17
    -0
      app/models/user.rb
  14. +8
    -0
      app/views/layouts/application.html.haml
  15. +19
    -0
      app/views/sessions/new.html.haml
  16. +19
    -0
      app/views/users/_form.html.haml
  17. +7
    -0
      app/views/users/edit.html.haml
  18. +23
    -0
      app/views/users/index.html.haml
  19. +5
    -0
      app/views/users/new.html.haml
  20. +15
    -0
      app/views/users/show.html.haml
  21. +407
    -0
      config/initializers/sorcery.rb
  22. +6
    -0
      config/routes.rb
  23. +11
    -0
      test/fixtures/users.yml
  24. +9
    -0
      test/functional/sessions_controller_test.rb
  25. +49
    -0
      test/functional/users_controller_test.rb
  26. +4
    -0
      test/unit/helpers/sessions_helper_test.rb
  27. +4
    -0
      test/unit/helpers/users_helper_test.rb
  28. +7
    -0
      test/unit/user_test.rb

+ 1
- 0
Gemfile View File

@@ -42,3 +42,4 @@ gem 'haml-rails'
gem 'mm-multi-parameter-attributes'
gem 'feedzirra'
gem 'htmlentities'
gem 'sorcery'

+ 13
- 0
Gemfile.lock View File

@@ -29,6 +29,7 @@ GEM
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
bcrypt-ruby (3.0.1)
bson (1.6.4)
bson_ext (1.6.4)
bson (~> 1.6.4)
@@ -44,6 +45,8 @@ GEM
erubis (2.7.0)
execjs (1.4.0)
multi_json (~> 1.0)
faraday (0.8.1)
multipart-post (~> 1.1)
feedzirra (0.0.31)
activesupport (>= 3.0.8)
builder (~> 3.0.0)
@@ -85,7 +88,12 @@ GEM
activesupport (~> 3.0)
plucky (~> 0.4.0)
multi_json (1.3.6)
multipart-post (1.1.5)
nokogiri (1.4.7)
oauth (0.4.6)
oauth2 (0.5.2)
faraday (~> 0.7)
multi_json (~> 1.0)
plucky (0.4.4)
mongo (~> 1.5)
polyglot (0.3.3)
@@ -121,6 +129,10 @@ GEM
tilt (~> 1.3)
sax-machine (0.0.20)
nokogiri (> 0.0.0)
sorcery (0.7.12)
bcrypt-ruby (~> 3.0.0)
oauth (~> 0.4.4)
oauth2 (~> 0.5.1)
sprockets (2.1.3)
hike (~> 1.2)
rack (~> 1.0)
@@ -149,4 +161,5 @@ DEPENDENCIES
mongo_mapper
rails (= 3.2.3)
sass-rails (~> 3.2.3)
sorcery
uglifier (>= 1.0.3)

+ 3
- 0
app/assets/javascripts/sessions.js.coffee View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

+ 3
- 0
app/assets/javascripts/users.js.coffee View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

+ 3
- 0
app/assets/stylesheets/sessions.css.scss View File

@@ -0,0 +1,3 @@
// Place all the styles related to the sessions controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

+ 3
- 0
app/assets/stylesheets/users.css.scss View File

@@ -0,0 +1,3 @@
// Place all the styles related to the Users controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

+ 6
- 0
app/controllers/application_controller.rb View File

@@ -1,3 +1,9 @@
class ApplicationController < ActionController::Base
protect_from_forgery
private
def not_authenticated
redirect_to login_path, :notice => "Please log in"
end
end

+ 2
- 2
app/controllers/feeds_controller.rb View File

@@ -1,6 +1,6 @@
class FeedsController < ApplicationController
http_basic_authenticate_with :name => ENV['auth_username'], :password => ENV['auth_password']
before_filter :require_login
# GET /feeds
# GET /feeds.json
def index


+ 19
- 0
app/controllers/sessions_controller.rb View File

@@ -0,0 +1,19 @@
class SessionsController < ApplicationController
def new
end
def create
user = login(params[:email], params[:password], params[:remember_me])
if user
redirect_back_or_to root_url, :notice => "Logged in OK"
else
flash.now.alert = "Email or password was invalid"
render :new
end
end
def destroy
logout
redirect_to root_path, :notice => "Logged out"
end
end

+ 83
- 0
app/controllers/users_controller.rb View File

@@ -0,0 +1,83 @@
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
@users = User.all

respond_to do |format|
format.html # index.html.erb
format.json { render json: @users }
end
end

# GET /users/1
# GET /users/1.json
def show
@user = User.find(params[:id])

respond_to do |format|
format.html # show.html.erb
format.json { render json: @user }
end
end

# GET /users/new
# GET /users/new.json
def new
@user = User.new

respond_to do |format|
format.html # new.html.erb
format.json { render json: @user }
end
end

# GET /users/1/edit
def edit
@user = User.find(params[:id])
end

# POST /users
# POST /users.json
def create
@user = User.new(params[:user])

respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.json { render json: @user, status: :created, location: @user }
else
format.html { render action: "new" }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end

# PUT /users/1
# PUT /users/1.json
def update
@user = User.find(params[:id])

respond_to do |format|
if @user.update_attributes(params[:user])
format.html { redirect_to @user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end

# DELETE /users/1
# DELETE /users/1.json
def destroy
@user = User.find(params[:id])
@user.destroy

respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end

+ 2
- 0
app/helpers/sessions_helper.rb View File

@@ -0,0 +1,2 @@
module SessionsHelper
end

+ 2
- 0
app/helpers/users_helper.rb View File

@@ -0,0 +1,2 @@
module UsersHelper
end

+ 17
- 0
app/models/user.rb View File

@@ -0,0 +1,17 @@
class User
include MongoMapper::Document

key :email, String
key :crypted_password, String
key :salt, String
authenticates_with_sorcery!
# attr_accessible :email, :password, :password_confirmation

validates_presence_of :email
validates_presence_of :password, :on => :create
validates_uniqueness_of :email
validates_length_of :password, :minimum => 3, :message => "password must be at least 3 characters long", :if => :password
validates_confirmation_of :password, :message => "should match confirmation", :if => :password

end

+ 8
- 0
app/views/layouts/application.html.haml View File

@@ -10,6 +10,14 @@
%body
= link_to(image_tag("TAL_logo_blue-h100.png", :size => "275x100", :alt => "Talk About Local logo"), :root, :class => "logo")
#userbar
- if current_user
Logged in as
= current_user.email
= link_to "Log out", logout_path
- else
= link_to "Log in", login_path
%p#notice= notice
= yield


+ 19
- 0
app/views/sessions/new.html.haml View File

@@ -0,0 +1,19 @@
%h1 Log in

= form_tag sessions_path do
.field
= label_tag :email
%br
= text_field_tag :email, params[:email]
.field
= label_tag :password
%br
= password_field_tag :password
.field
= check_box_tag :remember_me, 1, params[:remember_me]
= label_tag :remember_me

.actions
= submit_tag "Log in"

+ 19
- 0
app/views/users/_form.html.haml View File

@@ -0,0 +1,19 @@
= form_for @user do |f|
-if @user.errors.any?
#error_explanation
%h2= "#{pluralize(@user.errors.count, "error")} prohibited this user from being saved:"
%ul
- @user.errors.full_messages.each do |msg|
%li= msg

.field
= f.label :email
= f.text_field :email
.field
= f.label :password
= f.password_field :password
.field
= f.label :password_confirmation
= f.password_field :password_confirmation
.actions
= f.submit 'Save'

+ 7
- 0
app/views/users/edit.html.haml View File

@@ -0,0 +1,7 @@
%h1 Editing user

= render 'form'

= link_to 'Show', @user
\|
= link_to 'Back', users_path

+ 23
- 0
app/views/users/index.html.haml View File

@@ -0,0 +1,23 @@
%h1 Listing users

%table
%tr
%th Email
%th Crypted password
%th Salt
%th
%th
%th

- @users.each do |user|
%tr
%td= user.email
%td= user.crypted_password
%td= user.salt
%td= link_to 'Show', user
%td= link_to 'Edit', edit_user_path(user)
%td= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete

%br

= link_to 'New User', new_user_path

+ 5
- 0
app/views/users/new.html.haml View File

@@ -0,0 +1,5 @@
%h1 New user

= render 'form'

= link_to 'Back', users_path

+ 15
- 0
app/views/users/show.html.haml View File

@@ -0,0 +1,15 @@
%p#notice= notice

%p
%b Email:
= @user.email
%p
%b Crypted password:
= @user.crypted_password
%p
%b Salt:
= @user.salt

= link_to 'Edit', edit_user_path(@user)
\|
= link_to 'Back', users_path

+ 407
- 0
config/initializers/sorcery.rb View File

@@ -0,0 +1,407 @@
# The first thing you need to configure is which modules you need in your app.
# The default is nothing which will include only core features (password encryption, login/logout).
# Available submodules are: :user_activation, :http_basic_auth, :remember_me,
# :reset_password, :session_timeout, :brute_force_protection, :activity_logging, :external
# Rails.application.config.sorcery.submodules = [:remember_me, :reset_password]
Rails.application.config.sorcery.submodules = [:remember_me]

# Here you can configure each submodule's features.
Rails.application.config.sorcery.configure do |config|
# -- core --
# What controller action to call for non-authenticated users. You can also
# override the 'not_authenticated' method of course.
# Default: `:not_authenticated`
#
# config.not_authenticated_action =


# When a non logged in user tries to enter a page that requires login, save
# the URL he wanted to reach, and send him there after login, using 'redirect_back_or_to'.
# Default: `true`
#
# config.save_return_to_url =


# Set domain option for cookies; Useful for remember_me submodule.
# Default: `nil`
#
# config.cookie_domain =


# -- session timeout --
# How long in seconds to keep the session alive.
# Default: `3600`
#
# config.session_timeout =


# Use the last action as the beginning of session timeout.
# Default: `false`
#
# config.session_timeout_from_last_action =


# -- http_basic_auth --
# What realm to display for which controller name. For example {"My App" => "Application"}
# Default: `{"application" => "Application"}`
#
# config.controller_to_realm_map =


# -- activity logging --
# will register the time of last user login, every login.
# Default: `true`
#
# config.register_login_time =


# will register the time of last user logout, every logout.
# Default: `true`
#
# config.register_logout_time =


# will register the time of last user action, every action.
# Default: `true`
#
# config.register_last_activity_time =


# -- external --
# What providers are supported by this app, i.e. [:twitter, :facebook, :github, :google, :liveid] .
# Default: `[]`
#
# config.external_providers =


# You can change it by your local ca_file. i.e. '/etc/pki/tls/certs/ca-bundle.crt'
# Path to ca_file. By default use a internal ca-bundle.crt.
# Default: `'path/to/ca_file'`
#
# config.ca_file =


# Twitter wil not accept any requests nor redirect uri containing localhost,
# make sure you use 0.0.0.0:3000 to access your app in development
#
# config.twitter.key = ""
# config.twitter.secret = ""
# config.twitter.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=twitter"
# config.twitter.user_info_mapping = {:email => "screen_name"}
#
# config.facebook.key = ""
# config.facebook.secret = ""
# config.facebook.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=facebook"
# config.facebook.user_info_mapping = {:email => "name"}
#
# config.github.key = ""
# config.github.secret = ""
# config.github.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=github"
# config.github.user_info_mapping = {:email => "name"}
#
# config.google.key = ""
# config.google.secret = ""
# config.google.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=google"
# config.google.user_info_mapping = {:email => "email", :username => "name"}
#
# To use liveid in development mode you have to replace mydomain.com with
# a valid domain even in development. To use a valid domain in development
# simply add your domain in your /etc/hosts file in front of 127.0.0.1
#
# config.liveid.key = ""
# config.liveid.secret = ""
# config.liveid.callback_url = "http://mydomain.com:3000/oauth/callback?provider=liveid"
# config.liveid.user_info_mapping = {:username => "name"}


# --- user config ---
config.user_config do |user|
# -- core --
# specify username attributes, for example: [:username, :email].
# Default: `[:username]`
#
user.username_attribute_names = [:email]


# change *virtual* password attribute, the one which is used until an encrypted one is generated.
# Default: `:password`
#
# user.password_attribute_name =


# downcase the username before trying to authenticate, default is false
# Default: `false`
#
# user.downcase_username_before_authenticating =


# change default email attribute.
# Default: `:email`
#
# user.email_attribute_name =


# change default crypted_password attribute.
# Default: `:crypted_password`
#
# user.crypted_password_attribute_name =


# what pattern to use to join the password with the salt
# Default: `""`
#
# user.salt_join_token =


# change default salt attribute.
# Default: `:salt`
#
# user.salt_attribute_name =


# how many times to apply encryption to the password.
# Default: `nil`
#
# user.stretches =


# encryption key used to encrypt reversible encryptions such as AES256.
# WARNING: If used for users' passwords, changing this key will leave passwords undecryptable!
# Default: `nil`
#
# user.encryption_key =


# use an external encryption class.
# Default: `nil`
#
# user.custom_encryption_provider =


# encryption algorithm name. See 'encryption_algorithm=' for available options.
# Default: `:bcrypt`
#
# user.encryption_algorithm =


# make this configuration inheritable for subclasses. Useful for ActiveRecord's STI.
# Default: `false`
#
# user.subclasses_inherit_config =


# -- user_activation --
# the attribute name to hold activation state (active/pending).
# Default: `:activation_state`
#
# user.activation_state_attribute_name =


# the attribute name to hold activation code (sent by email).
# Default: `:activation_token`
#
# user.activation_token_attribute_name =


# the attribute name to hold activation code expiration date.
# Default: `:activation_token_expires_at`
#
# user.activation_token_expires_at_attribute_name =


# how many seconds before the activation code expires. nil for never expires.
# Default: `nil`
#
# user.activation_token_expiration_period =


# your mailer class. Required.
# Default: `nil`
#
# user.user_activation_mailer =
# when true sorcery will not automatically
# email activation details and allow you to
# manually handle how and when email is sent.
# Default: `false`
#
# user.activation_mailer_disabled =


# activation needed email method on your mailer class.
# Default: `:activation_needed_email`
#
# user.activation_needed_email_method_name =


# activation success email method on your mailer class.
# Default: `:activation_success_email`
#
# user.activation_success_email_method_name =


# do you want to prevent or allow users that did not activate by email to login?
# Default: `true`
#
# user.prevent_non_active_users_to_login =


# -- reset_password --
# reset password code attribute name.
# Default: `:reset_password_token`
#
# user.reset_password_token_attribute_name =


# expires at attribute name.
# Default: `:reset_password_token_expires_at`
#
# user.reset_password_token_expires_at_attribute_name =


# when was email sent, used for hammering protection.
# Default: `:reset_password_email_sent_at`
#
# user.reset_password_email_sent_at_attribute_name =


# mailer class. Needed.
# Default: `nil`
#
# user.reset_password_mailer =


# reset password email method on your mailer class.
# Default: `:reset_password_email`
#
# user.reset_password_email_method_name =


# when true sorcery will not automatically
# email password reset details and allow you to
# manually handle how and when email is sent
# Default: `false`
#
# user.reset_password_mailer_disabled =

# reset password email
# method on your mailer
# class.
# Default: `:reset_password_email`
#
# user.reset_password_email_method_name =

# how many seconds before the reset request expires. nil for never expires.
# Default: `nil`
#
# user.reset_password_expiration_period =


# hammering protection, how long to wait before allowing another email to be sent.
# Default: `5 * 60`
#
# user.reset_password_time_between_emails =


# -- brute_force_protection --
# Failed logins attribute name.
# Default: `:failed_logins_count`
#
# user.failed_logins_count_attribute_name =


# This field indicates whether user is banned and when it will be active again.
# Default: `:lock_expires_at`
#
# user.lock_expires_at_attribute_name =


# How many failed logins allowed.
# Default: `50`
#
# user.consecutive_login_retries_amount_limit =


# How long the user should be banned. in seconds. 0 for permanent.
# Default: `60 * 60`
#
# user.login_lock_time_period =

# Unlock token attribute name
# Default: `:unlock_token`
#
# user.unlock_token_attribute_name =

# Unlock token mailer method
# Default: `:send_unlock_token_email`
#
# user.unlock_token_email_method_name =

# when true sorcery will not automatically
# send email with unlock token
# Default: `false`
#
# user.unlock_token_mailer_disabled = true

# Unlock token mailer class
# Default: `nil`
#
# user.unlock_token_mailer = UserMailer

# -- activity logging --
# Last login attribute name.
# Default: `:last_login_at`
#
# user.last_login_at_attribute_name =


# Last logout attribute name.
# Default: `:last_logout_at`
#
# user.last_logout_at_attribute_name =


# Last activity attribute name.
# Default: `:last_activity_at`
#
# user.last_activity_at_attribute_name =


# How long since last activity is he user defined logged out?
# Default: `10 * 60`
#
# user.activity_timeout =


# -- external --
# Class which holds the various external provider data for this user.
# Default: `nil`
#
# user.authentications_class =


# User's identifier in authentications class.
# Default: `:user_id`
#
# user.authentications_user_id_attribute_name =


# Provider's identifier in authentications class.
# Default: `:provider`
#
# user.provider_attribute_name =


# User's external unique identifier in authentications class.
# Default: `:uid`
#
# user.provider_uid_attribute_name =
end

# This line must come after the 'user config' block.
# Define which model authenticates with sorcery.
config.user_class = "User"
end

+ 6
- 0
config/routes.rb View File

@@ -1,4 +1,10 @@
Apollo::Application.routes.draw do
get "logout" => "sessions#destroy", :as => "logout"
get "login" => "sessions#new", :as => "login"

resources :users
resources :sessions
get "posts/near"

resources :feeds do


+ 11
- 0
test/fixtures/users.yml View File

@@ -0,0 +1,11 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html

one:
email: MyString
crypted_password: MyString
salt: MyString

two:
email: MyString
crypted_password: MyString
salt: MyString

+ 9
- 0
test/functional/sessions_controller_test.rb View File

@@ -0,0 +1,9 @@
require 'test_helper'

class SessionsControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end

end

+ 49
- 0
test/functional/users_controller_test.rb View File

@@ -0,0 +1,49 @@
require 'test_helper'

class UsersControllerTest < ActionController::TestCase
setup do
@user = users(:one)
end

test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:users)
end

test "should get new" do
get :new
assert_response :success
end

test "should create user" do
assert_difference('User.count') do
post :create, user: { crypted_password: @user.crypted_password, email: @user.email, salt: @user.salt }
end

assert_redirected_to user_path(assigns(:user))
end

test "should show user" do
get :show, id: @user
assert_response :success
end

test "should get edit" do
get :edit, id: @user
assert_response :success
end

test "should update user" do
put :update, id: @user, user: { crypted_password: @user.crypted_password, email: @user.email, salt: @user.salt }
assert_redirected_to user_path(assigns(:user))
end

test "should destroy user" do
assert_difference('User.count', -1) do
delete :destroy, id: @user
end

assert_redirected_to users_path
end
end

+ 4
- 0
test/unit/helpers/sessions_helper_test.rb View File

@@ -0,0 +1,4 @@
require 'test_helper'

class SessionsHelperTest < ActionView::TestCase
end

+ 4
- 0
test/unit/helpers/users_helper_test.rb View File

@@ -0,0 +1,4 @@
require 'test_helper'

class UsersHelperTest < ActionView::TestCase
end

+ 7
- 0
test/unit/user_test.rb View File

@@ -0,0 +1,7 @@
require 'test_helper'

class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

Loading…
Cancel
Save