diff --git a/.gitignore b/.gitignore
index 01fc4f3..b0a4f11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
*~
/.gradle/
/.idea/
+/*/.idea/
/.micronaut/
/build/
+AuthGenHash/bin
+setenv.sh
+/UnityAuth/bin/
diff --git a/AuthGenHash/.sdkmanrc b/AuthGenHash/.sdkmanrc
new file mode 100644
index 0000000..fcebd7d
--- /dev/null
+++ b/AuthGenHash/.sdkmanrc
@@ -0,0 +1,3 @@
+# Enable auto-env through the sdkman_auto_env config
+# Add key=value pairs of SDKs to use below
+java=21.0.4-tem
diff --git a/AuthGenHash/build.gradle b/AuthGenHash/build.gradle
index 502357c..b4033b5 100644
--- a/AuthGenHash/build.gradle
+++ b/AuthGenHash/build.gradle
@@ -1,6 +1,8 @@
plugins {
- id("com.github.johnrengelman.shadow") version "8.1.1"
- id("io.micronaut.application") version "4.2.1"
+ id("com.gradleup.shadow") version "${shadowVersion}"
+ id("io.micronaut.application") version "${micronautPluginVersion}"
+ id("io.micronaut.test-resources") version "${micronautPluginVersion}"
+ id("io.micronaut.aot") version "${micronautPluginVersion}"
}
version = "0.1"
@@ -27,8 +29,8 @@ application {
mainClass.set("io.unityfoundation.auth.AuthGenHashCommand")
}
java {
- sourceCompatibility = JavaVersion.toVersion("17")
- targetCompatibility = JavaVersion.toVersion("17")
+ sourceCompatibility = JavaVersion.toVersion("21")
+ targetCompatibility = JavaVersion.toVersion("21")
}
diff --git a/AuthGenHash/gradle.properties b/AuthGenHash/gradle.properties
index 56a2e88..dbcdb13 100644
--- a/AuthGenHash/gradle.properties
+++ b/AuthGenHash/gradle.properties
@@ -1 +1,6 @@
-micronautVersion=4.2.4
+# Java
+javaVersion=21
+# Micronaut
+micronautVersion=4.8.2
+micronautPluginVersion=4.5.3
+shadowVersion=8.3.6
diff --git a/AuthGenHash/gradle/wrapper/gradle-wrapper.jar b/AuthGenHash/gradle/wrapper/gradle-wrapper.jar
index 7f93135..9bbc975 100644
Binary files a/AuthGenHash/gradle/wrapper/gradle-wrapper.jar and b/AuthGenHash/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/AuthGenHash/gradle/wrapper/gradle-wrapper.properties b/AuthGenHash/gradle/wrapper/gradle-wrapper.properties
index 3fa8f86..37f853b 100644
--- a/AuthGenHash/gradle/wrapper/gradle-wrapper.properties
+++ b/AuthGenHash/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/AuthGenHash/gradlew b/AuthGenHash/gradlew
index 1aa94a4..faf9300 100755
--- a/AuthGenHash/gradlew
+++ b/AuthGenHash/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -203,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
diff --git a/AuthGenHash/gradlew.bat b/AuthGenHash/gradlew.bat
index 6689b85..9b42019 100644
--- a/AuthGenHash/gradlew.bat
+++ b/AuthGenHash/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/AuthGenHash/settings.gradle b/AuthGenHash/settings.gradle
index ab73e66..0ff502e 100644
--- a/AuthGenHash/settings.gradle
+++ b/AuthGenHash/settings.gradle
@@ -1 +1 @@
-rootProject.name="AuthGenHash"
\ No newline at end of file
+rootProject.name="AuthGenHash"
diff --git a/DockerfileFrontend-dev b/DockerfileFrontend-dev
new file mode 100644
index 0000000..c54c554
--- /dev/null
+++ b/DockerfileFrontend-dev
@@ -0,0 +1,10 @@
+FROM node:24
+
+COPY frontend frontend
+WORKDIR frontend
+RUN npm install
+
+EXPOSE 3000
+
+# Start the app in development mode
+ENTRYPOINT ["npm", "run", "dev"]
diff --git a/FrontendDockerfile b/DockerfileFrontend-prod
similarity index 70%
rename from FrontendDockerfile
rename to DockerfileFrontend-prod
index 345f873..a12c03b 100644
--- a/FrontendDockerfile
+++ b/DockerfileFrontend-prod
@@ -1,5 +1,5 @@
# Build the frontend and serve with nginx
-FROM node:18
+FROM node:24 AS builder
COPY frontend frontend
WORKDIR frontend
@@ -7,5 +7,5 @@ RUN npm install && npm run build
FROM nginx:1.24.0-alpine
-COPY --from=0 /frontend/build /usr/share/nginx/html
+COPY --from=builder /frontend/build /usr/share/nginx/html
COPY nginx-default.conf /etc/nginx/conf.d/default.conf
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6015454
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+compose_api:
+ docker network create unity-network > /dev/null 2>&1 || true
+ docker compose -f ./docker-compose.local.yml up unity-auth-db unity-auth-api
+
+compose_ui:
+ docker network create unity-network > /dev/null 2>&1 || true
+ docker compose -f ./docker-compose.local.yml up unity-auth-db unity-auth-ui
+
+compose_all:
+ docker network create unity-network > /dev/null 2>&1 || true
+ docker compose -f ./docker-compose.local.yml up
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e541346
--- /dev/null
+++ b/README.md
@@ -0,0 +1,202 @@
+# UnityAuth
+
+UnityAuth is a comprehensive authentication and authorization service built with modern
+microservices architecture. It provides JWT-based authentication, user management, and
+a web-based administration interface.
+
+## QuickStart
+
+### Local Environment
+From the project root, copy `setenv.sh.example` into `setenv.sh` and update the correct
+environment variable values.
+* If used together with Libre311 project
+(https://github.com/UnityFoundation-io/Libre311.git), `LIBRE311_UI_BASE_URL` must be updated
+to base URL of Libre311 UI.
+* If use a local database, also update the `DATASOURCES_DEFAULT_*` environment variables
+ for the corresponding database.
+
+Run the UnityAuth API with:
+```shell
+source setenv.sh
+cd UnityAuth
+./gradlew run
+```
+
+Run the UnityAuth UI in another terminal windows:
+```shell
+source setenv.sh
+cd frontend
+npm install
+npm run dev
+```
+
+### Docker Environment
+To launch the auth service, you can use the docker compose from the project root:
+
+```sh
+docker compose -f docker-compose.local.yml up
+```
+
+This will start containers for the UnityAuth API, UI and database server with service
+names `unity-auth-api`, `unity-auth-ui`, and `unity-auth-db`, respectively.
+
+- **UnityAuth API** on http://localhost:9090 (inside Docker http://unity-auth-api:9090)
+- **UnityAuth UI** on http://localhost:3001 (inside Docker http://unity-auth-ui:3000)
+- **MySQL Database** is open on port `13306` in `localhost` (within Docker is port `3306`
+ with host name `unity-auth-db`)
+
+#### Hosts File Updates
+
+When using Docker environment, add these to your `/etc/hosts` file
+for consistent internal-external service name resolution:
+
+```txt
+127.0.0.1 unity-auth-api
+127.0.0.1 unity-auth-ui
+```
+
+You can log in with these accounts.
+**Password for all the following accounts is `test`**
+
+- **Unity Administrator** `unity_admin@example.com`
+- **Tenant Administrator** `tenant_admin@example.com`
+- **Libre311 Administrator** `libre311_admin@example.com`
+- **Libre311 Request Manager** `libre311_request_manager@example.com`
+- **Libre311 Jurisdiction Administrator** `libre311_jurisdiction_admin@example.com`
+- **Libre311 Jurisdiction Request Manager** `libre311_jurisdiction_request_manager@example.com`
+- **STL Sub-tenant Administrator** `stl_subtenant_admin@example.com`
+
+## Project Structure
+
+This repository contains three main subprojects:
+
+### 1. UnityAuth (Main Service)
+
+**Location:** `/UnityAuth/`
+**Technology:** Java 21 + Micronaut Framework
+
+The core authentication service that provides:
+
+- JWT token generation and validation
+- User authentication and authorization
+- RESTful API endpoints for authentication operations
+- Database integration with MySQL
+- JWK (JSON Web Key) management for token signing
+- Flyway database migrations
+
+**Key Features:**
+
+- Micronaut-based microservice architecture
+- JWT security with configurable key rotation
+- BCrypt password hashing
+- Database connection pooling with HikariCP
+- Reactive programming support with Reactor
+
+### 2. AuthGenHash (Utility Tool)
+
+**Location:** `/AuthGenHash/`
+**Technology:** Java 17 + Micronaut + PicoCLI
+
+A command-line utility for generating secure password hashes compatible with the UnityAuth service.
+
+**Purpose:**
+
+- Generate BCrypt password hashes for administrative users
+- Secure password handling (interactive mode prevents history logging)
+- Standalone tool for initial system setup and user management
+
+### 3. Frontend (Web Administration Interface)
+
+**Location:** `/frontend/`
+**Technology:** SvelteKit + TypeScript + Tailwind CSS
+
+A modern web application providing administrative interface for the UnityAuth service.
+
+**Features:**
+
+- User authentication and session management
+- User administration and management
+- Tenant management capabilities
+- Settings configuration
+- Responsive design with Tailwind CSS
+- TypeScript for type safety
+- Comprehensive testing with Playwright and Vitest
+
+**Key Technologies:**
+
+- SvelteKit for the web framework
+- TypeScript for type safety
+- Tailwind CSS for styling
+- Playwright for end-to-end testing
+- Vitest for unit testing
+- ESLint and Prettier for code quality
+
+## Architecture Overview
+
+The system follows a microservices architecture:
+
+1. **Database Layer:** MySQL database for persistent storage
+2. **API Layer:** UnityAuth service provides REST APIs
+3. **Frontend Layer:** SvelteKit web application
+4. **Utility Layer:** AuthGenHash for administrative tasks
+
+## Client Integration
+
+To integrate with the UnityAuth service, add this configuration to your client application's `application.yaml`:
+
+```yaml
+security:
+ enabled: true
+ token:
+ enabled: true
+ jwt:
+ enabled: true
+ signatures:
+ jwks:
+ unity:
+ url: ${AUTH_JWKS:`http://localhost:8081/keys`}
+```
+
+## Security Configuration
+
+The service uses JSON Web Keys (JWK) for token signing. To generate primary and secondary keys:
+
+1. Visit
+2. Generate JSON Web Keys
+3. Set environment variables:
+ - `JWK_PRIMARY`: Primary signing key
+ - `JWK_SECONDARY`: Secondary signing key for rotation
+
+## Development Environment
+
+### Prerequisites
+
+- Java 17 or higher
+- Node.js 18 or higher
+- Docker and Docker Compose
+- MySQL 8.0 (if running locally)
+
+### Individual Service Development
+
+#### UnityAuth Service
+
+```bash
+cd UnityAuth
+./gradlew run
+```
+
+#### Frontend Development
+
+```bash
+cd frontend
+npm install
+npm run dev
+```
+
+#### AuthGenHash Utility
+
+```bash
+cd AuthGenHash
+./gradlew shadowJar
+java -jar build/libs/AuthGenHash-0.1-all.jar -p
+```
diff --git a/UnityAuth/.dockerignore b/UnityAuth/.dockerignore
new file mode 100644
index 0000000..4a4327e
--- /dev/null
+++ b/UnityAuth/.dockerignore
@@ -0,0 +1,10 @@
+gradle/caches
+
+# Exclude gradle build caches but not wrapper
+.gradle/
+.DS_Store
+
+build/
+
+docker-compose.*
+DockerfileAPI
diff --git a/UnityAuth/.sdkmanrc b/UnityAuth/.sdkmanrc
new file mode 100644
index 0000000..fcebd7d
--- /dev/null
+++ b/UnityAuth/.sdkmanrc
@@ -0,0 +1,3 @@
+# Enable auto-env through the sdkman_auto_env config
+# Add key=value pairs of SDKs to use below
+java=21.0.4-tem
diff --git a/UnityAuth/DockerfileAPI b/UnityAuth/DockerfileAPI
new file mode 100644
index 0000000..e6526bb
--- /dev/null
+++ b/UnityAuth/DockerfileAPI
@@ -0,0 +1,34 @@
+# Stage 1: Build with Gradle
+FROM gradle:jdk21-jammy AS builder
+WORKDIR /workspace
+
+# 1. Copy Gradle wrapper first (rarely changes)
+COPY gradle/ gradle/
+COPY gradlew gradlew.bat ./
+
+# 2. Copy Gradle config files
+COPY gradle.properties settings.gradle ./
+
+# 3. Download Gradle
+RUN ./gradlew --version --no-daemon
+
+COPY --chown=gradle:gradle . .
+
+# Run the builder w/ the secret
+RUN ./gradlew buildLayers --no-daemon
+
+# Stage 2: Create the final image
+FROM eclipse-temurin:21-jre-jammy
+
+WORKDIR /home/app
+
+COPY --from=builder /workspace/build/docker/main/layers/libs /home/app/libs
+COPY --from=builder /workspace/build/docker/main/layers/app /home/app/
+COPY --from=builder /workspace/build/docker/main/layers/resources /home/app/resources
+
+RUN useradd -u 8877 unity
+# Change to non-root privilege
+USER unity
+
+EXPOSE 8080
+ENTRYPOINT ["java", "-jar", "/home/app/application.jar"]
diff --git a/UnityAuth/README.md b/UnityAuth/README.md
index abe22ea..12ed3a8 100644
--- a/UnityAuth/README.md
+++ b/UnityAuth/README.md
@@ -13,11 +13,11 @@ Insert this code to the client application.yaml file
signatures:
jwks:
unity:
- url: ${AUTH_JWKS:`http://localhost:8080/keys`}
+ url: ${AUTH_JWKS:`http://localhost:8081/keys`}
```
AUTH_JWKS points to this service:
-## How to create primary and seconday key
+## How to create primary and secondary key
Go to the https://mkjwk.org/. Create the JSON Web Keys and define JWK_PRIMARY and JWK_SECONDARY environment variables with generated JSON Web Key (JWK).
diff --git a/UnityAuth/build.gradle b/UnityAuth/build.gradle
index 27522d4..3612865 100644
--- a/UnityAuth/build.gradle
+++ b/UnityAuth/build.gradle
@@ -1,8 +1,8 @@
plugins {
- id("com.github.johnrengelman.shadow") version "8.1.1"
- id("io.micronaut.application") version "4.2.1"
- id("io.micronaut.test-resources") version "4.2.1"
- id("io.micronaut.aot") version "4.2.1"
+ id("com.gradleup.shadow") version "${shadowVersion}"
+ id("io.micronaut.application") version "${micronautPluginVersion}"
+ id("io.micronaut.test-resources") version "${micronautPluginVersion}"
+ id("io.micronaut.aot") version "${micronautPluginVersion}"
}
version = "0.1"
@@ -31,7 +31,8 @@ dependencies {
runtimeOnly("org.flywaydb:flyway-mysql")
runtimeOnly("org.yaml:snakeyaml")
testImplementation("io.micronaut:micronaut-http-client")
- aotPlugins platform("io.micronaut.platform:micronaut-platform:4.2.3")
+
+ aotPlugins platform("io.micronaut.platform:micronaut-platform:${micronautPluginVersion}")
aotPlugins("io.micronaut.security:micronaut-security-aot")
String databaseSelection = System.getenv("UNITYAUTH_DATABASE_DEPENDENCY")
@@ -46,8 +47,8 @@ application {
mainClass.set("io.unityfoundation.Application")
}
java {
- sourceCompatibility = JavaVersion.toVersion("17")
- targetCompatibility = JavaVersion.toVersion("17")
+ sourceCompatibility = JavaVersion.toVersion("21")
+ targetCompatibility = JavaVersion.toVersion("21")
}
graalvmNative.toolchainDetection = false
diff --git a/UnityAuth/docker-compose.api.yml b/UnityAuth/docker-compose.api.yml
new file mode 100644
index 0000000..e98d5e3
--- /dev/null
+++ b/UnityAuth/docker-compose.api.yml
@@ -0,0 +1,31 @@
+services:
+ unity-auth-db:
+ container_name: unity-auth-db
+ networks:
+ - unity-network
+ extends:
+ file: docker-compose.db.yml
+ service: unity-auth-db
+
+ unity-auth-api:
+ container_name: unity-auth-api
+ build:
+ dockerfile: DockerfileAPI
+ context: .
+ depends_on:
+ unity-auth-db:
+ condition: service_healthy
+ restart: unless-stopped
+ networks:
+ - unity-network
+ environment:
+ MICRONAUT_ENVIRONMENTS: docker
+ ports:
+ - "9090:9090"
+
+networks:
+ default:
+ name: unity-network
+ external: true
+ unity-network:
+ external: true
diff --git a/UnityAuth/docker-compose.db.yml b/UnityAuth/docker-compose.db.yml
new file mode 100644
index 0000000..7507e5a
--- /dev/null
+++ b/UnityAuth/docker-compose.db.yml
@@ -0,0 +1,29 @@
+services:
+ unity-auth-db:
+ container_name: unity-auth-db
+ image: mysql:8.0
+ # NOTE: use of "mysql_native_password" is not recommended: https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password
+ # (this is just an example, not intended to be a production configuration)
+ command: --default-authentication-plugin=mysql_native_password
+ restart: unless-stopped
+ networks:
+ - unity-network
+ environment:
+ MYSQL_ROOT_PASSWORD: test
+ MYSQL_DATABASE: test
+ ports:
+ - "13306:3306"
+ healthcheck:
+ test:
+ ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-ptest"]
+ timeout: 20s
+ retries: 10
+ interval: 10s
+ start_period: 30s
+
+networks:
+ default:
+ name: unity-network
+ external: true
+ unity-network:
+ external: true
diff --git a/UnityAuth/docker-compose.local.yml b/UnityAuth/docker-compose.local.yml
deleted file mode 100644
index 285fc86..0000000
--- a/UnityAuth/docker-compose.local.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-# Use root/example as user/password credentials
-version: '3.1'
-
-services:
- unity-auth-db:
- image: mysql
- # NOTE: use of "mysql_native_password" is not recommended: https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password
- # (this is just an example, not intended to be a production configuration)
- command: --default-authentication-plugin=mysql_native_password
- restart: always
- environment:
- MYSQL_ROOT_PASSWORD: test
- MYSQL_DATABASE: test
- ports:
- - "13306:3306"
\ No newline at end of file
diff --git a/UnityAuth/gradle.properties b/UnityAuth/gradle.properties
index b6c7fb6..dbcdb13 100644
--- a/UnityAuth/gradle.properties
+++ b/UnityAuth/gradle.properties
@@ -1 +1,6 @@
-micronautVersion=4.2.3
+# Java
+javaVersion=21
+# Micronaut
+micronautVersion=4.8.2
+micronautPluginVersion=4.5.3
+shadowVersion=8.3.6
diff --git a/UnityAuth/gradle/wrapper/gradle-wrapper.jar b/UnityAuth/gradle/wrapper/gradle-wrapper.jar
index 7f93135..9bbc975 100644
Binary files a/UnityAuth/gradle/wrapper/gradle-wrapper.jar and b/UnityAuth/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/UnityAuth/gradle/wrapper/gradle-wrapper.properties b/UnityAuth/gradle/wrapper/gradle-wrapper.properties
index 3fa8f86..37f853b 100644
--- a/UnityAuth/gradle/wrapper/gradle-wrapper.properties
+++ b/UnityAuth/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/UnityAuth/gradlew b/UnityAuth/gradlew
index 1aa94a4..faf9300 100755
--- a/UnityAuth/gradlew
+++ b/UnityAuth/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -203,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
diff --git a/UnityAuth/gradlew.bat b/UnityAuth/gradlew.bat
index 93e3f59..9b42019 100644
--- a/UnityAuth/gradlew.bat
+++ b/UnityAuth/gradlew.bat
@@ -1,92 +1,94 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/UnityAuth/settings.gradle b/UnityAuth/settings.gradle
index 50d302a..77d1cd3 100644
--- a/UnityAuth/settings.gradle
+++ b/UnityAuth/settings.gradle
@@ -1,2 +1 @@
rootProject.name = "unity-auth"
-
diff --git a/UnityAuth/src/main/java/io/unityfoundation/auth/UnityAuthenticationProvider.java b/UnityAuth/src/main/java/io/unityfoundation/auth/UnityAuthenticationProvider.java
index 04b8791..0d97a79 100644
--- a/UnityAuth/src/main/java/io/unityfoundation/auth/UnityAuthenticationProvider.java
+++ b/UnityAuth/src/main/java/io/unityfoundation/auth/UnityAuthenticationProvider.java
@@ -2,13 +2,13 @@
import static io.micronaut.security.authentication.AuthenticationFailureReason.CREDENTIALS_DO_NOT_MATCH;
+import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.HttpRequest;
-import io.micronaut.security.authentication.AuthenticationException;
import io.micronaut.security.authentication.AuthenticationFailed;
-import io.micronaut.security.authentication.AuthenticationProvider;
import io.micronaut.security.authentication.AuthenticationRequest;
import io.micronaut.security.authentication.AuthenticationResponse;
+import io.micronaut.security.authentication.provider.ReactiveAuthenticationProvider;
import io.unityfoundation.auth.entities.User;
import io.unityfoundation.auth.entities.UserRepo;
import jakarta.inject.Singleton;
@@ -20,7 +20,7 @@
import java.util.Objects;
@Singleton
-public class UnityAuthenticationProvider implements AuthenticationProvider> {
+public class UnityAuthenticationProvider implements ReactiveAuthenticationProvider,Object,Object> {
private final UserRepo userRepo;
private final PasswordEncoder passwordEncoder;
@@ -31,34 +31,6 @@ public UnityAuthenticationProvider(UserRepo userRepo,
this.passwordEncoder = passwordEncoder;
}
- /**
- * Authenticates the user with the given authentication request.
- *
- * @param httpRequest The HTTP request associated with the authentication.
- * @param authenticationRequest The authentication request containing user credentials.
- * @return A Publisher emitting an AuthenticationResponse upon successful authentication, or throwing
- * an AuthenticationException if authentication fails.
- */
- @Override
- public Publisher authenticate(@Nullable HttpRequest> httpRequest,
- AuthenticationRequest, ?> authenticationRequest) {
- return Mono.fromCallable(() -> findUser(authenticationRequest))
- .subscribeOn(Schedulers.boundedElastic())
- .flatMap(user -> {
- AuthenticationFailed authenticationFailed = validate(user, authenticationRequest);
- if (authenticationFailed != null) {
- return Mono.error(new AuthenticationException(authenticationFailed));
- } else {
- return Mono.just(AuthenticationResponse.success(
- (String) authenticationRequest.getIdentity(),
- Map.of(
- "first_name", Objects.toString(user.getFirstName(), ""),
- "last_name", Objects.toString(user.getLastName(), "")
- )
- ));
- }
- });
- }
private AuthenticationFailed validate(User user,
AuthenticationRequest, ?> authenticationRequest) {
@@ -78,5 +50,31 @@ private User findUser(AuthenticationRequest, ?> authRequest) {
return userRepo.findUserForAuthentication(username.toString()).orElse(null);
}
+ @Override
+ public @NonNull Publisher authenticate(@Nullable HttpRequest> requestContext,
+ @NonNull AuthenticationRequest