Skip to content

refactor: use Spring Security's resource server - #175

Merged
uniqueg merged 7 commits into
devfrom
refactor/165-resource-server
Nov 14, 2026
Merged

uniqueg merged 7 commits into
devfrom
refactor/165-resource-server

Conversation

@uniqueg

@uniqueg uniqueg commented Nov 14, 2026 •

Copy link
Copy Markdown
Member

Summary

Replaces the end-of-life Spring Security OAuth (spring-security-oauth2, spring-security-oauth2-autoconfigure, @EnableResourceServer) with the resource server of Spring Security 5.8, still on Spring Boot 2.7 (child 4 of #66).

  • ResourceServerConfiguration declares a SecurityFilterChain with oauth2ResourceServer().opaqueToken(). It is stateless, has no CSRF, and keeps the same public paths: service-info unless TESK_API_SERVICE_INFO_PUBLIC=false, the API description and the Swagger UI.
  • UserInfoTokenIntrospector validates tokens at the user info endpoint, as UserInfoTokenServices did. It builds the same User (ElixirPrincipalExtractor) and the same group authorities (GroupNamesSecurityExtractor).
  • ServiceClientTokenServices (feat(auth): accept tokens of allow-listed clients #154) is now an OpaqueTokenIntrospector. Its checks, messages and logger name are unchanged; the class keeps its name because operators configure its logger by that name.
  • AuthenticatedUser and an OpaqueTokenAuthenticationConverter keep the User as the principal of the request. This matters for TesService's @PreAuthorize rules, which test principal instanceof User.
  • CustomAuthenticationEntryPoint keeps the 401 answers: a JSON body with error/error_description, WWW-Authenticate: Bearer realm="oauth", error=…, error_description=…, and Cache-Control: no-store.
  • security.oauth2.resource.user-info-uri / SECURITY_OAUTH2_RESOURCE_USER_INFO_URI keeps working under the same name. No new key was added. Both Spring Security OAuth artifacts and the spring-security-oauth2 pin are removed; spring-security-oauth2-resource-server takes their place (no Nimbus or JOSE dependencies).
  • Docs: access control (token validation, the 401 answers, allowed token characters, timeouts), configuration, the API status codes, and the upgrade notes.

The existing auth integration tests are the contract and are unchanged: AuthIT, ClaimAuthIT, ServiceClientAuthIT, NoAuthIT, ServiceInfoTokenRequiredIT, SwaggerUi*AuthIT and LegacyUserLabelsIT. A new AuthErrorResponsesIT pins the 401 answers. I captured them on dev first. Four of its cases fail on dev and pass here; they are the deliberate changes below.

Deliberate changes, all listed in docs/upgrading.md:

  • The error_description/message of an invalid token no longer repeats the token. It is now Invalid access token.
  • An access_token parameter in the URL or a form is ignored. The token is read only from the header (RFC 6750).
  • A malformed bearer header (an empty token, or spaces) gets 401 invalid_token without a call to the user info endpoint. Before, it was passed on to the endpoint, and if the endpoint answered, the request was authenticated.
  • A user info answer without sub now gives 401 instead of 500.
  • Calls to the user info endpoint time out after 10 s (connect) and 30 s (read); before, they had no limit. TESK API no longer starts if the user info URL isn't an absolute http(s) URL. Failed calls log only the status or the cause, never the answer or the URL.

Closes #165

Verification

  • ./mvnw clean verify on Java 21 passes locally (last run on 8841552): over 18,400 unit tests and 109 integration tests, including all auth ITs unchanged plus AuthErrorResponsesIT.
  • ./mvnw spotless:check checkstyle:check on Java 8 (the CI Lint setup) reports 0 violations.
  • mkdocs build --strict passes.
  • AuthErrorResponsesIT was run against dev. The no-token cases and the user info request headers matched, which confirms the old answers are kept. The token echo, query-parameter, malformed-header and missing-sub cases failed on dev, which confirms they are the intended changes.
  • CI on 8841552 (after the automated review fixes): all jobs pass (CI passed, Test, Lint, Docs, Smoke test, Scan image, codecov patch 100% and project). The image smoke test (401 without a token, public service-info) runs in CI only.
  • CodeQL: alert #504 (java/spring-disabled-csrf-protection) on ResourceServerConfiguration. It is a false positive: this is a stateless bearer-token API with no session and no cookies. The old @EnableResourceServer also disabled CSRF, just out of CodeQL's sight, and keeping CSRF on would turn the 401 for a POST without a token into 403, which breaks AuthIT. The alert needs dismissing as a false positive (drafted for the maintainer). The alert in the test configuration is fixed: CSRF stays on there.

Declined review findings

  • Rename ServiceClientTokenServices: declined. docs/access-control.md documents its logger name, so renaming it would break operators' logging configuration. The class Javadoc now explains why the name stays.
  • Map user info 5xx/IO errors to a 5xx: declined. The old code answered 401 for every user info failure, and the contract tests expect that.
  • Upgrade note on public endpoints validating a sent token, and on Cache-Control/Pragma headers: declined. Both are already the behaviour on dev: public_serviceInfo_withInvalidToken_isUnauthorized covers the first, and the headers match what I captured on dev.
  • Make the timeouts configurable: declined. Fixed, documented values keep this PR free of configuration changes; they can become settings if a deployment needs it.
  • Replace the hand-written content negotiation of the 401 body: declined. It mirrors the former renderer, and unit tests cover it.
  • Automated review, fixed in 8841552: a blank sub is refused like a missing one; the user info URL must have a host; a client that refuses JSON (q=0) gets the 401 without a body.
  • Automated review: @Value ignores the environment variable: declined. Relaxed binding maps SECURITY_OAUTH2_RESOURCE_USER_INFO_URI to the key, as for TESK_API_SERVICE_INFO_PUBLIC.
  • Automated review: DNS timeout and total deadline for user info calls: declined. The old code had no limits; the docs now say the timeouts are per read and don't cover the host name lookup or the whole answer.
  • Sourcery: token input and 401 details differ from before: declined. These are the deliberate, documented changes (no tokens in URLs, no token echo, 401 instead of 500 without sub), listed in docs/upgrading.md.

Open questions

None.

Overlaps

🤖 Generated with Claude Code

Summary by Sourcery

Migrate TESK API authentication to Spring Security's opaque-token resource server while preserving existing authorization contracts and documenting the resulting token-validation behavior.

Bug Fixes:

  • Reject malformed, URL/form-supplied, missing-subject, and failed user-info tokens consistently with documented 401 responses instead of accepting or producing server errors.
  • Add bounded user-info endpoint requests and prevent startup with invalid endpoint URLs.

Enhancements:

  • Replace the end-of-life Spring Security OAuth resource-server integration with Spring Security's opaque-token resource server while preserving authorization behavior, principals, service-client validation, public paths, and configuration compatibility.
  • Preserve structured OAuth 401 responses, bearer challenges, and security headers without exposing access tokens or sensitive user-info responses.

Build:

  • Replace Spring Security OAuth dependencies with the Spring Security OAuth2 resource-server dependency.

Documentation:

  • Document token validation behavior, 401 responses, endpoint requirements, timeouts, and upgrade-impacting authentication changes.

Tests:

  • Add unit and integration coverage for opaque-token introspection, authentication principals, error responses, malformed tokens, endpoint failures, and timeout behavior while adapting service-client and controller security tests.

uniqueg and others added 4 commits November 14, 2026 00:50
Replace Spring Security OAuth (spring-security-oauth2 and
spring-security-oauth2-autoconfigure, end of life, not on Spring
Security 6) with the resource server of Spring Security 5.8:

- ResourceServerConfiguration declares a SecurityFilterChain with
  oauth2ResourceServer().opaqueToken(), stateless and without CSRF, with
  the same public paths.
- UserInfoTokenIntrospector validates tokens at the user info endpoint
  (security.oauth2.resource.user-info-uri, unchanged), as
  UserInfoTokenServices did, and builds the User and its group
  authorities with ElixirPrincipalExtractor and
  GroupNamesSecurityExtractor.
- ServiceClientTokenServices is an OpaqueTokenIntrospector now, with the
  same checks, messages and logger name.
- AuthenticatedUser carries the User; the authentication of a request
  keeps the User as principal, as the authorisation rules expect.
- CustomAuthenticationEntryPoint writes the same 401 answers: JSON body
  with error and error_description, WWW-Authenticate with realm "oauth".

Deliberate changes, covered by AuthErrorResponsesIT: the description of
an invalid token no longer repeats the token; tokens in an access_token
parameter are ignored; malformed bearer headers are refused without a
call to the user info endpoint; a user info without sub gives 401
instead of 500. The existing auth integration tests pass unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe how tokens are taken and validated with the resource server of
Spring Security, the 401 answers (WWW-Authenticate and body), that
SECURITY_OAUTH2_RESOURCE_USER_INFO_URI keeps its name, and the changes
that clients may notice in the upgrade notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Findings of the pre-push review:

- Time out calls to the user info endpoint (10 s connect, 30 s read),
  so that a hanging endpoint can't hold request threads; a timeout
  refuses the token.
- Refuse to start unless the user info URI is an absolute http(s) URL.
- Log the status of a refused user info call, not its answer, and only
  the exception class for unreadable answers.
- Test AuthenticatedUser on its own, parse the JSON bodies in the entry
  point tests, and test a blank message.
- Javadoc that describes the current behaviour; why
  ServiceClientTokenServices keeps its name (the documented logger).
- Docs: allowed token characters, timeouts, URL check, and the 401
  without a body for requests that accept no JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Accept user info URLs whose host URI doesn't parse (e.g. with "_",
  as in Docker Compose): check for an authority, not a host.
- Log the cause of an unreachable endpoint, not the message with the
  URI, which may hold credentials.
- Describe a 401 without a message as "Unauthorized", not "null".
- Test the timeouts, a slow and a reset endpoint, and that refused
  calls log the status but not the answer.
- Upgrade notes: own bullet for the user info endpoint; no claim about
  the former answer to requests that accept no JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Data structures

Review the authenticated-principal representation and its conversion into request authentication, which preserve User as the principal and avoid retaining the access token.

  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/AuthenticatedUser.java L1-77

API

Review the resource-server filter chain and the authentication entry point together: they define protected and public routes and the externally visible 401 response contract.

  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/CustomAuthenticationEntryPoint.java L9-23, L28-55, L68-139 (+3 small edits)
  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/ResourceServerConfiguration.java L16-27, L68-81, L99-131 (+8 small edits)

Uses of the API

Check that task handling continues to obtain the User principal directly, with a fallback for requests without one.

  • src/main/java/uk/ac/ebi/tsc/tesk/tes/api/TasksApiController.java L14 (removed lines), L153-160

Implementation

Review the user-info introspector's endpoint validation, timeouts, refusal handling, and construction of the authenticated user and authorities.

  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java L1-170

Review service-client token validation as an opaque-token introspector, including its delegation to user-info validation and client-principal construction.

  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/ServiceClientTokenServices.java L57-61, L205-224, L231-238 (+9 small edits)

Check that user and group extraction retain the existing authorization semantics while supplying the resource-server introspector.

  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/ElixirPrincipalExtractor.java L15-22 (+3 small edits)
  • src/main/java/uk/ac/ebi/tsc/tesk/config/security/GroupNamesSecurityExtractor.java L7 (removed lines), L14-19, L29-32

Configuration

Review removal of the legacy Spring Security OAuth dependencies and addition of the Spring Security resource-server dependency.

  • pom.xml L48 (removed lines), L111-114

Documentation

Check the access-control documentation against token extraction, validation, timeout, and 401-response behavior.

  • docs/access-control.md L48-69

Review the API status-code documentation's link to the detailed unauthorized-response contract.

  • docs/api.md L345

Check the configuration documentation for the required user-info endpoint setting and its retained environment-variable name.

  • docs/configuration.md L31

Review upgrade notes for intentional client-visible changes and endpoint requirements.

  • docs/upgrading.md L45-72

Tests

Review integration coverage for unauthenticated requests, malformed or invalid tokens, user-info calls, and the 401 response contract.

  • src/integration-test/java/uk/ac/ebi/tsc/tesk/AuthErrorResponsesIT.java L1-200

Check unit coverage for authenticated-principal behavior and the 401 entry-point response.

  • src/test/java/uk/ac/ebi/tsc/tesk/config/security/AuthenticatedUserTest.java L1-82
  • src/test/java/uk/ac/ebi/tsc/tesk/config/security/CustomAuthenticationEntryPointTest.java L1-156

Review tests for service-client introspection and user-info endpoint validation, failures, logging, and timeouts.

  • src/test/java/uk/ac/ebi/tsc/tesk/config/security/ServiceClientTokenServicesTest.java L157-163, L294-301, L543-559 (+14 small edits)
  • src/test/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospectorTest.java L1-286

Check the controller test's resource-server setup and that CSRF remains enabled in that test configuration.

  • src/test/java/uk/ac/ebi/tsc/tesk/tes/api/TasksApiControllerTest.java L38-45, L66-99

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codecov

codecov Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.82%. Comparing base (2cbab7a) to head (f1f1a44).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #175      +/-   ##
==========================================
+ Coverage   75.81%   76.82%   +1.01%     
==========================================
  Files          71       73       +2     
  Lines        3345     3439      +94     
  Branches      402      412      +10     
==========================================
+ Hits         2536     2642     +106     
+ Misses        651      640      -11     
+ Partials      158      157       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Codecov requires full coverage of the patch:

- Test an OAuth 2.0 error without a description, a user info URL
  without an authority, and an unexpected error while checking a
  service client's token.
- Drop the null check of the introspector's principal (introspectors
  never return null) and log the most specific cause of an unreachable
  endpoint.
