Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c3d5cb2
added password resets controller and ,migrations
May 21, 2013
b67edf3
added password reset services to active_directory services
May 21, 2013
554ce49
added password reset views
May 21, 2013
c10b23c
added gem recaptcha
May 21, 2013
d6bbb7e
added password reset js
May 21, 2013
232bdce
added person mailer
May 21, 2013
e013d64
added crud methods for password reset controller
May 21, 2013
147ba53
added text for password mailer
May 21, 2013
e125d92
modified active directory service methods
May 21, 2013
1b02284
added forgot passwor link in the cmu_sv layout view
May 21, 2013
70bbaca
added password reset mail text
May 21, 2013
1c4b636
modified title of new password reset view
May 21, 2013
4946f91
added host url in development environment
May 21, 2013
6a44a47
updated with professor master
May 21, 2013
7f8e973
modified flash message for successful password reset
May 21, 2013
9c50dd7
fixed bug in specs
May 22, 2013
c70c27e
fixed bug in specs
May 22, 2013
0cfef8c
updated schema
Jun 10, 2013
be9e560
added 'at' at the end of active_directory-account_create
Jun 10, 2013
6036f8f
modified notification message on successful password reset
Jun 10, 2013
af57d11
renamed active directory services to active directory services
Jun 10, 2013
0a4156a
renamed active directory services to active directory services
Jun 10, 2013
bfdd2d7
renamed ActiveDirectory to ActiveDirectoryServices
Jun 11, 2013
d8f00d3
bug fix in reset_password method
Jun 11, 2013
cfbfb52
bug fix in PersonJob
Jun 11, 2013
beef5ef
renamed ActiveDirectory spec to ActiveDirectoryServices
Jun 11, 2013
b8ca292
Edward's code to deal with password resets with conflict resolution b…
professor Jun 11, 2013
763b1a5
Renamed auth_token to be new_user_token and altered generate_token me…
professor Jun 11, 2013
19b374d
Not sure how we lost some of this data in the last commit
professor Jun 12, 2013
171a7bd
updated schema
Jun 13, 2013
f5318df
bug fix
Jun 13, 2013
54f73b9
renamed variables in password_resets new.htm.erb
Jun 13, 2013
a50d9d5
modified password resets variables
Jun 13, 2013
2c3eae8
added renamed variables in password resets controller and added defau…
Jun 13, 2013
baf8e1e
renamed active_directory_created to active_directory_created_at
Jun 14, 2013
5fcc9f2
used content for javascript instead of creating a new file
Jun 14, 2013
bc70852
refactored active directory create_account service
Jun 14, 2013
8a9d8bc
removed scaffolded password_resets spec
Jun 14, 2013
d9ff124
edited host url config and passwor reset scripts
Jun 14, 2013
8c52281
modified recaptcha to use environment variables
Jun 14, 2013
5858f13
fixed a bug in password_resets_controller spec'
Jun 14, 2013
10b0874
set name password_mismatch_warning
Jun 14, 2013
d751b97
cleaned up the people new.html.erb
Jun 18, 2013
6682c4d
updated branch with master
Jun 18, 2013
e51f728
performed some general modifications
Jun 19, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ gem 'pg'

gem 'net-ldap'

gem "recaptcha", :require => "recaptcha/rails"

gem 'cancan'

# gem 'smtp_tls' # Used for sending mail to gmail
Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,14 @@ GEM
cocaine (0.2.0)
columnize (0.3.6)
daemons (1.1.9)

debugger (1.6.0)
columnize (>= 0.3.1)
debugger-linecache (~> 1.2.0)
debugger-ruby_core_source (~> 1.2.1)
debugger-linecache (1.2.0)
debugger-ruby_core_source (1.2.2)

delayed_job (2.1.4)
activesupport (~> 3.0)
daemons
Expand Down Expand Up @@ -194,6 +196,7 @@ GEM
rake (0.8.7)
rdoc (3.12.2)
json (~> 1.4)
recaptcha (0.3.5)
rest-client (1.6.7)
mime-types (>= 1.16)
rmagick (2.13.2)
Expand Down Expand Up @@ -295,6 +298,7 @@ DEPENDENCIES
rails (= 3.0.20)
rake (= 0.8.7)
rdoc
recaptcha
rmagick
rspec-rails
seedbank
Expand Down
59 changes: 59 additions & 0 deletions app/controllers/password_resets_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
class PasswordResetsController < ApplicationController
layout 'cmu_sv'

