Monday, November 25, 2013

OAuth authentication to Box.com via node.js

Below is some code that implements a 'hello world'-level integration between a node.js app and the box.com 2.0 API.

Box uses OAuth 2.0 for app access to user folders/files.  The majority of the code below is just to get thru the OAuth 2.0 handshakes.  That handshake process mandates the first step be via GUI - hence the simplistic auth.html page below.  The user passes their username/password directly to box.com, bypassing your app.  Box has a fairly detailed discussion of their OAuth process here.


First step in the OAuth process is to pass the client_id and redirect_uri of your box.com app to box.com. You obtain a client_id and client_secret when you register your app at Box.com.  Below is a bare-bones GUI for sending that info to Box.

auth.html - Code

auth.html - Rendered in the Browser




The user would push the 'submit' button to start the process.  Box will verify this is a valid client_id and then redirect to their login page.



Following a successful account login, Box will present the user with the choice as to whether to allow your app to access their files.



 When the user pushes the 'Grant' button, the following chain of events are set in motion.
  1. Box initiates a HTTPS GET/POST to the redirect URI you specified in the initial GET/POST to Box.
  2. That POST will contain a OAuth 'code' parameter.  You will use that in the next step.
  3. That temporary (30 second lifetime) 'code' parameter needs to be swapped for an OAuth 'token'.  The swap happens with a HTTPS POST back to Box.  That POST needs to contain several authentication parameters: client_id (again), client_secret, and your newly-obtained 'code'.
  4. If the POST to Box is successful, they will return back a JSON-formatted list of items, one of which is an OAuth token.
  5. At this point, you can invoke the Box.com's REST API (API 2.0) by including that token in 'Authorization' header in your GET's.
Node.js code below to implement all the above.

boxserver.js





Here are screenshots of a box.com folder and the results of the simple code above being run against it.









Copyright ©1993-2024 Joey E Whelan, All rights reserved.

















































Saturday, November 23, 2013

Force Redirection of HTTP to SSL in Tomcat

If you have a particular app within Tomcat that you want to restrict to SSL access, this can be accomplished with a couple edits.

web.xml file (located in the WEB-INF director under the specific app directory)

1.  Add a user-data-constraint under the security-constraint directive.

<security-constraint>
      <web-resource-collection>
        <web-resource-name>
              REST calls
        </web-resource-name>
        <url-pattern>/*</url-pattern>
     </web-resource-collection>
      <auth-constraint>
          <role-name>myrole</role-name>
      </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>

  </security-constraint>



server.xml file (located in the conf directory within your tomcat instance)

Scenario 1:  Tomcat is acting as the web server, in addition to being the servlet container.

1.  server.xml:  Set the redirectPort property on the Connector directive that specifies where Tomcat is listening for HTTP traffic.  Here, Tomcat is listening on 8080 for HTTP traffic and has a redirectPort of 8443.
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />


2.  server.xml:  Add a Connector directive for SSL with same port you specified in Step 1.

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
             keystoreFile="/etc/ssl/tomcat/keystore.jks" keystorePass="password"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" /> 



Scenario 2:  Tomcat is only acting as a servlet container.  Apache httpd (or other flavor) is acting as the web server.

1. server.xml:  Set the redirectPort property on the Connector directive where Tomcat is listening for AJP calls (in Apache httpd - the modJk module acts as the connector to Tomcat).  Here we're setting the redirectPort to where Apache httpd is configured for SSL.

 <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8909" protocol="AJP/1.3" redirectPort="443" />


Copyright ©1993-2024 Joey E Whelan, All rights reserved.


HTTP Basic Auth on Node.js

Implementing HTTP Basic Auth on node.js is a fairly simple exercise if you're using the express.js module.


On the server side, you utilize the built-in basicAuth() method in express.

Server Side
var express = require('express');
var app = express();


app.use(express.basicAuth('username', 'password'));


On the client side, you pass the username/password in as an Authorization header.

Client Side
getValue = function(key, options)
{
    var retVal='';
    var opts = {
            host : 'theHost',
            port : '3000',
            path : '/rest/key'
            headers: {     'Content-Type' : 'text/plain',
                        'Authorization': 'Basic ' + new Buffer('username' + ':' + 'password').toString('base64') };
            method: 'GET'
    };
   
    var req = https.request(opts, function(res) {
        res.on('data', function(chunk) {
            retVal += chunk;
        });
        res.on('end', function() {
            if (options !== undefined && options.callback !== undefined)
                options.callback(retVal);
        });
    });
   
    req.on('error', function(err) {
       console.log('error');
    });
    req.end();
};

Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Tuesday, November 19, 2013

Implementing HTTP Basic Auth with Java Jersey REST services

Server Side

Given we're using Jersey (a servlet) to implement the REST services, a logical place to implement HTTP Basic Auth would be at the servlet container level.  In this case - that's Apache Tomcat.  That can be easily implemented by adding configuration to two areas in Tomcat's config files:  web.xml and tomcat-users.xml

web.xml configuration:

<security-constraint>
      <web-resource-collection>
        <web-resource-name>
              REST calls
        </web-resource-name>
        <url-pattern>/*</url-pattern>
     </web-resource-collection>
      <auth-constraint>
          <role-name>ctispan</role-name>
      </auth-constraint>
  </security-constraint>
    <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>CTISpan REST</realm-name>
    </login-config>


tomcat-users.xml configuration:

<tomcat-users>
<role rolename="ctispan"/>
    <user username="client" password="password" roles="ctispan"/>
</tomcat-users>


Note the relationship between the two files - specifically the "role-name" property.

Client Side

Implementing Basic Auth on the client side is a simple matter of adding the Jersey-provided Basic Auth filter to the client.

import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;

private ClientRS(URI uri, String clientname, String clientpassword)
    {
        logger.debug("Entering ClientRS(uri= " + uri +
                ", clientname= " + clientname +
                ", clientpassword= " + clientname + ")");
        ClientConfig config = new DefaultClientConfig();
        this.client = Client.create(config);
        if (clientname != null && clientpassword != null)
            this.client.addFilter(new HTTPBasicAuthFilter(clientname, clientpassword));
        this.service = this.client.resource(uri);
        logger.debug("Exiting ClientRS()");
    }

Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Monday, November 18, 2013

Implementing REST services with Java Jersey and Apache Tomcat - Client Side

Continuing from the previous post, below is some sample code implementing a Jersey client to invoke an HTTP GET to the server


/**
 * Java client to access tje REST interface to the cache.
 *
 * @author Joey Whelan
 */
