diff --git a/FROST-Server.Auth.Basic/src/main/resources/liquibase/basicAuthTables.xml b/FROST-Server.Auth.Basic/src/main/resources/liquibase/basicAuthTables.xml
index 22b82f852..a3d58a061 100644
--- a/FROST-Server.Auth.Basic/src/main/resources/liquibase/basicAuthTables.xml
+++ b/FROST-Server.Auth.Basic/src/main/resources/liquibase/basicAuthTables.xml
@@ -34,6 +34,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FROST-Server.Auth.Keycloak/pom.xml b/FROST-Server.Auth.Keycloak/pom.xml
index 1423b03d7..09527ea50 100644
--- a/FROST-Server.Auth.Keycloak/pom.xml
+++ b/FROST-Server.Auth.Keycloak/pom.xml
@@ -25,6 +25,11 @@
FROST-Server.Core
${project.version}
+
+ ${project.groupId}
+ FROST-Server.SQLjooq
+ ${project.version}
+
${project.groupId}
FROST-Server.Util
diff --git a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/DatabaseHandler.java b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/DatabaseHandler.java
new file mode 100644
index 000000000..b3601148a
--- /dev/null
+++ b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/DatabaseHandler.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.frostserver.auth.keycloak;
+
+import static de.fraunhofer.iosb.ilt.frostserver.auth.keycloak.KeycloakAuthProvider.TAG_USERNAME_COLUMN;
+import static de.fraunhofer.iosb.ilt.frostserver.auth.keycloak.KeycloakAuthProvider.TAG_USER_TABLE;
+import static de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.ConnectionUtils.TAG_DB_URL;
+
+import de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.ConnectionUtils;
+import de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.ConnectionUtils.ConnectionWrapper;
+import de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings;
+import de.fraunhofer.iosb.ilt.frostserver.settings.Settings;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import org.jooq.DSLContext;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.SQLDialect;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author scf
+ */
+public class DatabaseHandler {
+
+ /**
+ * The logger for this class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHandler.class);
+
+ private static final Map INSTANCES = new HashMap<>();
+
+ private final Settings authSettings;
+ private final String connectionUrl;
+ private final String userTable;
+ private final String usernameColumn;
+
+ public static void init(CoreSettings coreSettings) {
+ if (INSTANCES.get(coreSettings) == null) {
+ createInstance(coreSettings);
+ }
+ }
+
+ private static synchronized DatabaseHandler createInstance(CoreSettings coreSettings) {
+ return INSTANCES.computeIfAbsent(coreSettings, (s) -> {
+ LOGGER.info("Initialising DatabaseHandler.");
+ return new DatabaseHandler(coreSettings);
+ });
+ }
+
+ public static DatabaseHandler getInstance(CoreSettings coreSettings) {
+ DatabaseHandler instance = INSTANCES.get(coreSettings);
+ if (instance == null) {
+ LOGGER.error("DatabaseHandler not initialised.");
+ }
+ return instance;
+ }
+
+ private DatabaseHandler(CoreSettings coreSettings) {
+ authSettings = coreSettings.getAuthSettings();
+ connectionUrl = authSettings.get(TAG_DB_URL, ConnectionUtils.class, false);
+ userTable = authSettings.get(TAG_USER_TABLE, KeycloakAuthProvider.class);
+ usernameColumn = authSettings.get(TAG_USERNAME_COLUMN, KeycloakAuthProvider.class);
+ }
+
+ /**
+ * Checks if the user is registered locally and if not, add the user.
+ *
+ * @param username the username
+ */
+ public void enureUserInUsertable(String username) {
+ try (final ConnectionWrapper connectionProvider = new ConnectionWrapper(authSettings, connectionUrl)) {
+ final DSLContext dslContext = DSL.using(connectionProvider.get(), SQLDialect.POSTGRES);
+ final Field usernameField = DSL.field(DSL.name(usernameColumn), String.class);
+ final Table table = DSL.table(DSL.name(userTable));
+ long count = dslContext
+ .selectCount()
+ .from(table)
+ .where(usernameField.eq(username))
+ .fetchOne()
+ .component1();
+ if (count == 0) {
+ dslContext.insertInto(table)
+ .set(usernameField, username)
+ .execute();
+ connectionProvider.commit();
+ }
+ } catch (SQLException | RuntimeException exc) {
+ LOGGER.error("Failed to register user locally.", exc);
+ }
+ }
+
+}
diff --git a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java
index 090ac7e94..fc854d00c 100644
--- a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java
+++ b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java
@@ -23,6 +23,7 @@
import de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings;
import de.fraunhofer.iosb.ilt.frostserver.settings.Settings;
import de.fraunhofer.iosb.ilt.frostserver.settings.annotation.DefaultValue;
+import de.fraunhofer.iosb.ilt.frostserver.settings.annotation.DefaultValueBoolean;
import de.fraunhofer.iosb.ilt.frostserver.settings.annotation.DefaultValueInt;
import de.fraunhofer.iosb.ilt.frostserver.util.AuthProvider;
import de.fraunhofer.iosb.ilt.frostserver.util.LiquibaseUser;
@@ -79,6 +80,15 @@ public class KeycloakAuthProvider implements AuthProvider, LiquibaseUser, Config
@DefaultValueInt(10)
public static final String TAG_MAX_CLIENTS_PER_USER = "maxClientsPerUser";
+ @DefaultValueBoolean(false)
+ public static final String TAG_REGISTER_USER_LOCALLY = "registerUserLocally";
+
+ @DefaultValue("USERS")
+ public static final String TAG_USER_TABLE = "userTable";
+
+ @DefaultValue("USER_NAME")
+ public static final String TAG_USERNAME_COLUMN = "usernameColumn";
+
/**
* The logger for this class.
*/
@@ -95,6 +105,8 @@ public class KeycloakAuthProvider implements AuthProvider, LiquibaseUser, Config
private CoreSettings coreSettings;
private String roleAdmin;
private int maxClientsPerUser;
+ private boolean registerUserLocally;
+ private DatabaseHandler databaseHandler;
private final Map clientidToUserinfo = new ConcurrentHashMap<>();
private final Map usernameToUserinfo = new ConcurrentHashMap<>();
@@ -113,6 +125,11 @@ public void init(CoreSettings coreSettings) {
final Settings authSettings = coreSettings.getAuthSettings();
roleAdmin = authSettings.get(TAG_AUTH_ROLE_ADMIN, CoreSettings.class);
maxClientsPerUser = authSettings.getInt(TAG_MAX_CLIENTS_PER_USER, getClass());
+ registerUserLocally = authSettings.getBoolean(TAG_REGISTER_USER_LOCALLY, KeycloakAuthProvider.class);
+ if (registerUserLocally) {
+ DatabaseHandler.init(coreSettings);
+ databaseHandler = DatabaseHandler.getInstance(coreSettings);
+ }
}
@Override
@@ -173,6 +190,9 @@ private boolean checkLogin(AbstractKeycloakLoginModule loginModule, UserData use
client.setSubject(subject);
CLIENTMAP.put(clientId, client);
client.getSubject().getPrincipals().stream().forEach(t -> userData.roles.add(t.getName()));
+ if (registerUserLocally) {
+ databaseHandler.enureUserInUsertable(userData.userName);
+ }
}
return login;
} catch (LoginException ex) {
diff --git a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakFilter.java b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakFilter.java
index bee289f8c..ae8591061 100644
--- a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakFilter.java
+++ b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakFilter.java
@@ -17,6 +17,7 @@
*/
package de.fraunhofer.iosb.ilt.frostserver.auth.keycloak;
+import static de.fraunhofer.iosb.ilt.frostserver.auth.keycloak.KeycloakAuthProvider.TAG_REGISTER_USER_LOCALLY;
import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTHENTICATE_ONLY;
import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTH_ALLOW_ANON_READ;
import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTH_ROLE_ADMIN;
@@ -43,7 +44,6 @@
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.keycloak.adapters.AdapterDeploymentContext;
@@ -79,6 +79,8 @@ public class KeycloakFilter implements Filter {
private Map roleMappings;
private String roleAdmin;
private boolean authenticateOnly;
+ private boolean registerUserLocally;
+ private DatabaseHandler databaseHandler;
private AdapterDeploymentContext deploymentContext;
private NodesRegistrationManagement nodesRegistrationManagement;
@@ -96,7 +98,11 @@ public void init(FilterConfig filterConfig) throws ServletException {
Settings authSettings = coreSettings.getAuthSettings();
roleMappings = AuthUtils.loadRoleMapping(authSettings);
roleAdmin = authSettings.get(TAG_AUTH_ROLE_ADMIN, CoreSettings.class);
- authenticateOnly = "T".equals(authSettings.get(TAG_AUTHENTICATE_ONLY, "F"));
+ authenticateOnly = authSettings.getBoolean(TAG_AUTHENTICATE_ONLY, CoreSettings.class);
+ registerUserLocally = authSettings.getBoolean(TAG_REGISTER_USER_LOCALLY, KeycloakAuthProvider.class);
+ if (registerUserLocally) {
+ databaseHandler = DatabaseHandler.getInstance(coreSettings);
+ }
final boolean anonRead = authSettings.getBoolean(TAG_AUTH_ALLOW_ANON_READ, CoreSettings.class);
roleMappersByPath.put("/Data", method -> Role.ADMIN);
@@ -209,19 +215,21 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
LOGGER.debug("Request handled by authentication actions.");
return;
} else {
+ final KeycloakAccount account = findKeycloakAccount(httpRequest);
+ final Principal principalBasic = account.getPrincipal();
+ final Set roles = account.getRoles();
+ final String userName = principalBasic.getName();
+ final PrincipalExtended pe = new PrincipalExtended(userName, roles.contains(roleAdmin), roles);
+ if (registerUserLocally) {
+ databaseHandler.enureUserInUsertable(userName);
+ }
if (authenticateOnly) {
- final KeycloakAccount account = findKeycloakAccount(httpRequest);
- final Principal principalBasic = account.getPrincipal();
- final Set roles = account.getRoles();
- final PrincipalExtended pe = new PrincipalExtended(principalBasic.getName(), roles.contains(roleAdmin), roles);
chain.doFilter(new RequestWrapper(httpRequest, pe), response);
return;
}
-
- HttpServletRequestWrapper wrapper = tokenStore.buildWrapper();
- if (wrapper.isUserInRole(roleMappings.get(requiredRole))) {
+ if (roles.contains(roleMappings.get(requiredRole))) {
LOGGER.debug("User has correct role.");
- chain.doFilter(wrapper, response);
+ chain.doFilter(new RequestWrapper(httpRequest, pe), response);
return;
}
}
diff --git a/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/AbstractAuthTests.java b/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/AbstractAuthTests.java
index 20976e6be..93e4d243c 100644
--- a/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/AbstractAuthTests.java
+++ b/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/AbstractAuthTests.java
@@ -67,10 +67,10 @@ public abstract class AbstractAuthTests extends AbstractTestClass {
private static final List DATASTREAMS = new ArrayList<>();
private static final List OBSERVATIONS = new ArrayList<>();
- private static SensorThingsService serviceAdmin;
- private static SensorThingsService serviceWrite;
- private static SensorThingsService serviceRead;
- private static SensorThingsService serviceAnon;
+ protected static SensorThingsService serviceAdmin;
+ protected static SensorThingsService serviceWrite;
+ protected static SensorThingsService serviceRead;
+ protected static SensorThingsService serviceAnon;
private final boolean anonymousReadAllowed;
private final AuthTestHelper ath;
diff --git a/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/KeyCloakTests.java b/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/KeyCloakTests.java
index d3bd822b6..6e81be074 100644
--- a/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/KeyCloakTests.java
+++ b/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/f01auth/KeyCloakTests.java
@@ -17,13 +17,26 @@
*/
package de.fraunhofer.iosb.ilt.statests.f01auth;
+import static de.fraunhofer.iosb.ilt.statests.TestSuite.KEY_DB_NAME;
+import static de.fraunhofer.iosb.ilt.statests.util.EntityUtils.filterForException;
+import static de.fraunhofer.iosb.ilt.statests.util.EntityUtils.testFilterResults;
+
import dasniko.testcontainers.keycloak.KeycloakContainer;
import de.fraunhofer.iosb.ilt.frostclient.SensorThingsService;
+import de.fraunhofer.iosb.ilt.frostclient.model.Entity;
+import de.fraunhofer.iosb.ilt.frostclient.models.SensorThingsSensingV11;
import de.fraunhofer.iosb.ilt.frostclient.utils.TokenManagerOpenIDConnect;
import de.fraunhofer.iosb.ilt.statests.ServerVersion;
import de.fraunhofer.iosb.ilt.statests.TestSuite;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
+import org.apache.commons.io.IOUtils;
+import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,11 +58,47 @@ public abstract class KeyCloakTests extends AbstractAuthTests {
public static final String KEYCLOAK_FROST_CONFIG_SECRET = "5aa9087d-817f-47b6-92a1-2b5f7caac967";
public static final String KEYCLOAK_TOKEN_PATH = "/realms/FROST-Test/protocol/openid-connect/token";
+ private static final SensorThingsSensingV11 mdlSensing = new SensorThingsSensingV11();
+ private static final SensorThingsUserModel mdlUsers = new SensorThingsUserModel();
+ private static final SensorThingsService baseService = new SensorThingsService(mdlSensing, mdlUsers);
+ private static final List USERS = new ArrayList<>();
+
+ private static String modelUrl(String name) {
+ return resourceUrl("finegrainedsecurity/model/", name);
+ }
+
+ private static String resourceUrl(String path, String name) {
+ try {
+ return IOUtils.resourceToURL(path + "/" + name, KeyCloakTests.class.getClassLoader()).getFile();
+ } catch (IOException ex) {
+ LOGGER.error("Failed", ex);
+ return "";
+ }
+ }
+
static {
+ final String dbName = "keycloakauth";
+ SERVER_PROPERTIES.put("auth.db.url", TestSuite.createDbUrl(dbName));
+ SERVER_PROPERTIES.put("auth.db.driver", "org.postgresql.Driver");
+ SERVER_PROPERTIES.put("auth.db.username", TestSuite.VAL_PG_USER);
+ SERVER_PROPERTIES.put("auth.db.password", TestSuite.VAL_PG_PASS);
+ SERVER_PROPERTIES.put(KEY_DB_NAME, dbName);
+
SERVER_PROPERTIES.put("auth_provider", "de.fraunhofer.iosb.ilt.frostserver.auth.keycloak.KeycloakAuthProvider");
SERVER_PROPERTIES.put("auth_keycloakConfigUrl", TestSuite.getInstance().getKeycloak().getAuthServerUrl() + "/realms/FROST-Test/clients-registrations/install/" + KEYCLOAK_FROST_CLIENT_ID);
SERVER_PROPERTIES.put("auth_keycloakConfigSecret", KEYCLOAK_FROST_CONFIG_SECRET);
SERVER_PROPERTIES.put("auth_allowAnonymousRead", "false");
+ SERVER_PROPERTIES.put("auth_registerUserLocally", "true");
+ SERVER_PROPERTIES.put("plugins.coreModel.idType", "LONG");
+ SERVER_PROPERTIES.put("plugins.modelLoader.enable", "true");
+ SERVER_PROPERTIES.put("plugins.modelLoader.modelPath", "");
+ SERVER_PROPERTIES.put("plugins.modelLoader.modelFiles", modelUrl("Role.json") + ", " + modelUrl("UserNoPass.json"));
+ SERVER_PROPERTIES.put("plugins.modelLoader.liquibasePath", "target/test-classes/finegrainedsecurity/liquibase");
+ SERVER_PROPERTIES.put("plugins.modelLoader.liquibaseFiles", "tablesSecurityUPR.xml");
+ SERVER_PROPERTIES.put("plugins.modelLoader.idType.Role", "STRING");
+ SERVER_PROPERTIES.put("plugins.modelLoader.idType.User", "STRING");
+ SERVER_PROPERTIES.put("persistence.idGenerationMode.Role", "ClientGeneratedOnly");
+ SERVER_PROPERTIES.put("persistence.idGenerationMode.User", "ClientGeneratedOnly");
}
public KeyCloakTests(ServerVersion version) {
@@ -59,7 +108,29 @@ public KeyCloakTests(ServerVersion version) {
@Override
protected void setUpVersion() {
LOGGER.info("Setting up for version {}.", version.urlPart);
+ sMdl = mdlSensing;
super.setUpVersion();
+ USERS.clear();
+ USERS.add(mdlUsers.newUser("c8e84639-9914-4b1e-b756-349afed255f6", null));
+ USERS.add(mdlUsers.newUser("1d6b3bb2-a869-4686-b781-c1ea481e6085", null));
+ USERS.add(mdlUsers.newUser("74fe01f1-2ecc-4696-87f0-340ee3fe1a86", null));
+ }
+
+ @Test
+ void test_100_ReadUser() {
+ LOGGER.info(" test_100_ReadUser");
+ testFilterResults(serviceAdmin, mdlUsers.etUser, "", USERS);
+ filterForException(serviceAnon, mdlUsers.etUser, "", AuthTestHelper.HTTP_CODE_403_FORBIDDEN);
+ }
+
+ @Override
+ protected SensorThingsService createService() {
+ try {
+ return new SensorThingsService(baseService.getModelRegistry())
+ .setEndpoint(new URL(serverSettings.getServiceUrl(version)));
+ } catch (MalformedURLException ex) {
+ throw new IllegalArgumentException("Serversettings contains malformed URL.", ex);
+ }
}
@Override
diff --git a/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/util/EntityUtils.java b/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/util/EntityUtils.java
index e431f0911..ac1491d26 100644
--- a/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/util/EntityUtils.java
+++ b/FROST-Server.Tests/src/test/java/de/fraunhofer/iosb/ilt/statests/util/EntityUtils.java
@@ -135,6 +135,10 @@ public static void deleteAll(SensorThingsService service) throws ServiceFailureE
deleteAll(service.dao(mr.getEntityTypeForName("Thing")));
}
for (de.fraunhofer.iosb.ilt.frostclient.model.EntityType et : mr.getEntityTypes()) {
+ if ("user".equalsIgnoreCase(et.entityName)) {
+ // Can't usually delete users.
+ continue;
+ }
try {
deleteAll(service.dao(et));
} catch (NotFoundException exc) {
diff --git a/FROST-Server.Tests/src/test/resources/finegrainedsecurity/liquibase/tablesSecurityUPR.xml b/FROST-Server.Tests/src/test/resources/finegrainedsecurity/liquibase/tablesSecurityUPR.xml
index 7e01102dc..1c52ce386 100644
--- a/FROST-Server.Tests/src/test/resources/finegrainedsecurity/liquibase/tablesSecurityUPR.xml
+++ b/FROST-Server.Tests/src/test/resources/finegrainedsecurity/liquibase/tablesSecurityUPR.xml
@@ -20,6 +20,38 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -46,6 +78,34 @@
onDelete="CASCADE" onUpdate="CASCADE" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -64,8 +124,7 @@
-
+
@@ -77,8 +136,7 @@
-
+
-
+
diff --git a/FROST-Server.Tests/src/test/resources/finegrainedsecurity/model/UserNoPass.json b/FROST-Server.Tests/src/test/resources/finegrainedsecurity/model/UserNoPass.json
new file mode 100644
index 000000000..65f95a367
--- /dev/null
+++ b/FROST-Server.Tests/src/test/resources/finegrainedsecurity/model/UserNoPass.json
@@ -0,0 +1,52 @@
+{
+ "conformance": [],
+ "simplePropertyTypes": [],
+ "entityTypes": [
+ {
+ "name": "User",
+ "plural": "Users",
+ "adminOnly": false,
+ "table": "USERS",
+ "entityProperties": [
+ {
+ "name": "username",
+ "type": "Id",
+ "handlers": [
+ {
+ "@class": "de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.fieldmapper.FieldMapperId",
+ "field": "USER_NAME"
+ }
+ ],
+ "annotations": []
+ }
+ ],
+ "navigationProperties": [
+ {
+ "name": "Roles",
+ "entitySet": true,
+ "entityType": "Role",
+ "required": false,
+ "inverse": {
+ "name": "Users",
+ "entitySet": true,
+ "required": false,
+ "annotations": []
+ },
+ "handlers": [
+ {
+ "@class": "de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.fieldmapper.FieldMapperManyToMany",
+ "field": "USER_NAME",
+ "linkTable": "USER_ROLES",
+ "linkOurField": "USER_NAME",
+ "linkOtherField": "ROLE_NAME",
+ "otherTable": "ROLES",
+ "otherField": "ROLE_NAME"
+ }
+ ],
+ "annotations": []
+ }
+ ],
+ "annotations": []
+ }
+ ]
+}