diff --git a/pom.xml b/pom.xml index b4e881e..01fd07d 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,12 @@ runtime + + com.fasterxml.jackson.core + jackson-databind + 2.11.1 + + org.apache.olingo odata-commons-api diff --git a/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java b/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java index c1756f3..e34fa2a 100644 --- a/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java +++ b/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java @@ -87,6 +87,17 @@ public class GenericEntityCollectionProcessor implements EntityCollectionProcess EntityCollection entitySet = getData(edmEntitySet); // 3rd: create a serializer based on the requested format (json) + try + { + uriInfo.asUriInfoAll().getFormatOption().getFormat(); // If Format is given, then we will use what it has. + } + catch (Exception e) + { + responseFormat = ContentType.JSON; // If format is not set in the $format, then use JSON. + // There is some magic that will select XML if you're viewing from a browser or something which I'm bypassing here. + // If you want a different $format, explicitly state it. + } + ODataSerializer serializer = odata.createSerializer(responseFormat); // 4th: Now serialize the content: transform from the EntitySet object to InputStream diff --git a/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java b/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java index c861efc..1ee1570 100644 --- a/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java +++ b/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java @@ -175,13 +175,6 @@ public class RESOedmProvider extends CsdlAbstractEdmProvider List schemas = new ArrayList(); schemas.add(schema); - CsdlEnumType type = new CsdlEnumType(); - type.setMembers(new ArrayList()); - type.setName("EnumTest"); - type.setUnderlyingType(EdmPrimitiveTypeKind.Int64.getFullQualifiedName()); - - schema.getEnumTypes().add(type); - return schemas; } diff --git a/src/main/java/org/reso/service/security/BasicAuthProvider.java b/src/main/java/org/reso/service/security/providers/BasicAuthProvider.java similarity index 95% rename from src/main/java/org/reso/service/security/BasicAuthProvider.java rename to src/main/java/org/reso/service/security/providers/BasicAuthProvider.java index 16cb624..81fbe15 100644 --- a/src/main/java/org/reso/service/security/BasicAuthProvider.java +++ b/src/main/java/org/reso/service/security/providers/BasicAuthProvider.java @@ -1,7 +1,7 @@ -package org.reso.service.security; +package org.reso.service.security.providers; -import org.reso.service.servlet.RESOservlet; +import org.reso.service.security.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/reso/service/security/BearerAuthProvider.java b/src/main/java/org/reso/service/security/providers/BearerAuthProvider.java similarity index 95% rename from src/main/java/org/reso/service/security/BearerAuthProvider.java rename to src/main/java/org/reso/service/security/providers/BearerAuthProvider.java index 45f392e..44586a9 100644 --- a/src/main/java/org/reso/service/security/BearerAuthProvider.java +++ b/src/main/java/org/reso/service/security/providers/BearerAuthProvider.java @@ -1,12 +1,12 @@ -package org.reso.service.security; +package org.reso.service.security.providers; +import org.reso.service.security.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.util.Base64; import java.util.Enumeration; public class BearerAuthProvider implements Provider diff --git a/src/main/java/org/reso/service/servlet/RESOservlet.java b/src/main/java/org/reso/service/servlet/RESOservlet.java index 3ee227c..f45bb48 100644 --- a/src/main/java/org/reso/service/servlet/RESOservlet.java +++ b/src/main/java/org/reso/service/servlet/RESOservlet.java @@ -1,6 +1,7 @@ package org.reso.service.servlet; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.olingo.commons.api.edmx.EdmxReference; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; @@ -9,9 +10,10 @@ import org.reso.service.data.GenericEntityCollectionProcessor; import org.reso.service.data.definition.LookupDefinition; import org.reso.service.data.meta.ResourceInfo; import org.reso.service.edmprovider.RESOedmProvider; -import org.reso.service.security.BasicAuthProvider; -import org.reso.service.security.BearerAuthProvider; +import org.reso.service.security.providers.BasicAuthProvider; import org.reso.service.security.Validator; +import org.reso.service.security.providers.BearerAuthProvider; +import org.reso.service.servlet.util.SimpleError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,12 +25,15 @@ import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.*; + public class RESOservlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(RESOservlet.class); private Connection connect = null; private Validator validator = null; + private OData odata = null; + ODataHttpHandler handler = null; @Override public void init() throws ServletException @@ -44,7 +49,7 @@ public class RESOservlet extends HttpServlet } this.validator = new Validator(); - //this.validator.addProvider(new BasicAuthProvider()); + this.validator.addProvider(new BasicAuthProvider()); this.validator.addProvider(new BearerAuthProvider()); String mysqlHost = env.get("SQL_HOST"); @@ -64,33 +69,42 @@ public class RESOservlet extends HttpServlet } catch (Exception e) { LOG.error("Server Error occurred in connecting to the database", e); } + + // Set up ODATA + this.odata = OData.newInstance(); + RESOedmProvider edmProvider = new RESOedmProvider(); + + ResourceInfo defn = new LookupDefinition(); + edmProvider.addDefinition(defn); + + ServiceMetadata edm = odata.createServiceMetadata(edmProvider, new ArrayList()); + + // create odata handler and configure it with CsdlEdmProvider and Processor + this.handler = odata.createHandler(edm); + + GenericEntityCollectionProcessor lookupEntityCollectionProcessor = new GenericEntityCollectionProcessor(this.connect, defn); + + this.handler.register(lookupEntityCollectionProcessor); + } protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { + + // Due to order of operations, the unauthorized response won't be called unless the verification fails. if (!this.validator.verify(req) && this.validator.unauthorizedResponse(resp)) - { // Due to order of operations, the unauthorized response won't be called unless the verification fails. - resp.getWriter().println("

