package eu.geoknow.generator.rest;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.UUID;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.ws.rs.CookieParam;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.ontos.ldiw.vocabulary.LDIWO;
import eu.geoknow.generator.configuration.FrameworkConfiguration;
import eu.geoknow.generator.exceptions.InformationMissingException;
import eu.geoknow.generator.graphs.GraphsManager;
import eu.geoknow.generator.graphs.beans.Contribution;
import eu.geoknow.generator.graphs.beans.NamedGraph;
import eu.geoknow.generator.rdf.SecureRdfStoreManagerImpl;
import eu.geoknow.generator.users.FrameworkUserManager;
import eu.geoknow.generator.users.UserProfile;
/**
*
* @author alejandragarciarojas
*
* TODO: errors on the server are not given back to the client
*/
@Path("/session")
public class AuthorizedSessions {
private static final Logger log = Logger.getLogger(AuthorizedSessions.class);
private static final String jsonResponseFormat = "application/sparql-results+json";
private FrameworkUserManager frameworkUserManager;
private String sessionsGraph;
private String endpoint;
private SecureRdfStoreManagerImpl frameworkRdfStoreManager;
public AuthorizedSessions(@Context ServletContext context) throws ServletException,
InformationMissingException {
try {
frameworkUserManager = FrameworkConfiguration.getInstance().getFrameworkUserManager();
sessionsGraph = FrameworkConfiguration.getInstance().getAuthSessionsGraph();
endpoint = FrameworkConfiguration.getInstance().getAuthSparqlEndpoint();
frameworkRdfStoreManager = FrameworkConfiguration.getInstance().getSystemRdfStoreManager();
log.debug(this.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@PUT
@Produces(MediaType.APPLICATION_JSON)
public Response create(@CookieParam(value = "user") Cookie userc,
@CookieParam(value = "token") String token) {
/*
* authenticates the user, throw exception if failed
*/
UserProfile userProfile;
try {
// authenticates the user, throw exception if fail
userProfile = frameworkUserManager.validate(userc, token);
if (userProfile == null)
return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid credentials").build();
log.info(" user: " + userProfile.getUsername());
} catch (Exception e) {
log.error(e);
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
// TODO reuse an existing session token, if it exists?
/*
* generates a session for the user and stores it in the sessions graph <accountURI>
* LDIWO.sessionToken "1fe39ef0-6987-11e4-9803-0800200c9a66"^^xsd:string
*/
String sessionToken = UUID.randomUUID().toString();
String query =
"PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>" + "\n" + "INSERT DATA { GRAPH <"
+ sessionsGraph + "> { <" + userProfile.getAccountURI() + "> <" + LDIWO.sessionToken
+ "> \"" + sessionToken + "\"^^xsd:string . } }";
log.debug(query);
try {
frameworkRdfStoreManager.execute(query, jsonResponseFormat);
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
JsonObject body = new JsonObject();
body.addProperty("endpoint", "rest/session/" + sessionToken);
return Response.status(Response.Status.CREATED).entity(body.toString()).build();
}
@GET
@Path("{sessionToken}")
public Response get(@PathParam("sessionToken") String sessionToken, @Context UriInfo uriInfo,
@Context HttpHeaders headers) throws Exception {
MultivaluedMap<String, String> formParams = new MultivaluedHashMap<String, String>();
return post(sessionToken, uriInfo, formParams, headers);
}
@POST
@Path("{sessionToken}")
public Response post(@PathParam("sessionToken") String sessionToken, @Context UriInfo uriInfo,
MultivaluedMap<String, String> formParams, @Context HttpHeaders headers) throws Exception {
String username = "";
try {
username = getUser(sessionToken);
} catch (Exception e) {
log.error(e);
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
log.debug("user:" + username + "-");
if (username.equals(""))
return Response.status(Response.Status.NOT_FOUND).build();
UsernamePasswordCredentials credentials =
new UsernamePasswordCredentials(FrameworkConfiguration.getInstance()
.getWorkbenchSystemAdmin(), FrameworkConfiguration.getInstance()
.getWorkbenchSystemAdminPassword());
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, credentials);
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
// create post method and set parameters
HttpPost proxyMethod = new HttpPost(endpoint);
MultivaluedMap<String, String> requestHeaders = headers.getRequestHeaders();
log.debug("REQUEST HEADERS");
for (Entry<String, List<String>> entity : requestHeaders.entrySet()) {
log.debug(entity.getKey() + " -> " + entity.getValue());
if (entity.getKey().equals("cookie") || entity.getKey().equals("content-length"))
continue;
proxyMethod.addHeader(entity.getKey(), entity.getValue().get(0));
}
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
// when is GET we extract query params using uriInfo
for (Entry<String, List<String>> entity : uriInfo.getQueryParameters().entrySet())
postParameters.add(new BasicNameValuePair(entity.getKey(), entity.getValue().get(0)));
// when is POST we extract using formParams
for (String key : formParams.keySet())
postParameters.add(new BasicNameValuePair(key, formParams.getFirst(key)));
proxyMethod.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8"));
// create the httpclient and reads/wirtes repsponse
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
final CloseableHttpResponse response = httpClient.execute(proxyMethod, context);
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(OutputStream os) throws IOException, WebApplicationException {
// TODO Auto-generated method stub
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
int b;
while ((b = response.getEntity().getContent().read()) != -1) {
writer.write(b);
}
writer.flush();
}
};
return Response.ok(stream).build();
} catch (Exception e) {
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
// retuns response
}
private String getUser(String sessionToken) throws Exception {
/*
* retrieves form user that created that session and the rdfUser and paswword for that user
*/
String username = "";
String query =
"PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>" + "\n" + "SELECT ?user FROM <"
+ sessionsGraph + "> WHERE { ?user " + " <" + LDIWO.sessionToken + "> \""
+ sessionToken + "\"^^xsd:string .}";
String result = frameworkRdfStoreManager.execute(query, jsonResponseFormat);
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(result);
Iterator<JsonNode> bindingsIter = rootNode.path("results").path("bindings").elements();
if (bindingsIter.hasNext()) {
JsonNode bindingNode = bindingsIter.next();
username = bindingNode.get("user").path("value").textValue();
}
return username;
}
@DELETE
@Path("{sessionToken}")
public Response delete(@PathParam("sessionToken") String sessionToken, @CookieParam(
value = "user") Cookie userc, @CookieParam(value = "token") String token) {
/*
* authenticates the user, throw exception if failed
*/
UserProfile userProfile;
try {
// authenticates the user, throw exception if fail
userProfile = frameworkUserManager.validate(userc, token);
if (userProfile == null)
return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid credentials").build();
log.info(" user: " + userProfile.getUsername());
} catch (Exception e) {
log.error(e);
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
String query =
"DELETE { GRAPH <" + sessionsGraph + "> {?s ?p ?o .} } " + "WHERE { GRAPH <"
+ sessionsGraph + "> { ?s ?p ?o . FILTER(str(?o) = \"" + sessionToken + "\") } } ";
log.debug(query);
try {
log.info(frameworkRdfStoreManager.execute(query, jsonResponseFormat));
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
return Response.status(Response.Status.NO_CONTENT).build();
}
/**
* Update the metadata of a contributiuon
*
* @param sessionToken
* @param userc
* @param token
* @return
*/
@PUT
@Path("{sessionToken}")
public Response addContribution(@PathParam("sessionToken") String sessionToken,
Contribution contribution) {
/*
* Check that the session exists
*/
String username = "";
try {
username = getUser(sessionToken);
} catch (Exception e) {
log.error(e);
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
log.debug("user:" + username + "-");
if (username.equals(""))
return Response.status(Response.Status.UNAUTHORIZED).build();
try {
if (contribution.getDate() == null) {
// 2015-06-12T14:35:00
Calendar cal = GregorianCalendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
format.setCalendar(cal);
contribution.setDate(format.format(cal.getTime()));
}
GraphsManager manager = new GraphsManager();
NamedGraph graph = manager.addContribution(contribution);
Gson gson = new Gson();
String json = "{ \"namedgraph\" : " + gson.toJson(graph) + "}";
return Response.status(Response.Status.OK).entity(json).type(MediaType.APPLICATION_JSON)
.build();
} catch (Exception e) {
log.error(e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
}
}