Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,9 @@ private static Object generateByFieldName(final String fieldName,
if (key.equals("port"))
return coerce(FAKER.number().numberBetween(1024, 65535), type, schema);
if (key.equals("latitude"))
return coerce(Double.parseDouble(FAKER.address().latitude().replace(",", ".")), type, schema);
return coerce(FAKER.number().randomDouble(6, -90, 90), type, schema);
if (key.equals("longitude"))
return coerce(Double.parseDouble(FAKER.address().longitude().replace(",", ".")), type, schema);
return coerce(FAKER.number().randomDouble(6, -180, 180), type, schema);

// --- Booleans ---
if ("boolean".equals(type)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ static Schema<?> bestResponseSchema(final Operation operation) {
}

// default
return schemaFromResponse(responses.getDefault());
return schemaFromResponse(responses.get(ApiResponses.DEFAULT));
}

@SuppressWarnings("rawtypes")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import static java.util.Collections.*;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.forgerock.http.util.Loader;
Expand Down Expand Up @@ -81,12 +82,27 @@ public static Heaplet getHeaplet(Class<?> c) {
// we're directly pointing to the Heaplet
if (Heaplet.class.isAssignableFrom(c)) {
try {
heaplet = c.asSubclass(Heaplet.class).newInstance();
heaplet = instantiate(c.asSubclass(Heaplet.class));
} catch (Exception e) {
logger.warn("An error occurred while trying to instantiate {} as a Heaplet", c.getName(), e);
// Ignored
}
}
return heaplet;
}

/**
* Invokes the no-arg constructor, letting an {@link Error} thrown by it propagate as
* {@code Class.newInstance()} did.
*/
private static Heaplet instantiate(final Class<? extends Heaplet> c) throws ReflectiveOperationException {
try {
return c.getDeclaredConstructor().newInstance();
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error) {
throw (Error) e.getTargetException();
}
throw e;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2014-2016 ForgeRock AS.
* Portions Copyright 2026 3A Systems, LLC.
*/
package org.forgerock.openig.ldap;

Expand Down Expand Up @@ -192,13 +193,4 @@ private ConnectionFactory getConnectionFactory(final String host, final int port
}
return factory;
}

@Override
protected void finalize() throws Throwable {
for (ConnectionFactory factory : factories.values()) {
factory.close();
}
factories.clear();
super.finalize();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -152,8 +153,14 @@
throw new JsonValueException(value, "expecting " + type.getName());
}
try {
return (T) c.newInstance();
} catch (ExceptionInInitializerError | InstantiationException | IllegalAccessException e) {
return (T) c.getDeclaredConstructor().newInstance();
} catch (InvocationTargetException e) {
final Throwable target = e.getTargetException();
if (target instanceof Error) {
throw (Error) target;
}
throw new JsonValueException(value, target);
} catch (ExceptionInInitializerError | ReflectiveOperationException e) {
throw new JsonValueException(value, e);
}
}
Expand Down Expand Up @@ -459,7 +466,7 @@
if (node.isNull()) {
return null;
} else if (node.isString()) {
return bindings -> node.as(JsonValues.expression(Map.class, initialBindings)).eval(bindings);

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (macos-latest, 27)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (windows-latest, 11)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (ubuntu-latest, 11)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (ubuntu-latest, 17)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (ubuntu-latest, 25)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (windows-latest, 27)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (macos-latest, 11)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (ubuntu-latest, 27)

[unchecked] unchecked conversion

Check warning on line 469 in openig-core/src/main/java/org/forgerock/openig/util/JsonValues.java

View workflow job for this annotation

GitHub Actions / build-maven (ubuntu-latest, 21)

[unchecked] unchecked conversion
} else if (node.isMap()) {
return new Function<>() {
// Avoid 'environment' entry's value to be null (cause an error in AM)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2022-2026 3A Systems, LLC.
*/

package org.openidentityplatform.openig.filter;

import java.io.IOException;
Expand All @@ -11,6 +27,8 @@
import org.forgerock.http.protocol.Request;
import org.forgerock.http.protocol.Response;
import org.forgerock.http.protocol.Status;
import org.forgerock.json.JsonValue;
import org.forgerock.json.JsonValueException;
import org.forgerock.openig.heap.GenericHeaplet;
import org.forgerock.openig.heap.HeapException;
import org.forgerock.services.context.Context;
Expand Down Expand Up @@ -56,8 +74,8 @@ public void start() throws HeapException {
try {
final URI uri=new URI(server);
filter.icap=new ICAPClient(uri.getHost(), uri.getPort()>0?uri.getPort():1344);
filter.icap.setConnectTimeout(Integer.parseInt(config.get("connect_timeout").defaultTo("5000").as(expression(String.class)).eval()));
filter.icap.setReadTimeout(Integer.parseInt(config.get("read_timeout").defaultTo("15000").as(expression(String.class)).eval()));
filter.icap.setConnectTimeout(timeout("connect_timeout", "5000"));
filter.icap.setReadTimeout(timeout("read_timeout", "15000"));
filter.service=config.get("service").defaultTo("").as(expression(String.class)).eval();
filter.rewrite=Boolean.parseBoolean(config.get("rewrite").defaultTo("true").as(expression(String.class)).eval());
logger.info("start {} connect_timeout={} read_timeout={}",uri,filter.icap.getConnectTimeout(),filter.icap.getReadTimeout());
Expand All @@ -66,6 +84,17 @@ public void start() throws HeapException {
}
}

/** Reads a timeout (in milliseconds) from the config, naming the field when the value is not an int. */
private int timeout(String name, String defaultValue) {
final JsonValue value=config.get(name).defaultTo(defaultValue);
final String evaluated=value.as(expression(String.class)).eval();
try {
return Integer.parseInt(evaluated);
} catch (NumberFormatException e) {
throw new JsonValueException(value, "Expecting a number of milliseconds that fits in an int, got: "+evaluated, e);
}
}

@Override
public void destroy() {
super.destroy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
import org.forgerock.http.protocol.Status;
import org.forgerock.http.servlet.HttpFrameworkServlet;
import org.forgerock.services.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Principal implements java.security.Principal {
private static final Logger logger=LoggerFactory.getLogger(Principal.class);


final Context context;
Expand All @@ -42,11 +45,32 @@ public String getName() {
long lastAuthorize=0;
Status res=null;

/** System property holding the re-authorization interval, in seconds. */
static final String TTL_PROPERTY="org.openidentityplatform.openig.websocket.ttl";
static final long DEFAULT_TTL_SECONDS=180;
static final long TTL_MILLIS=ttlMillis(System.getProperty(TTL_PROPERTY));

/** Parses the re-authorization interval, falling back to the default when the value is not a number. */
static long ttlMillis(String seconds) {
if (seconds!=null) {
try {
return Long.parseLong(seconds.trim())*1000;
} catch (NumberFormatException e) {
logger.warn("Ignoring invalid value \"{}\" of system property {}, using {} seconds", seconds, TTL_PROPERTY, DEFAULT_TTL_SECONDS);
}
}
return DEFAULT_TTL_SECONDS*1000;
}

/** Tells whether the cached authorization result has to be refreshed at the given time. */
boolean expired(long now) {
return res==null || now-lastAuthorize>=TTL_MILLIS;
}

public Status authorize() throws InterruptedException, ExecutionException {
final long ttl=Long.parseLong(System.getProperty("org.openidentityplatform.openig.websocket.ttl", "180"))*1000;
if (res==null || System.currentTimeMillis()-lastAuthorize>=ttl) {
if (expired(System.currentTimeMillis())) {
synchronized (this) {
if (res==null || (System.currentTimeMillis()-lastAuthorize)>=ttl) {
if (expired(System.currentTimeMillis())) {
res=HttpFrameworkServlet.getGatewayHttpFrameworkServlet().handler.handle(context, request).get().getStatus();
lastAuthorize=System.currentTimeMillis();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,20 @@ public void generate_normalisesFieldNameForLookup() {
assertThat(MockDataGenerator.generate("FIRSTNAME", schema)).isInstanceOf(String.class);
}

@Test
public void generate_returnsCoordinatesInRange() {
final Schema<Double> schema = new Schema<>();
schema.setType("number");
for (int i = 0; i < 100; i++) {
final Object latitude = MockDataGenerator.generate("latitude", schema);
final Object longitude = MockDataGenerator.generate("longitude", schema);
assertThat(latitude).isInstanceOf(Number.class);
assertThat(longitude).isInstanceOf(Number.class);
assertThat(((Number) latitude).doubleValue()).isBetween(-90.0, 90.0);
assertThat(((Number) longitude).doubleValue()).isBetween(-180.0, 180.0);
}
}

// -----------------------------------------------------------------------
// Numeric generation with constraints
// -----------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,14 @@ public void bestResponseSchema_falls_to201_when200IsAbsent() {
assertThat(schema.getDescription()).isEqualTo("schema-201");
}

@Test
public void bestResponseSchema_fallsBackToDefaultResponse() {
final Operation op = buildOperation("default");
final Schema<?> schema = OpenApiMockResponseHandler.bestResponseSchema(op);
assertThat(schema).isNotNull();
assertThat(schema.getDescription()).isEqualTo("schema-default");
}

@Test
public void bestResponseSchema_returnsNull_whenNoResponseSchema() {
final Operation op = new Operation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.forgerock.json.JsonValue.object;
import static org.forgerock.openig.heap.Keys.TEMPORARY_STORAGE_HEAP_KEY;

import org.forgerock.json.JsonValue;
import org.forgerock.openig.heap.domain.Author;
import org.forgerock.openig.heap.domain.AuthorHeaplet;
import org.forgerock.openig.heap.domain.Book;
Expand Down Expand Up @@ -141,4 +142,44 @@ public Object create() throws HeapException {
return null;
}
}

@Test
public void shouldIgnoreGivenHeapletClassWhoseConstructorThrowsAnException() throws Exception {
assertThat(Heaplets.getHeaplet(ThrowingHeaplet.class)).isNull();
}

@Test(expectedExceptions = NoClassDefFoundError.class)
public void shouldPropagateErrorThrownByGivenHeapletClassConstructor() throws Exception {
Heaplets.getHeaplet(FailingHeaplet.class);
}

public static class ThrowingHeaplet implements Heaplet {
public ThrowingHeaplet() {
throw new IllegalStateException("boom");
}

@Override
public Object create(Name name, JsonValue config, Heap heap) {
return null;
}

@Override
public void destroy() {
}
}

public static class FailingHeaplet implements Heaplet {
public FailingHeaplet() {
throw new NoClassDefFoundError("boom");
}

@Override
public Object create(Name name, JsonValue config, Heap heap) {
return null;
}

@Override
public void destroy() {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
package org.forgerock.openig.util;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.forgerock.json.JsonValue.array;
import static org.forgerock.json.JsonValue.field;
import static org.forgerock.json.JsonValue.json;
import static org.forgerock.json.JsonValue.object;
import static org.forgerock.json.JsonValueFunctions.listOf;
import static org.forgerock.openig.el.Bindings.bindings;
import static org.forgerock.openig.util.JsonValues.asFunction;
import static org.forgerock.openig.util.JsonValues.asNewInstance;
import static org.forgerock.openig.util.JsonValues.evaluated;
import static org.forgerock.openig.util.JsonValues.firstOf;
import static org.forgerock.openig.util.JsonValues.getWithDeprecation;
Expand All @@ -41,6 +43,7 @@
import org.forgerock.json.JsonException;
import org.forgerock.json.JsonPointer;
import org.forgerock.json.JsonValue;
import org.forgerock.json.JsonValueException;
import org.forgerock.openig.el.Bindings;
import org.forgerock.openig.el.ExpressionException;
import org.forgerock.openig.heap.Heap;
Expand Down Expand Up @@ -320,4 +323,51 @@ public static Object[][] asFunctionProvider() {
};
//@Checkstyle:on
}

@Test
public void shouldAsNewInstanceWrapExceptionThrownByConstructor() throws Exception {
assertThatThrownBy(() -> asNewInstance(json(ThrowingConstructor.class.getName()), Object.class))
.isInstanceOf(JsonValueException.class)
.hasCauseInstanceOf(IllegalStateException.class);
}

@Test(expectedExceptions = NoClassDefFoundError.class)
public void shouldAsNewInstancePropagateErrorThrownByConstructor() throws Exception {
asNewInstance(json(FailingConstructor.class.getName()), Object.class);
}

@Test(expectedExceptions = ExceptionInInitializerError.class)
public void shouldAsNewInstancePropagateInitializerErrorRaisedByConstructor() throws Exception {
asNewInstance(json(ConstructorTouchingBrokenClass.class.getName()), Object.class);
}

public static class ThrowingConstructor {
public ThrowingConstructor() {
throw new IllegalStateException("boom");
}
}

public static class FailingConstructor {
public FailingConstructor() {
throw new NoClassDefFoundError("boom");
}
}

public static class ConstructorTouchingBrokenClass {
public ConstructorTouchingBrokenClass() {
BrokenStaticInitializer.touch();
}
}

/**
* Only the first access raises {@link ExceptionInInitializerError}, later ones get a
* {@link NoClassDefFoundError}: keep this class private to the test above.
*/
static class BrokenStaticInitializer {
static final int VALUE = Integer.parseInt("boom");

static int touch() {
return VALUE;
}
}
}
Loading
Loading