### Build OpenIG Community Edition Source: https://github.com/forgerock/openig-community-edition/blob/master/README.md Clone the repository and use Maven to clean and install the project. This is the standard procedure for building the OpenIG Community Edition from source. ```bash git clone git@github.com:ForgeRock/openig-community-edition-2.1.0.git cd openig-community-edition-2.1.0 mvn clean install ``` -------------------------------- ### Verify Maven and Java Versions Source: https://github.com/forgerock/openig-community-edition/blob/master/README.md Run this command to ensure your environment has the correct versions of Maven and Java installed for building the project. ```bash mvn --version ``` -------------------------------- ### Programmatic CookieFilter Setup Source: https://context7.com/forgerock/openig-community-edition/llms.txt Set up CookieFilter programmatically to define which cookies to suppress, relay, or manage. This example suppresses tracking cookies, relays session tokens, and manages JSESSIONID/SMSESSION. ```java import org.forgerock.openig.filter.CookieFilter; import java.net.CookiePolicy; CookieFilter filter = new CookieFilter(); filter.suppressed.add("tracking-cookie"); // stripped from both request & response filter.relayed.add("session-token"); // passed through as-is filter.managed.add("JSESSIONID"); // intercepted; stored in proxy session filter.defaultAction = CookieFilter.Action.SUPPRESS; // suppress unclassified cookies filter.policy = CookiePolicy.ACCEPT_ALL; // accept all managed cookies ``` -------------------------------- ### Programmatic HeaderFilter Setup Source: https://context7.com/forgerock/openig-community-edition/llms.txt Programmatically configure HeaderFilter to modify request or response headers. This example adds CORS and security headers to the response while removing server-specific headers. ```java import org.forgerock.openig.filter.HeaderFilter; import org.forgerock.openig.http.MessageType; HeaderFilter filter = new HeaderFilter(); filter.messageType = MessageType.RESPONSE; filter.remove.add("Server"); filter.remove.add("X-Powered-By"); filter.add.add("Access-Control-Allow-Origin", "*"); filter.add.add("X-Frame-Options", "DENY"); // After next.handle(exchange): removes "Server"/"X-Powered-By" and injects CORS/security headers ``` -------------------------------- ### Programmatic HttpBasicAuthFilter Setup Source: https://context7.com/forgerock/openig-community-edition/llms.txt Set up HttpBasicAuthFilter programmatically by defining username, password expressions, and a failure handler. This filter retries requests once upon a 401 response. ```java import org.forgerock.openig.filter.HttpBasicAuthFilter; import org.forgerock.openig.el.Expression; HttpBasicAuthFilter filter = new HttpBasicAuthFilter(); filter.username = new Expression("${exchange.session['storedUser']}"); filter.password = new Expression("${exchange.session['storedPass']}"); filter.failureHandler = new StaticResponseHandler(); // redirect to login // Behavior: // 1. Strips any existing Authorization header from request // 2. Attaches cached credentials from session if available // 3. If backend returns 401, evaluates username/password expressions and retries once // 4. On second 401 or null credentials → calls failureHandler // 5. Strips WWW-Authenticate from the response before returning to client ``` -------------------------------- ### AuditFilter Source: https://context7.com/forgerock/openig-community-edition/llms.txt An example filter that injects a correlation ID into the request headers and logs non-200 responses. ```APIDOC ## AuditFilter ### Description This `Filter` implementation demonstrates pre-processing and post-processing logic. It adds a unique correlation ID to outgoing requests and logs any responses that do not have a 200 status code. ### Filter Interface Implements the `org.forgerock.openig.filter.Filter` interface. ### Method Signature `void filter(Exchange exchange, Handler next) throws HandlerException, IOException` ### Behavior 1. **Pre-processing**: Adds a "X-Correlation-Id" header to `exchange.request.headers` with a timestamp-based value. 2. **Delegation**: Calls `next.handle(exchange)` to pass the exchange to the next filter or handler in the chain. 3. **Post-processing**: After the next handler completes, it checks `exchange.response.status`. If the status is not 200, it prints an error message to `System.err` including the status and request URI. ### Dependencies Requires a `Handler` or `Filter` to be passed as the `next` argument. ``` -------------------------------- ### Initialize and Use HeapImpl for Object Registry Source: https://context7.com/forgerock/openig-community-edition/llms.txt Instantiate HeapImpl, load configuration, retrieve objects, and destroy the heap. Configuration is provided as a parsed JSON map. ```java import org.forgerock.openig.heap.HeapImpl; import org.forgerock.json.fluent.JsonValue; import java.util.Map; import java.util.List; // JSON heap configuration string (parsed to JsonValue): /* { "objects": [ { "name": "ClientHandler", "type": "ClientHandler", "config": { "connections": 64 } }, { "name": "MainChain", "type": "Chain", "config": { "filters": [ "AuditFilter", "BasicAuthFilter" ], "handler": "ClientHandler" } } ] } */ HeapImpl heap = new HeapImpl(); heap.init(new JsonValue(parsedConfigMap)); // loads and wires all objects // Retrieve the top-level handler to process exchanges: Handler root = (Handler) heap.get("MainChain"); root.handle(exchange); // dispatches through the full pipeline heap.destroy(); // frees all heaplet resources ``` -------------------------------- ### Build and Populate Exchange Manually Source: https://context7.com/forgerock/openig-community-edition/llms.txt Demonstrates how to construct an Exchange object programmatically, setting up request details and arbitrary attributes for later access via EL expressions. ```java import org.forgerock.openig.http.Exchange; import org.forgerock.openig.http.Request; import org.forgerock.openig.http.Response; import java.net.URI; // Building and populating an exchange manually (e.g., in a test or custom handler) Exchange exchange = new Exchange(); Request request = new Request(); request.method = "POST"; request.uri = new URI("https://app.example.com/login"); request.version = "HTTP/1.1"; request.headers.add("Content-Type", "application/x-www-form-urlencoded"); exchange.request = request; // Store arbitrary data accessible from EL as ${exchange.userId} exchange.put("userId", "jdoe"); // After handler invocation: // exchange.response.status → HTTP status code (e.g., 302) // exchange.response.headers → response headers map // exchange.session.get("key") → session-scoped data ``` -------------------------------- ### Programmatic Chain Construction for Filter Pipeline Source: https://context7.com/forgerock/openig-community-edition/llms.txt Illustrates the programmatic creation of a Chain, which defines a sequence of Filters and a terminal Handler for processing an Exchange. This is equivalent to JSON heap configuration. ```java import org.forgerock.openig.filter.Chain; // Programmatic construction (equivalent to JSON heap config below) Chain chain = new Chain(); chain.filters.add(new AuditFilter()); // first in, first executed on request chain.filters.add(new HttpBasicAuthFilter()); // second, wraps the terminal handler chain.handler = new ClientHandler(storage); // terminal: forwards to remote server // Equivalent JSON heap configuration: /* { "name": "MainChain", "type": "Chain", "config": { "filters": [ "AuditFilter", "BasicAuthFilter" ], "handler": "ClientHandler" } } */ // chain.handle(exchange) → AuditFilter → BasicAuthFilter → ClientHandler ``` -------------------------------- ### Evaluate and Set Expressions with Exchange Context Source: https://context7.com/forgerock/openig-community-edition/llms.txt Shows how to use the Expression class to read values from and write values to an Exchange object using JUEL syntax. Handles nested properties and null-safe access. ```java import org.forgerock.openig.el.Expression; import org.forgerock.openig.el.ExpressionException; import org.forgerock.openig.http.Exchange; import org.forgerock.openig.http.Request; import java.net.URI; Exchange exchange = new Exchange(); Request request = new Request(); request.method = "GET"; request.uri = new URI("https://app.example.com/api?user=jdoe"); exchange.request = request; exchange.put("authenticated", Boolean.FALSE); // Read: extract query parameter Expression userExpr = new Expression("${exchange.request.form['user'][0]}"); String user = userExpr.eval(exchange, String.class); // → "jdoe" // Write: set an exchange attribute via lvalue expression Expression authExpr = new Expression("${exchange.authenticated}"); authExpr.set(exchange, Boolean.TRUE); Boolean auth = (Boolean) new Expression("${exchange.authenticated}").eval(exchange); // → true // Conditional check Expression condExpr = new Expression("${exchange.request.method == 'POST'}"); Boolean isPost = condExpr.eval(exchange, Boolean.class); // → false // Null-safe: unresolvable expressions return null, never throw Expression safe = new Expression("${exchange.nonexistent.deep.path}"); Object result = safe.eval(exchange); // → null (no exception) ``` -------------------------------- ### Structured Logging with Logger and LogTimer Source: https://context7.com/forgerock/openig-community-edition/llms.txt Utilize Logger for leveled logging (debug, info, warning, error) and LogTimer for performance timing. Requires a LogSink implementation. ```java import org.forgerock.openig.log.Logger; import org.forgerock.openig.log.ConsoleLogSink; import org.forgerock.openig.log.LogTimer; Logger logger = new Logger(new ConsoleLogSink(), "MyFilter"); // Leveled logging logger.debug("Processing request for: " + exchange.request.uri); logger.info("Authentication succeeded for user: " + username); logger.warning("Backend returned unexpected status: " + exchange.response.status); logger.error("Failed to connect to upstream: " + e.getMessage()); // Timing instrumentation (writes STAT entries to sink) LogTimer timer = logger.getTimer().start(); try { next.handle(exchange); } finally { timer.stop(); // logs elapsed ms at STAT level: "MyFilter: elapsed=42" } // Named event timer LogTimer queryTimer = logger.getTimer("dbLookup").start(); Map row = executeQuery(userId); queryTimer.stop(); // logs: "MyFilter.dbLookup: elapsed=7" ``` -------------------------------- ### Log Request/Response with CaptureFilter Source: https://context7.com/forgerock/openig-community-edition/llms.txt Utilize `CaptureFilter` to log the full request and response details, including headers and entity content, to a specified file. An optional EL `condition` can be configured to control when captures occur. Ensure the `file` path is writable and `captureEntity` is set to `true` if entity content logging is desired. ```json { "name": "DebugCapture", "type": "CaptureFilter", "config": { "file": "/var/log/openig/capture.txt", "charset": "UTF-8", "captureEntity": true, "condition": "${exchange.request.uri.path == '/api/login'}" } } ``` -------------------------------- ### Implement a Custom HealthCheckHandler in Java Source: https://context7.com/forgerock/openig-community-edition/llms.txt This custom handler always returns a 200 OK response with a plain text body. Ensure any pre-existing response entity is closed before creating a new response. ```java import org.forgerock.openig.handler.Handler; import org.forgerock.openig.handler.HandlerException; import org.forgerock.openig.http.Exchange; import org.forgerock.openig.http.Response; import java.io.IOException; // Custom handler that always returns 200 OK with a fixed body public class HealthCheckHandler implements Handler { @Override public void handle(Exchange exchange) throws HandlerException, IOException { // Always close any pre-existing response entity first if (exchange.response != null && exchange.response.entity != null) { exchange.response.entity.close(); } Response response = new Response(); response.status = 200; response.reason = "OK"; response.version = "HTTP/1.1"; response.headers.add("Content-Type", "text/plain"); exchange.response = response; // Expected: exchange.response.status == 200 } } ``` -------------------------------- ### Configure StaticRequestFilter to Replace Request Source: https://context7.com/forgerock/openig-community-edition/llms.txt Employ StaticRequestFilter to substitute the current request with a new one, defining its method, URI, version, headers, and form fields. Form fields are POST-encoded or appended as query parameters. ```json { "name": "LoginSubmitFilter", "type": "StaticRequestFilter", "config": { "method": "POST", "uri": "https://app.internal.example.com/login", "version": "HTTP/1.1", "headers": { "Content-Type": [ "application/x-www-form-urlencoded" ], "Host": [ "app.internal.example.com" ] }, "form": { "username": [ "${exchange.session['username']}" ], "password": [ "${exchange.session['password']}" ], "_csrf": [ "${exchange.attributes['csrfToken']}" ] } } } ``` -------------------------------- ### Configure HttpBasicAuthFilter for Basic Authentication Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use this filter to intercept 401 responses, supply credentials from EL expressions, and cache them for subsequent requests. Configure username, password, and a failure handler. ```json { "name": "BasicAuthFilter", "type": "HttpBasicAuthFilter", "config": { "username": "${exchange.session['username']}", "password": "${exchange.session['password']}", "failureHandler": "LoginPageHandler" } } ``` -------------------------------- ### DispatchHandler: Route Exchanges by Condition Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use DispatchHandler to route exchanges based on an ordered list of conditions. The first condition that evaluates to true determines the handler. An optional baseURI can rewrite the request URI. ```json { "name": "Router", "type": "DispatchHandler", "config": { "bindings": [ { "condition": "${exchange.request.uri.path == '/api'}", "baseURI": "https://api-backend.internal:8443", "handler": "ApiChain" }, { "condition": "${exchange.request.uri.path == '/admin'}", "baseURI": "https://admin-backend.internal:9000", "handler": "AdminChain" }, { "handler": "DefaultChain" } ] } } ``` -------------------------------- ### SequenceHandler: Multi-Step Request Sequences Source: https://context7.com/forgerock/openig-community-edition/llms.txt Process an exchange through a series of handlers in order using SequenceHandler. Each step can have a postcondition to control sequence continuation. Halts if any postcondition is false. ```json { "name": "LoginSequence", "type": "SequenceHandler", "config": { "bindings": [ { "handler": "FetchLoginFormChain", "postcondition": "${exchange.response.status == 200}" }, { "handler": "ExtractCSRFChain", "postcondition": "${exchange.attributes['csrfToken'] != null}" }, { "handler": "SubmitCredentialsChain" } ] } } ``` -------------------------------- ### Encrypt/Decrypt HTTP Headers with CryptoHeaderFilter (Programmatic) Source: https://context7.com/forgerock/openig-community-edition/llms.txt Implement `CryptoHeaderFilter` programmatically for encrypting or decrypting HTTP headers. This approach requires explicit instantiation of the filter and setting its properties, including `messageType`, `operation`, `algorithm`, `charset`, and `key`. The key must be decoded from Base64. ```java import org.forgerock.openig.filter.CryptoHeaderFilter; import org.forgerock.openig.http.MessageType; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; CryptoHeaderFilter filter = new CryptoHeaderFilter(); filter.messageType = MessageType.REQUEST; filter.operation = CryptoHeaderFilter.Operation.DECRYPT; filter.algorithm = "DES/ECB/NoPadding"; filter.charset = java.nio.charset.Charset.forName("UTF-8"); filter.key = new SecretKeySpec(new Base64(0).decode("c29tZXNlY3JldA=="), "DES"); filter.headers.add("X-SSO-Token"); ``` -------------------------------- ### Implement an AuditFilter in Java Source: https://context7.com/forgerock/openig-community-edition/llms.txt This filter injects a correlation ID into the request headers before proceeding and logs non-200 responses. It requires the Handler and Exchange classes. ```java import org.forgerock.openig.filter.Filter; import org.forgerock.openig.handler.Handler; import org.forgerock.openig.handler.HandlerException; import org.forgerock.openig.http.Exchange; import java.io.IOException; // Filter that injects a request header and inspects the response status public class AuditFilter implements Filter { @Override public void filter(Exchange exchange, Handler next) throws HandlerException, IOException { // Pre-processing: add a correlation ID to the outgoing request exchange.request.headers.add("X-Correlation-Id", "req-" + System.currentTimeMillis()); // Delegate to the next filter/handler in the chain next.handle(exchange); // Post-processing: log non-200 responses if (exchange.response.status != 200) { System.err.println("Unexpected status: " + exchange.response.status + " for " + exchange.request.uri); } } } ``` -------------------------------- ### StaticResponseHandler: Serve Fixed HTTP Responses Source: https://context7.com/forgerock/openig-community-edition/llms.txt Employ StaticResponseHandler to serve hard-coded responses without backend forwarding. Useful for failure handlers or redirect targets. Status, reason, headers, and entity body are configurable. ```json { "name": "LoginRedirectHandler", "type": "StaticResponseHandler", "config": { "status": 302, "reason": "Found", "headers": { "Location": [ "https://sso.example.com/login?goto=${urlEncode(exchange.request.uri)}" ], "Cache-Control": [ "no-cache" ] } } } ``` ```json { "name": "ForbiddenHandler", "type": "StaticResponseHandler", "config": { "status": 403, "reason": "Forbidden", "headers": { "Content-Type": [ "text/html" ] }, "entity": "

