Merge branch 'master' of https://github.com/OWASP/railsgoat
This commit is contained in:
@@ -49,7 +49,6 @@ group :assets do
|
||||
gem 'uglifier'
|
||||
end
|
||||
|
||||
|
||||
gem 'jquery-rails'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
@@ -78,3 +77,5 @@ gem 'aruba'
|
||||
gem 'execjs'
|
||||
gem 'therubyracer'
|
||||
|
||||
# Add SMTP server support using MailCatcher
|
||||
gem 'mailcatcher'
|
||||
|
||||
@@ -79,6 +79,7 @@ GEM
|
||||
gherkin (~> 2.12)
|
||||
multi_json (>= 1.7.5, < 2.0)
|
||||
multi_test (>= 0.0.2)
|
||||
daemons (1.1.9)
|
||||
database_cleaner (1.0.1)
|
||||
debug_inspector (0.0.2)
|
||||
diff-lcs (1.2.5)
|
||||
@@ -150,6 +151,15 @@ GEM
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mailcatcher (0.5.12)
|
||||
activesupport (~> 3.0)
|
||||
eventmachine (~> 1.0.0)
|
||||
haml (>= 3.1, < 5)
|
||||
mail (~> 2.3)
|
||||
sinatra (~> 1.2)
|
||||
skinny (~> 0.2.3)
|
||||
sqlite3 (~> 1.3)
|
||||
thin (~> 1.5.0)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
multi_json (1.8.2)
|
||||
@@ -172,6 +182,8 @@ GEM
|
||||
rack (>= 0.4)
|
||||
rack-livereload (0.3.15)
|
||||
rack
|
||||
rack-protection (1.5.1)
|
||||
rack
|
||||
rack-ssl (1.3.3)
|
||||
rack
|
||||
rack-test (0.6.2)
|
||||
@@ -231,6 +243,13 @@ GEM
|
||||
multi_json
|
||||
simplecov-html (~> 0.7.1)
|
||||
simplecov-html (0.7.1)
|
||||
sinatra (1.4.4)
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (~> 1.3, >= 1.3.4)
|
||||
skinny (0.2.3)
|
||||
eventmachine (~> 1.0.0)
|
||||
thin (~> 1.5.0)
|
||||
slim (2.0.2)
|
||||
temple (~> 0.6.6)
|
||||
tilt (>= 1.3.3, < 2.1)
|
||||
@@ -246,6 +265,10 @@ GEM
|
||||
therubyracer (0.12.0)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thin (1.5.1)
|
||||
daemons (>= 1.0.9)
|
||||
eventmachine (>= 0.12.6)
|
||||
rack (>= 1.0.0)
|
||||
thor (0.18.1)
|
||||
tilt (1.4.1)
|
||||
timers (1.1.0)
|
||||
@@ -290,6 +313,7 @@ DEPENDENCIES
|
||||
jquery-fileupload-rails
|
||||
jquery-rails
|
||||
launchy
|
||||
mailcatcher
|
||||
poltergeist
|
||||
powder
|
||||
pry
|
||||
|
||||
@@ -69,6 +69,27 @@ $ rake training
|
||||
|
||||
NOTE: As vulnerabilities are fixed in the application, these specs will not change to `passing`, but to `pending`.
|
||||
|
||||
## Processing Email
|
||||
|
||||
In order for RailsGoat to effectively process email, you will first need to run MailCatcher, an SMTP server that will intercept email messages and display them in a web interface.
|
||||
|
||||
To start an instance of MailCatcher, simply run:
|
||||
|
||||
```
|
||||
$ mailcatcher
|
||||
```
|
||||
|
||||
If successful, you should see the following output:
|
||||
|
||||
```
|
||||
Starting MailCatcher
|
||||
==> smtp://127.0.0.1:1025
|
||||
==> http://127.0.0.1:1080
|
||||
*** MailCatcher runs as a daemon by default. Go to the web interface to quit.
|
||||
```
|
||||
|
||||
Alternatively, you can run MailCatcher in the foreground by running `mailcatcher -f` in your terminal.
|
||||
|
||||
## Contributing
|
||||
|
||||
As changes are made to the application, the Capybara RSpecs can be used to verify that the vulnerabilities in the application are still intact. To use them in this way, and have them `pass` instead of `fail`, set the `RAILSGOAT_MAINTAINER` environment variable.
|
||||
|
||||
@@ -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/
|
||||
@@ -4616,7 +4616,7 @@ button.close {
|
||||
.signup .signup-wrapper .actions {
|
||||
padding: 10px; }
|
||||
.signup .signup-wrapper .actions a {
|
||||
color: #b3b3b3; }
|
||||
color: #ffffff; }
|
||||
.signup .signup-wrapper .checkbox {
|
||||
visibility: hidden; }
|
||||
.signup .signup-wrapper .checkbox-wrapper {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
// Place all the styles related to the password_resets controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||
@@ -2,23 +2,23 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
before_filter :authenticated, :has_info
|
||||
helper_method :current_user, :is_admin?
|
||||
|
||||
|
||||
# Our security guy keep talking about sea-surfing, cool story bro.
|
||||
# protect_from_forgery
|
||||
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
@current_user ||= User.find_by_user_id(session[:user_id].to_s)
|
||||
end
|
||||
|
||||
|
||||
def authenticated
|
||||
path = request.fullpath.present? ? root_url(:url => request.fullpath) : root_url
|
||||
redirect_to path and reset_session if not current_user
|
||||
end
|
||||
|
||||
def is_admin?
|
||||
current_user.admin if current_user
|
||||
current_user.admin if current_user
|
||||
end
|
||||
|
||||
def administrative
|
||||
@@ -27,11 +27,11 @@ class ApplicationController < ActionController::Base
|
||||
redirect_to root_url
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def has_info
|
||||
redirect = false
|
||||
if current_user
|
||||
begin
|
||||
begin
|
||||
if !(current_user.retirement || current_user.paid_time_off.schedule || current_user.paid_time_off || current_user.work_info || current_user.performance)
|
||||
redirect = true
|
||||
end
|
||||
@@ -41,5 +41,5 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
redirect_to home_dashboard_index_path if redirect
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
class PasswordResetsController < ApplicationController
|
||||
skip_before_filter :authenticated
|
||||
|
||||
|
||||
def reset_password
|
||||
user = Marshal.load(Base64.decode64(params[:user])) unless params[:user].nil?
|
||||
|
||||
if user && params[:password] && params[:confirm_password] && params[:password] == params[:confirm_password]
|
||||
user.password = params[:password]
|
||||
user.save!
|
||||
flash[:success] = "Your password has been reset please login"
|
||||
redirect_to :login
|
||||
else
|
||||
flash[:error] = "Error resetting your password. Please try again."
|
||||
redirect_to :login
|
||||
end
|
||||
end
|
||||
|
||||
def confirm_token
|
||||
if !params[:token].nil? && is_valid?(params[:token])
|
||||
flash[:success] = "Password reset token confirmed! Please create a new password."
|
||||
render :reset_password
|
||||
else
|
||||
flash[:error] = "Invalid password reset token. Please try again."
|
||||
redirect_to :login
|
||||
end
|
||||
end
|
||||
|
||||
def forgot_password
|
||||
@user = User.find_by_email(params[:email]) unless params[:email].nil?
|
||||
|
||||
if @user && password_reset_mailer(@user)
|
||||
flash[:success] = "Password reset email sent to #{params[:email]}"
|
||||
redirect_to :login
|
||||
else
|
||||
flash[:error] = "There was an issue sending password reset email to #{params[:email]}".html_safe unless params[:email].nil?
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def password_reset_mailer(user)
|
||||
token = generate_token(user.id, user.email)
|
||||
UserMailer.forgot_password(user.email, token).deliver
|
||||
end
|
||||
|
||||
def generate_token(id, email)
|
||||
hash = Digest::MD5.hexdigest(email)
|
||||
"#{id}-#{hash}"
|
||||
end
|
||||
|
||||
def is_valid?(token)
|
||||
if token =~ /(?<user_id>\d+)-(?<email_hash>[A-Z0-9]{32})/i
|
||||
|
||||
# Fetch the user by their id, and hash their email address
|
||||
@user = User.find_by_id($~[:user_id])
|
||||
email = Digest::MD5.hexdigest(@user.email)
|
||||
|
||||
# Compare and validate our hashes
|
||||
return true if email == $~[:email_hash]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,18 +1,8 @@
|
||||
class UsersController < ApplicationController
|
||||
|
||||
skip_before_filter :has_info
|
||||
skip_before_filter :authenticated, :only => [:new, :create, :forgot_password]
|
||||
skip_before_filter :authenticated, :only => [:new, :create]
|
||||
|
||||
def forgot_password
|
||||
@user = User.find_by_email(params[:email]) unless params[:email].nil?
|
||||
|
||||
if @user && password_reset_mailer_setup(@user)
|
||||
flash[:success] = "Password reset email sent to #{params[:email]}"
|
||||
redirect_to :login
|
||||
else
|
||||
flash[:error] = "There was an issue sending password reset email to #{params[:email]}".html_safe unless params[:email].nil?
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@user = User.new
|
||||
@@ -63,16 +53,4 @@ class UsersController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def password_reset_mailer_setup(user)
|
||||
token = generate_token(user.id, user.email)
|
||||
#reset_password_mailer(user.email, token)
|
||||
end
|
||||
|
||||
def generate_token(id, email)
|
||||
hash = Digest::MD5.hexdigest(email)
|
||||
"#{id}~#{hash}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
module PasswordResetsHelper
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
class UserMailer < ActionMailer::Base
|
||||
default from: "noreply@railsgoat.dev"
|
||||
|
||||
def forgot_password(email, token)
|
||||
@token = token
|
||||
@url = url_for(controller: "password_resets", action: "reset_password", only_path: false) + "?token=#{token}"
|
||||
|
||||
mail(to: "#{email}", subject: "Reset your MetaCorp password")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
<div class="row-fluid">
|
||||
<h2 align="center">MetaCorp</h2>
|
||||
<h3 align="center">A GoatGroup Company</h3>
|
||||
<div class="span12">
|
||||
<div class="row-fluid">
|
||||
<div class="span4 offset4">
|
||||
|
||||
<div class="signup">
|
||||
<%= form_tag "forgot_password", :class=> "signup-wrapper" do %>
|
||||
|
||||
<div class="header">
|
||||
<h2>Forgot Password</h2>
|
||||
<p>Fill out the form below to reset your password.</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<%= label_tag "Email Address" %>
|
||||
<%= text_field_tag :email, params[:email], {:class => "input input-block-level"} %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= submit_tag "Reset Password", {:class => "btn btn-danger btn-large"} %>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
<div class="row-fluid">
|
||||
<h2 align="center">MetaCorp</h2>
|
||||
<h3 align="center">A GoatGroup Company</h3>
|
||||
<div class="span12">
|
||||
<div class="row-fluid">
|
||||
<div class="span4 offset4">
|
||||
|
||||
<!-- TODO -->
|
||||
<!-- Create a form that allows a user to reset their password -->
|
||||
<!-- This form is just a placeholder with no working functionality -->
|
||||
|
||||
<div class="signup">
|
||||
<%= form_tag "password_resets", :class=> "signup-wrapper" do %>
|
||||
|
||||
<div class="header">
|
||||
<h2>Create Password</h2>
|
||||
<p>Fill out the form below to create a new password.</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<%= hidden_field_tag 'user', Base64.encode64(Marshal.dump(@user)) %>
|
||||
<%= label_tag "Enter Password" %>
|
||||
<%= password_field_tag :password, params[:password], {:class => "input input-block-level"} %>
|
||||
<%= label_tag "Confirm Password" %>
|
||||
<%= password_field_tag :confirm_password, params[:confirm_password], {:class => "input input-block-level"} %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= submit_tag "Create Password", {:class => "btn btn-danger btn-large"} %>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,34 +1,36 @@
|
||||
<div class="row-fluid">
|
||||
<h2 align="center">MetaCorp</h2>
|
||||
<h3 align="center">A GoatGroup Company</h3>
|
||||
<h2 align="center">MetaCorp</h2>
|
||||
<h3 align="center">A GoatGroup Company</h3>
|
||||
<div class="span12">
|
||||
<div class="row-fluid">
|
||||
<div class="span4 offset4">
|
||||
<div class="signup">
|
||||
<%= form_tag "sessions", :class=> "signup-wrapper" do %>
|
||||
<div class="header">
|
||||
|
||||
<h2>Login</h2>
|
||||
<p>Fill out the form below to login to your control panel.</p>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span4 offset4">
|
||||
|
||||
<div class="content">
|
||||
<%= hidden_field_tag :url, @url%>
|
||||
<%= label_tag "Email Address" %>
|
||||
<%= text_field_tag :email, params[:email], {:class => "input input-block-level"} %>
|
||||
<div class="signup">
|
||||
<%= form_tag "sessions", :class=> "signup-wrapper" do %>
|
||||
|
||||
<%= label_tag :password, nil %>
|
||||
<%= password_field_tag :password, nil, {:class => "input input-block-level"}%>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= link_to "Forgot Password", forgot_password_path, {:class => "btn btn-warning btn-small"} %>
|
||||
<%= submit_tag "Login", {:class => "btn btn-info btn-large pull-right"} %>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
<div class="header">
|
||||
<h2>Login</h2>
|
||||
<p>Fill out the form below to login to your control panel.</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<%= hidden_field_tag :url, @url%>
|
||||
<%= label_tag "Email Address" %>
|
||||
<%= text_field_tag :email, params[:email], {:class => "input input-block-level"} %>
|
||||
<%= label_tag :password, nil %>
|
||||
<%= password_field_tag :password, nil, {:class => "input input-block-level"}%>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= link_to "Forgot Password", forgot_password_path, {:class => "btn btn-danger btn-large"} %>
|
||||
<%= submit_tag "Login", {:class => "btn btn-info btn-large pull-right"} %>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Need help logging in?</h1>
|
||||
<p>
|
||||
A password reset was requested for your user account.<br>
|
||||
<br>
|
||||
|
||||
To reset your MetaCorp password, simply click on the
|
||||
following link and follow the instructions:<br>
|
||||
<br>
|
||||
|
||||
<%= link_to "Click here to reset your password", @url %><br>
|
||||
<br>
|
||||
|
||||
If you don't want to change your password, you can ignore this email.
|
||||
</p>
|
||||
<p>Thanks, and have a great day!</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
Need help logging in?
|
||||
==========================================================
|
||||
|
||||
A password reset was requested for your user account.
|
||||
|
||||
To reset your MetaCorp password, simply copy the
|
||||
following link and follow the instructions:
|
||||
|
||||
<%= @url %>
|
||||
|
||||
If you don't want to change your password, you can ignore this email.
|
||||
|
||||
Thanks, and have a great day!
|
||||
@@ -1,30 +0,0 @@
|
||||
<div class="row-fluid">
|
||||
<h2 align="center">MetaCorp</h2>
|
||||
<h3 align="center">A GoatGroup Company</h3>
|
||||
<div class="span12">
|
||||
<div class="row-fluid">
|
||||
<div class="span4 offset4">
|
||||
<div class="signup">
|
||||
<%= form_tag "forgot_password", :class=> "signup-wrapper" do %>
|
||||
<div class="header">
|
||||
|
||||
<h2>Forgot Password</h2>
|
||||
<p>Fill out the form below to reset your email.</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<%= label_tag "Email Address" %>
|
||||
<%= text_field_tag :email, params[:email], {:class => "input input-block-level"} %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= submit_tag "Send Forgot Password Email", {:class => "btn btn-warning btn-small"} %>
|
||||
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,7 +34,12 @@ Railsgoat::Application.configure do
|
||||
|
||||
# Expands the lines which load the assets
|
||||
config.assets.debug = true
|
||||
|
||||
|
||||
# ActionMailer settings for email support
|
||||
config.action_mailer.delivery_method = :smtp
|
||||
config.action_mailer.smtp_settings = { :address => "localhost", :port => 1025 }
|
||||
config.action_mailer.default_url_options = { :host => "localhost:3000" }
|
||||
|
||||
config.middleware.insert_before(
|
||||
Rack::Lock, Rack::LiveReload,
|
||||
:min_delay => 500,
|
||||
|
||||
+5
-3
@@ -3,10 +3,12 @@ Railsgoat::Application.routes.draw do
|
||||
get "login" => "sessions#new"
|
||||
get "signup" => "users#new"
|
||||
get "logout" => "sessions#destroy"
|
||||
match "forgot_password" => "users#forgot_password"
|
||||
match "forgot_password" => "password_resets#forgot_password"
|
||||
get "password_resets" => "password_resets#confirm_token"
|
||||
post "password_resets" => "password_resets#reset_password"
|
||||
|
||||
|
||||
resources :sessions do
|
||||
|
||||
end
|
||||
|
||||
resources :users do
|
||||
@@ -83,4 +85,4 @@ Railsgoat::Application.routes.draw do
|
||||
|
||||
root :to => "sessions#new"
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
require 'spec_helper'
|
||||
@@ -0,0 +1,15 @@
|
||||
require 'spec_helper'
|
||||
|
||||
# Specs in this file have access to a helper object that includes
|
||||
# the PasswordResetsHelper. For example:
|
||||
#
|
||||
# describe PasswordResetsHelper do
|
||||
# describe "string concat" do
|
||||
# it "concats two strings with spaces" do
|
||||
# expect(helper.concat_strings("this","that")).to eq("this that")
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
describe PasswordResetsHelper do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
require "spec_helper"
|
||||
@@ -0,0 +1,5 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe "password_resets/new.html.erb" do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
Reference in New Issue
Block a user