public class ClientRS
{
   
    /** The service. */
    private WebResource service;
   
    /** The client. */
    private Client client;
   
    /** The logger. */
    private static Logger logger = Logger.getLogger(ClientRS.class);
    

    /**
     * Builds the REST client object
     *
     * @param spec the spec
     * @return the client rs
     */


    public static ClientRS build(String spec)
    {
        logger.debug("Entering build(spec= " + spec + ")");
        URI uri = null;
   
        try
        {
            URL url = new URL(spec);
            uri = url.toURI();
            logger.debug("Exiting build()");
            return new ClientRS(uri);
        }
        catch (Exception e)
        {
            logger.error(e);
            logger.debug("Exiting build()");
            return null;
        }
    }
      /**
     * Private constructor to instantiate a new REST client.
     *
     * @param uri the uri
     */
    private ClientRS(URI uri)
    {
        logger.debug("Entering ClientRS(uri= " + uri + ")");
        ClientConfig config = new DefaultClientConfig();
        this.client = Client.create(config);
        this.service = this.client.resource(uri);
        logger.debug("Exiting ClientRS()");
    }
   
   
    /**
     * Retrieves value from cache based on key
     *
     * @param key the key
     * @return HTTP response
     */
    public ClientResponse getValue(String key)
    {
        logger.debug("Entering getValue(key= " + key + ")");
        ClientResponse response = service.path("key").path(key).accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);
        logger.debug("Exiting getValue(), response= " + response);
        return response;
    }


Invocation of the client:

String rsSpec = "https://1.1.1.1:8443/ctispan/rest";
ClientRS client = ClientRS.build(rsSpec);
ClientResponse resp = null;

if (client != null) resp = client.getValue("111");
        if (resp != null)
            System.out.println("status code: " + resp.getStatus() + " entity: " +  resp.getEntity(String.class));



Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Sunday, November 17, 2013

Implementing REST services with Java Jersey and Apache Tomcat - Server Side

This is a multi-part discussion on how to implement RESTful web services interfaces using Java using the Jersey API.

Jersey is an JAX-RS API (JSR 311) that makes creation of REST services fairly straight forward.  Jersey is implemented as a servlet; hence you'll need a servlet container to utilize Jersey.  Tomcat is one such container and what we'll be using here.  I'll be using Eclipse as the Java IDE and the embedded Tomcat instance in that IDE.

In Eclipse, create a new 'Dynamic Web Project'.
     
Download the Jersey API and add it your Java Build Path in Project Properties.
    Add <servlet> and <servlet-mapping> entries to the  web.xml file (WEB-INF folder).   
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
          <param-name>com.sun.jersey.config.property.packages</param-name>
          <param-value>com.jwisoft.ctispan.server</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>  
    <servlet-mapping> <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/rest/*</url-pattern>
      </servlet-mapping>
    Write your Java functions that will correspond to HTTP verbs (GET, POST, etc).  Jersey utilizes annotations to specify the path and HTTP method a Java function implements (among other things).  The example below provides a retrieval (GET) function for a simple in-memory cache:
    @GET
    @Path("/key/{key}")
        public Response getValue(@PathParam("key") String key)
        {
            logger.debug("Entering getValue(key= " + key + ")");
            InMemCache cache = (InMemCache) context.getAttribute("cache");
            String value = cache.getValue(key);
            Response response = null;
           
            if (value != null)
                response = Response.status(Response.Status.OK).type(MediaType.TEXT_PLAIN).entity(value).build();
            else
                response = Response.status(Response.Status.NOT_FOUND).build();
           
            logger.debug("Exiting getValue(), response= " + response);
            return response;
        }  
     
    Explanation:
    @GET - this annotation means this method is what will be called for a HTTP GET for the URL path as described below.
    @Path  - this annotation signifies the URL path that will invoke this Java method.  Braces "{}" identify query params.
    @PathParam - this annotations identifies the query params from the HTTP request. 
    The 'Response' lines of code build up a '200 OK' or '404 Not Found' HTTP response, depending on whether key is in the cache or not.
     
     

Copyright ©1993-2024 Joey E Whelan, All rights reserved.