EUREKA-72: Investigate options consortia UI bundles
- 1 Spike Overview
- 2 Background
- 3 Problem Statement
- 4 Scope
- 5 Proposed Solutions
- 5.1 Option 1: Custom JavaScript Functions with Login Form Customization
- 5.1.1 Overview
- 5.1.2 Sequence Diagram
- 5.1.3 Implementation Details
- 5.1.4 Pros
- 5.1.5 Cons
- 5.1.6 JavaScript functions example
- 5.1.7 Summary
- 5.2 Option 2: Keycloak Custom Authenticator for All Tenants
- 5.2.1 Overview
- 5.2.2 Sequence Diagram
- 5.2.3 Implementation Details
- 5.2.4 Pros
- 5.2.5 Cons
- 5.2.6 Authenticator implemenation example
- 5.2.7 Keycloak Authentication flow configuration
- 5.2.8 Summary
- 5.1 Option 1: Custom JavaScript Functions with Login Form Customization
- 6 Conclusion
Spike Overview
https://folio-org.atlassian.net/browse/EUREKA-72
Objective: To determine an approach for implementing Automatic Tenant Selection in FOLIO, allowing users to log into their home tenant without being prompted to select it manually, thereby enhancing the user experience across consortia institutions.
Background
FOLIO is a collaborative, open-source library services platform that enables multiple institutions within a consortium to use the same application. Each institution is represented as a separate tenant within FOLIO, and staff users are defined within their institution's tenant context. Users have capabilities assigned to them that define the actions they can perform within their tenant.
Currently, if a user from Institution A (Tenant A) needs to perform actions in Institution B (Tenant B), a shadow user is created in Tenant B with the necessary capabilities. The user must switch affiliations within the FOLIO application to change the tenant context for their session.
Keycloak is used as the Identity and Access Management (IAM) system for FOLIO, with each tenant represented as a separate Realm. Real FOLIO users correspond to Keycloak users with credentials, allowing them to authenticate and log in. Shadow users in FOLIO correspond to Keycloak users without credentials and cannot be used for login operations. Capabilities assigned in FOLIO are reflected as permissions granted to Keycloak users.
The current FOLIO implementation includes:
Single UI Bundle: Users log into a central tenant and switch affiliations as needed.
Manual Tenant Selection: Users select their tenant from a drop-down menu and are directed to the appropriate UI bundle for their tenant, authenticating in the Keycloak Realm associated with their tenant.
The need has arisen for an Automatic Tenant Selection feature where users are not prompted to select their tenant. Instead, the system detects the user's home tenant upon login and directs them accordingly.
Problem Statement
The spike aims to address the challenge of implementing Automatic Tenant Selection in FOLIO. The goal is to enable users to see a unified login screen and, upon authentication, be automatically directed to their home tenant without manual selection. This requires a method to detect the user's home tenant based on the user’s credentials and adjust the authentication flow accordingly within Keycloak and FOLIO.
Scope
In Scope
Investigate methods to automatically detect a user's home tenant during the login process.
Explore configurations or extensions in Keycloak to support automatic tenant selection based on user credentials.
Assess how automatic tenant selection affects authentication flow, session management, and capability assignments in FOLIO.
Ensure the proposed solution aligns with FOLIO's architecture and maintains security and compliance standards.
Out of Scope
Implementation or deployment of the automatic tenant selection feature.
Modifications to existing tenant switching mechanisms or shadow user management.
User interface design changes beyond the login screen.
Proposed Solutions
Two possible options have been identified to implement Automatic Tenant Selection in FOLIO:
Custom JavaScript Functions with Login Form Customization
Keycloak Custom Authenticator for All Tenants
Each option is analyzed in detail below, including high-level sequence diagrams, implementation details, and the pros and cons.
Option 1: Custom JavaScript Functions with Login Form Customization
Overview
This option involves customizing the Keycloak login form using JavaScript to determine the correct tenant (realm) based on the user's input (username). The process includes intercepting the login request, retrieving the user's tenant information by communicating with mod-login-keycloak
, and then redirecting the user to authenticate against the appropriate tenant realm.
Sequence Diagram
The high-level sequence diagram for this option is as follows:
Implementation Details
Customize Keycloak Login Page
JavaScript Injection: Modify the Keycloak login page to include custom JavaScript code that executes when the user submits their credentials.
Intercept Submission: The JavaScript code intercepts the form submission event to prevent the default behavior.
Retrieve User's Tenant
HTTP Request to
mod-login-keycloak
: The JavaScript code sends an HTTP POST request tomod-login-keycloak
, passing the entered username and password.Authentication Check:
mod-login-keycloak
communicates with Keycloak to validate the user's credentials.Tenant Resolution: Upon successful validation,
mod-login-keycloak
determines the user's home tenant.
Redirect to Tenant's Login Page
Construct Tenant URL: The JavaScript code constructs the URL for the tenant's login page based on the tenant information received.
Redirection: The JavaScript function requests the tenant-specific login page. It does not render it for the user but sends the authentication Post request to Keycloak.
Authenticate Against Tenant Realm
Submit Credentials: The user's credentials are submitted to the tenant realm's for authentication.
Validation: Keycloak validates the credentials within the tenant realm.
Authentication Success: Upon successful authentication, the user is redirected to the FOLIO landing page.
Pros
User Experience
Unified Login Screen: Users access a single login screen without the need to select their tenant manually.
Seamless Redirection: Redirection to the tenant realm happens transparently to the user.
Implementation Simplicity
Minimal Backend Changes: The logic is handled primarily on the client side through JavaScript.
No Custom Authenticator Required: Avoids the complexity of developing and maintaining a custom Keycloak authenticator.
Flexibility
Easy Updates: Changes to tenant resolution logic can be applied by updating the JavaScript code.
Cons
Security Concerns
Credential Exposure Risk: User credentials are handled in the browser and sent over HTTP to
mod-login-keycloak
before authentication, increasing the risk of interception.Client-Side Vulnerabilities: JavaScript code can be manipulated or disabled by users or malicious actors.
Man-in-the-Middle Attacks: Increased risk if HTTPS is not strictly enforced.
mod-login-keycloak
has to expose unathorized API that can be used for hacking
Maintenance Overhead
Browser Compatibility: Ensuring the JavaScript functions correctly across all browsers and devices.
Debugging Difficulty: Client-side issues can be harder to trace and resolve.
mod-login-keycloak
extra complexity:mod-login-keycloak
must be improved to handle credentials validation and realm resolution.
Reliance on Client-Side Logic
User Manipulation: Technically savvy users could alter the JavaScript to change the authentication flow.
Accessibility Issues: Users with JavaScript disabled or using assistive technologies may encounter problems.
Complex Error Handling
User Feedback: Providing meaningful error messages is more complex when multiple steps are involved client-side.
JavaScript functions example
function get_realm_link_by_username() {
const username = document.getElementById("username").value;
// Determine which link to return based on the username content
// This is just a stub. The HTTP call to mod-login-keycloak must be done here instead.
if (username.includes("coltest")) {
const link = document.getElementById("social-college");
return link ? link.href : null;
} else if (username.includes("unitest")) {
const link = document.getElementById("social-university");
return link ? link.href : null;
}
// Return null if no matching link is found
return null;
}
async function process_complex_realm_login() {
const href = get_realm_link_by_username();
if (!href) {
console.error("No matching realm link found for username.");
return;
}
try {
// Perform a GET request to the resolved href
const response = await fetch(href);
// Check if the response is OK (status code 200-299)
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// Parse the response as text
const result = await response.text();
// Create a new DOM parser to convert the HTML string to a document object
const parser = new DOMParser();
const doc = parser.parseFromString(result, "text/html");
// Extract the action attribute from the form in the parsed document
const fetchedFormAction = doc.querySelector("#kc-form-login")?.action;
// Check if the action was found and apply it to the current form, then submit
if (fetchedFormAction) {
const currentForm = document.getElementById("kc-form-login");
currentForm.action = fetchedFormAction; // Set the current form's action
currentForm.method = "post"; // Set the current form's method to POST.
// Submit the form programmatically
currentForm.submit();
} else {
console.error("Form action not found in the fetched content.");
}
} catch (error) {
// Log any errors to the console
console.error("Error fetching login link:", error);
}
}
Summary
While this option offers a quick way to implement Automatic Tenant Selection with minimal backend changes, it introduces significant security risks and maintenance challenges due to its reliance on client-side scripting and handling of user credentials in the browser.
Option 2: Keycloak Custom Authenticator for All Tenants
Overview
This option involves developing a custom Keycloak Authenticator (e.g., FolioAuthenticator
) and configuring Keycloak to use this authenticator across all realms configured for consortia and institutional tenants. The custom authenticator handles tenant detection and authentication flow server-side, enhancing security and centralizing the logic.
Sequence Diagram
The high-level sequence diagram for this option is as follows:
Implementation Details
Develop Custom Authenticator (
FolioAuthenticator
)Server-Side Logic: Implement the authenticator using Keycloak's Service Provider Interface (SPI).
Tenant Detection: Incorporate logic to determine the user's home tenant based on the username or other identifiers and configured identity providers.
Encrypted Data Handling: Prepare and handle encrypted custom data containing credentials and timestamp for secure transmission between realms.
Configure Keycloak Realms
Consortia Realm: Apply the
FolioAuthenticator
to the central consortia realm.Institutional Realms: Apply the same authenticator to each institutional tenant realm.
Authentication Flow: Modify the authentication flow in Keycloak to include the custom authenticator.
Authentication Flow
Initial Login Request: User submits credentials to the consortia realm.
Tenant Resolution: The custom authenticator checks if the username exists and retrieves the user's identity provider (tenant realm).
Redirect Handling: If the user's identity provider is found, the authenticator prepares encrypted custom data and redirects the user to the tenant realm's login page.
Fallback Mechanism: If the identity provider is not found, proceed with default authentication in the consortia realm.
Tenant Realm Authentication
Data Decryption: The tenant realm's custom authenticator decrypts the received custom data.
Credential Validation: The tenant realm validates the user's credentials.
Authentication Success: User is authenticated and redirected to the FOLIO landing page.
Pros
Enhanced Security
Server-Side Credential Handling: Credentials are processed within Keycloak servers, reducing exposure.
Encrypted Data Transmission: Sensitive information is encrypted when transmitted between realms.
Reduced Attack Surface: Less reliance on client-side scripting minimizes vulnerabilities.
Centralized Logic
Consistency Across Realms: The custom authenticator standardizes authentication flow for all tenants.
Easier Maintenance: Updates to authentication logic are centralized.
Improved Performance
Streamlined Authentication: Fewer external calls and redirections improve login speed.
Scalable Solution: Better suited for handling a large number of tenants.
User Experience
Seamless Login Flow: Users experience a smooth login process without unnecessary redirects or prompts.
Fallback Authentication: Supports default authentication if tenant detection fails.
Cons
Development Complexity
Custom Authenticator Development: Requires in-depth knowledge of Keycloak's SPI and authentication mechanisms.
Testing and Validation: Extensive testing is needed to ensure reliability across different scenarios.
Maintenance Overhead
Version Compatibility: The custom authenticator must be maintained with Keycloak updates.
Configuration Management: All realms must be correctly configured to use the custom authenticator. This configuration must be made transparently during the Consortia configuration. (mgr-tenants? mod-consortia-keycloak? which one should be responsible for that?)
Deployment Challenges
Rollout Strategy: Deploying changes across multiple realms requires careful planning.
Error Handling Complexity: Properly managing authentication errors across realms can be complex.
Potential Single Point of Failure
Authenticator Dependency: Issues with the custom authenticator could affect authentication for all users.
Authenticator implemenation example
The authenticator implementation example can be foulnd here:
https://github.com/folio-org/folio-keycloak-plugins/tree/feature/ecs-folio-authenticator/ecs-folio-authenticator
Keycloak Authentication flow configuration
TODO:
Summary
This option offers a secure, server-side solution that centralizes authentication logic within Keycloak, enhancing performance and scalability. However, it requires significant development effort and careful maintenance to ensure compatibility with Keycloak updates and realm configurations.
Conclusion
Both options aim to implement Automatic Tenant Selection in FOLIO to enhance the user experience. Here's a comparative analysis:
Aspect | Option 1: Custom JavaScript Functions | Option 2: Keycloak Custom Authenticator |
---|---|---|
Security | Potential vulnerabilities due to client-side credential handling | Enhanced security with server-side processing |
User Experience | Unified login but may face delays and security warnings | Seamless and secure login experience |
Implementation | Easier initial setup, minimal backend changes | Requires custom development and in-depth Keycloak expertise |
Maintenance | Potential issues with browser compatibility and JavaScript updates | Centralized logic simplifies maintenance across all realms |
Scalability | May become unwieldy as the number of tenants increases | Better suited for scaling with multiple tenants |
Complexity | Simpler to implement but riskier in terms of security | More complex but offers a robust, secure solution |