Unauthorized

"); + { + SimpleError error = new SimpleError(SimpleError.AUTH_REQUIRED); + ObjectMapper objectMapper = new ObjectMapper(); + + PrintWriter out = resp.getWriter(); + out.println(objectMapper.writeValueAsString(error)); + out.flush(); return; } try { - // create odata handler and configure it with CsdlEdmProvider and Processor - OData odata = OData.newInstance(); - RESOedmProvider edmProvider = new RESOedmProvider(); - - ResourceInfo defn = new LookupDefinition(); - edmProvider.addDefinition(defn); - - ServiceMetadata edm = odata.createServiceMetadata(edmProvider, new ArrayList()); - ODataHttpHandler handler = odata.createHandler(edm); - - GenericEntityCollectionProcessor lookupEntityCollectionProcessor = new GenericEntityCollectionProcessor(this.connect, defn); - - handler.register(lookupEntityCollectionProcessor); - - // let the handler do the work - handler.process(req, resp); + this.handler.process(req, resp); } catch (RuntimeException e) { LOG.error("Server Error occurred in RESOservlet", e); diff --git a/src/main/java/org/reso/service/servlet/TokenServlet.java b/src/main/java/org/reso/service/servlet/TokenServlet.java new file mode 100644 index 0000000..51f754b --- /dev/null +++ b/src/main/java/org/reso/service/servlet/TokenServlet.java @@ -0,0 +1,83 @@ +package org.reso.service.servlet; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.reso.service.security.providers.BearerAuthProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.util.Enumeration; +import javax.servlet.ServletException; +import javax.servlet.http.*; + +import org.reso.service.servlet.util.Token; +import org.reso.service.servlet.util.SimpleError; + + +public class TokenServlet extends HttpServlet +{ + public static final String ID_HEADER = "client_id"; + public static final String SECRET_HEADER = "client_secret"; + + public static final String AUTH_CLIENT_ID = "reso"; + public static final String AUTH_CLIENT_SECRET = "secret"; + + + private static final Logger LOG = LoggerFactory.getLogger(HttpServlet.class); + + private String getHeader(final HttpServletRequest req, String header) + { + Enumeration headers = req.getHeaders(header); + + while (headers.hasMoreElements()) + { + return headers.nextElement(); + } + + return null; + } + + private String getField(final HttpServletRequest req, String name) + { + String param = req.getParameter(name); + if (param==null) + { + return getHeader(req,name); + } + + return param; + } + + protected void service(final HttpServletRequest req, final HttpServletResponse response) throws ServletException, IOException { + + String client_id = getField(req, TokenServlet.ID_HEADER); + String client_secret = getField(req, TokenServlet.SECRET_HEADER); + + String jsonString = null; + + PrintWriter out = response.getWriter(); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + + ObjectMapper objectMapper = new ObjectMapper(); + + if (client_id!=null && client_secret!=null && client_id.equals(TokenServlet.AUTH_CLIENT_ID) && client_secret.equals(TokenServlet.AUTH_CLIENT_SECRET)) + { + Token token = new Token(BearerAuthProvider.AUTH_BEARER_TOKEN,"bearer","create"); + + jsonString = objectMapper.writeValueAsString(token); + } + else + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + + SimpleError error = new SimpleError(SimpleError.INVALID_REQUEST); + + jsonString = objectMapper.writeValueAsString(error); + } + + out.print(jsonString); + out.flush(); + } + +} diff --git a/src/main/java/org/reso/service/servlet/util/SimpleError.java b/src/main/java/org/reso/service/servlet/util/SimpleError.java new file mode 100644 index 0000000..a7c5063 --- /dev/null +++ b/src/main/java/org/reso/service/servlet/util/SimpleError.java @@ -0,0 +1,21 @@ +package org.reso.service.servlet.util; + + +public class SimpleError +{ + String error; + static public String AUTH_REQUIRED = "auth_required"; + static public String INVALID_REQUEST = "invalid_request"; + + + public SimpleError(String error) + { + this.error = error; + } + + + public String getError() + { + return error; + } +} diff --git a/src/main/java/org/reso/service/servlet/util/Token.java b/src/main/java/org/reso/service/servlet/util/Token.java new file mode 100644 index 0000000..2e62a53 --- /dev/null +++ b/src/main/java/org/reso/service/servlet/util/Token.java @@ -0,0 +1,69 @@ +package org.reso.service.servlet.util; + + + +public class Token +{ + String accessToken; + String tokenType; + String scope; + + + public Token(String authBearerToken, String tokenType, String scope) + { + this.accessToken = authBearerToken; + this.tokenType = tokenType; + this.scope = scope; + } + + + /** + * Set the attribute with the name that corresponds to this method name. + * + * @param accessToken The value to set the attribute to. + */ + public void setAccessToken(String accessToken) + { + this.accessToken = accessToken; + } + + + /** + * Set the attribute with the name that corresponds to this method name. + * + * @param tokenType The value to set the attribute to. + */ + public void setTokenType(String tokenType) + { + this.tokenType = tokenType; + } + + + /** + * Set the attribute with the name that corresponds to this method name. + * + * @param scope The value to set the attribute to. + */ + public void setScope(String scope) + { + this.scope = scope; + } + + + public String getAccessToken() + { + return accessToken; + } + + + public String getTokenType() + { + return tokenType; + } + + + public String getScope() + { + return scope; + } +} \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index c708639..4c1397b 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -10,6 +10,17 @@ 1 + + TokenServlet + org.reso.service.servlet.TokenServlet + 1 + + + + TokenServlet + /token + + RESOservlet /*