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.

Friday, October 25, 2013

SSL Configuration on Node.js for Server and Client sides

My previous post discussed how to simply generate a RSA private key and self-signed certificate. Those items will be used now to implement a node.js (utilizing express.js) server and client.

Server-side code

var fs = require('fs');
var https = require('https');
var express = require('express');

var appHttps = express();
var privateKey = fs.readFileSync('/sslcerts/key.pem'); //set path to your key
var certificate = fs.readFileSync('/sslcerts/cert.pem'); //set path to your cert
var credentials = {key: privateKey, cert: certificate};

var httpsServer = https.createServer(credentials, appHttps);
httpsServer.listen('8443');

//this is a framework for a REST interface
 appHttps.get('/ctispan/rest/key/:id',   
        function(req, res)
        {

                res.send(200,'hello world');
        });



Client-side code

This is written in a classical (as in class) type format.  Javascript isn't a class-type language, but my background is in Java which is.  Hence, I tend to mold things to what I'm comfortable with (classes).

var https = require('https');
var fs = require('fs');


function ClientRS(host, port, path)
{
    this.host = host;
    this.port = port;
    this.path = path;
 };

ClientRS.prototype.getValue = function(key, callback)
{
    var retVal='';
    var options = {
            host : this.host,
            port : this.port,
            path : this.path + "/key/" + key,
            ca: [fs.readFileSync(properties.sslHACert)],    //*see note below
            method: 'GET'
    };


var req = https.request(options, function(res) {
        console.log('GET status code: ', res.statusCode);
        res.on('data', function(chunk) {
            retVal += chunk;
        });
        res.on('end', function() {
            if (callback !== undefined)
                callback(retVal);
        });
    });
   
    req.end();

};

