# HG changeset patch
# User casties
# Date 1332339837 -3600
# Node ID 9393c9c9b91677c5b6e93bbc3a973578853dc73d
# Parent 2e5d526079de0f2b89e46bb76cad714b40362dc9
saves annotations now!
diff -r 2e5d526079de -r 9393c9c9b916 .classpath
--- a/.classpath Wed Mar 21 11:09:20 2012 +0100
+++ b/.classpath Wed Mar 21 15:23:57 2012 +0100
@@ -42,7 +42,11 @@
-
-
+
+
+
+
+
+
diff -r 2e5d526079de -r 9393c9c9b916 WebContent/WEB-INF/web.xml.template
--- a/WebContent/WEB-INF/web.xml.template Wed Mar 21 11:09:20 2012 +0100
+++ b/WebContent/WEB-INF/web.xml.template Wed Mar 21 15:23:57 2012 +0100
@@ -4,38 +4,36 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
-RESTfulJavaWebServices-Restlet
-
-
-org.restlet.application
-de.mpiwg.itgroup.annotationManager.restlet.RestServer
-
-
-
-de.mpiwg.itgroup.annotationManager.jaas.configFilePath
-file:///etc/jaasAuth.conf
-
-
-
-de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreUser
-USERNAME
-
-
-
-de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreUserPassword
-PASSWORD
-
-
-
-RestletServlet
-
-org.restlet.ext.servlet.ServerServlet
-
-
-
-
-
-RestletServlet
-/annotator/*
-
+ RESTfulJavaWebServices-Restlet
+
+
+ org.restlet.application
+ de.mpiwg.itgroup.annotationManager.restlet.RestServer
+
+
+ de.mpiwg.itgroup.annotationManager.jaas.configFilePath
+ file:///etc/jaasAuth.conf
+
+
+ de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreUser
+ USERNAME
+
+
+ de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreUserPassword
+ PASSWORD
+
+
+ de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreConnectionURL
+ jdbc:virtuoso://virtuoso.mpiwg-berlin.mpg.de:1111
+
+
+
+ RestletServlet
+ org.restlet.ext.servlet.ServerServlet
+
+
+
+ RestletServlet
+ /annotator/*
+
\ No newline at end of file
diff -r 2e5d526079de -r 9393c9c9b916 src/de/mpiwg/itgroup/annotationManager/RDFHandling/Convert.java
--- a/src/de/mpiwg/itgroup/annotationManager/RDFHandling/Convert.java Wed Mar 21 11:09:20 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/RDFHandling/Convert.java Wed Mar 21 15:23:57 2012 +0100
@@ -298,7 +298,10 @@
String user = context.getParameters().getFirstValue("de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreUser");
String pw = context.getParameters().getFirstValue("de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreUserPassword");
String connectionURL = context.getParameters().getFirstValue("de.mpiwg.itgroup.annotationManager.virtuoso.tripleStoreConnectionURL");
-
+ if (user == null || pw == null || connectionURL == null) {
+ logger.error(String.format("Missing triplestore parameters! (user=%s pw=%s url=%s)", user, pw, connectionURL));
+ throw new TripleStoreStoreError();
+ }
//TripleStoreHandler th = new TripleStoreHandler("jdbc:virtuoso://virtuoso.mpiwg-berlin.mpg.de:1111", user, pw);
TripleStoreHandler th = new TripleStoreHandler(connectionURL, user, pw);
diff -r 2e5d526079de -r 9393c9c9b916 src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorAnnotations.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorAnnotations.java Wed Mar 21 11:09:20 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorAnnotations.java Wed Mar 21 15:23:57 2012 +0100
@@ -51,7 +51,7 @@
*/
@Get("json")
public Representation doGetJSON(Representation entity) {
-
+ logger.debug("AnnotatorAnnotations doGetJSON!");
doOptions(entity);
// TODO: what to do with authentication?
boolean authenticated = isAuthenticated(entity);
@@ -73,9 +73,9 @@
results = new JSONArray();
for (Convert.Annotation annot : annots) {
- JSONObject jo = annot2AnnotatorJSON(annot);
+ JSONObject jo = createAnnotatorJson(annot);
if (jo != null) {
- results.put(annot2AnnotatorJSON(annot));
+ results.put(createAnnotatorJson(annot));
} else {
setStatus(Status.SERVER_ERROR_INTERNAL, "JSon Error");
return null;
@@ -98,22 +98,27 @@
}
/**
- * POST with JSON content-type. json hash: username: name des users xpointer: xpointer auf den Ausschnitt (incl. der URL des
+ * POST with JSON content-type.
+ *
+ * json hash: username: name des users xpointer: xpointer auf den Ausschnitt (incl. der URL des
* Dokumentes) text: text der annotation annoturl: url auf eine Annotation falls extern
*
* @return
*/
@Post("json")
public Representation doPostJson(Representation entity) {
- JsonRepresentation jrep;
- Annotation annot;
+ logger.debug("AnnotatorAnnotations doPostJSON!");
+ // set headers
+ setCorsHeaders();
+ Annotation annot = null;
try {
- jrep = new JsonRepresentation(entity);
+ JsonRepresentation jrep = new JsonRepresentation(entity);
JSONObject jo = jrep.getJsonObject();
if (jo == null) {
setStatus(Status.SERVER_ERROR_INTERNAL);
return null;
}
+ // get Annotation object from posted JSON
annot = createAnnotation(jo, entity);
} catch (IOException e1) {
setStatus(Status.SERVER_ERROR_INTERNAL);
@@ -122,19 +127,21 @@
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return null;
}
- if (annot.xpointer == null || annot.creator == null) {
+ if (annot == null || annot.xpointer == null || annot.creator == null) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return null;
}
- Annotation retVal;
+ Annotation storedAnnot;
try {
- retVal = new Convert("file:///annotations").storeAnnotation(annot);
+ // store Annotation
+ storedAnnot = new Convert("file:///annotations").storeAnnotation(annot);
} catch (TripleStoreStoreError e) {
e.printStackTrace();
setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error");
return null;
}
- JSONObject jo = annot2AnnotatorJSON(retVal);
+ // return stored annotation
+ JSONObject jo = createAnnotatorJson(storedAnnot);
JsonRepresentation retRep = new JsonRepresentation(jo);
return retRep;
}
@@ -147,6 +154,7 @@
*/
@Post("html")
public Representation doPostHtml(Representation entity) {
+ logger.debug("AnnotatorAnnotations doPostHtml!");
Convert.Annotation annot;
annot = handleForm(entity);
if (annot.xpointer == null || annot.creator == null) {
@@ -177,16 +185,15 @@
return retRep;
}
-
/**
*
- * @param entity should contain a form with the parameters "username", "password", "xpointer","text","uri","type"
- *
- * username,password is optional, if not given BasicAuthentification is used.
+ * @param entity
+ * should contain a form with the parameters "username", "password", "xpointer","text","uri","type"
*
- *
+ * username,password is optional, if not given BasicAuthentification is used.
*
- * If username given as a URI, the username will be transformed to an URI, username will be added to the MPIWG namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
+ * If username given as a URI, the username will be transformed to an URI, username will be added to the MPIWG
+ * namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
*
* @return
*/
@@ -213,7 +220,7 @@
User authUser = null;
if (userFromForm == null) {
- authUser = handleBasicAuthentification(entity);
+ authUser = getHttpAuthUser(entity);
}
// weder BasicAuth noch FormAuth
@@ -228,17 +235,17 @@
username = authUser.getIdentifier();
}
- //username should be a URI, if not it will set to the MPIWG namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
- String usernameOrig=username;
+ // username should be a URI, if not it will set to the MPIWG namespace defined in
+ // de.mpiwg.itgroup.annotationManager.Constants.NS
+ String usernameOrig = username;
if (!username.startsWith("http"))
- username=NS.MPIWG_PERSONS+username;
-
- if (mode.equals("complexAnnotation")){// Annotation mit text in externer ressource
-
+ username = NS.MPIWG_PERSONS + username;
+
+ if (mode.equals("complexAnnotation")) {// Annotation mit text in externer ressource
+
Context context = getContext();
String drupalPath = context.getParameters().getFirstValue("de.mpiwg.itgroup.annotationManager.drupalServer");
-
-
+
AnnotationHandler ah = new AnnotationHandler(drupalPath);
JSONObject newAnnot;
try {
@@ -249,7 +256,7 @@
return null;
}
try {
- annot= new Convert.Annotation(xpointer, username, null, text, type, newAnnot.getString("node_uri"));
+ annot = new Convert.Annotation(xpointer, username, null, text, type, newAnnot.getString("node_uri"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -257,8 +264,7 @@
return null;
}
} else
- annot = new Convert.Annotation(xpointer, username, null, text,
- type, url);
+ annot = new Convert.Annotation(xpointer, username, null, text, type, url);
return annot;
}
diff -r 2e5d526079de -r 9393c9c9b916 src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorResourceImpl.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorResourceImpl.java Wed Mar 21 11:09:20 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorResourceImpl.java Wed Mar 21 15:23:57 2012 +0100
@@ -20,6 +20,7 @@
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import org.restlet.data.ClientInfo;
import org.restlet.data.Form;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
@@ -45,12 +46,45 @@
}
/**
+ * returns a hex String of a SHA256 digest of text.
+ *
+ * @param text
+ * @return
+ */
+ public String getSha256Digest(String text) {
+ String digest = null;
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(text.getBytes("UTF-8"));
+ byte[] dg = md.digest();
+ StringBuffer sb = new StringBuffer();
+ for (byte b : dg) {
+ sb.append(String.format("%02x", b));
+ }
+ digest = sb.toString();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return digest;
+ }
+
+ /**
* Handle options request to allow CORS for AJAX.
*
* @param entity
*/
@Options
public void doOptions(Representation entity) {
+ logger.debug("AnnotatorResourceImpl doOptions!");
+ setCorsHeaders();
+ }
+
+ /**
+ * set headers to allow CORS for AJAX.
+ */
+ protected void setCorsHeaders() {
Form responseHeaders = (Form) getResponse().getAttributes().get("org.restlet.http.headers");
if (responseHeaders == null) {
responseHeaders = new Form();
@@ -80,49 +114,42 @@
* @return
*/
public boolean isAuthenticated(Representation entity) {
- // get authToken
+ return (checkAuthToken(entity) != null);
+ }
+
+ /**
+ * checks Annotator Auth plugin authentication information from headers. returns userId if successful.
+ *
+ * @param entity
+ * @return
+ */
+ public String checkAuthToken(Representation entity) {
Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers");
String consumerKey = requestHeaders.getFirstValue("x-annotator-consumer-key", true);
if (consumerKey == null) {
- return false;
+ return null;
}
+ // get stored consumer secret for key
RestServer restServer = (RestServer) getApplication();
String consumerSecret = restServer.getConsumerSecret(consumerKey);
logger.debug("requested consumer key=" + consumerKey + " secret=" + consumerSecret);
if (consumerSecret == null) {
- return false;
+ return null;
}
String userId = requestHeaders.getFirstValue("x-annotator-user-id", true);
String issueTime = requestHeaders.getFirstValue("x-annotator-auth-token-issue-time", true);
if (userId == null || issueTime == null) {
- return false;
+ return null;
}
// compute hashed token based on the values we know
// computed_token = hashlib.sha256(consumer.secret + user_id + issue_time).hexdigest()
- String computedToken;
- try {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- String computedString = consumerSecret + userId + issueTime;
- md.update(computedString.getBytes("UTF-8"));
- byte[] dg = md.digest();
- StringBuffer sb = new StringBuffer();
- for (byte b : dg) {
- sb.append(String.format("%02x", b));
- }
- computedToken = sb.toString();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- return false;
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- return false;
- }
+ String computedToken = getSha256Digest(consumerSecret + userId + issueTime);
// compare to the token we got
String authToken = requestHeaders.getFirstValue("x-annotator-auth-token", true);
logger.debug(String.format("got: authToken=%s consumerSecret=%s userId=%s issueTime=%s", authToken, consumerSecret, userId,
issueTime));
if (!computedToken.equals(authToken)) {
- return false;
+ return null;
}
// check token lifetime
// validity = iso8601.parse_date(issue_time)
@@ -140,10 +167,10 @@
e.printStackTrace();
}
if (tokenValidity == null || tokenValidity.isAfterNow() || tokenExpiry.isBeforeNow()) {
- return false;
+ return null;
}
// must be ok then
- return true;
+ return userId;
}
/**
@@ -152,36 +179,45 @@
* @param annot
* @return
*/
- public JSONObject annot2AnnotatorJSON(Convert.Annotation annot) {
+ public JSONObject createAnnotatorJson(Convert.Annotation annot) {
+ boolean makeUserObject = true;
JSONObject jo = new JSONObject();
try {
jo.put("text", annot.text);
jo.put("uri", annot.url);
- JSONObject userObject = new JSONObject();
- userObject.put("id", annot.creator);
-
- RestServer restServer = (RestServer) getApplication();
-
- String userID = annot.creator;
- if (userID.startsWith(NS.MPIWG_PERSONS)) {
- userID = userID.replace(NS.MPIWG_PERSONS, ""); // entferne NAMESPACE
+ if (makeUserObject) {
+ // create user object
+ JSONObject userObject = new JSONObject();
+ // save creator as uri
+ userObject.put("uri", annot.creator);
+ // make short user id
+ String userID = annot.creator;
+ if (userID.startsWith(NS.MPIWG_PERSONS)) {
+ userID = userID.replace(NS.MPIWG_PERSONS, ""); // entferne NAMESPACE
+ }
+ // save as id
+ userObject.put("id", userID);
+ // get full name
+ RestServer restServer = (RestServer) getApplication();
+ String userName = restServer.getUserNameFromLdap(userID);
+ userObject.put("name", userName);
+ // save user object
+ jo.put("user", userObject);
+ } else {
+ // save user as string
+ jo.put("user", annot.creator);
}
- String userName = restServer.getUserNameFromLdap(userID);
- userObject.put("name", userName);
- jo.put("user", userObject);
-
- List xpointer = new ArrayList();
-
+ List xpointers = new ArrayList();
if (annot.xpointers == null || annot.xpointers.size() == 0)
- xpointer.add(annot.xpointer);
+ xpointers.add(annot.xpointer);
else {
for (String xpointerString : annot.xpointers) {
- xpointer.add(xpointerString);
+ xpointers.add(xpointerString);
}
}
- jo.put("ranges", transformToRanges(xpointer));
+ jo.put("ranges", transformToRanges(xpointers));
jo.put("id", annot.annotationUri);
return jo;
} catch (JSONException e) {
@@ -235,56 +271,56 @@
}
/**
- * creates an Annotation object with data from JSON.
- * uses the specification from the annotator project.
+ * creates an Annotation object with data from JSON.
+ *
+ * uses the specification from the annotator project: {@link https://github.com/okfn/annotator/wiki/Annotation-format}
*
- * @see{https://github.com/okfn/annotator/wiki/Annotation-format}
+ * The username will be transformed to an URI if not given already as URI, if not it will set to the MPIWG namespace defined in
+ * de.mpiwg.itgroup.annotationManager.Constants.NS
*
- * The username will be transformed to an URI if not given already
- * as URI, if not it will set to the MPIWG namespace defined in
- * de.mpiwg.itgroup.annotationManager.Constants.NS
* @param jo
* @return
* @throws JSONException
*/
public Convert.Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException {
- Convert.Annotation annot;
String url = jo.getString("uri");
String text = jo.getString("text");
-
- String username = null;
- if (jo.has("user")) {
- // not required, if no username given authuser
- // will be used otherwise username and password
- // has to be submitted
- JSONObject user = jo.getJSONObject("user");
- if (user.has("id")) {
- username = user.getString("id");
- if (!user.has("password")) {
- User authUser = handleBasicAuthentification(entity);
- if (authUser == null) {
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return null;
- }
- username = authUser.getIdentifier();
- } else {
- String password = user.getString("password");
- if (!((RestServer) getApplication()).authenticate(username, password, getRequest())) {
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return null;
- }
- }
- }
-
- } else {
- User authUser = handleBasicAuthentification(entity);
- if (authUser == null) {
+
+ // check authentication
+ String authUser = checkAuthToken(entity);
+ if (authUser == null) {
+ // try http auth
+ User httpUser = getHttpAuthUser(entity);
+ if (httpUser == null) {
setStatus(Status.CLIENT_ERROR_FORBIDDEN);
return null;
}
- username = authUser.getIdentifier();
+ authUser = httpUser.getIdentifier();
}
-
+ // username not required, if no username given authuser will be used
+ String username = null;
+ String userUri = null;
+ if (jo.has("user")) {
+ if (jo.get("user") instanceof String) {
+ // user is just a String
+ username = jo.getString("user");
+ // TODO: what if username and authUser are different?
+ } else {
+ // user is an object
+ JSONObject user = jo.getJSONObject("user");
+ if (user.has("id")) {
+ username = user.getString("id");
+ }
+ if (user.has("uri")) {
+ userUri = user.getString("uri");
+ }
+ }
+ }
+ if (username == null) {
+ username = authUser;
+ }
+
+ // create xpointer
String xpointer;
if (jo.has("ranges")) {
JSONObject ranges = jo.getJSONArray("ranges").getJSONObject(0);
@@ -292,7 +328,7 @@
String end = ranges.getString("end");
String startOffset = ranges.getString("startOffset");
String endOffset = ranges.getString("endOffset");
-
+
try {
xpointer = url
+ "#"
@@ -307,13 +343,36 @@
} else {
xpointer = url;
}
-
+
// username should be a URI, if not it will set to the MPIWG namespace defined in
// de.mpiwg.itgroup.annotationManager.Constants.NS
- if (!username.startsWith("http"))
- username = NS.MPIWG_PERSONS + username;
-
- return new Convert.Annotation(xpointer, username, null, text, null);
+ if (userUri == null) {
+ if (username.startsWith("http")) {
+ userUri = username;
+ } else {
+ userUri = NS.MPIWG_PERSONS + username;
+ }
+ }
+ return new Convert.Annotation(xpointer, userUri, null, text, null);
+ }
+
+ /**
+ * returns the logged in User.
+ *
+ * @param entity
+ * @return
+ */
+ protected User getHttpAuthUser(Representation entity) {
+ RestServer restServer = (RestServer) getApplication();
+ if (!restServer.authenticate(getRequest(), getResponse())) {
+ // Not authenticated
+ return null;
+ }
+
+ ClientInfo ci = getRequest().getClientInfo();
+ logger.debug(ci);
+ return getRequest().getClientInfo().getUser();
+
}
}
diff -r 2e5d526079de -r 9393c9c9b916 src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorSearch.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorSearch.java Wed Mar 21 11:09:20 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorSearch.java Wed Mar 21 15:23:57 2012 +0100
@@ -69,9 +69,9 @@
ja = new JSONArray();
for (Convert.Annotation annot : annots) {
- JSONObject jo = annot2AnnotatorJSON(annot);
+ JSONObject jo = createAnnotatorJson(annot);
if (jo != null) {
- ja.put(annot2AnnotatorJSON(annot));
+ ja.put(createAnnotatorJson(annot));
} else {
setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error");
return null;
diff -r 2e5d526079de -r 9393c9c9b916 src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java Wed Mar 21 11:09:20 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java Wed Mar 21 15:23:57 2012 +0100
@@ -186,8 +186,8 @@
Router router = new Router(getContext());
- router.attach("/annotations", AddAndReadAnnotations.class);
- router.attach("/search", AnnotatorSearch.class); // annotator api askes
+ router.attach("/annotator/annotations", AnnotatorAnnotations.class);
+ router.attach("/annotator/search", AnnotatorSearch.class); // annotator api askes
// for different uris
// for search and
// adding