# Display new password reset page
def index
redirect_to new_password_reset_path
end

# Create new password reset request
def create
@user = User.find_by_email(params[:cmu_email])
@active_directory_services = ActiveDirectory.new

if verify_recaptcha(:model => @user, :attribute => "verification code")
if @user && @user.personal_email == params[:personal_email]
@active_directory_services.send_password_reset_token(@user)
else
flash[:error] = "Your email entries did not match our records. Please try again or contact help@sv.cmu.edu"
redirect_to new_password_reset_path and return
end
redirect_to root_url, :notice => "Password reset instructions have been sent to #{@user.personal_email}."
else
flash[:error] = "Verification code is wrong"
redirect_to new_password_reset_path
end
end

# Display edit form with password reset token link
def edit
@user = User.find_by_password_reset_token!(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to new_password_reset_path, :flash => {:error => "Password reset link is invalid."}
end

# Do actual password reset
def update
@user = User.find_by_password_reset_token!(params[:id])
@active_directory_services = ActiveDirectory.new
respond_to do |format|
if @user.password_reset_sent_at > 2.hours.ago
if params[:new_password]
if @active_directory_services.reset_password(@user, params[:new_password]) == "Success"
flash[:notice] = "Password has been reset!"
format.html { redirect_to root_url }
else
flash[:error]="Password reset was unsuccessful. Read the instructions below or contact help@sv.cmu.edu"
redirect_to edit_password_reset_path and return
end
else
flash[:error]="Invalid new password parameter. Contact help@sv.cmu.edu"
redirect_to edit_password_reset_path and return
end
else
flash[:error] = "Password reset link has expired."
format.html { redirect_to new_password_reset_path }
end
end
end
end
2 changes: 2 additions & 0 deletions app/helpers/password_resets_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module PasswordResetsHelper
end
8 changes: 8 additions & 0 deletions app/mailers/password_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class PasswordMailer < ActionMailer::Base
default :from => "whiteboard-noreply@#{GOOGLE_DOMAIN}"

def password_reset(user)
@user = user
mail :to => user.personal_email, :subject => "Whiteboard Password Reset"
end
end
11 changes: 11 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class User < ActiveRecord::Base
before_save :person_before_save,
:update_is_profile_valid

before_create :set_new_user_token

validates_uniqueness_of :webiso_account, :case_sensitive => false
validates_uniqueness_of :email, :case_sensitive => false

Expand Down Expand Up @@ -399,6 +401,15 @@ def self.notify_it_about_expired_accounts
end
end

def set_new_user_token
self.new_user_token = SecureRandom.urlsafe_base64
end

def set_password_reset_token
self.password_reset_token = SecureRandom.urlsafe_base64
end


protected
def person_before_save
# We populate some reasonable defaults, but this can be overridden in the database
Expand Down
1 change: 1 addition & 0 deletions app/views/layouts/cmu_sv.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<li class="standard"><font color="#626262">My Deliverables (Login required)</font></li>
<li class="standard"><font color="#626262">My Teams (Login required)</font></li>
<li class="standard"><%= link_to "Login ", user_omniauth_authorize_path(:google_apps), :class => "Lv1NavLink" %></li>
<%= link_to "Forgot password", new_password_reset_path%>
<% end %>
</ul>
<div class="hr">
Expand Down
13 changes: 13 additions & 0 deletions app/views/password_mailer/password_reset.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Hi <%=@user.human_name%>,

A password reset request for your login to Whiteboard has been received at <%=Time.now.to_s%>

To reset your password, please follow this link.

<%= edit_password_reset_url(@user.password_reset_token) %>

Access to this link is only valid for 2 hours.

If you did not request a password reset, report this to help@sv.cmu.edu immediately.

Thanks.
103 changes: 103 additions & 0 deletions app/views/password_resets/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<% content_for :javascript do %>

<script type="text/javascript">

// Check whether the new password matches with the confirmation password
function validatePasswordEditForm(){
var newPass = $("#new_password").val()
var confirmPass = $("#confirm_password").val()

if ((newPass == confirmPass)) {
return true
}else{
return warnPasswordMismatch()
}
}

// Warn if new password and confirmation password mismatches
function warnPasswordMismatch(){
$("#password_mismatch_warning").empty()
$("#password_mismatch_warning").append($('<div/>').css('color', 'red').text('Password mismatch'));
return false
}

// Password strength meter

var shortPass = 'Too short'
var badPass = 'Bad'
var goodPass = 'Good'
var strongPass = 'Strong'


function passwordStrength(password){
score = 0

// password length should be greater than 8
if (password.length < 8 ) { return shortPass }

// password has a number
if (password.match(/(.*[0-9])/)) score += 5

// password has 3 numbers
if (password.match(/(.*[0-9].*[0-9].*[0-9])/)) score += 5

// password has a symbol
if (password.match(/(.*[!,@,#,$,%,^,&,*,?,_,~])/)) score += 5

// password has upper and lower chars
if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)) score += 10

// password has number and chars
if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/)) score += 15
//
// password has number and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([0-9])/)) score += 15

// password has char and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([a-zA-Z])/)) score += 15

// password is just numbers or chars
if (password.match(/^\w+$/) || password.match(/^\d+$/) ) score -= 10

// ensure 0 < score < 100
if ( score < 0 ) score = 0
if ( score > 100 ) score = 100

if (score < 20 ) return badPass
if (score >= 20 && score < 25 ) return goodPass

return strongPass
}

// jQuery script to show password strength
$(function() {
$("#new_password").keyup(
function() {
$('#result').html(passwordStrength($('#new_password').val()))
});
});

</script>

<% end %>

<%= form_for @user, { :url => password_reset_path(params[:id]) } do |f| %>
<p>
<h1> Resetting password for <%= @user.human_name %>'s account.</h1>
</p>
<p>
<b>Instructions</b>
<br/>The new password must have a digit character, a capital letter, and a minimum of eight characters.
</p>
<p>
<label for="p" class="screen-reader-text">New password:</label><br/>
<input type="password" id="new_password" name="new_password" value="">
<span style="color:green" id='result'></span>
</p>
<p>
<label for="p" class="screen-reader-text">Confirm password:</label><br/>
<input type="password" id="confirm_password" name="confirm_password" value="">
</p>
<div id="password_mismatch_warning"></div> <br/>
<div class="actions"><%= f.submit "Update Password", :onclick=>"return validatePasswordEditForm()" %></div>
<% end %>
55 changes: 55 additions & 0 deletions app/views/password_resets/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<% content_for :javascript do %>


<script type="text/javascript">

// Option for recaptcha theme
var RecaptchaOptions = {
theme : 'clean'
}

// Validate password reset form
function validatePasswordResetForm(){
if ( ($("#cmu_email").val()=="") || ($("#personal_email").val()=="") ){
return warnBlankFields()
} else{
return true
}
}

// Warn if any email input field is blank
function warnBlankEmailFields(){
$("#blank_email_warning").empty()
$("#blank_email_warning").append($('<div/>').css('color', 'red').text('Blank fields are not allowed'));
return false
}



</script>

<% end %>


<% content_for :title, 'Whiteboard Password Reset' %>

<h1 xmlns="http://www.w3.org/1999/html">Reset account password</h1>

<form action="<%= password_resets_path%>" id="password_reset_form" method="post" role="reset" onsubmit="return validatePasswordResetForm()">

<div>
<label for="pe" class="screen-reader-text">CMU email</label> </br>
<input type="text" id="cmu_email" name="cmu_email" value="" placeholder=<%="@#{GOOGLE_DOMAIN}"%>></br> </br>
<label for="se" class="screen-reader-text">Personal email</label> </br>
<input type="text" id="personal_email" name="personal_email" value=""></br> </br>
<div id="blank_email_warning"></div> <br/>
<%= recaptcha_tags :ssl => true %>
</br>
<input type="submit" value=" Go " id="resetSubmit">
</div>
</br>

</form>



Loading