* That 'ca' line is necessary for self-signed certificates.  You need to tell node that the self-signed certificate is trusted (cause it shouldn't be in normal circumstances), otherwise you'll get thrown one of these beauties (that will terminate your client):

Error: DEPTH_ZERO_SELF_SIGNED_CERT


Invoking the Client code

callback = function(returnData) {
    console.log('in test client, returnData: ' + returnData);
};


var ClientRS = require('ClientRS');
client = new ClientRS('myhost', '8443', '/ctispan/rest');


client.getValue('111', callback);

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

Generating a SSL key + self-signed cert with openssl

Steps below for creating a PKI key + cert for your HTTPS implementation.  Linux command line is assumed.

Key

$ openssl genpkey -out key.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048

Output of this is a 2048-bit private key (key.pem).


Certificate

$ openssl req -new -x509 -key key.pem -out cert.pem -days 9999

This takes the private key generated in the step above (key.pem) and creates a self-signed PKI certificate (cert.pem).  I put a expiration date of 9999 days on it.


Note - You generally want to use a resolvable DNS entry for the Common Name (CN) field in your certificate.  Putting an IP address in that field will bring you troubles from RFC 2818

In some cases, the URI is specified as an IP address rather than a
   hostname. In this case, the iPAddress subjectAltName must be present
   in the certificate and must exactly match the IP in the URI.
 
Net, you have to add a subjectAltName (SAN) field to your certificate with that same IP address.  I can attest that the Java Runtime Environment and node.js enforce this RFC clause.  You can avoid the entire problem by using a host name.

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

Installing Node.js on Redhat variants (rhel, centos, fedora)

No need for the source code download/compile cycle.

# yum install npm

Done.

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

Friday, September 27, 2013

IOS Codec Preferences


The topic of codec selection comes up regularly in the VoIP provider world. Specifically, concerns regarding customers that have ‘hard coded’ their codec to G729 to the point they won’t allow G711. This explains how codecs get assigned to call legs in Cisco IOS.


You can set up a codec class as described below.

voice class codec 100
codec preference 1 g729r8
codec preference 2 g711ulaw

That works just as you would expect: G729 is the top preference, if that’s not available revert to G711.

Now, you apply that to a voip dial peer:

dial-peer voice 150 voip
destination-pattern .T
session protocol sipv2
session target ipv4:1.1.1.1
voice-class codec 100


I personally have another dial-peer set up for outbound fax. For that, I “hard code” to G711, like this:

dial-peer voice 160 voip
destination-pattern *.T
translation-profile outgoing fax
session protocol sipv2
session target ipv4:1.1.1.1
codec g711ulaw

Interestingly enough – if you specify no codec for a dial-peer – IT WILL DEFAULT TO G729 AND NOT ALLOW G711. Net, you get the hard-coded G729 scenario if you do nothing to your dial peer.

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

Cisco IOS Voice Translation Rules


There’s a ton of documentation/examples out there on the interweb about how to use IOS voice translation rules so I’m not going to try to repeat them. Instead, I’ll show one interesting use-case that took me a bit to figure out.

So, the scenario here is implementation of seven-digit dialing for the local area code. I want to append “719” to any seven-digit out dialed number. For ten-digit out dialed numbers, I want to leave them as is.

Here’s how to do it, building up from the basics:

rule 1 /\(..........\)/ /\1/

Rule 1 is ‘matching’ on any ten-digit number, keeping all the matched digits, then copying them all to the replacement number. That solves the “leave them as is” problem with ten digit dialing.

rule 2 /\(.......\)/ /719\1/

Rule 2 is matching on any seven-digit number, keeping those matched digits, then appending “719” on to those kept digits in the replacement number. That effectively provides the seven digit dialing functionality for 719 area codes.

Now we put these rules into a translation set:

voice translation-rule 2
rule 1 /\(..........\)/ /\1/
rule 2 /\(.......\)/ /719\1/

A ten-digit number gets matched first (since that’s precedence 1) and left alone. Rule processing stops. Seven digit numbers fall to the next rule and get the area code appended.

Last steps:

- Put the rule into a translation profile

voice translation-profile addareacode
translate called 2


- Apply the profile to a dial peer in outgoing mode:

dial-peer voice 150 voip
translation-profile outgoing addareacode
destination-pattern .T

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

DNS-jailed Network


The goal here is to develop a network segment that’s locked down to a specific service (HTTP) and to force that segment into a specific DNS server environment for the purpose of filtering out DNS resolution of undesirable websites such as Facebook, youtube, OnLineBootyCall.com, etc. We leverage the services from OpenDNS.com to do this. Net, we’ll be building a cheap (as in FREE) web filter for the kids. This concept can easily be extended to the Spouse, live-in Mother-in-Law, etc.


Step 1: Establish an account on OpenDNS.com (free). Here you can define the ‘Web Content Filtering’ context you prefer. At “High”, I find it filters out all the undesirable sites plus more that you may want to allow in at an “individual domain” level.

Step 2: Define a DNS view and view-list for the “kids”.

ip dns view kids
domain name-server 208.67.222.222
domain name-server 208.67.220.220
ip dns view-list kidslist
view kids 1

Here, I’m forcing DNS forwarding in this particular view to a couple of OpenDNS.com servers. Using OpenDNS's free filtering tools, you can effectively lock down browser activity.  You need to assign this DNS view to the VLAN segment where your jailbirds will reside as described here.

Step 3: If you’re going to use DHCP on this network segment, you’ll want to define a specific DHCP scope that assigns the default gateway and DNS server for the segment. Here, I’m using a 192.168.5.x VLAN for the ‘kids’. They get a router address for both the default gateway and DNS server. 

ip dhcp pool kids
network 192.168.5.0 255.255.255.0
default-router 192.168.5.1
dns-server 192.168.5.1

Step 4: Define an ACL for this segment to lock it down to DHCP and HTTP traffic (only) and restrict DNS traffic to the router/DNS view we defined previously. Of note, even if the ‘kids’ get to a tech sophistication level where they understand how to assign a different DNS server to their interface – it won’t work. All DNS traffic is blocked other than to the DNS server we defined in Step 3.

ip access-list extended kids_inACL
permit udp any any eq bootpc
permit udp any any eq bootps
permit tcp any any eq www
permit udp any host 192.168.5.1 eq domain
deny ip any any log


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

Cisco IOS DNS Views


DNS views are a fairly recent (12.4ish) addition to IOS to provide the capability for some advanced DNS name server functionality. They allow you to utilize the router as a DNS server and segregate DNS names + forwarding. This comes in handy when you want a split DNS environment - i.e., different name spaces and forwarding for different segments of the network. Obviously, you’re not likely to see the enterprise using the router as a DNS server – but it’s quite effective in the small network builder space (home network for instance).

The starting point in this configuration is creation of the view itself.

ip dns view internal
domain name abcxyz.com
domain name-server 8.8.8.8
domain name-server 8.8.4.4

The command above creates the DNS view named "internal", sets the domain name to "abcxyz.com" and sets up DNS forwarding to a pair of Google's DNS servers.

Now, I can create my own DNS namespace within that view.

ip host view internal server1 192.168.1.111
ip host view internal server2 192.168.1.112
ip host view internal server3 192.168.1.112
ip host view internal server4 192.168.1.114
ip host view internal server5 192.168.1.115

Next step is to assign the view to a ‘view list’. A view list is an ordered list of view where you can put additional restrictions. A view list is also what you assign to a network segment (interface). For this exercise, we’re just adding 1 view to a list named ‘internallist’ (note the highly creative naming conventions I’m using).

ip dns view-list internallist
view internal 1

Now, I assign the view list to a subinterface/VLAN.

interface FastEthernet0/1.1
description data vlan
encapsulation dot1Q 1 native
ip address 192.168.1.1 255.255.255.0
ip dns view-group internallist
ip nat inside

Done. Now, this VLAN has visibility to the “internal” DNS namespace above and utilizes DNS forwarding to Google’s DNS servers.

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