Updated Krill version & added controller tests with OAuth2 access token.
Change-Id: Ib26d297a1446e5a4a6d6f4c5035b4e0a0e5f3fb9
diff --git a/full/Changes b/full/Changes
index a3308c8..0a58ea6 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,10 +1,11 @@
version 0.60.3
-09/05/2018
+30/05/2018
- improved user authentication by using authentication filter for authorization code request (margaretha)
- limited client authentication to client id checking in authorization code request (margaretha)
- - added user_id in the oauth2_access_token table (margaretha)
+ - added user_id in the oauth2_access_token database table (margaretha)
- implemented OAuth2Authentication provider for token context management (margaretha)
- added parameter checking for authorization DAO (margaretha)
+ - added controller tests using OAuth2 access token (margaretha)
version 0.60.2
03/05/2018
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java b/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java
index 68c815d..566d64b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java
@@ -36,7 +36,7 @@
if (accessToken.isRevoked()) {
throw new KustvaktException(StatusCodes.EXPIRED);
}
-
+
ZonedDateTime expiry =
accessToken.getCreatedDate().plusSeconds(config.getTokenTTL());
String scopes = scopeService
@@ -44,7 +44,7 @@
TokenContext c = new TokenContext();
c.setUsername(accessToken.getUserId());
- c.setExpirationTime(expiry.toEpochSecond());
+ c.setExpirationTime(expiry.toInstant().toEpochMilli());
c.setToken(authToken);
c.setTokenType(TokenType.BEARER);
c.addContextParameter(Attributes.SCOPES, scopes);
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java
index c2de972..dcc7499 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java
@@ -3,6 +3,7 @@
import java.util.Set;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
@@ -13,6 +14,7 @@
import org.springframework.transaction.annotation.Transactional;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.oauth2.entity.AccessScope;
import de.ids_mannheim.korap.oauth2.entity.AccessToken;
import de.ids_mannheim.korap.oauth2.entity.AccessToken_;
@@ -50,7 +52,8 @@
}
- public AccessToken retrieveAccessToken (String accessToken) {
+ public AccessToken retrieveAccessToken (String accessToken)
+ throws KustvaktException {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<AccessToken> query =
builder.createQuery(AccessToken.class);
@@ -58,6 +61,12 @@
query.select(root);
query.where(builder.equal(root.get(AccessToken_.token), accessToken));
Query q = entityManager.createQuery(query);
- return (AccessToken) q.getSingleResult();
+ try {
+ return (AccessToken) q.getSingleResult();
+ }
+ catch (NoResultException e) {
+ throw new KustvaktException(StatusCodes.INVALID_ACCESS_TOKEN,
+ "Access token is not found");
+ }
}
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
index 0c66a2f..51f8644 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
@@ -120,7 +120,7 @@
}
else if (TimeUtils.isExpired(context.getExpirationTime())) {
throw new KustvaktException(StatusCodes.EXPIRED,
- "Login is expired.");
+ "Access token is expired");
}
}
diff --git a/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql b/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
index b42ae28..2a203f3 100644
--- a/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
+++ b/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
@@ -31,4 +31,11 @@
"PUBLIC", 1, "http://korap.ids-mannheim.de/public", 1360724310,
"https://korap.ids-mannheim.de/public/redirect","system",
"This is a test native public client.");
+
+
+INSERT INTO oauth2_access_token(token,user_id)
+VALUES("249c64a77f40e2b5504982cc5521b596","dory");
+
+INSERT INTO oauth2_access_token(token,user_id,created_date)
+VALUES("fia0123ikBWn931470H8s5gRqx7Moc4p","marlin","2018-05-30 16:25:50")
\ No newline at end of file
diff --git a/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql b/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql
index d62e4df..c55d659 100644
--- a/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql
+++ b/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql
@@ -5,7 +5,7 @@
WHERE rowid = new.rowid;
END;
-CREATE TRIGGER insert_access_token_date AFTER INSERT ON oauth2_access_token
+CREATE TRIGGER insert_access_token_date BEFORE INSERT ON oauth2_access_token
BEGIN
UPDATE oauth2_access_token
SET created_date = DATETIME('now', 'localtime')
diff --git a/full/src/main/resources/default-config.xml b/full/src/main/resources/default-config.xml
index eef04e8..e3910dc 100644
--- a/full/src/main/resources/default-config.xml
+++ b/full/src/main/resources/default-config.xml
@@ -192,7 +192,7 @@
<constructor-arg ref="kustvakt_db" />
</bean>
- <bean id="kustvaktResponseHandler" class="de.ids_mannheim.korap.web.KustvaktExceptionHandler">
+ <bean id="kustvaktExceptionHandler" class="de.ids_mannheim.korap.web.KustvaktExceptionHandler">
<constructor-arg index="0" name="iface" ref="kustvakt_auditing" />
</bean>
@@ -249,13 +249,16 @@
ref="kustvakt_encryption" />
</bean>
+ <bean id="oauth2_auth"
+ class="de.ids_mannheim.korap.authentication.OAuth2Authentication" />
+
<util:list id="kustvakt_authproviders"
value-type="de.ids_mannheim.korap.interfaces.AuthenticationIface">
<ref bean="ldap_auth" />
<ref bean="session_auth" />
<!-- <ref bean="api_auth" /> -->
<ref bean="openid_auth" />
- <ref bean="client_auth" />
+ <ref bean="oauth2_auth" />
</util:list>
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java
index 927e3f0..98502ea 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java
@@ -169,14 +169,14 @@
- private ClientResponse builtSimpleClientResponse (String collectionQuery) {
+ private ClientResponse searchQuery (String collectionQuery) {
return resource().path("search").queryParam("q", "[orth=das]")
.queryParam("ql", "poliqarp").queryParam("cq", collectionQuery)
.get(ClientResponse.class);
}
- private ClientResponse builtClientResponseWithIP (String collectionQuery,
+ private ClientResponse searchQueryWithIP (String collectionQuery,
String ip) throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
return resource().path("search").queryParam("q", "[orth=das]")
@@ -192,7 +192,7 @@
@Test
public void testAvailabilityFreeAuthorized () throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability = CC-BY-SA");
+ searchQuery("availability = CC-BY-SA");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -205,7 +205,7 @@
public void testAvailabilityRegexFreeAuthorized ()
throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability = /.*BY.*/");
+ searchQuery("availability = /.*BY.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -216,7 +216,7 @@
@Test
public void testAvailabilityFreeUnauthorized () throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability = ACA-NC");
+ searchQuery("availability = ACA-NC");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -228,7 +228,7 @@
public void testAvailabilityRegexFreeUnauthorized ()
throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability = /ACA.*/");
+ searchQuery("availability = /ACA.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -237,7 +237,7 @@
@Test
public void testAvailabilityRegexNoRewrite () throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"availability = /CC-BY.*/ & availability = /ACA.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -266,7 +266,7 @@
public void testAvailabilityRegexFreeUnauthorized3 ()
throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability = /.*NC.*/");
+ searchQuery("availability = /.*NC.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
// System.out.println(response.getEntity(String.class));
@@ -279,7 +279,7 @@
public void testNegationAvailabilityFreeUnauthorized ()
throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability != /CC-BY.*/");
+ searchQuery("availability != /CC-BY.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -290,7 +290,7 @@
public void testNegationAvailabilityFreeUnauthorized2 ()
throws KustvaktException {
ClientResponse response =
- builtSimpleClientResponse("availability != /.*BY.*/");
+ searchQuery("availability != /.*BY.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -300,7 +300,7 @@
@Test
public void testNegationAvailabilityWithOperationOrUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"availability = /CC-BY.*/ | availability != /CC-BY.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -310,7 +310,7 @@
@Test
public void testComplexNegationAvailabilityFreeUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"textClass=politik & availability != /CC-BY.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -322,7 +322,7 @@
@Test
public void testComplexAvailabilityFreeUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"textClass=politik & availability=ACA-NC");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -334,7 +334,7 @@
@Test
public void testComplexAvailabilityFreeUnauthorized3 ()
throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"textClass=politik & availability=/.*NC.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -346,7 +346,7 @@
@Test
public void testAvailabilityPublicAuthorized () throws KustvaktException {
ClientResponse response =
- builtClientResponseWithIP("availability=ACA-NC", "149.27.0.32");
+ searchQueryWithIP("availability=ACA-NC", "149.27.0.32");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -356,7 +356,7 @@
@Test
public void testAvailabilityPublicUnauthorized () throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"availability=QAO-NC-LOC:ids", "149.27.0.32");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
@@ -369,7 +369,7 @@
@Test
public void testAvailabilityRegexPublicAuthorized ()
throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"availability= /ACA.*/", "149.27.0.32");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -381,7 +381,7 @@
@Test
public void testNegationAvailabilityPublicUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"availability != ACA-NC", "149.27.0.32");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -393,7 +393,7 @@
@Test
public void testNegationAvailabilityRegexPublicUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"availability != /ACA.*/", "149.27.0.32");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -405,7 +405,7 @@
@Test
public void testComplexAvailabilityPublicUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"textClass=politik & availability=QAO-NC-LOC:ids",
"149.27.0.32");
@@ -419,7 +419,7 @@
@Test
public void testNegationComplexAvailabilityPublicUnauthorized ()
throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"textClass=politik & availability!=QAO-NC-LOC:ids",
"149.27.0.32");
@@ -431,7 +431,7 @@
@Test
public void testAvailabilityRegexAllAuthorized () throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"availability= /ACA.*/", "10.27.0.32");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
@@ -441,7 +441,7 @@
@Test
public void testAvailabilityOr () throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"availability=/CC-BY.*/ | availability=/ACA.*/");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
@@ -452,7 +452,7 @@
@Test
public void testRedundancyOrPub () throws KustvaktException {
- ClientResponse response = builtClientResponseWithIP(
+ ClientResponse response = searchQueryWithIP(
"availability=/CC-BY.*/ | availability=/ACA.*/ | availability=/QAO-NC/",
"149.27.0.32");
@@ -467,7 +467,7 @@
@Test
public void testAvailabilityOrCorpusSigle () throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"availability=/CC-BY.*/ | corpusSigle=GOE");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
@@ -478,7 +478,7 @@
@Test
public void testOrWithoutAvailability () throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse(
+ ClientResponse response = searchQuery(
"corpusSigle=GOE | textClass=politik");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
@@ -489,7 +489,7 @@
@Test
public void testWithoutAvailability () throws KustvaktException {
- ClientResponse response = builtSimpleClientResponse("corpusSigle=GOE");
+ ClientResponse response = searchQuery("corpusSigle=GOE");
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
new file mode 100644
index 0000000..00b1eb6
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
@@ -0,0 +1,108 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.ClientResponse.Status;
+
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+public class OAuth2AccessTokenTest extends SpringJerseyTest {
+
+ // test access token for username: dory
+ private static String testAccessToken;
+
+ @BeforeClass
+ public static void init () throws IOException {
+ InputStream is = OAuth2AccessTokenTest.class.getClassLoader()
+ .getResourceAsStream("test-oauth2.token");
+
+ try (BufferedReader reader =
+ new BufferedReader(new InputStreamReader(is));) {
+ testAccessToken = reader.readLine();
+ }
+ }
+
+ @Test
+ public void testListVC () throws KustvaktException {
+ ClientResponse response = resource().path("vc").path("list")
+ .header(Attributes.AUTHORIZATION, "Bearer " + testAccessToken)
+ .get(ClientResponse.class);
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ String entity = response.getEntity(String.class);
+ JsonNode node = JsonUtils.readTree(entity);
+ assertEquals(4, node.size());
+ }
+
+ @Test
+ public void testSearchWithOAuth2Token ()
+ throws KustvaktException, IOException {
+ ClientResponse response = resource().path("search")
+ .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
+ .header(Attributes.AUTHORIZATION, "Bearer " + testAccessToken)
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .get(ClientResponse.class);
+
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+
+ String ent = response.getEntity(String.class);
+ JsonNode node = JsonUtils.readTree(ent);
+ assertNotNull(node);
+ assertEquals(25, node.at("/matches").size());
+ }
+
+ @Test
+ public void testSearchWithUnknownToken ()
+ throws KustvaktException, IOException {
+ ClientResponse response = resource().path("search")
+ .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
+ .header(Attributes.AUTHORIZATION,
+ "Bearer ljsa8tKNRSczJhk20öhq92zG8z350")
+ .get(ClientResponse.class);
+
+ assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
+ response.getStatus());
+
+ String ent = response.getEntity(String.class);
+ JsonNode node = JsonUtils.readTree(ent);
+ assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
+ node.at("/errors/0/0").asInt());
+ assertEquals("Access token is not found", node.at("/errors/0/1").asText());
+ }
+
+ @Test
+ public void testSearchWithExpiredToken ()
+ throws KustvaktException, IOException {
+ ClientResponse response = resource().path("search")
+ .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
+ .header(Attributes.AUTHORIZATION,
+ "Bearer fia0123ikBWn931470H8s5gRqx7Moc4p")
+ .get(ClientResponse.class);
+
+ String ent = response.getEntity(String.class);
+
+ assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
+ response.getStatus());
+
+ JsonNode node = JsonUtils.readTree(ent);
+ assertEquals(StatusCodes.EXPIRED, node.at("/errors/0/0").asInt());
+ assertEquals("Access token is expired", node.at("/errors/0/1").asText());
+ }
+}
diff --git a/full/src/test/resources/test-config.xml b/full/src/test/resources/test-config.xml
index 964487a..75edbc4 100644
--- a/full/src/test/resources/test-config.xml
+++ b/full/src/test/resources/test-config.xml
@@ -252,6 +252,10 @@
<constructor-arg type="de.ids_mannheim.korap.interfaces.EncryptionIface"
ref="kustvakt_encryption" />
</bean>
+
+ <bean id="oauth2_auth"
+ class="de.ids_mannheim.korap.authentication.OAuth2Authentication" />
+
<util:list id="kustvakt_authproviders"
value-type="de.ids_mannheim.korap.interfaces.AuthenticationIface">
@@ -260,6 +264,7 @@
<ref bean="session_auth" />
<!-- <ref bean="api_auth" /> -->
<ref bean="openid_auth" />
+ <ref bean="oauth2_auth" />
</util:list>
diff --git a/full/src/test/resources/test-oauth2.token b/full/src/test/resources/test-oauth2.token
new file mode 100644
index 0000000..eb7b4af
--- /dev/null
+++ b/full/src/test/resources/test-oauth2.token
@@ -0,0 +1 @@
+249c64a77f40e2b5504982cc5521b596
\ No newline at end of file