Omitted foundry injection in empty span, fixed multiple license rewrite.

Change-Id: I6bbe809d35fc016eda8849c8c1e6cbe84eff9b4f
diff --git a/core/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java b/core/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java
index 1881db8..40cb90d 100644
--- a/core/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java
+++ b/core/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java
@@ -138,12 +138,12 @@
             if (!new DateTime(client.getJWTClaimsSet().getExpirationTimeClaim())
                     .isAfterNow())
                 throw new KustvaktException(StatusCodes.EXPIRED,
-                        "authentication token is expired", token);
+                        "Authentication token is expired", token);
         }
         catch (ParseException | JOSEException e) {
             //todo: message or entity, how to treat??!
             throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT,
-                    "token could not be verified", token);
+                    "Token could not be verified", token);
         }
         return client;
     }
diff --git a/core/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java b/core/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
index 7f19536..09d495f 100644
--- a/core/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
+++ b/core/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
@@ -56,7 +56,7 @@
     }
 
 
-    public abstract TokenContext getTokenStatus (TokenType type,
+    public abstract TokenContext getTokenContext (TokenType type,
             String token, String host, String useragent)
             throws KustvaktException;
 
diff --git a/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java b/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
index 23d2838..948ec50 100644
--- a/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
+++ b/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
@@ -42,8 +42,10 @@
             mapper = new LayerMapper(config);
             
         if (node.get("@type").equals("koral:span")) {
-            JsonNode term = rewriteQuery(node.at("/wrap"), config, user);
-            node.replaceAt("/wrap", term, new RewriteIdentifier("koral:term", "replace"));
+            if (!node.at("/wrap").rawNode().isMissingNode()){
+                JsonNode term = rewriteQuery(node.at("/wrap"), config, user);
+                node.replaceAt("/wrap", term, new RewriteIdentifier("koral:term", "replace"));
+            }
         }
         else if (node.get("@type").equals("koral:term") && !node.has("foundry")) {
             String layer;
diff --git a/full/pom.xml b/full/pom.xml
index 238fbc6..17df97e 100644
--- a/full/pom.xml
+++ b/full/pom.xml
@@ -30,7 +30,7 @@
 				<directory>src/test/resources</directory>
 				<filtering>true</filtering>
 				<includes>
-					<include>**/*.prop</include>
+					<include>**/*.token</include>
 					<include>**/*.xml</include>
 					<include>**/*.conf</include>
 					<include>**/*.info</include>
@@ -88,6 +88,7 @@
 					<excludes>
 						<exclude>de/ids_mannheim/korap/suites/*.java</exclude>
 						<exclude>de/ids_mannheim/korap/dao/*.java</exclude>
+						<exclude>de/ids_mannheim/korap/authentication/*.java</exclude>
 						<exclude>**/KustvaktServerTest.java</exclude>
 						<exclude>**/ResourceServiceTest.java</exclude>
 						<exclude>**/ResourceInfoServiceTest.java</exclude>
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/APIAuthentication.java b/full/src/main/java/de/ids_mannheim/korap/authentication/APIAuthentication.java
index 8c41ab0..7b7da01 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/APIAuthentication.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/APIAuthentication.java
@@ -22,7 +22,7 @@
  * 
  * Created by hanl on 5/23/14.
  */
-public abstract class APIAuthentication implements AuthenticationIface {
+public class APIAuthentication implements AuthenticationIface {
 
     private JWTSigner signedToken;
     private Cache invalided =
@@ -34,6 +34,13 @@
         this.signedToken = new JWTSigner(config.getSharedSecret(),
                 config.getIssuer(), config.getTokenTTL());
     }
+    
+    /** EM: for testing
+     * @param signedToken
+     */
+    public APIAuthentication (JWTSigner signedToken) {
+        this.signedToken = signedToken;
+    }
 
     @Override
     public TokenContext getTokenContext (String authToken)
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
index 0b98f76..528b8a1 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
@@ -98,7 +98,7 @@
 	 * @throws KustvaktException
 	 */
 	@Override
-	public TokenContext getTokenStatus(TokenType type, String token, 
+	public TokenContext getTokenContext(TokenType type, String token, 
 	        String host, String useragent) throws KustvaktException {
 
 		AuthenticationIface provider = getProvider(type , null);
@@ -109,11 +109,6 @@
 			        "token type not defined or found", "token_type");
 
 		TokenContext context = provider.getTokenContext(token);
-		if (context != null && TimeUtils.isExpired(context.getExpirationTime()))
-			throw new KustvaktException(StatusCodes.EXPIRED);
-		else if (context == null)
-			throw new KustvaktException(StatusCodes.NO_RESULT_FOUND);
-
 		// if (!matchStatus(host, useragent, context))
 		// provider.removeUserSession(token);
 		return context;
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 2474a5a..4f6c541 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
@@ -1,18 +1,18 @@
 package de.ids_mannheim.korap.config;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 import java.util.regex.Pattern;
 
-import lombok.Getter;
-
 /** Configuration for Kustvakt full version including properties concerning
  *  authentication and licenses. 
  * 
  * @author margaretha
  *
  */
-@Getter
+
 public class FullConfiguration extends KustvaktConfiguration {
 
     private String ldapConfig;
@@ -21,6 +21,10 @@
     private String publicOnlyRegex;
     private String allOnlyRegex;
 
+    private List<String> freeRegexList;
+    private List<String> publicRegexList;
+    private List<String> allRegexList;
+
     private Pattern publicLicensePattern;
     private Pattern freeLicensePattern;
     private Pattern allLicensePattern;
@@ -45,18 +49,39 @@
     }
 
     private void setLicensePatterns (Properties properties) {
-        freeLicensePattern = compilePattern(freeOnlyRegex);
-        publicLicensePattern =
-                compilePattern(freeOnlyRegex + "|" + publicOnlyRegex);
-        allLicensePattern = compilePattern(
-                freeOnlyRegex + "|" + publicOnlyRegex + "|" + allOnlyRegex);
+        setFreeLicensePattern(compilePattern(freeOnlyRegex));
+        setPublicLicensePattern(
+                compilePattern(freeOnlyRegex + "|" + publicOnlyRegex));
+        setAllLicensePattern(compilePattern(
+                freeOnlyRegex + "|" + publicOnlyRegex + "|" + allOnlyRegex));
     }
 
     private void setLicenseRegex (Properties properties) {
         freeOnlyRegex = properties.getProperty("availability.regex.free", "");
+        freeRegexList = splitAndAddToList(freeOnlyRegex);
+
         publicOnlyRegex =
                 properties.getProperty("availability.regex.public", "");
+        publicRegexList = splitAndAddToList(publicOnlyRegex);
+
         allOnlyRegex = properties.getProperty("availability.regex.all", "");
+        allRegexList = splitAndAddToList(allOnlyRegex);
+    }
+
+    private List<String> splitAndAddToList (String regex) {
+        List<String> list;
+        if (regex.contains("|")) {
+            String[] regexes = regex.split("\\|");
+            list = new ArrayList<>(regexes.length);
+            for (String s : regexes) {
+                list.add(s.trim());
+            }
+        }
+        else{
+            list = new ArrayList<>(1);
+            list.add(regex);
+        }
+        return list;
     }
 
 
@@ -69,4 +94,64 @@
         }
     }
 
+    public String getLdapConfig () {
+        return ldapConfig;
+    }
+
+    public Pattern getPublicLicensePattern () {
+        return publicLicensePattern;
+    }
+
+    public void setPublicLicensePattern (Pattern publicLicensePattern) {
+        this.publicLicensePattern = publicLicensePattern;
+    }
+
+    public Pattern getFreeLicensePattern () {
+        return freeLicensePattern;
+    }
+
+    public void setFreeLicensePattern (Pattern freeLicensePattern) {
+        this.freeLicensePattern = freeLicensePattern;
+    }
+
+    public Pattern getAllLicensePattern () {
+        return allLicensePattern;
+    }
+
+    public void setAllLicensePattern (Pattern allLicensePattern) {
+        this.allLicensePattern = allLicensePattern;
+    }
+
+    public String getAuthenticationScheme () {
+        return authenticationScheme;
+    }
+
+    public void setAuthenticationScheme (String authenticationScheme) {
+        this.authenticationScheme = authenticationScheme;
+    }
+
+    public List<String> getFreeRegexList () {
+        return freeRegexList;
+    }
+
+    public void setFreeRegexList (List<String> freeRegexList) {
+        this.freeRegexList = freeRegexList;
+    }
+
+    public List<String> getPublicRegexList () {
+        return publicRegexList;
+    }
+
+    public void setPublicRegexList (List<String> publicRegexList) {
+        this.publicRegexList = publicRegexList;
+    }
+
+    public List<String> getAllRegexList () {
+        return allRegexList;
+    }
+
+    public void setAllRegexList (List<String> allRegexList) {
+        this.allRegexList = allRegexList;
+    }
+
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
index 44388dd..2cc465c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
+++ b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
@@ -116,16 +116,16 @@
         List<String> userAvailabilities = new ArrayList<String>();
         switch (user.getCorpusAccess()) {
             case PUB:
-                userAvailabilities.add(fullConfig.getFreeOnlyRegex());
-                userAvailabilities.add(fullConfig.getPublicOnlyRegex());
+                userAvailabilities.addAll(fullConfig.getFreeRegexList());
+                userAvailabilities.addAll(fullConfig.getPublicRegexList());
                 break;
             case ALL:
-                userAvailabilities.add(fullConfig.getFreeOnlyRegex());
-                userAvailabilities.add(fullConfig.getPublicOnlyRegex());
-                userAvailabilities.add(fullConfig.getAllOnlyRegex());
+                userAvailabilities.addAll(fullConfig.getFreeRegexList());
+                userAvailabilities.addAll(fullConfig.getPublicRegexList());
+                userAvailabilities.addAll(fullConfig.getAllRegexList());
                 break;
             case FREE:
-                userAvailabilities.add(fullConfig.getFreeOnlyRegex());
+                userAvailabilities.addAll(fullConfig.getFreeRegexList());
                 break;
         }
 
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 a6df6a8..75ef3cc 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
@@ -17,13 +17,14 @@
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.user.TokenContext;
+import de.ids_mannheim.korap.utils.TimeUtils;
 import de.ids_mannheim.korap.web.FullResponseHandler;
 import de.ids_mannheim.korap.web.utils.KustvaktContext;
 
 /**
  * @author hanl, margaretha
  * @date 28/01/2014
- * @last update 7/12/2017
+ * @last update 12/2017
  */
 @Component
 @Provider
@@ -34,7 +35,7 @@
     private HttpAuthorizationHandler authorizationHandler;
 
     @Autowired
-    private AuthenticationManagerIface userController;
+    private AuthenticationManagerIface authenticationManager;
 
     @Autowired
     private FullResponseHandler kustvaktResponseHandler;
@@ -53,19 +54,21 @@
             try {
                 authData = authorizationHandler
                         .parseAuthorizationHeaderValue(authorization);
+
                 switch (authData.getAuthenticationScheme()) {
                     case BASIC:
-                        context = userController.getTokenStatus(TokenType.BASIC,
-                                authData.getToken(), host, ua);
+                        context = authenticationManager.getTokenContext(
+                                TokenType.BASIC, authData.getToken(), host, ua);
                         break;
                     case SESSION:
-                        context = userController.getTokenStatus(TokenType.SESSION,
-                                authData.getToken(), host, ua);
+                        context = authenticationManager.getTokenContext(
+                                TokenType.SESSION, authData.getToken(), host,
+                                ua);
                         break;
                     // EM: bearer or api
                     default:
-                        context = userController.getTokenStatus(TokenType.API,
-                                authData.getToken(), host, ua);
+                        context = authenticationManager.getTokenContext(
+                                TokenType.API, authData.getToken(), host, ua);
                         break;
                 }
                 checkContext(context, request);
@@ -94,6 +97,10 @@
             throw new KustvaktException(StatusCodes.AUTHENTICATION_FAILED,
                     "Request is not secure.");
         }
+        else if (TimeUtils.isExpired(context.getExpirationTime())) {
+            throw new KustvaktException(StatusCodes.EXPIRED,
+                    "Login is expired.");
+        }
     }
 
 
diff --git a/full/src/main/resources/kustvakt.conf b/full/src/main/resources/kustvakt.conf
index 8e8a59c..ee3bb7d 100644
--- a/full/src/main/resources/kustvakt.conf
+++ b/full/src/main/resources/kustvakt.conf
@@ -18,6 +18,7 @@
 default.layer.c = corenlp
 
 ## availability regex
+## only support |
 availability.regex.free = CC-BY.*
 availability.regex.public = ACA.* | QAO.NC
 availability.regex.all = QAO.*
diff --git a/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java b/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java
new file mode 100644
index 0000000..b1d43fa
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java
@@ -0,0 +1,48 @@
+package de.ids_mannheim.korap.authentication;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.KustvaktConfiguration;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.config.TokenType;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.user.KorAPUser;
+import de.ids_mannheim.korap.user.TokenContext;
+import de.ids_mannheim.korap.user.User;
+
+public class APIAuthenticationTest extends SpringJerseyTest {
+
+    @Autowired
+    private KustvaktConfiguration config;
+
+    @Test
+    public void testCreateGetTokenContext ()
+            throws KustvaktException, IOException, InterruptedException {
+        User user = new KorAPUser();
+        user.setUsername("testUser");
+
+        Map<String, Object> attr = new HashMap<>();
+        attr.put(Attributes.HOST, "localhost");
+        attr.put(Attributes.USER_AGENT, "java");
+
+        APIAuthentication auth = new APIAuthentication(config);
+        TokenContext context = auth.createTokenContext(user, attr);
+
+        // get token context
+        String authToken = context.getToken();
+        context = auth.getTokenContext(authToken);
+
+        TokenType tokenType = context.getTokenType();
+        assertEquals(TokenType.API, tokenType);
+        assertEquals("testUser", context.getUsername());
+    }
+
+}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java b/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
index e174d02..cb83753 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
@@ -3,6 +3,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -18,6 +22,7 @@
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.AuthenticationScheme;
 import de.ids_mannheim.korap.config.SpringJerseyTest;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -29,7 +34,6 @@
     private HttpAuthorizationHandler handler;
 
     @Test
-    //    @Ignore
     public void testStoreVC () throws KustvaktException {
         String json =
                 "{\"name\": \"new vc\",\"type\": \"PRIVATE\",\"createdBy\": "
@@ -37,8 +41,8 @@
 
         ClientResponse response = resource().path("vc").path("store")
                 .header(Attributes.AUTHORIZATION,
-                        handler.createBasicAuthorizationHeaderValue(
-                                "user","pass"))
+                        handler.createBasicAuthorizationHeaderValue("user",
+                                "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
                 .post(ClientResponse.class);
         String entity = response.getEntity(String.class);
@@ -46,6 +50,31 @@
     }
 
     @Test
+    public void testStoreVCWithExpiredToken () throws IOException, KustvaktException {
+        String json =
+                "{\"name\": \"new vc\",\"type\": \"PRIVATE\",\"createdBy\": "
+                        + "\"test class\",\"collectionQuery\": \"corpusSigle=GOE\"}";
+
+        InputStream is = getClass().getClassLoader().getResourceAsStream("test-user.token");
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+
+        String authToken = reader.readLine();
+        
+        ClientResponse response = resource().path("vc").path("store")
+                .header(Attributes.AUTHORIZATION,
+                        AuthenticationScheme.API.displayName() + " "
+                                + authToken)
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
+                .post(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.EXPIRED, node.at("/errors/0/0").asInt());
+        assertEquals("Authentication token is expired",
+                node.at("/errors/0/1").asText());
+    }
+
+    @Test
     public void testStoreVCUnauthorized () throws KustvaktException {
         String json =
                 "{\"name\": \"new vc\",\"type\": \"PRIVATE\",\"createdBy\": "
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index b16b08e..082817d 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -23,6 +23,7 @@
 default.layer.c = corenlp
 
 ## availability regex
+## only support |
 availability.regex.free = CC-BY.*
 availability.regex.public = ACA.* | QAO-NC
 availability.regex.all = QAO.*
@@ -50,6 +51,7 @@
 security.validation.stringLength = 150
 security.validation.emailLength = 50
 security.encryption.algo=BCRYPT
+security.sharedSecret=testSecret
 
 ## applicable: rewrite, foundry, filter, deny
 security.rewrite.strategies=filter, foundry, rewrite
\ No newline at end of file
diff --git a/full/src/test/resources/test-user.token b/full/src/test/resources/test-user.token
new file mode 100644
index 0000000..665b76d
--- /dev/null
+++ b/full/src/test/resources/test-user.token
@@ -0,0 +1 @@
+eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MTMwOTYwMjA0NjYsInN1YiI6InRlc3RVc2VyIiwiaXNzIjoiaHR0cDpcL1wva29yYXAuaWRzLW1hbm5oZWltLmRlIn0.n4BhCXsFMizEHepNK5AnF32a3kxyvgiesth74ZHimEY
\ No newline at end of file