68 Commits

Author SHA1 Message Date
Jan Sandbrink 0383ae171c Consider Sec-Fetch-Site header for session auth
This warden strategy is primarily used to allow APIv3 requests
from the browser, which only authenticates using its session cookie.

Since this is susceptible to cross-site-request-forgery, prevention of
CSRF must take place. This was so far only ensured through the usage of
the X-Requested-With header. When a client sent along this header, the
server could know that a CORS-preflight request must have been made and
thus the browser most certainly has validated that the request is valid
according to CORS rules.

However, the header itself is a non-standard header and while some JavaScript
frameworks add it to requests, not all of them do. For us this was practically
visible on the API docs hosted under `/api/docs`.

The solution is to expect the browser to send the Sec-Fetch-Site header with a value
of same-origin. This header can't be set through JavaScript, but only by the browser
and the value "same-origin" ensures that scheme, host and port are the same for requester
and requested endpoint, thus eliminating CSRF concerns. This feature is widely supported by
all major browsers, the last of which was Safari which added support 3 years ago.

We might want to consider dropping the check for X-Requested-With entirely, since it should be
superfluous. For now it was left in place for greater compatibility.
2026-05-12 08:13:14 +02:00
Jan Sandbrink 508c8bbad7 Always respond in Bearer method for WWW-Authenticate header
The intention of this change is to always respond in the metadata-rich
version of the header that indicates things like the required scope and
the URL of the resource_metadata endpoint, which was previously hidden
and only visible if clients used a non-standard HTTP request header.

semantically it's probably the preferable version of the header by now
anyways, because:

* all APIs accept some kind of Bearer token, not all of them accept Basic auth
* Even API tokens can now be passed as Bearer tokens

Practically the Basic auth header also caused unintended browser pop-ups when the frontend
code didn't include the correct request header to avoid the Basic auth offer, this now can't
happen anymore, since the Basic auth version of the header is only returned, if the client actively
tried to authenticate through Basic auth.
2026-02-10 09:02:07 +01:00
Jan Sandbrink 4d305df714 Allow to use API Tokens as Bearer tokens
We generate those tokens with a prefix, so that we
can decide by looking at a token, whether it's an API Token
or a different kind of token, so that we can decide which
code path to choose for validating the token.

The usage of access tokens as Bearer token has the usability advantage,
that you can paste them as plaintext into tools that expect you
to specify the token as a header.

Also the Basic auth approach for our old tokens usually rather caused
issues, such as browsers prompting for credentials in surprising situations.
If we were to deprecate basic authentication one day, this change today could've
been the first step towards that.
2026-02-05 08:07:04 +01:00
Jan Sandbrink 649119b83c Include resource_metadata in WWW-Authenticate header
This is giving clients another chance to discover the metadata URL.
2025-12-10 08:47:35 +01:00
Jan Sandbrink 167304552f Properly escape values in WWW-Authenticate
We even had a spec testing behaviour of a string that needed
escaping, but due to the fact that we constructed the relatively large
header content in the spec, we never noticed that escaping was indeed
missing in that case.
2025-12-03 15:56:21 +01:00
Jan Sandbrink 5c41f592b2 Add scope-hint to WWW-Authenticate header
This one is defined as optional by RFC 6750, which defines
the usage of bearer tokens. It allows a client to know, which
scopes are required to access a given resource when using Bearer tokens.
2025-12-03 15:56:21 +01:00
Jan Sandbrink cfcb7f3874 Properly check whether user is locked
The current implementation opens a small window of
opportunity to authenticate through a previously issued
access token even after a user account was locked.

If access tokens had a longer lifetime, this could become
a large window of opportunity.
2025-06-18 09:04:16 +02:00
Jan Sandbrink 1fafb59c18 Refactor DoorkeeperOAuth strategy
This was initiated by Rubocop complaining
about the method complexity.

Rewriting it with no changes.
Adding additional test cases to specify expected behaviour,
also making edge cases visible that are otherwise covered by
separate feature specs in a different location.
2025-05-26 16:43:09 +02:00
Jan Sandbrink a5986538e6 Only accept access tokens of enabled OAuth applications
We introduced the ability to disable doorkeeper applications in
the past, but apparently we didn't check that an application whose
token we validate is also enabled.

