81 Commits

Author SHA1 Message Date
ansv7779 5144f81fed Fix impersonating non-developer with OIDC session
/ build (push) Successful in 1m53s
When a developer tried to impersonate a user (principal) that had an active OIDC session, it triggered an edge case. The edge case found the existing session from the non-developer which lead to the JWT generation trying to populate the OIDC claim "auth_time". The authentication time is looked up from the `FactorGrantedAuthority`'s in the custom principals authorities. Since there was no such authority it failed.

When a developer impersonates a user such an authority is now added so that the claim can be populated if necessary.
2026-06-04 22:31:44 +02:00
ansv7779 4100de5492 Upgrade to Spring Boot 4.0 (#18)
/ build (push) Successful in 57s
The new ["modular design"](https://spring.io/blog/2025/10/28/modularizing-spring-boot/) required a few changes in the starter Maven dependencies. It also caused some minor Java import changes. The main problem that arose was that the spring-boot-web-server dependency got scoped to "runtime" in Maven. This broke the embedded Docker build since it was excluded from dependency lists. Therefore, it had to be manually added back in the correct "provided" scope.

spring-boot-starter-web, JTE, and Testcontainers had new artifact names. Jackson had to be added as an explicit dependency (for testing only) since it's no longer included by default in Spring Boot.

## Spring Boot OAuth 2.0 Authorization Server
There were some internal changes that broke the "custom" developer authorization. The OAuth2AuthorizationEndpointFilter got split into two separate ones (for MFA purposes), and the split off one is executed much much earlier in the chain. Therefore, the old method of changing the HTTP method of the request to trick the regular filter from the custom one no longer works. Luckily an unrelated change had added POST support to the OAuth2AuthorizationEndpointFilter which meant we could stop changing the HTTP method and change the form to submit everything as form fields instead of query parameters. A lot of mechanical changes in the tests were required for this.

MFA support also meant that OIDC ID tokens require the authenticated principal to have a FactorGrantedAuthority which was added to the Shibboleth authentication.

Lastly the default for clients changed to require PKCE, this was turned off in the tests to match production (not required for clients with credentials).

Reviewed-by: Stefan Nenzén <nenzen@dsv.su.se>
Reviewed-on: #18
2026-05-22 20:22:13 +02:00
ansv7779 8fd97f4bde Fix usages of deprecated APIs
/ build (push) Successful in 1m47s
2026-05-20 00:46:37 +02:00
ansv7779 5175464144 Fix contrast issue
/ build (push) Successful in 1m51s
2026-05-18 20:50:10 +02:00
ansv7779 bc4dbaf5f7 Database index for looking up authorizations by any attribute
/ build (push) Successful in 1m13s
Instead of being forced to use a table scan it now uses the available indexes for direct access to the correct rows.

Fixes #15

Old `ANALYZE` output
```
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: v2_oauth2_authorization
         type: ALL
possible_keys: I_authorization_code_token,I_authorization_access_token
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 7473
       r_rows: 11669.00
     filtered: 100.00
   r_filtered: 0.00
        Extra: Using where
```
and after indexes were added
```
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: v2_oauth2_authorization
         type: index_merge
possible_keys: I_authorization_code_token,I_authorization_access_token,I_authorization_device_code_token,I_authorization_state,I_authorization_user_code_token,I_authorization_refresh_token,I_authorization_id_token
          key: I_authorization_state,I_authorization_code_token,I_authorization_device_code_token,I_authorization_user_code_token,I_authorization_access_token,I_authorization_refresh_token,I_authorization_id_token
      key_len: 3075,3075,3075,3075,3075,3075,3075
          ref: NULL
         rows: 7
       r_rows: 0.00
     filtered: 100.00
   r_filtered: 100.00
        Extra: Using sort_union(I_authorization_state,I_authorization_code_token,I_authorization_device_code_token,I_authorization_user_code_token,I_authorization_access_token,I_authorization_refresh_token,I_authorization_id_token); Using where
```
2026-02-23 14:04:41 +01:00
ansv7779 1aa1532ce7 Automatically publish container images on tag push (#17)
/ build (push) Successful in 2m10s
Publish container to package registry / docker-build-test-publish (push) Successful in 5m18s
When tags matching the pattern 'v*' are pushed a new image is built and published. It is tagged with the number, and the "latest" rolling tag is updated.

Reviewed-by: Stefan Nenzén <nenzen@dsv.su.se>
Reviewed-on: #17
v2
2026-02-23 10:53:05 +01:00
ansv7779 d177664137 Upgrade to Spring Boot 3.5.11
/ build (push) Successful in 1m39s
2026-02-20 09:39:20 +01:00
ansv7779 e20d7e7dd4 Enable public clients to exchange codes for access tokens (#14)
/ build (push) Successful in 2m7s
Public clients are intended to be supported with PKCE as a requirement. However, since exchanging the authorization code for a token is a cross-origin POST request it will be blocked due to lack of a CORS policy.

This change introduces a CORS policy for just the token exchange endpoint where POST is allowed.

Reviewed-on: #14
Reviewed-by: Stefan Nenzén <nenzen@dsv.su.se>
2026-02-20 09:15:54 +01:00
ansv7779 a74f354830 Speed up client and authorization lookup with database indexes (#12)
/ build (push) Successful in 2m26s
During a normal OIDC login workflow (authentication/consent, code exchange, and user info lookup), that results in SQL queries filtering on columns that are now indexed. Before it used to table scan which was extremely slow.

Reviewed-by: Stefan Nenzén <nenzen@dsv.su.se>
Reviewed-on: #12
2026-02-18 15:32:29 +01:00
ansv7779 fb3ad6f8ab Include entitlements in UserInfo and ID token (#8)
/ build (push) Successful in 1m31s
Primary reason for this inclusion is for Nextcloud social login.
The login function uses the OIDC UserInfo endpoint to gather profile
data (name/email) as well as a way to assign group memberships in
Nextcloud which are based on some attribute in the UserInfo response.
We want to use entitlements as a way to assign groups in Nextcloud and
therefore the entitlements must be included in the UserInfo endpoint.
If they are included in the UserInfo endpoint then it makes sense to
also include them in the ID token.
v1
2025-05-12 14:44:58 +02:00
ansv7779 e6e5c8570e Fix encoding issues of Shibboleth attributes (#7)
/ build (push) Successful in 1m49s
There is some encoding error with the injection of Shibboleth attributes somewhere between the Apache SAML plugin -> AJP -> Tomcat. Tomcat treats the data as ISO-8859-1 while it actually is UTF-8.
2025-05-12 10:44:47 +02:00
ansv7779 bd9227d4f1 Allow clients to authenticate using form post (#6)
/ build (push) Successful in 1m48s
Nextcloud OAuth 2 login sends credentials as form parameters instead of using HTTP Basic.
2025-05-08 15:59:19 +02:00
ansv7779 1d469c7346 Autofocus the custom principal field during developer authorization flow
/ build (push) Successful in 2m13s
Simple change but very convenient.
2025-04-29 20:10:21 +02:00
ansv7779 20cd09737d Include your own entitlements during custom authorization flow
/ build (push) Successful in 2m35s
2025-04-28 16:27:40 +02:00
ansv7779 360119ad6a Generate a client secret when a public client goes private
/ build (push) Successful in 2m11s
This can also be used as a way to get a new client secret for a private client by switching to public and back.
2025-04-25 10:56:27 +02:00
ansv7779 18945e22bf Support for user consent (#4)
/ build (push) Successful in 1m45s
All clients will now require user consent.

Users with developer access can configure their clients to not require consent.
2025-04-25 10:21:16 +02:00
ansv7779 8307bc4906 Verify public clients are not issued refresh tokens
/ build (push) Successful in 1m56s
2025-04-15 14:42:12 +02:00
ansv7779 3822f1229c Change the OAuth 2 / OIDC endpoint URLs.
A decision was made to not deploy as a drop-in replacement but rather migrate applications to the new authorzitanion server.
This means it is no longer necessary to maintain backwards-compatible URLs and can instead use more "standard" URLs.
Not super-critical since they should be discovered via metadata but still nice that the URLs map closer to what the endpoint is called in the various specifications.
2025-04-15 14:32:56 +02:00
ansv7779 09f2fe9430 Change the default JTE templates to be pre-compiled and switch to development mode only in the "dev" profile.
This is done so that the default artifact produced my `mvnw package` works out of the box without explicitly changing to pre-compiled templates.
2025-04-15 13:50:40 +02:00
ansv7779 14f7ca66cb Utilize X-Forwarded-* headers in embedded Docker container
/ build (push) Successful in 1m58s
2025-04-08 22:48:57 +02:00
ansv7779 1a2a84f674 Immediately show authorization request errors before showing the custom authorization form
/ build (push) Successful in 1m54s
2025-04-02 00:37:42 +02:00
ansv7779 857d59d391 Better error handling, especially during developer authorization 2025-04-02 00:16:52 +02:00
ansv7779 c421125eb4 Fix Shibboleth/Tomcat providing a principal with a blank name in the unauthenticated case
/ build (push) Successful in 1m52s
2025-04-01 20:11:08 +02:00
ansv7779 71862afb55 Introduce a training run in the Docker build to speed it up
/ build (push) Successful in 1m34s
See https://openjdk.org/jeps/483
2025-03-28 15:51:24 +01:00
ansv7779 c9559ca930 Edit clients
/ build (push) Successful in 2m2s
2025-03-28 13:27:06 +01:00
ansv7779 a4f99f1b29 WAR file is never executed but rather deployed to an application server 2025-03-28 12:49:13 +01:00
ansv7779 9a6e21a396 Persist tokens between restarts
/ build (push) Successful in 1m30s
Utilize Java serialization to turn the entire OAuth2Authorization to a binary blob and store that in the database. Could not find a better way to do it given the types involved (like Map<String, Object> properties). Sure, Java serialization can fail on arbitrary objects but hopefully since OAuth2Authorization implements java.io.Serializable any properties put in are serializable as well.
2025-03-28 11:58:35 +01:00
ansv7779 f0947c5ff8 Remove accidental port mapping
/ build (push) Successful in 1m30s
2025-03-28 11:39:46 +01:00
ansv7779 0bb0cff7ca Build on push
/ build (push) Successful in 1m28s
2025-03-27 15:16:33 +01:00
ansv7779 2c6716865b Allow setting custom entitlements 2025-03-27 15:03:45 +01:00
ansv7779 7fd46e88fe Handle client redirect URI being null 2025-03-27 00:34:27 +01:00
ansv7779 9e8962c909 Migrate data from old authorization server
The new tables are prefixed with v2_ to allow simultaneous deployments
2025-03-26 18:53:13 +01:00
ansv7779 87d6bd594c Provide an embedded Docker container for local development (#1)
Allow developers to add this as a service to their Docker Compose file to enable local OAuth 2.0 flows.

See the following example:
```
services:
  oauth2:
    build: https://gitea.dsv.su.se/DMC/oauth2-authorization-server.git
    restart: unless-stopped
    ports:
      - "<host_port>:8080"
    environment:
      CLIENT_ID=awesome-app
      CLIENT_SECRET=p4ssw0rd
      CLIENT_REDIRECT_URI=http://localhost/oauth2/callback
```

Reviewed-on: #1
2025-03-26 18:51:20 +01:00
ansv7779 411bba57b2 Better description about the ways to verify tokens to let developer decide based on characteristics 2025-03-25 19:47:16 +01:00
ansv7779 464031bd17 Fix HTTP header name 2025-03-25 19:33:39 +01:00
ansv7779 bb8c0a2e60 General OAuth 2.0 documentation 2025-03-25 15:28:44 +01:00
ansv7779 becbcec39f Upgrade Spring Boot version 2025-03-25 12:59:02 +01:00
ansv7779 245585c3d8 Add development instructions 2025-03-25 12:57:42 +01:00
ansv7779 fbca82d17e Lower required Java version 2025-03-25 12:57:31 +01:00
ansv7779 a9f8f5bd53 Fix +x flag on mvnw 2025-03-25 12:44:32 +01:00
ansv7779 cefb4af44d Include end user's entitlements (public information) in the access token 2025-03-24 23:05:27 +01:00
ansv7779 0d78322828 Move UserInfo endpoint for compatibility with old authorization server 2025-03-24 00:15:12 +01:00
ansv7779 54afb20c4d Allow a persistent RSA key pair to be used for signing
Persistent as in it survives application restarts.
2025-03-22 17:47:32 +01:00
ansv7779 95ee6e77d7 Add and remove additional client owners 2025-03-22 16:45:35 +01:00
ansv7779 8578984e6e Support resource servers using token introspection 2025-03-22 15:35:24 +01:00
ansv7779 ef56e5c4b5 Fix public client code flow 2025-03-22 13:31:26 +01:00
ansv7779 90218e988b Improved navigation by adding a breadcrumb 2025-03-22 12:22:27 +01:00
ansv7779 71e82e0020 Display currently registered clients 2025-03-22 12:21:46 +01:00
ansv7779 68660f96a4 Register new clients
Error controller must handle all HTTP methods, not just GET. For example if getting an error on submitting a form.

All the test that previously excluded DataSourceConfiguration can no longer do so because of the ClientAdminController that requires a ClientManagementService whose implementation relies on a DataSource.
2025-03-22 11:55:49 +01:00
ansv7779 0f5a79f7b9 Fully populate all attributes as the fake user during development 2025-03-21 19:21:56 +01:00