Skip to content

Commit f8eba0c

Browse files
bhumi1102OughtPutsp8AmandaPerinoRidhwana
authored
[RF-DOCS] Document Rails 8 Authentication generator feature [ci-skip] (rails#53802)
Co-authored-by: Harriet Oughton <[email protected]> Co-authored-by: Petrik de Heus <[email protected]> Co-authored-by: Amanda Perino <[email protected]> Co-authored-by: Ridhwana <[email protected]> Co-authored-by: Ahmad hamza <[email protected]> Co-authored-by: Malik Parvez <[email protected]> Co-authored-by: Yousaf Khan <[email protected]> Co-authored-by: Karl Lingiah <[email protected]> Co-authored-by: Dalvin Josias Sejour <[email protected]> Co-authored-by: Venkat-RK <[email protected]>
1 parent e982267 commit f8eba0c

File tree

1 file changed

+206
-5
lines changed

1 file changed

+206
-5
lines changed

guides/source/security.md

Lines changed: 206 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
Securing Rails Applications
44
===========================
55

6-
This manual describes common security problems in web applications and how to avoid them with Rails.
6+
This guide describes common security problems in web applications and how to avoid them with Rails.
77

88
After reading this guide, you will know:
99

10+
* How to use the built-in authentication generator.
1011
* All countermeasures _that are highlighted_.
1112
* The concept of sessions in Rails, what to put in there and popular attack methods.
1213
* How just visiting a site can be a security problem (with CSRF).
@@ -29,6 +30,210 @@ The threats against web applications include user account hijacking, bypass of a
2930

3031
In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs, and make updating and security checks a habit (check the [Additional Resources](#additional-resources) chapter). It is done manually because that's how you find the nasty logical security problems.
3132

33+
Authentication
34+
--------------
35+
36+
Authentication is often one of the first features implemented in a web
37+
application. It serves as the foundation for securing user data and is part of
38+
most modern web applications.
39+
40+
Starting with version 8.0, Rails comes with a default authentication generator,
41+
which provides a solid starting point for securing your application by only
42+
allowing access to verified users.
43+
44+
The authentication generator adds all of the relevant models, controllers,
45+
views, routes, and migrations needed for basic authentication and password reset
46+
functionality.
47+
48+
To use this feature in your application, you can run `rails generate
49+
authentication`. Here are all of the files the generator modifies and new files
50+
it adds:
51+
52+
```bash
53+
$ rails generate authentication
54+
invoke erb
55+
create app/views/passwords/new.html.erb
56+
create app/views/passwords/edit.html.erb
57+
create app/views/sessions/new.html.erb
58+
create app/models/session.rb
59+
create app/models/user.rb
60+
create app/models/current.rb
61+
create app/controllers/sessions_controller.rb
62+
create app/controllers/concerns/authentication.rb
63+
create app/controllers/passwords_controller.rb
64+
create app/mailers/passwords_mailer.rb
65+
create app/views/passwords_mailer/reset.html.erb
66+
create app/views/passwords_mailer/reset.text.erb
67+
create test/mailers/previews/passwords_mailer_preview.rb
68+
gsub app/controllers/application_controller.rb
69+
route resources :passwords, param: :token
70+
route resource :session
71+
gsub Gemfile
72+
bundle install --quiet
73+
generate migration CreateUsers email_address:string!:uniq password_digest:string! --force
74+
rails generate migration CreateUsers email_address:string!:uniq password_digest:string! --force
75+
invoke active_record
76+
create db/migrate/20241010215312_create_users.rb
77+
generate migration CreateSessions user:references ip_address:string user_agent:string --force
78+
rails generate migration CreateSessions user:references ip_address:string user_agent:string --force
79+
invoke active_record
80+
create db/migrate/20241010215314_create_sessions.rb
81+
```
82+
83+
As shown above, the authentication generator modifies the `Gemfile` to add the
84+
[bcrypt](https://github.com/bcrypt-ruby/bcrypt-ruby/) gem. The generator uses
85+
the `bcrypt` gem to create a hash of the password, which is then stored in the
86+
database (instead of the plain-text password). As this process is not
87+
reversible, there's no way to go from the hash back to the password. The hashing
88+
algorithm is deterministic though, so the stored password is able to be compared
89+
with the hash of the user-inputted password during authentication.
90+
91+
The generator adds two migration files for creating `user` and `session` tables.
92+
Next step is to run the migrations:
93+
94+
```bash
95+
$ bin/rails db:migrate
96+
```
97+
98+
Then, if you visit `/session/new` in your browser (you will see this route has
99+
been added in `routes.rb`), you'll see a form that accepts an email and a
100+
password with "sign in" button. This form routes to the `SessionsController`
101+
which was added by the generator. If you provide an email/password for a user
102+
that exists in the database, you will be able to successfully authenticate with
103+
those credentials and login to the application.
104+
105+
NOTE: After running the Authentication generator, you do need to implement your
106+
own *sign up flow* and add the necessary views, routes, and controller actions.
107+
There is no code generated that creates new `user` records and allows users to
108+
"sign up" in the first place. This is something you'll need to wire up based on
109+
the requirements of your application.
110+
111+
Here is a list of modified files:
112+
113+
```bash
114+
On branch main
115+
Changes not staged for commit:
116+
(use "git add <file>..." to update what will be committed)
117+
(use "git restore <file>..." to discard changes in working directory)
118+
modified: Gemfile
119+
modified: Gemfile.lock
120+
modified: app/controllers/application_controller.rb
121+
modified: config/routes.rb
122+
123+
Untracked files:
124+
(use "git add <file>..." to include in what will be committed)
125+
app/controllers/concerns/authentication.rb
126+
app/controllers/passwords_controller.rb
127+
app/controllers/sessions_controller.rb
128+
app/mailers/passwords_mailer.rb
129+
app/models/current.rb
130+
app/models/session.rb
131+
app/models/user.rb
132+
app/views/passwords/
133+
app/views/passwords_mailer/
134+
app/views/sessions/
135+
db/migrate/
136+
db/schema.rb
137+
test/mailers/previews/
138+
```
139+
140+
### Reset Password
141+
142+
The authentication generator also adds reset password functionality. You can see
143+
a "forgot password?" link on the "sign in" page. Clicking that link navigates to
144+
the `/passwords/new` path and routes to the passwords controller. The `new`
145+
method of the `PasswordsController` class runs through the flow for sending a
146+
password reset email.
147+
148+
The mailers for *reset password* are also set up by the generator at
149+
`app/mailers/password_mailer.rb` and render the following email to send to the
150+
user:
151+
152+
```html+erb
153+
# app/views/passwords_mailer/reset.html.erb
154+
<p>
155+
You can reset your password within the next 15 minutes on
156+
<%= link_to "this password reset page", edit_password_url(@user.password_reset_token) %>.
157+
</p>
158+
```
159+
160+
### Implementation Details
161+
162+
This section covers some of the implementation details around the authentication
163+
flow added by the authentication generator: The `has_secure_password` method,
164+
the `authenticate_by` method, and the `Authentication` concern.
165+
166+
#### `has_secure_password`
167+
168+
The
169+
[`has_secure_password`](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password)
170+
method is added to the `user` model and takes care of storing a hashed password
171+
using the `bcrypt` algorithm:
172+
173+
```ruby
174+
class User < ApplicationRecord
175+
has_secure_password
176+
has_many :sessions, dependent: :destroy
177+
178+
normalizes :email_address, with: -> e { e.strip.downcase }
179+
end
180+
```
181+
182+
#### `authenticate_by`
183+
184+
The
185+
[`authenticate_by`](https://api.rubyonrails.org/classes/ActiveRecord/SecurePassword/ClassMethods.html)
186+
method is used in the `SessionsController` while creating a new session to
187+
validate that the credentials provided by the user match the credentials stored
188+
in the database (e.g. password) for that user:
189+
190+
```ruby
191+
class SessionsController < ApplicationController
192+
def create
193+
if user = User.authenticate_by(params.permit(:email_address, :password))
194+
start_new_session_for user
195+
redirect_to after_authentication_url
196+
else
197+
redirect_to new_session_url, alert: "Try another email address or password."
198+
end
199+
end
200+
201+
# ...
202+
end
203+
```
204+
205+
If the credentials are valid, a new `Session` is created for that user.
206+
207+
#### Session Management
208+
209+
The core functionality around session management is implemented in the
210+
`Authentication` controller concern, which is included by the
211+
`ApplicationController` in your application. You can explore details of the
212+
[authentication
213+
concern](https://github.com/rails/rails/blob/main/railties/lib/rails/generators/rails/authentication/templates/app/controllers/concerns/authentication.rb.tt)
214+
in the source code.
215+
216+
One method to note in the `Authentication` concern is `authenticated?`, a helper
217+
method available in view templates. You can use this method to conditionally
218+
display links/buttons depending on whether a user is currently authenticated.
219+
For example:
220+
221+
```html+erb
222+
<% if authenticated? %>
223+
<%= button_to "Sign Out", session_path, method: :delete %></li>
224+
<% else %>
225+
<%= link_to "Sign In", new_session_path %>
226+
<% end %>
227+
```
228+
229+
TIP: You can find all of the details for the Authentication generator in the
230+
Rails source code. You are encouraged to explore the implementation details and
231+
not treat authentication as a black box.
232+
233+
With the authentication generator configured as above, your application is ready
234+
for a more secure user authentication and password recovery process in just a
235+
few steps.
236+
32237
Sessions
33238
--------
34239

@@ -439,10 +644,6 @@ Another (additional) approach is to store the file names in the database and nam
439644
User Management
440645
---------------
441646

442-
NOTE: _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._
443-
444-
There are a number of authentication plug-ins for Rails available. Good ones, such as the popular [devise](https://github.com/heartcombo/devise) and [authlogic](https://github.com/binarylogic/authlogic), store only cryptographically hashed passwords, not plain-text passwords. Since Rails 3.1 you can also use the built-in [`has_secure_password`](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password) method which supports secure password hashing, confirmation, and recovery mechanisms.
445-
446647
### Brute-Forcing Accounts
447648

448649
NOTE: _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with rate-limiting, more generic error messages and possibly require to enter a CAPTCHA._

0 commit comments

Comments
 (0)