Now we make sure that only tokens of enabled applications are accepted.
2025-05-26 15:31:53 +02:00
Jan Sandbrink 5792f3665b Add authentication_provider field to user factory
This is intended to be a more natural and readable way of manipulating the
identity_url of a user. It also means that if we ever decide to change
the way how the identity_url is built or how providers are attached to
a user, it should be easier to switch the majority of tests relying on it
over to the new schema.
2025-04-25 09:15:17 +02:00
Jan Sandbrink 52061873bc Validate scope of JWTs
So far we are only accepting JWTs for requests to
APIv3 and our scopes are not more fine-grained than that.

However, warden strategies are generally responsible for validating
the scopes of a token (e.g. compare DoorkeeperOAuth) to the scope
of the currently accessed API.
2025-04-17 10:26:10 +02:00
Jan Sandbrink 47bb07194f Check if users are active before authenticating them 2025-03-27 09:38:53 +01:00
Jan Sandbrink 0a401b2045 Fail when user can't be found
Previously we would have "fallen out" of the
JWT strategy, even though the token was clearly intended
to be handled by this strategy. For my configuration this
led to the final error message being generated by the Basic auth
strategy, leading to a wrong error message.

Backported into 15.4 to avoid conflicts.
2025-03-27 09:09:34 +01:00
Jan Sandbrink 11d9f6933d Deindent OIDC authentication request specs
Previously we went into a context for all the things
that could be correct about a request. While this helps
in distinguishing from the bad scenario, it also forces
to indent by one context per thing that can go wrong.
This also means that certain error cases were artifically
nested inside a "good" case, even though there was no
immediate dependency between the one thing being good, but
not the other.

Now the happy path has no extra indentation/context and
all the things that can go wrong, have one context inside
the main context for the happy path. This is hopefully clearer.

Backported into 15.4 to avoid conflicts.
2025-03-27 09:09:29 +01:00
ulferts 57ae2fc7ec turn user-agent expectation version independent
Backported into 15.4 to avoid conflicts.
2025-03-27 09:09:10 +01:00
ulferts db25503dfe adapt gem version present in spec expectation 2025-02-17 10:16:52 +01:00
Jan Sandbrink 17a366f002 Monadize JwtParser
Instead of relying on raised exceptions
for lots of our control flow, we are now
using a failed operation to represent these.

We are using the Failure result for all previously
considered exceptions, because all of them were kind of
expectable error conditions.
2025-01-13 16:22:30 +01:00
Jan Sandbrink 28f0ffafef Extract JWT parsing into separate class
JWT parsing is rather involved, because we need to fetch
proper certificates first. We will need to parse JWTs in
a different context than authorization as well,
so it makes sense to have the parsing centralized.