- Keep CSRF protection on in TasksApiControllerTest: the resource
  server exempts requests with a bearer token (CodeQL alert).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@uniqueg
uniqueg marked this pull request as ready for review November 14, 2026 00:30
@sourcery-ai

sourcery-ai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Linked issues

Checked at commit f1f1a44

#165 refactor: use Spring Security's resource server · 6 of 7 met

# Requirement Status Notes
1 Replace the legacy resource-server configuration with a SecurityFilterChain using opaque-token introspection at the user info endpoint. ✅ Met ResourceServerConfiguration builds a stateless SecurityFilterChain and wires an OpaqueTokenIntrospector into the resource server.
2 Keep the User principal, group authorities and claim authorisation, service-client JWT checks, and public paths. ✅ Met The extractors still build the User and authorities, service-client tokens are delegated to ServiceClientTokenServices, and the configured public paths remain in the filter chain.
3 Keep behaviour exactly, including token handling and the JSON error responses and WWW-Authenticate headers. 🟡 Partly met The 401 response structure and headers remain, but the change intentionally alters invalid-token descriptions, accepted token inputs, malformed-header handling, and the response for user info without a sub.
4 Keep SECURITY_OAUTH2_RESOURCE_USER_INFO_URI working, without a new key unless the old key remains a fallback. ✅ Met The existing property is still read and documented; no replacement key is introduced.
5 Keep the named auth integration tests unchanged and passing. ✅ Met The named existing auth integration tests are not changed in the diff, and the PR reports that they pass.
6 Remove the legacy OAuth dependencies and pin, and update the access-control and configuration documentation. ✅ Met The old OAuth dependencies and pin are removed; the resource-server dependency and documentation updates are present.
7 Pass the auth integration tests and the smoke test, with no configuration change needed for existing deployments. ✅ Met The PR reports the test and CI smoke-test jobs passed, and retains the existing configuration key.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 6 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/ResourceServerConfiguration.java" line_range="61" />
<code_context>
             @Value("${openapi.taskExecutionService.base-path:/ga4gh/tes/v1}") String baseUrl,
             @Value("${tesk.api.service-info.public:true}") boolean serviceInfoPublic,
