Merge remote-tracking branch 'origin/master' into new-index
Conflicts:
src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
src/main/java/de/ids_mannheim/korap/user/User.java
src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
Change-Id: I2067b58c279c98915beb0a85462a6f3ea5744f36
diff --git a/src/main/java/de/ids_mannheim/korap/config/Attributes.java b/src/main/java/de/ids_mannheim/korap/config/Attributes.java
index 1789e61..07fc6ab 100644
--- a/src/main/java/de/ids_mannheim/korap/config/Attributes.java
+++ b/src/main/java/de/ids_mannheim/korap/config/Attributes.java
@@ -10,6 +10,9 @@
public static final String OPENID_AUTHENTICATION = "id_token";
public static final String BASIC_AUTHENTICATION = "basic";
+ public static final String LOCATION = "location"; // location of Client: User.INTERN/EXTERN
+ public static final String CORPUS_ACCESS = "corpusAccess"; // User.ALL/PUB/FREE.
+
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
public static final String SCOPES = "scopes";
diff --git a/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java b/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
index 86d6d60..ac16556 100644
--- a/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
+++ b/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
@@ -56,53 +56,50 @@
* getAccount(): KorAPUser: Account muss vorhanden sein.
* DemoUser, DefaultUser: Account nicht vorhanden.
*/
-// @Override
-// public User getAccount (String username) throws KustvaktException {
-//
-// Map<String, String> namedParameters = Collections.singletonMap("username", username);
-// final String sql = "select a.* from korap_users as a where a.username=:username;";
-// User user = null;
-//
-// try {
-// user = this.jdbcTemplate.queryForObject(sql, namedParameters,
-// new RowMapperFactory.UserMapper());
-// return user;
-// }
-// catch (EmptyResultDataAccessException ae) {
-// jlog.warn("No user found for name '{}'", username);
-// // if no username, so return a DemoUser , FB.
-// // return User.UserFactory.getDemoUser();
-// return UserFactory.getDemoUser();
-// }
-// catch (DataAccessException e) {
-// jlog.warn("Could not retrieve user for name: " + username, e);
-//
-// /* DemoUser and DefaultUser have no account,
-// * so it's ok they are not found.
-// throw new DatabaseException(username, "korap_users",
-// StatusCodes.DB_GET_FAILED,
-// "Could not retrieve the user with username: " + username,
-// username);
-// */
-// }
-//
-// // DemoUser or DefaultUser?
-//
-// { // User cannot be found in SQL DB since LDAP Authentication,
-// // so create a User Object here.
-// // TODO: what more data should be stored into it?
-// // 28.04.17/FB
-// user = new KorAPUser(); // oder eigentlich new DemoUser oder new DefaultUser.
-// user.setUsername(username);
-// return user;
-// }
-//
-//
-// }
+ @Override
+ public User getAccount (String username) throws KustvaktException {
+
+ Map<String, String> namedParameters = Collections.singletonMap("username", username);
+ final String sql = "select a.* from korap_users as a where a.username=:username;";
+ User user = null;
+
+ try {
+ user = this.jdbcTemplate.queryForObject(sql, namedParameters,
+ new RowMapperFactory.UserMapper());
+ return user;
+ }
+ catch (EmptyResultDataAccessException ae) {
+ jlog.warn("No user found for name '{}'", username);
+ }
+ catch (DataAccessException e) {
+ jlog.warn("Could not retrieve user for name: " + username, e);
+
+ /* DemoUser and DefaultUser have no account,
+ * so it's ok they are not found.
+ throw new DatabaseException(username, "korap_users",
+ StatusCodes.DB_GET_FAILED,
+ "Could not retrieve the user with username: " + username,
+ username);
+ */
+ }
+
+ // DemoUser or DefaultUser?
+
+ { // User cannot be found in SQL DB since LDAP Authentication,
+ // so create a User Object here.
+ // TODO: what more data should be stored into it?
+ // 28.04.17/FB
+ user = new KorAPUser(); // oder eigentlich new DemoUser oder new DefaultUser.
+ user.setUsername(username);
+ return user;
+ }
+
+
+ } // getAccount()
// usersettings are fetched plus basic account info, no details, since i rarely use them anyway! (by Hanl)
/* Version before LDAP Authentication - 09.05.17/FB
- @Deprecated */
+ @Deprecated
@Override
public User getAccount (String username) throws KustvaktException {
@@ -129,7 +126,7 @@
}
return user;
}
-
+ */
@Override
public int updateAccount (User user) throws KustvaktException {
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
index e110a5b..f7bc10d 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
@@ -1,5 +1,6 @@
package de.ids_mannheim.korap.interfaces;
+import de.ids_mannheim.korap.config.Attributes;
import de.ids_mannheim.korap.config.KustvaktCacheable;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.user.TokenContext;
@@ -10,6 +11,8 @@
import java.util.Map;
import java.util.Set;
+import javax.ws.rs.core.HttpHeaders;
+
/**
* @author hanl
* @date 15/06/2015
@@ -68,6 +71,7 @@
Map<String, Object> attr, String provider_key)
throws KustvaktException;
+ public abstract void setAccessAndLocation(User user, HttpHeaders headers);
public abstract void logout (TokenContext context) throws KustvaktException;
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
index e4c0022..6fcae2f 100644
--- a/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
@@ -33,10 +33,9 @@
if (subnode.has("collection")) {
builder.setBaseQuery(JsonUtils.toJSON(subnode));
}
- // EM
- // fix me: later store the collection queries as KoralQuery in the database
+
switch (user.getCorpusAccess()) {
- case PUBLIC:
+ case PUB:
builder = new KoralCollectionQueryBuilder();
builder.with("availability = /CC-BY.*/ | availablity = /ACA.*/");
break;
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java b/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
index 43440f3..b083a9b 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
@@ -1,6 +1,7 @@
package de.ids_mannheim.korap.security.auth;
import com.sun.org.apache.xpath.internal.SourceTree;
+
import de.ids_mannheim.korap.auditing.AuditRecord;
import de.ids_mannheim.korap.config.Attributes;
import de.ids_mannheim.korap.config.BeansFactory;
@@ -17,23 +18,37 @@
import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
import de.ids_mannheim.korap.interfaces.defaults.ApacheValidator;
import de.ids_mannheim.korap.user.*;
+import de.ids_mannheim.korap.user.User.Location;
import de.ids_mannheim.korap.user.User.CorpusAccess;
import de.ids_mannheim.korap.utils.StringUtils;
import de.ids_mannheim.korap.utils.TimeUtils;
import de.ids_mannheim.korap.security.auth.LdapAuth3;
+
+import javax.ws.rs.core.HttpHeaders;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+
// import com.novell.ldap.*; search() funktioniert nicht korrekt, ausgewechselt gegen unboundID's Bibliothek 20.04.17/FB
//Using JAR from unboundID:
import com.unboundid.ldap.sdk.LDAPException;
+
+
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import javax.ws.rs.core.MultivaluedMap;
+
/**
* contains the logic to authentication and registration processes.
* Uses
@@ -190,7 +205,60 @@
return user;
}
-
+ // a. set location depending on X-Forwarded-For.
+ // X-Forwarded-For: clientIP, ProxyID, ProxyID...
+ // the following private address spaces may be used to define intranet spaces:
+ // 10.0.0.0 - 10.255.255.255 (10/8 prefix)
+ // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
+ // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
+ // b. set corpusAccess depending on location:
+ // 16.05.17/FB
+
+ @Override
+ public void setAccessAndLocation(User user, HttpHeaders headers)
+
+ {
+ Boolean DEBUG_LOG = true;
+ MultivaluedMap<String,String> headerMap = headers.getRequestHeaders();
+ Location location = Location.INTERN;
+ CorpusAccess corpusAccess = CorpusAccess.FREE;
+
+ if( headerMap != null && headerMap.size() > 0 )
+ {
+ Iterator<String> it = headerMap.keySet().iterator();
+ while( it.hasNext() )
+ {
+ String key = (String)it.next();
+ if( key.equals("X-Forwarded-For"))
+ {
+ List<String> vals = new ArrayList<String>(Arrays.asList(headerMap.getFirst(key).split(",")));
+ String clientAddress = vals.get(0);
+
+ if( clientAddress.startsWith("10.0.") || clientAddress.startsWith("172.16.") || clientAddress.startsWith("192.168."))
+ location = Location.INTERN;
+ else
+ location = Location.EXTERN;
+ if( location == Location.EXTERN )
+ corpusAccess = CorpusAccess.PUB;
+ else
+ corpusAccess = CorpusAccess.ALL;
+
+ if( DEBUG_LOG == true )
+ {
+ System.out.printf("Debug: X-Forwarded-For : '%s' (%d values) -> %s\n", vals, vals.size(), vals.get(0));
+ System.out.printf("Debug: X-Forwarded-For : location = %s corpusAccess = %s\n",
+ location == Location.INTERN ? "INTERN" : "EXTERN",
+ corpusAccess == CorpusAccess.ALL ? "ALL" : corpusAccess == CorpusAccess.PUB ? "PUB" : "FREE");
+ }
+ }
+ }
+ }
+
+ user.setLocation(location);
+ user.setCorpusAccess(corpusAccess);
+
+ } // getAccess
+
@Override
public TokenContext createTokenContext (User user,
Map<String, Object> attr, String provider_key)
@@ -417,6 +485,14 @@
// DefaultUser sonst.
User user = new KorAPUser();
user.setUsername(username);
+ /* folgender Code funktioniert hier noch nicht, da die Headers noch nicht ausgewertet
+ * worden sind - 23.05.17/FB
+ Object o = attr.get(Attributes.LOCATION);
+ String loc = (String)o.toString();
+ int location = Integer.parseInt(loc);
+ user.setLocation(location);
+ user.setCorpusAccess(Integer.parseInt(attr.get(Attributes.CORPUS_ACCESS).toString()));
+ */
unknown = user;
jlog.trace("Authentication: found username " + unknown.getUsername());
diff --git a/src/main/java/de/ids_mannheim/korap/user/User.java b/src/main/java/de/ids_mannheim/korap/user/User.java
index 68e59ac..5846b73 100644
--- a/src/main/java/de/ids_mannheim/korap/user/User.java
+++ b/src/main/java/de/ids_mannheim/korap/user/User.java
@@ -45,15 +45,28 @@
private List<Userdata> userdata;
private boolean isAdmin;
-
- private CorpusAccess corpusAccess = CorpusAccess.FREE;
-
+
+ // Values for corpusAccess:
public enum CorpusAccess {
- FREE, // without login
- PUBLIC, // extern
- ALL; // intern
- }
-
+ FREE, // Access to licence free corpora only, without login
+ PUB, // Access to public (= öffentliche Korpora) only, externes Login.
+ ALL // Access to all corpora, internes Login.
+ };
+
+ @Getter
+ @Setter
+ private CorpusAccess corpusAccess = CorpusAccess.FREE;
+
+ // values for location (set using the X-forwarded-for Header):
+ public enum Location {
+ INTERN, // KorAP accessed by internal Client (inside intranet).
+ EXTERN // KorAP accessed by external Client (outside intranet).
+ };
+
+ @Getter
+ @Setter
+ private Location location = Location.EXTERN;
+
protected User () {
this.fields = new ParamFields();
@@ -62,7 +75,8 @@
this.username = "";
this.id = -1;
this.userdata = new ArrayList<>();
- this.corpusAccess = CorpusAccess.FREE;
+ this.location = Location.EXTERN;
+ this.corpusAccess = CorpusAccess.FREE;
}
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
index ee63565..c2fa34d 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
@@ -26,10 +26,12 @@
import javax.xml.ws.handler.MessageContext; // FB
import javax.annotation.Resource; // FB
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.ArrayList;
import java.util.Iterator; // 07.02.17/FB
//import com.sun.xml.internal.messaging.saaj.util.Base64;
@@ -43,7 +45,7 @@
@Produces(MediaType.TEXT_HTML + ";charset=utf-8")
public class AuthService {
- private static Boolean DEBUG_LOG = false;
+ private static Boolean DEBUG_LOG = true;
//todo: bootstrap function to transmit certain default configuration settings and examples (example user queries,
// default usersettings, etc.)
@@ -148,7 +150,7 @@
}
System.out.printf("Debug: requestAPIToken: isSecure = %s.\n", secCtx.isSecure() ? "yes" : "no");
} // DEBUG_LOG
-
+
// "Invalid syntax for username and password"
if (values == null)
throw KustvaktResponseHandler
@@ -164,6 +166,7 @@
attr.put(Attributes.SCOPES, scopes);
attr.put(Attributes.HOST, host);
attr.put(Attributes.USER_AGENT, agent);
+
TokenContext context;
try {
// User user = controller.authenticate(0, values[0], values[1], attr); Implementation by Hanl
@@ -171,6 +174,10 @@
// Userdata data = this.controller.getUserData(user, UserDetails.class); // Implem. by Hanl
// todo: is this necessary?
// attr.putAll(data.fields());
+ controller.setAccessAndLocation(user, headers);
+
+ attr.put(Attributes.LOCATION, user.getLocation());
+ attr.put(Attributes.CORPUS_ACCESS, user.getCorpusAccess());
context = controller.createTokenContext(user, attr, Attributes.API_AUTHENTICATION);
}
catch (KustvaktException e) {
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
index 3d9e186..c877b04 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
@@ -17,6 +17,7 @@
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -468,11 +469,14 @@
}
+ // was heißt search by name all? FB
@SuppressWarnings("unchecked")
@GET
@Path("search")
- public Response searchbyNameAll (@Context SecurityContext securityContext,
- @Context Locale locale, @QueryParam("q") String q,
+ public Response searchbyNameAll (
+ @Context SecurityContext securityContext,
+ @Context HttpHeaders headers,
+ @Context Locale locale, @QueryParam("q") String q,
@QueryParam("ql") String ql, @QueryParam("v") String v,
@QueryParam("context") String ctx,
@QueryParam("cutoff") Boolean cutoff,
@@ -487,8 +491,8 @@
User user;
try {
user = controller.getUser(context.getUsername());
- // EM: set user.corpusAccess, default is CorpusAccess.FREE
- }
+ controller.setAccessAndLocation(user, headers);
+ }
catch (KustvaktException e) {
jlog.error("Failed retrieving user in the search service: {}",
e.string());
@@ -1102,6 +1106,7 @@
// EM: legacy support
// should be deprecated after a while
+ /*
@GET
@Path("/corpus/{corpusId}/{docId}/{matchId}/matchInfo")
public Response getMatchInfo (@Context SecurityContext ctx,
@@ -1122,12 +1127,16 @@
return getMatchInfo(ctx, locale, corpusId, ids[0], ids[1], matchId, foundries, layers, spans);
}
+ */
// fixme: only allowed for corpus?!
@GET
@Path("/corpus/{corpusId}/{docId}/{textId}/{matchId}/matchInfo")
- public Response getMatchInfo (@Context SecurityContext ctx,
- @Context Locale locale, @PathParam("corpusId") String corpusId,
+ public Response getMatchInfo (
+ @Context SecurityContext ctx,
+ @Context HttpHeaders headers,
+ @Context Locale locale,
+ @PathParam("corpusId") String corpusId,
@PathParam("docId") String docId,
@PathParam("textId") String textId,
@PathParam("matchId") String matchId,
@@ -1138,31 +1147,31 @@
TokenContext tokenContext = (TokenContext) ctx.getUserPrincipal();
spans = spans != null ? spans : false;
- String matchid = searchKrill.getMatchId(corpusId, docId, textId,
- matchId);
+ String matchid = searchKrill.getMatchId(corpusId, docId, textId, matchId);
if (layers == null || layers.isEmpty())
layers = new HashSet<>();
boolean match_only = foundries == null || foundries.isEmpty();
-// User user;
-// try {
-// user = controller.getUser(tokenContext.getUsername());
-// }
-// catch (KustvaktException e) {
-// jlog.error("Failed getting user in the matchInfo service: {}",
-// e.string());
-// throw KustvaktResponseHandler.throwit(e);
-// }
-// if (user instanceof DemoUser){
-// try {
-// ResourceFinder.searchPublicFiltered(Corpus.class, corpusId);
-// }
-// catch (KustvaktException e) {
-// throw KustvaktResponseHandler.throwit(e);
-// }
-// }
-//
+ User user;
+ try {
+ user = controller.getUser(tokenContext.getUsername());
+ controller.setAccessAndLocation(user, headers);
+ System.out.println("Debug: getMatchInfo: setting Access & Location: done.");
+ }
+ catch (KustvaktException e) {
+ jlog.error("Failed getting user in the matchInfo service: {}",
+ e.string());
+ throw KustvaktResponseHandler.throwit(e);
+ }
+ if (user instanceof DemoUser){
+ try {
+ ResourceFinder.searchPublicFiltered(Corpus.class, corpusId);
+ }
+ catch (KustvaktException e) {
+ throw KustvaktResponseHandler.throwit(e);
+ }
+ }
String results;
// // fixme: checks for policy matching
// // fixme: currently disabled, due to mishab in foundry/layer spec
@@ -1223,7 +1232,7 @@
CorpusAccess corpusAccess = CorpusAccess.FREE;
Pattern p;
switch (corpusAccess) {
- case PUBLIC:
+ case PUB:
p = config.getPublicLicensePattern();
break;
case ALL:
@@ -1263,7 +1272,6 @@
e.getMessage(), "");
}
jlog.debug("MatchInfo results: "+results);
-
return Response.ok(results).build();
}