This also allowed to add specs for this previously
not (unit) tested piece of code.
2025-01-13 16:22:30 +01:00
ulferts b428fc8026 adapt spec expectation 2024-12-19 10:10:28 +01:00
ulferts d8ae1a88b9 adapt spec expectation to bumped json version 2024-12-04 08:36:54 +01:00
ulferts 1381cb0c22 adapt spec expectation to bumped json version 2024-11-22 08:48:03 +01:00
ulferts 0bf92d0dbd adapt user agent expectations in specs 2024-11-21 13:55:45 +01:00
Aaron Contreras 8577af8a97 Bump json-jwt 2024-10-28 10:48:47 -05:00
Pavel Balashou e0c5dd3ef6 Update OIDC configuration UI. 2024-10-21 13:03:46 +02:00
Oliver Günther 4a3dfcc74e Add comma to authenticate header 2024-09-25 12:05:55 +02:00
Ivan Kuchin 4911b8a149 remove years from copyrights (except for COPYRIGHT file) 2024-07-31 15:02:49 +02:00
Pavel Balashou d264f9ab13 [#55643] Cache request for jwt signature keys.
https://community.openproject.org/work_packages/55643

- Configure `JSON::JWK::Set::Fetcher` to use `Rails.cache` for caching
- Hande not found kid case
2024-07-24 18:25:27 +02:00
Pavel Balashou f611ba3bcb [#55643] Extend API authentication to accept JWT issued by OpenID provider to other client.
https://community.openproject.org/work_packages/55643

- Add new warden authentication stategy to handle jwt issued by configured OIDC.
- Modify exisiting doorkeeper_oauth stategy to ignore jwts.
- Fill in WWW-Autheticate header with auth failure information.
- Make keycloak docker dev setup use postgres as a database.
2024-07-23 10:42:04 +02:00
Christophe Bliard a885fef2bd Conform to RSpecRails/HaveHttpStatus cop
With a hack to get `have_http_status` to work with `Rack::MockResponse`.
2024-06-24 17:50:57 +02:00
ulferts 3b2121f733 Revert "Merge remote-tracking branch 'origin/release/13.4' into dev"
This reverts commit 40b2bbeb09, reversing
changes made to b4c6cb17cc.
2024-03-21 11:31:17 +01:00
Ivan Kuchin 7787e457a3 Revert "Merge branch 'dev' into release/13.4"
This reverts commit a901541269, reversing
changes made to e573ca00b7.
2024-03-20 20:19:08 +01:00
Ivan Kuchin 9e4934cd0a change quotes using rubocop --only Style/StringLiterals,Style/QuotedSymbols -a 2024-03-20 18:05:22 +01:00
Christophe Bliard c795874f7f Update copyright year for 2024
command used: `rg -l 'Copyright \(C\) 2012-202\d the OpenProject' | xargs -n 100 sed -i -r 's/Copyright \(C\) 2012-202. the OpenProject/Copyright (C) 2012-2024 the OpenProject/'`
2024-01-02 16:23:54 +01:00
Christophe Bliard 4c2a9d0aa8 Enable RSpec zero monkey patching mode
The plan for RSpec 4.0 is to disable monkey patching.

See https://github.com/rspec/rspec-core/blob/main/features/configuration/zero_monkey_patching_mode.feature for details.
2023-05-31 19:22:29 +02:00
Christophe Bliard aa23106c11 lint: autocorrect RSpec/FactoryBot/ConsistentParenthesesStyle
command is

    rubocop -A --only RSpec/FactoryBot/ConsistentParenthesesStyle modules spec
2023-03-07 15:04:32 +01:00
Christophe Bliard 85b3258a29 Autocorrect with some rubocop cops
RSpec/Rails/InferredSpecType and Style/RedundantConstantBase

rubocop --autocorrect-all --only RSpec/Rails/InferredSpecType,Style/RedundantConstantBase spec modules/*/spec
2023-01-13 14:28:59 +01:00
Christophe Bliard 21a696ef9b Update copyright information for 2023 2022-12-30 15:51:26 +01:00
Christophe Bliard 48a4f1b6ad lint with rubocop --autocorrect (safe cops only) 2022-06-02 10:40:10 +02:00
Eric Schubert 3e07975584 [#41480] respond with 401 on invalid bearer tokens
- https://community.openproject.org/work_packages/41480
- amend strategy for doorkeeper to react on all bearer tokens
- added ouath request spec for valid, invalid and revoked token
2022-04-08 14:58:03 +02:00
Christophe Bliard bc8d423ec2 update copyright information for 2022 2022-03-01 17:05:59 +01:00
Oliver Günther f08bea3467 Remove FactoryBot.* prefix where applicable 2022-01-25 08:19:06 +01:00
Oliver Günther ccfa29c728 Move license and copyright docs to root, fix names and references 2021-09-02 21:50:46 +02:00
ulferts 1bdd2ab9ae safe automatic fixes by rubocop (#8994) 2021-02-11 16:02:18 +01:00
ulferts 6140f4c7e9 update copyright to 2021 (#8925)
Updates the copyright to 2021 for all files that have a copyright. Files in our source code without the copyright header still do not receive one automatically. Additionally, backlisted files are also excluded.

Previously the copyright of chiliproject which references redmine stated a copyright of redmine up to and including 2017 which is not true for the code we have in here. Because of that I changed that to 2013
2021-01-13 17:47:45 +01:00
Oliver Günther 38ecb6b28c [32486] Use error response for unauthenticated instead of warden
Instead of warden responding with 401 "unauthorized", use our own
error response that correctly sets the `WWWW-Authenticat` header.

We tripped into the default 401 error that does not output any headers
if we're not returning any users.

This was caused by another issue: The `session` object may be
present, even though no session id exists. Checking `session&.id`
instead always yields the anonymous user.

This will ensure consumers of APIV3 to always get a JSON / HAL response
as well.

https://community.openproject.com/wp/32486
2020-03-25 08:39:17 +01:00
Henriette Dinger bd7f4e4814 Update copyright notice 2020-01-15 11:31:26 +01:00
Oliver Günther 2fc4416601 Store User.current in current thread 2019-07-11 10:34:13 +01:00
Jens Ulferts 02cdabed65 prevent access to user api for locked admins 2019-01-14 11:26:21 +01:00
Oliver Günther 059770f533 FactoryGirl => FactoryBot
Removes the deprecation
2018-05-07 22:38:20 +02:00
Oliver Günther 6ef4211e77 Bump copyright to 2018 (#6171)
[ci skip]
2018-02-12 08:51:12 +01:00