-            ObjectProvider<ResourceServerTokenServices> tokenServices) {
+            @Value("${security.oauth2.resource.user-info-uri:}") String userInfoUri) {

         this.errorAttributes = errorAttributes;
</code_context>
<issue_to_address>
**Environment override is ignored**

When a deployment configures a custom provider using the documented `SECURITY_OAUTH2_RESOURCE_USER_INFO_URI` environment variable, `@Value` looks up the dashed property directly rather than binding it as a `@ConfigurationProperties` value, so `SECURITY_OAUTH2_RESOURCE_USER_INFO_URI` is not resolved as `security.oauth2.resource.user-info-uri`; the bundled default then remains active and requests for a deployment's custom provider are refused.

Bind the setting through `@ConfigurationProperties` or explicitly resolve the documented environment-variable name, and add a test that sets it as an environment property.
</issue_to_address>

### Comment 2
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java" line_range="114" />
<code_context>
+            logger.warn("Refused token: the user info has an error");
+            throw new BadOpaqueTokenException(INVALID_TOKEN);
+        }
+        if (userInfo.get("sub") == null) {
+            logger.warn("Refused token: the user info has no sub");
+            throw new BadOpaqueTokenException(INVALID_TOKEN);
</code_context>
<issue_to_address>
**Malformed subjects authenticate**

When the user-info endpoint returns an empty or non-string `sub`, the introspector rejects only a null `sub`; an empty or non-string value passes, and `ElixirPrincipalExtractor` converts it with `toString()` into a user ID. The request is authenticated with an identity that does not satisfy OpenID Connect's subject requirements.

Require `sub` to be a non-empty string before constructing the user.
</issue_to_address>

### Comment 3
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java" line_range="97" />
<code_context>
+        this.userInfoUri = URI.create(userInfoUri.trim());
+        String scheme = this.userInfoUri.getScheme();
+        if (!("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme))
+                || this.userInfoUri.getRawAuthority() == null) {
+            throw new IllegalStateException(
+                    "security.oauth2.resource.user-info-uri (SECURITY_OAUTH2_RESOURCE_USER_INFO_URI)"
</code_context>
<issue_to_address>
**Invalid user-info hosts pass startup**

When the configured user-info URI has an HTTP(S) scheme and a non-null authority but no host, the raw-authority check accepts the URI, so the application starts and user-info calls fail; `userInfo()` then treats valid tokens as invalid, and authenticated requests receive 401 responses instead of a startup configuration error.

Validate that the URI has a host, not merely a non-null raw authority.

Also at `docs/upgrading.md:58`.
</issue_to_address>

### Comment 4
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/CustomAuthenticationEntryPoint.java" line_range="129-130" />
<code_context>
+        }
+        MediaType.sortBySpecificityAndQuality(accepted);
+        for (MediaType mediaType : accepted) {
+            for (HttpMessageConverter<?> converter : this.messageConverters) {
+                if (converter.canWrite(body.getClass(), mediaType)) {
+                    ((HttpMessageConverter<Object>) converter)
+                            .write(body, mediaType, new ServletServerHttpResponse(response));
</code_context>
<issue_to_address>
**Rejected JSON still gets an error body**

When the request's `Accept` header gives JSON quality zero, the media-type loop still considers the JSON entry, and `converter.canWrite` checks compatibility without excluding quality-zero media types, so the entry point writes a JSON error body despite the client's rejection.

Skip media types with quality zero before checking converters.
</issue_to_address>

### Comment 5
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java" line_range="78" />
<code_context>
+     */
+    static RestTemplate restTemplate() {
+        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
+        requestFactory.setConnectTimeout(CONNECT_TIMEOUT_MS);
+        requestFactory.setReadTimeout(READ_TIMEOUT_MS);
+        return new RestTemplate(requestFactory);
</code_context>
<issue_to_address>
**DNS stalls bypass the timeout**

When the configured endpoint hostname's DNS lookup stalls, `SimpleClientHttpRequestFactory`'s connect timeout does not bound a blocking JVM DNS lookup, so `RestTemplate.exchange` can hold request threads past the documented 10-second limit while resolving the user-info host; callers keep waiting instead of receiving a refusal.

Bound DNS resolution or run endpoint calls behind a separately enforced overall deadline.
</issue_to_address>

### Comment 6
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java" line_range="79" />
<code_context>
+    static RestTemplate restTemplate() {
+        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
+        requestFactory.setConnectTimeout(CONNECT_TIMEOUT_MS);
+        requestFactory.setReadTimeout(READ_TIMEOUT_MS);
+        return new RestTemplate(requestFactory);
+    }
</code_context>
<issue_to_address>
**Slow responses exceed the read limit**

When the endpoint sends response data often enough to avoid each individual read timeout but never completes, `setReadTimeout` limits individual blocking reads rather than the total response duration, so `RestTemplate.exchange` keeps the request thread occupied beyond the documented limit.

Enforce a total response deadline in addition to the per-read timeout.

Also at `src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java:80`.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 6 findings to address first, and the resource-server migration now decides which bearer tokens are accepted and which protected API requests proceed; a validation or filter-chain mistake could expose task data or permit protected actions. Reverting stops further impact, but cannot undo data already exposed or actions already performed.

Blocking findings: src/main/java/uk/ac/ebi/tsc/tesk/config/security/ResourceServerConfiguration.java:61, src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java:114, src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java:97, src/main/java/uk/ac/ebi/tsc/tesk/config/security/CustomAuthenticationEntryPoint.java:130, src/main/java/uk/ac/ebi/tsc/tesk/config/security/UserInfoTokenIntrospector.java:78, and 1 more


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Refuse user info answers with a blank sub, require a host in the
user info URL, and send no body when the client refuses JSON
(q=0). Document that the timeouts are per read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New gaps against the linked issues

Keep both upgrade notes: token validation (#165) and ignore_error
(#160).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New gaps against the linked issues

@uniqueg
uniqueg merged commit 73fb752 into dev Nov 14, 2026
25 checks passed
@uniqueg
uniqueg deleted the refactor/165-resource-server branch November 14, 2026 16:14
uniqueg added a commit that referenced this pull request Nov 14, 2026
…lient

Resolves pom.xml: #175 removed spring-security-oauth2 and its
autoconfigure, so the Bouncy Castle exclusion goes with them; the
removed pins stay removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uniqueg added a commit that referenced this pull request Nov 14, 2026
spring-security-jwt left with #175, so there are no older Bouncy
Castle jars left to keep out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uniqueg added a commit that referenced this pull request Nov 14, 2026
Brings in #161, #174, #175, #176, #178, #181, #183 and #184. The
conflict in docs/upgrading.md is resolved by merging both lists under
"To 1.3.0": the upgrade order for filer labels and Java 21 come first,
and the TES 1.1 fields item no longer says that ignore_error: true is
refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uniqueg added a commit that referenced this pull request Nov 14, 2026
Lists the changes merged into dev since the notes were written:
Java 21 (#161), ignore_error (#174), the resource server (#175),
output file logs (#176), the Kubernetes client (#178), Dependabot
labels (#181), the executor job selector (#183) and full test coverage
(#184). Adds a Breaking changes section, as in the 1.2.0 notes, and
sets date-released to the planned tag date, 2026-11-16.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: use Spring Security's resource server

2 participants