Implemented initial super client registration for user authentication.
Change-Id: I60a7396bef8c2f9b2c2e8bf1cb6e0d5018c79408
diff --git a/core/Changes b/core/Changes
index 1926b51..43d6a0b 100644
--- a/core/Changes
+++ b/core/Changes
@@ -3,6 +3,7 @@
- Added OAuth2 scopes: INSTALL_USER_CLIENT, UNINSTALL_USER_CLIENT
- Added status codes
- Implemented searching option using a network endpoint
+ - Updated JsonUtils
# version 0.67.1
diff --git a/core/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java b/core/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java
index b018688..792a6bb 100644
--- a/core/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java
+++ b/core/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java
@@ -2,6 +2,7 @@
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -46,8 +47,7 @@
"Failed deserializing json object: " + json, json, e);
}
}
-
-
+
public static ObjectNode createObjectNode () {
return mapper.createObjectNode();
}
@@ -71,6 +71,10 @@
return mapper.readValue(json, cl);
}
+ public static <T> T read (InputStream is, Class<T> cl) throws IOException {
+ return mapper.readValue(is, cl);
+ }
+
public static <T> T readFile (String path, Class<T> clazz)
throws IOException {
@@ -78,7 +82,7 @@
}
- public static void writeFile (String path, String content)
+ public static void writeFile (String path, Object content)
throws IOException {
mapper.writeValue(new File(path), content);
}
diff --git a/full/Changes b/full/Changes
index 049a39f..c2adc2a 100644
--- a/full/Changes
+++ b/full/Changes
@@ -19,7 +19,7 @@
service paths under /plugins.
2022-06-03
- Implemented searching option using a network endpoint
-
+ - Implemented initial super client registration for user authentication.
# version 0.67.1
diff --git a/full/src/main/java/de/ids_mannheim/de/init/Initializator.java b/full/src/main/java/de/ids_mannheim/de/init/Initializator.java
index 2062e20..bea303e 100644
--- a/full/src/main/java/de/ids_mannheim/de/init/Initializator.java
+++ b/full/src/main/java/de/ids_mannheim/de/init/Initializator.java
@@ -6,10 +6,12 @@
import org.springframework.beans.factory.annotation.Autowired;
import de.ids_mannheim.korap.annotation.FreeResourceParser;
+import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.config.NamedVCLoader;
import de.ids_mannheim.korap.constant.OAuth2Scope;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.oauth2.dao.AccessScopeDao;
+import de.ids_mannheim.korap.oauth2.service.OAuth2InitClientService;
import de.ids_mannheim.korap.util.QueryException;
/**
@@ -19,7 +21,7 @@
* @author margaretha
*
*/
-public class Initializator{
+public class Initializator {
@Autowired
private AccessScopeDao accessScopeDao;
@@ -27,20 +29,33 @@
private NamedVCLoader vcLoader;
@Autowired
private FreeResourceParser resourceParser;
-
+ @Autowired
+ private FullConfiguration config;
+ @Autowired
+ private OAuth2InitClientService clientService;
+
public Initializator () {}
public void init () throws IOException, QueryException, KustvaktException {
setInitialAccessScope();
resourceParser.run();
+
+ if (config.createInitialSuperClient()) {
+ clientService.createInitialSuperClient(
+ OAuth2InitClientService.OUTPUT_FILENAME);
+ }
+
Thread t = new Thread(vcLoader);
t.start();
}
public void initTest () throws IOException, KustvaktException {
setInitialAccessScope();
+ if (config.createInitialSuperClient()) {
+ clientService.createInitialTestSuperClient();
+ }
}
-
+
public void initResourceTest () throws IOException, KustvaktException {
setInitialAccessScope();
resourceParser.run();
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
index 32f98f8..77108d8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
@@ -92,6 +92,8 @@
private String rsaKeyId;
private String namedVCPath;
+
+ private boolean createInitialSuperClient;
public FullConfiguration (Properties properties) throws Exception {
super(properties);
@@ -127,7 +129,6 @@
config.setMaxBytesLocalDisk(properties.getProperty("cache.max.bytes.local.disk", "2G"));
jlog.info("max local heap:"+config.getMaxBytesLocalHeapAsString());
jlog.info("max local disk:"+config.getMaxBytesLocalDiskAsString());
-
}
private void setSecurityConfiguration (Properties properties) {
@@ -247,6 +248,8 @@
"oauth2.password.authentication", "TEST")));
setNativeClientHost(properties.getProperty("oauth2.native.client.host",
"korap.ids-mannheim.de"));
+ setCreateInitialSuperClient(Boolean.valueOf(
+ properties.getProperty("oauth2.initial.super.client", "false")));
setMaxAuthenticationAttempts(Integer
.parseInt(properties.getProperty("oauth2.max.attempts", "1")));
@@ -674,4 +677,14 @@
public void setRefreshTokenLongExpiry (int refreshTokenLongExpiry) {
this.refreshTokenLongExpiry = refreshTokenLongExpiry;
}
+
+ public boolean createInitialSuperClient () {
+ return createInitialSuperClient;
+ }
+
+ public void setCreateInitialSuperClient (boolean initialSuperClient) {
+ this.createInitialSuperClient = initialSuperClient;
+ }
+
+
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2InitClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2InitClientService.java
new file mode 100644
index 0000000..e35b0e4
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2InitClientService.java
@@ -0,0 +1,110 @@
+package de.ids_mannheim.korap.oauth2.service;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.interfaces.EncryptionIface;
+import de.ids_mannheim.korap.oauth2.dao.OAuth2ClientDao;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientDto;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
+
+@Service
+public class OAuth2InitClientService {
+
+ private static Logger log =
+ LogManager.getLogger(OAuth2InitClientService.class);
+ public static String OAUTH2_CLIENT_JSON_INPUT_FILE =
+ "initial_super_client.json";
+ public static String OUTPUT_FOLDER = "client";
+ public static String OUTPUT_FILENAME = "super_client_info";
+ public static String TEST_OUTPUT_FILENAME = "test_super_client_info";
+
+ @Autowired
+ private OAuth2ClientService clientService;
+ @Autowired
+ private OAuth2ClientDao clientDao;
+ @Autowired
+ private EncryptionIface encryption;
+
+ public void createInitialSuperClient (String outputFilename)
+ throws IOException, KustvaktException {
+
+ File dir = new File(OUTPUT_FOLDER);
+ if (!dir.exists()) {
+ dir.mkdir();
+ }
+
+ String path = OUTPUT_FOLDER + "/" + outputFilename;
+ File f = new File(path);
+
+ if (!f.exists()) {
+ OAuth2ClientJson json = readOAuth2ClientJsonFile();
+ OAuth2ClientDto clientDto =
+ clientService.registerClient(json, "system");
+ String clientId = clientDto.getClient_id();
+ OAuth2Client client = clientService.retrieveClient(clientId);
+ client.setSuper(true);
+ clientDao.updateClient(client);
+ JsonUtils.writeFile(path, clientDto);
+
+ log.info(
+ "Initial super client has been successfully registered. See "+path);
+ }
+ else {
+ JsonNode node = JsonUtils.readFile(path, JsonNode.class);
+ String existingClientId = node.at("/client_id").asText();
+ String clientSecret = node.at("/client_secret").asText();
+ String secretHashcode = encryption.secureHash(clientSecret);
+
+ try {
+ clientService.retrieveClient(existingClientId);
+ log.info(
+ "Super client info file exists. Initial super client "
+ + "registration is cancelled.");
+ }
+ catch (Exception e) {
+ log.info("Super client info file exists but the client "
+ + "doesn't exist in the database.");
+ OAuth2ClientJson json = readOAuth2ClientJsonFile();
+ OAuth2ClientDto clientDto =
+ clientService.registerClient(json, "system");
+ String clientId = clientDto.getClient_id();
+ OAuth2Client client = clientService.retrieveClient(clientId);
+ client.setSuper(true);
+ client.setId(existingClientId);
+ client.setSecret(secretHashcode);
+ clientDao.updateClient(client);
+ }
+ }
+ }
+
+ private OAuth2ClientJson readOAuth2ClientJsonFile () throws IOException, KustvaktException {
+ File f = new File(OAUTH2_CLIENT_JSON_INPUT_FILE);
+ if (f.exists()) {
+ return JsonUtils.readFile(OAUTH2_CLIENT_JSON_INPUT_FILE,
+ OAuth2ClientJson.class);
+ }
+ else {
+ InputStream is = getClass().getClassLoader()
+ .getResourceAsStream("json/"+OAUTH2_CLIENT_JSON_INPUT_FILE);
+ return JsonUtils.read(is, OAuth2ClientJson.class);
+ }
+
+ }
+
+ public void createInitialTestSuperClient ()
+ throws IOException, KustvaktException {
+ createInitialSuperClient(TEST_OUTPUT_FILENAME);
+ }
+}
diff --git a/full/src/main/resources/json/initial_super_client.json b/full/src/main/resources/json/initial_super_client.json
new file mode 100644
index 0000000..a8c997b
--- /dev/null
+++ b/full/src/main/resources/json/initial_super_client.json
@@ -0,0 +1,5 @@
+{
+ "name":"initial super client",
+ "type": "CONFIDENTIAL",
+ "description":"initial super client for user authentication"
+}
\ No newline at end of file
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/InitialSuperClientTest.java b/full/src/test/java/de/ids_mannheim/korap/web/InitialSuperClientTest.java
new file mode 100644
index 0000000..46e2526
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/InitialSuperClientTest.java
@@ -0,0 +1,76 @@
+package de.ids_mannheim.korap.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.jersey.api.client.ClientResponse;
+
+import de.ids_mannheim.korap.config.FullConfiguration;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.dao.OAuth2ClientDao;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.oauth2.service.OAuth2InitClientService;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.controller.OAuth2TestBase;
+
+public class InitialSuperClientTest extends OAuth2TestBase {
+
+ @Autowired
+ private FullConfiguration config;
+ @Autowired
+ private OAuth2ClientDao clientDao;
+
+ private String path = OAuth2InitClientService.OUTPUT_FOLDER + "/"
+ + OAuth2InitClientService.TEST_OUTPUT_FILENAME;
+
+ @Test
+ public void testCreatingInitialSuperClient ()
+ throws IOException, KustvaktException {
+ assertTrue(config.createInitialSuperClient());
+
+ File f = new File(path);
+ assertTrue(f.exists());
+
+ JsonNode node = JsonUtils.readFile(path, JsonNode.class);
+ String superClientId = node.at("/client_id").asText();
+ String superClientSecret = node.at("/client_secret").asText();
+
+ OAuth2Client superClient = clientDao.retrieveClientById(superClientId);
+ assertTrue(superClient.isSuper());
+
+ testLogin(superClientId, superClientSecret);
+
+ removeSuperClientFile();
+ }
+
+ private void testLogin (String superClientId, String superClientSecret)
+ throws KustvaktException {
+ ClientResponse response = requestTokenWithPassword(superClientId,
+ superClientSecret, "username", "password");
+
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ assertTrue(!node.at("/access_token").isMissingNode());
+ assertTrue(!node.at("/refresh_token").isMissingNode());
+ assertTrue(!node.at("/expires_in").isMissingNode());
+ assertEquals("all", node.at("/scope").asText());
+ assertEquals("Bearer", node.at("/token_type").asText());
+ }
+
+ private void removeSuperClientFile () {
+ File f = new File(path);
+ if (f.exists()) {
+ f.delete();
+ }
+ }
+}
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index fb17890..e72b1fd 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -66,6 +66,8 @@
oauth2.default.scopes = search match_info
oauth2.client.credentials.scopes = client_info
+oauth2.initial.super.client=true
+
## OpenId
### multiple values are separated by space
openid.grant.types = authorization_code