403 Forbidden

" } } ``` -------------------------------- ### Encrypt/Decrypt HTTP Headers with CryptoHeaderFilter (JSON Config) Source: https://context7.com/forgerock/openig-community-edition/llms.txt Configure `CryptoHeaderFilter` using JSON to encrypt or decrypt specified HTTP headers. Set `messageType` to `REQUEST` or `RESPONSE`, `operation` to `ENCRYPT` or `DECRYPT`, and provide a Base64-encoded `key`. Ensure the `algorithm` and `keyType` match your encryption requirements. ```json { "name": "DecryptSSOHeader", "type": "CryptoHeaderFilter", "config": { "messageType": "REQUEST", "operation": "DECRYPT", "algorithm": "DES/ECB/NoPadding", "keyType": "DES", "key": "c29tZXNlY3JldA==", "charset": "UTF-8", "headers": [ "X-SSO-Token", "X-Encrypted-User" ] } } ``` -------------------------------- ### ClientHandler: Forward Requests to Remote Servers Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use ClientHandler to send requests to remote HTTP/HTTPS servers. It manages a connection pool and handles response population. Ensure exchange.request.uri is set to the upstream server address before calling handle. ```json { "name": "ClientHandler", "type": "ClientHandler", "config": { "connections": 64 } } ``` ```java import org.forgerock.openig.handler.ClientHandler; import org.forgerock.openig.io.TemporaryStorage; TemporaryStorage storage = new TemporaryStorage(); ClientHandler client = new ClientHandler(64, storage); // max 64 pooled connections // exchange.request.uri must be set to the upstream server address // After client.handle(exchange): // exchange.response.status → e.g., 200 // exchange.response.headers → upstream response headers (hop-by-hop stripped) // exchange.response.entity → BranchingInputStream wrapping response body ``` -------------------------------- ### SQL Attributes Lookup with SqlAttributesFilter Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use `SqlAttributesFilter` to perform lazy SQL lookups against a database. The results are exposed as a Map at the specified `target` EL location, populated only on first access. Ensure the `dataSource` is correctly configured and the `preparedStatement` and `parameters` are valid. ```json { "name": "UserLookup", "type": "SqlAttributesFilter", "config": { "target": "${exchange.userRecord}", "dataSource": "java:comp/env/jdbc/UserDB", "preparedStatement": "SELECT email, role, display_name FROM users WHERE username = ?", "parameters": [ "${exchange.session['username']}" ] } } ``` -------------------------------- ### CSV File Attributes Lookup with FileAttributesFilter Source: https://context7.com/forgerock/openig-community-edition/llms.txt Employ `FileAttributesFilter` for lazy lookups in delimiter-separated files like CSV. The matched row is placed as a Map at the `target` EL location. Configure `file`, `charset`, `separator`, `key`, and `value` appropriately. The `header` option should be set to `true` if the file includes a header row. ```json { "name": "RoleMapping", "type": "FileAttributesFilter", "config": { "target": "${exchange.roleData}", "file": "/etc/openig/config/roles.csv", "charset": "UTF-8", "separator": "COMMA", "header": true, "key": "username", "value": "${exchange.session['username']}" } } ``` -------------------------------- ### Configure CookieFilter for Cookie Management Source: https://context7.com/forgerock/openig-community-edition/llms.txt Configure CookieFilter to suppress, relay, or manage cookies. The default action for unclassified cookies can be set, and a cookie policy can be applied. ```json { "name": "CookieManager", "type": "CookieFilter", "config": { "suppressed": [ "tracking-cookie", "analytics" ], "relayed": [ "session-token" ], "managed": [ "JSESSIONID", "SMSESSION" ], "defaultAction": "SUPPRESS" } } ``` -------------------------------- ### HealthCheckHandler Source: https://context7.com/forgerock/openig-community-edition/llms.txt A custom handler implementation that always returns a 200 OK response with plain text content. ```APIDOC ## HealthCheckHandler ### Description This handler is an example of a custom `Handler` implementation. It is designed to always return an HTTP 200 OK status with a simple text body, typically used for health checks. ### Handler Interface Implements the `org.forgerock.openig.handler.Handler` interface. ### Method Signature `void handle(Exchange exchange) throws HandlerException, IOException` ### Behavior 1. Closes any pre-existing response entity in the exchange. 2. Creates a new `Response` object. 3. Sets the status to 200, reason to "OK", and version to "HTTP/1.1". 4. Adds a "Content-Type" header with the value "text/plain". 5. Assigns the created response to `exchange.response`. ### Expected Outcome `exchange.response.status` will be 200. ``` -------------------------------- ### Configure HeaderFilter to Add and Remove HTTP Headers Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use HeaderFilter to remove specified headers and add new ones to requests or responses. Header names for removal are case-insensitive. ```json { "name": "AddCORSHeaders", "type": "HeaderFilter", "config": { "messageType": "RESPONSE", "remove": [ "Server", "X-Powered-By" ], "add": { "Access-Control-Allow-Origin": [ "*" ], "X-Frame-Options": [ "DENY" ], "Cache-Control": [ "no-store", "no-cache" ] } } } ``` -------------------------------- ### Configure AssignmentFilter for Conditional Assignments Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use AssignmentFilter to evaluate EL assignment bindings before request handling or after response reception. Bindings can have conditions, targets, and values. Null values clear the target. ```json { "name": "InjectCredentials", "type": "AssignmentFilter", "config": { "onRequest": [ { "condition": "${exchange.session['authenticated'] == true}", "target": "${exchange.request.headers['X-User']}", "value": "${exchange.session['username']}" }, { "target": "${exchange.request.headers['X-Request-Time']}", "value": "${system['currentTimeMillis']}" } ], "onResponse": [ { "condition": "${exchange.response.status == 302}", "target": "${exchange.session['lastRedirect']}", "value": "${exchange.response.headers['Location'][0]}" } ] } } ``` -------------------------------- ### Configure EntityExtractFilter for Regex Extraction Source: https://context7.com/forgerock/openig-community-edition/llms.txt Apply EntityExtractFilter to extract named data from message bodies using regular expressions. Results are stored in a map at a specified EL target, useful for capturing dynamic values like tokens. ```json { "name": "ExtractCSRF", "type": "EntityExtractFilter", "config": { "messageType": "RESPONSE", "target": "${exchange.attributes}", "bindings": [ { "key": "csrfToken", "pattern": "name=\"_csrf\"\\s+value=\"([^\"]+)\"", "template": "$1" }, { "key": "nonce", "pattern": "]+name=\"nonce\"[^>]+value=\"([^\"]+)\"" } ] } } ``` -------------------------------- ### Configure SwitchFilter for Conditional Flow Diversion Source: https://context7.com/forgerock/openig-community-edition/llms.txt Use SwitchFilter to evaluate conditions and divert the exchange to a specified handler. This filter is useful for implementing conditional logic in request or response processing chains. ```json { "name": "AuthGate", "type": "SwitchFilter", "config": { "onRequest": [ { "condition": "${exchange.session['authenticated'] != true}", "handler": "LoginRedirectHandler" }, { "condition": "${exchange.request.uri.path == '/admin' and exchange.session['role'] != 'admin'}", "handler": "ForbiddenHandler" } ], "onResponse": [ { "condition": "${exchange.response.status == 401}", "handler": "SessionClearHandler" } ] } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.