Commit Graph

3283 Commits

Author SHA1 Message Date
Jean Boussier
9ebfb149ed Better handle basic authentication without a password
https://github.com/rails/rails/pull/43209 immediately rejects
the request if no password is passed, but there are legitimate
uses for accepting authentication without a password.
2022-03-04 14:40:04 +01:00
Brad Trick
880a1bedb9 Allow skip_forgery_protection if no protection set
Calling `skip_forgery_protection` without first calling
`protect_from_forgery`--either manually or through default
settings--raises an `ArgumentError` because `verify_authenticity_token`
has not been defined as a callback.

Since Rails 7.0 adds `skip_forgery_protection` to the
`Rails::WelcomeController` (PR #42864), this behavior means that setting
`default_protect_from_forgery` to false and visiting the Rails Welcome
page (`/`) raises an error.

This behavior also created an issue for `ActionMailbox` that was
previously fixed in the Mailbox controller by running
`skip_forgery_protection` only if `default_protect_from_forgery` was
true (PR #35935).

This PR addresses the underlying issue by setting the `raise` option for
`skip_before_action` to default to false inside
`skip_forgery_protection`.

The fix is implemented in `request_forgery_protection.rb`. The change to
`ActionMailbox`'s `base_controller.rb` removes the now-unnecessary
check of `default_protect_from_forgery`.

The tests added in `request_forgery_protection_test.rb` and
`routing_test.rb` both raise an error when run against the current
codebase and pass with the changes noted above.
2022-02-27 21:58:42 -05:00
Jon Dufresne
c2e756a944 Remove body content from redirect responses
Modern browsers don't render this HTML so it goes unused in practice.
The delivered bytes are therefore a small waste (although very small)
and unnecessary and could be optimized away.

Additionally, the HTML fails validation. Using the W3C v.Nu, we see the
following errors:

    Warning: Consider adding a lang attribute to the html start tag to declare the language of this document.

    Error: Start tag seen without seeing a doctype first. Expected <!DOCTYPE html>.

    Error: Element head is missing a required instance of child element title.

These errors may surface in site-wide compliance tests (either internal
tests or external contractual tests). Avoid the false positives by
removing the HTML.

While these warnings and errors could be resolved, it would be simpler
on future maintenance to remove the body altogether (especially as it
isn't rendered by the browser). As the same string is copied around a
few places, this removes multiple touch points to resolve the current
validation errors as well as new ones.

Many other frameworks and web servers don't include an HTML body on
redirect, so there isn't a reason for Rails to do so. By removing the
custom Rails HTML, there are fewing "fingerprints" that a malicious bot
could use to identify the backend technologies.

Application controllers that wish to add a response body after calling
redirect_to can continue to do so.
2022-02-25 13:31:54 -04:00
Jean Boussier
d32767884d Copy over the IsolatedExecutionState in AC::Live
Fix: https://github.com/rails/rails/issues/44496

It's really unfortunate, but since thread locals were copied
since a decade and we moved most of them into IsolatedExecutionState
we now need to copy it too to keep backward compatibility.

However I think it's one more sign that AC::Live should be
rethought.
2022-02-21 11:40:52 +01:00
John Hawthorn
139ef8a0bc
Merge pull request #44174 from jguecaimburu/add_lowdash_support_to_path_parser_locale_regex
Add support to locales with lowdash in Resolver::PathParser
2022-02-17 08:27:34 -08:00
Petrik
c9cb1aa198 Silence uninitialized instance var warning in tests
Running the Action Pack tests outputs a warning:

    ./actionpack/test/controller/test_case_test.rb:1007: warning: instance variable @counter not initialized

Surrounding the line with silence_warnings cleans up the output.
2022-02-10 16:31:02 +01:00
Jean Boussier
4f12bcd7f1 Remove the deprecated urlsafe_csrf_tokens configuration
Ref: https://github.com/rails/rails/pull/43817

Normally we remove deprecated code much later, but in this case
it's in the way of https://github.com/rails/rails/pull/44283
so I think it would make sense to remove it now.
2022-02-01 10:35:43 +01:00
Juan Guecaimburu
bd0753b396 Add support to locales with lowdash in Resolver::PathParser
In previous versions of Rails, a dynamic regex was built to find templates.
After that, PathParser started to be used to both match and sort templates.
With the dynamic regex, templates with lowdash locales (es_AR) were
found properly. But the PathParser regex does not match locales with this
format, only allowing dash (es-AR) or no dash (es). Templates with lowdash
locales have a wrong virtual path and get filtered.

In this commit the PathParser regex is extended to support the lowdash.
2022-01-14 15:11:58 -03:00
Yutaka Kamei
0b7f37fbed
Initialize ActionController::Parameters with @logging_context
`params` contains `@logging_context` in its instance to notify
unpermitted parameters including the context through Rails
Instrumentation API. However, the logging context disappeared when
`params` is updated with some methods, such as `require`, `slice`,
`merge`, etc, so the subscriber of `unpermitted_parameters` could not
get the information.

This patch tries to initialize `Parameters` with `@logging_context`
where it makes sense to pass the information. The following methods will
be affected with this patch:

* `require`
* `deep_dup`
* `slice`
* `except`
* `extract!`
* `transform_values`
* `transform_keys`
* `deep_transform_keys`
* `select`
* `reject`
* `compact`
* `merge`
* `reverse_merge`
2021-12-16 23:11:49 +09:00
Aaron Patterson
8159996ea0
Dup arrays that get "converted"
We don't want to expose these cache keys to users because users can
mutate the key causing the cache to behave inconsistently.

Fixes: #43681
2021-12-15 14:30:27 -08:00
Rafael Mendonça França
ab754e95d8
Merge pull request #43817 from etiennebarrie/deprecate-non-url-safe-csrf-tokens
Deprecate non-URL-safe CSRF tokens
2021-12-15 01:48:51 +00:00
Alex Ghiculescu
054fa96bac ActionController::TestCase: reset instance variables after each request
`ActionController::TestCase` keeps a `@controller` instance variable, which represents the controller being tested. At the end of each request inside a test, its [params and format](https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/testing.rb) are reset. But any other instance variables set in the test aren't reset. This creates a problem if you do something like this:

```ruby
class UserController
  def show
    @user ||= User.find(params[:id])
    render plain: @user.name
  end
end
```

```ruby

test "gets the user" do
  get :show, params: { id: users(:one).id }
  assert "one", response.body

  get :show, params: { id: users(:two).id }
  assert "two", response.body
end
```

The second assertion will fail, because `@user` won't be re-assigned in the second test (due to `||=`). This example is a bit contrived, but it shows how instance variables persisting between requests can lead to surprising outcomes.

This PR fixes this by clearing all instance variables that were created on the controller while a request was processed.

It explicitly excludes instance variables that were created *before* any requests were run. And it leaves the instance variable around until the *next* request in the test. This means that you can still do this:

```ruby

test "gets the user" do
  @controller.user = users(:one) # assuming `Controller#user` users an ivar internally, you can set the ivar here...

  get :show_current
  assert "one", response.body

  assert_equal users(:one), @controller.user # and you can read the ivar here
end
```
2021-12-09 16:22:54 -06:00
Rafael Mendonça França
7160f46a9e
Merge pull request #43368 from FestaLab/render-hash-syntax
Replaces the hash rocket operator in favor of the newer Ruby syntax on render
2021-12-08 18:13:44 -05:00
Rafael Mendonça França
481343ed91
Merge PR #41769 2021-11-25 19:27:09 +00:00
Rafael Mendonça França
1f4a541421
Remove deprecated support to passing a path to fixture_file_upload relative to fixture_path 2021-11-17 21:51:15 +00:00
Nikita Vasilevsky
2a00c89a7d
Enable Lint/DuplicateMethods rubocop rule 2021-11-15 13:51:28 -05:00
Kasper Timm Hansen
c3758a71af Raise ActionController::Redirecting::UnsafeRedirectError for unsafe redirect_to redirects.
This allows `rescue_from` to be used to add a default fallback route:

```ruby
rescue_from ActionController::Redirecting::UnsafeRedirectError do
  redirect_to root_url
end
```

Co-Authored-By: Chris Oliver <excid3@gmail.com>
2021-11-05 03:23:12 +01:00
danmcge
a2b3e3d523 Add url_from to verify a URL is internal and safe to redirect to
Closes https://github.com/rails/rails/pull/43327

Co-Authored-By: Kasper Timm Hansen <kaspth@gmail.com>
2021-11-05 01:56:37 +01:00
Kasper Timm Hansen
922729eb48 Extract open redirect protection to separate method
Let's us separate what's location generation and what's protection: fewer
arguments, avoids overloading safe, and polluting response_options.

The exception message has been clarified a bit too.
2021-11-04 03:28:02 +01:00
Rafael Mendonça França
20ced4757e
Merge pull request #43444 from sabulikia/support-custom-csrf-strategy
Add support for custom CSRF strategies.
2021-10-14 12:33:52 -04:00
ignacio-chiazzo
4df32bc139 Allow multiline to be passed in routes when using wildcards.
Fixed a bug in action_dispatch where routes with newlines weren't detected when using wildcard segments
2021-10-13 19:14:20 -04:00
Jack McCracken
f40405c138 Add support for custom CSRF strategies. 2021-10-13 14:15:17 -04:00
Daniel Colson
ccb3cb573b
Replace ableist language
The word "Crazy" has long been associated with mental illness. While
there may be other dictionary definitions, it's difficult for some of us
to separate the word from the stigmatization, gaslighting, and bullying
that often comes along with it.

This commit replaces instances of the word with various alternatives. I
find most of these more focused and descriptive than what we had before.
2021-10-05 22:27:09 -04:00
Liuri Loami
d3e5833459 Replaces the "hash rocket" operator in favor of the newer Ruby syntax when rendering on render 2021-10-03 23:33:56 -03:00
Rafael França
badf915283
Merge pull request #42501 from HParker/allow-specifying-numeric-strong_params
Allow permitting numeric params
2021-09-21 01:14:39 -04:00
Rafael França
20db0845cd
Merge pull request #43209 from mpestov/check-basic-auth-credentials
Check basic auth credentials before authenticate
2021-09-20 18:13:14 -04:00
mpestov
22e6cb2576 Check basic auth credentials contains a colon 2021-09-16 00:29:34 +03:00
Christian Sutter
1f4714c3f7 Change default X-XSS-Protection header to '0'
This header has been deprecated and the XSS auditor it triggered
has been removed from all major modern browsers (in favour of
Content Security Policy) that implemented this header to begin with
(Firefox never did).

[OWASP](https://owasp.org/www-project-secure-headers/#x-xss-protection)
suggests setting this header to '0' to disable the default behaviour
on old browsers as it can introduce additional security issues.

Added the new behaviour as a framework default from Rails 7.0.
2021-09-14 14:14:21 +01:00
Anton Rieder
db286625d0
Don't show deprecation warning for equal paths
Before, if a user set `file_fixture_path` to the same path as
`fixture_path`, this would have resulted in a deprecation warning such
as:

"Please modify the call from `fixture_file_upload('rails.jpg')` to
`fixture_file_upload('rails.jpg')"
2021-09-08 11:45:19 +02:00
Jean Boussier
c91c266872 Enable Style/ExplicitBlockArgument cop
This reduce the stack size which is beneficial for
exceptions performance.

See: https://gist.github.com/byroot/cb3bcadcc3701c2518d002fb8d3a4e7a

However the cop is unsafe because it might change the block arity,
so it can run into some false positives.
2021-09-05 17:06:19 +02:00
Haroon Ahmed
f69406b3fe Add a test to catch regressions for render_to_string to not override subsequent render 2021-08-23 20:40:21 +01:00
Xavier Noria
e933dc0b84 Let the Action Pack autoload with Zeitwerk 2021-08-21 20:20:23 +02:00
Xavier Noria
2306a8e645 Setup the once autoloader on bootstrap 2021-08-17 05:23:51 +02:00
Daniel Colson
f35305785d
Introduce Journey::Ast to avoid extra ast walks
This commit introduces a new `Journey::Ast` class that wraps the root
node of an ast. The purpose of this class is to reduce the number of
walks through the ast by taking a single pass through each node and
caching values for later use.

To avoid retaining additional memory, we clear out these ast objects
after eager loading.

Benefits
---

* Performance improvements (see benchmarks below)
* Keeps various ast manipulations together in a single class, rather
  than scattered throughout
* Adding some names to things will hopefully make this code a little
  easier to follow for future readers

Benchmarks
---

We benchmarked loading a real routes file with > 3500 routes.
master was at a9336a67b0 when we ran these. Note that these benchmarks
also include a few small changes that we didn't include in this commit,
but that we will follow up with after this gets merged - these
additional changes do not change the benchmarks significantly.

Time:

```
master      - 0.798 ± 0.024 (500 runs)
this branch - 0.695 ± 0.029 (500 runs)
```

Allocations:

```
master      - 980149 total allocated objects
this branch - 931357 total allocated objects
```

Stackprof:

Seeing `ActionDispatch::Journey::Visitors::Each#visit` more frequently
on the stack is what led us down this path in the first place. These
changes seem to have done the trick.

```
master:
  TOTAL    (pct)     SAMPLES    (pct)     FRAME
    52   (0.5%)          52   (0.5%)     ActionDispatch::Journey::Nodes::Node#symbol?
    58   (0.5%)          45   (0.4%)     ActionDispatch::Journey::Scanner#scan
    45   (0.4%)          45   (0.4%)     ActionDispatch::Journey::Nodes::Cat#type
    43   (0.4%)          43   (0.4%)     ActionDispatch::Journey::Visitors::FunctionalVisitor#terminal
    303  (2.7%)          43   (0.4%)     ActionDispatch::Journey::Visitors::Each#visit
    69   (0.6%)          40   (0.4%)     ActionDispatch::Routing::Mapper::Scope#each

this commit:
  TOTAL    (pct)     SAMPLES    (pct)     FRAME
    82   (0.6%)          42   (0.3%)     ActionDispatch::Journey::Scanner#next_token
    31   (0.2%)          31   (0.2%)     ActionDispatch::Journey::Nodes::Node#symbol?
    30   (0.2%)          30   (0.2%)     ActionDispatch::Journey::Nodes::Node#initialize
```

See also the benchmark script in https://github.com/rails/rails/pull/39935#issuecomment-887791294

Co-authored-by: Eric Milford <ericmilford@gmail.com>
2021-07-29 16:23:11 -04:00
Rafael França
8ee27ff84d
Merge pull request #41822 from benoittgt/better-error-message-InvalidAuthenticityToken
Help identifying why we have an InvalidAuthenticityToken exception
2021-07-28 20:36:38 -04:00
Gannon McGibbon
5e93cff835
Raise error on unpermitted open redirects.
Add `allow_other_host` options to `redirect_to`.
Opt in to this behaviour with `ActionController::Base.raise_on_open_redirects = true`.
2021-07-22 14:03:59 -04:00
Bodacious
39ab10164b
Exclude added flash types from action_methods 2021-07-14 08:35:27 +02:00
Benoit Tigeot
602d568404
Help identifying why we have an InvalidAuthenticityToken exception
We want to be able to more easily identify if it is a
valid_request_origin validation error or a HTTP Origin header mismatch.

Previously we had too look at the logs to know which type of issue it
was.

Related:
  * https://discuss.rubyonrails.org/t/proposal-for-improving-invalidauthenticitytoken-error-when-invalid-same-origin/77509
  * https://github.com/rails/rails/issues/38447

Extract warning_message assignment to a method

Avoid having to know the ProtectionMethods::Exception interface

Properly scope exception test in exception test class

There is no need to match error raised every times

Use clearer test description
2021-07-07 09:52:10 +02:00
Petrik
0409ed57ac Clean up checks to see if DidYouMean is defined
As of Ruby 2.7 DidYouMean is included as a default gem, so there is no
need to check if DidYouMean is defined in the test suite. We still need
to check if the DidYouMean modules are defined in the actual code, as
someone might run Rails with DidYouMean disabled by using the
`--disable-did_you_mean` flag. This is ussually done for performance
reasons.

This commit also includes some of the changes made by Yuki in:
https://github.com/rails/rails/pull/39555
These changes include replacing Jaro with the more accurate
SpellChecker, and using DidYouMean::Correctable for simplere
corrections.

The DidYouMean::SpellChecker does have a treshold for corrections.
If there is not enough similarity it might not return a suggestion.
To stop the tests from failing some test data had to be changed.

For example, `non_existent` does not meet the treshold for `hello`, but
`ello` does:

DidYouMean::SpellChecker.new(dictionary: %w[hello]).correct('non_existent')
=> []
DidYouMean::SpellChecker.new(dictionary: %w[hello]).correct('ello')
=> ["hello"]

The treshold makes sense for spelling errors. But maybe we should add a
different SpellChecker that helps to get a suggestion even if there is
little overlap. For example for when a model only has 2 attributes
(title and body), it's helpful to get a suggestion for `name`

Co-Authored-By: Yuki Nishijima <yk.nishijima@gmail.com>
2021-07-04 13:43:50 +02:00
Dirkjan Bussink
0523532a3c
Always use OpenSSL constants for Digest operations
As also previously discussed in
https://github.com/rails/rails/pull/40770#issuecomment-748347066, this
moves the usage of Digest constants to always use the OpenSSL version of
those Digest implementations.
2021-06-30 13:57:54 +02:00
Guillermo Iguaran
6f1ff6fc65
Merge pull request #42609 from tadas-s/remove-ie6-7-8-specific-hack
Remove IE6-7-8 file download related hack/fix
2021-06-25 16:08:38 -07:00
Tadas Sasnauskas
d08035b0f2 Remove IE6-7-8 file download related hack/fix
IE 6-7-8 has bug when 'Cache-Control: no-cache' head would break file download.
It's been fixed in IE9 (which is also ancient and barely used version).

Some extra details [here][1] and [here][2].

The way this fix is implemented clashes with what's been done in PR #40324. By
adding ':public' key to cache control header set it wipes default headers.

Since IE 6-7-8 are ancient browsers - let's just get rid of this hack.

[1]: https://stackoverflow.com/q/9766639/843067
[2]: https://stackoverflow.com/q/3415370/843067
2021-06-25 19:15:19 +01:00
Jean Boussier
fcc3cd3265 Consider AC::Parameters as Hash in url_for
Ref: https://github.com/rails/rails/pull/42020

It's not uncommon to want to forward request parameters,
as such the `:params` paramter of `url_for` often receive
an AC::Parameters instance.
2021-06-25 18:07:48 +02:00
Rafael Mendonça França
3a98e7da62
Merge pull request #41609 2021-06-23 18:29:49 +00:00
Rafael França
cb52350f38
Merge pull request #40324 from tadas-s/cache-control-no-store
Implement 'no_store' HTTP cache directive
2021-06-23 14:27:58 -04:00
Rafael França
ec6935606e
Merge pull request #42437 from HParker/digest-find-parent-controller-template
Use the lookup_context to find the correct template path
2021-06-23 13:59:09 -04:00
Aaron Patterson
2f012f74cc
Merge pull request #42020 from chaymaeBZ/merge-params-when-it-is-a-hash
Only merge params option if params is a Hash in url_for helper
2021-06-21 13:04:21 -07:00
HParker
5c7a785fce Allow permitting numeric params
When specifying numeric parameters, strong params lets you permit them all using the same permitted params for each.

For example params like,
```ruby
book: {
        authors_attributes: {
          '0': { name: "William Shakespeare", age_of_death: "52" },
          '1': { name: "Unattributed Assistant" },
          '2': "Not a hash",
          'new_record': { name: "Some name" }
        }
      }
```

can be permitted with,
```
permit book: { authors_attributes: [ :name ] }
```

This returns the name keys for each of the numeric keyed params that have a name field,
```ruby
{ "book" => { "authors_attributes" => { "0" => { "name" => "William Shakespeare" }, "1" => { "name" => "Unattributed Assistant" } } } }
```

This is exactly what you want most of the time. Rarely you might need
to specify different keys for particular numeric attributes. This
allows another strong params syntax for those cases where you can
specify the keys allowed for each individual numerically keys attributes
hash.

After this change using the same params above, you can permit the name and age for only the `0` key and only the name for the `1` key,

```ruby
permit book: { authors_attributes: { '1': [ :name ], '0': [ :name, :age_of_death ] } }
```

This returns exactly the parameters that you specify,

```ruby
{ "book" => { "authors_attributes" => { "0" => { "name" => "William Shakespeare", "age_of_death" => "52" }, "1" => { "name" => "Unattributed Assistant" } } } }
```

Sidenote: this allows `permit` to do the equivalent to
```ruby
params.require(:book).permit(authors_attributes: { '1': [:name]})
```

without raising when `book: ... ` is not present.

The simpler syntax should be preferred, but in cases where you need more control, this is a nice option to have.
2021-06-15 15:39:08 -07:00
Tadas Sasnauskas
07da73429a Implement 'no_store' HTTP cache directive method
Summary
=======

Currently there is no way to set "Cache-Control: no-store" header using
built-in cache control methods ("expires_now"/"expires_in"/etc..). One of
the [top StackOverflow][1] answers currently suggests putting it directly
into header set.

Unfortunately, it cannot later be overridden in specific/individual actions by
calling say 'expires_in 5.minutes'. Resulting header in that case is
stays the same, i.e. 'Cache-Control: no-store'.

This:
 1. Adds the 'no_store' method to set "Cache-Control: no-store" header.
 2. Changes cache control "merge and normalize" code so default "no-store"
    directive can be overridden using built in cache control methods mentioned
    above.

What's the use of it
--------------------

Couple examples:

* To [prevent rendering stale content][3] if browser return button is used
('expires_now' does not help).
* To prevent browser disk cache being used. In some situations it's considered
a [privacy/security risk][4].

Other Information
=================

Mozilla developer docs for [Cache-Control][2] header.

[1]: https://stackoverflow.com/questions/10744169/rails-set-no-cache-method-cannot-disable-browser-caching-in-safari-and-opera
[2]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
[3]: https://engineering.mixmax.com/blog/chrome-back-button-cache-no-store/
[4]: https://portswigger.net/kb/issues/00700100_cacheable-https-response
2021-06-12 08:58:14 +01:00
HParker
26259b0660 Use the lookup_context to find the correct template path
This replaces the controller/action method of finding a path with the lookup_context which should always find the same thing as the render method finds.
2021-06-09 15:56:45 -07:00