Making WebEx Work With An Enterprise Proxy

As an administrator of enterprise systems you expect products/software you deploy and maintain to just work but we don’t live in a perfect world and the occasional bug will happen. One such bug caused me and my colleagues trouble for nearly 6 years and since I am positive others are having this issue (as proof by a simple Google search) I wanted to provide a work around that have proved successful for us.

In my early days at JTV I deployed Microsoft’s ISA product for our browsing proxies and have since upgraded to the new version, Threat Management Gateway (TMG). This solution has worked fairly well for all but one application, WebEx, which would prompt for authentication credentials continuously. My fix on Windows system was to install the ISA/TMG firewall client and configure Java to use a “Direct Connection”. There is no equivalent software for the MAC and despite creating proxy rules to let a MAC users system browse the internet freely without authentication their problem still persisted.

With a rise in the number of MAC users at JTV and a corporate decision to use WebEx for conferencing with an international office the pressure was on to make WebEx work for MAC users and I was granted time to research and fix the issue. Knowing that the old tricks I had tried would not work I had to look in another place and found the issue to be with the Proxy PAC file we use to instruct our clients on how to access network resources through the proxy. The PAC file is java script that a client (browser) executes with each request to determine how to access the requested resource; the script is processed in order. Take this simple script as an example.

function FindProxyForURL(url, host)
{
        // Direct connections to non-FQDN hosts
        if (isPlainHostName(host)) ||
           (host == "127.0.0.1") ||
           (host == "example.local") ||
           (shExpMatch(host, "jtv.com")) ||
           (isInNet(host, "192.168.0.0", "255.255.0.0")) ||
           (isInNet(host, "10.0.0.0", "255.0.0.0")))
        {
           return "DIRECT"
	}
	else
        {
          return "PROXY proxy.example.local:8080"
        }
}

The script in this example should send any traffic not specifically excluded to the proxy defined at the end of the script and as you can see no traffic going to the WebEx domains are excluded. While reviewing the proxy logs I was seeing traffic to WebEx domains when MAC users attempted to establish a WebEx connection yet there were no errors and the session never connected. A packet capture revealed that after this initial burst traffic to WebEx the WebEx client was trying to make a direct connection and was trying to bypass the proxy entirely; direct connections to the internet are not allowed in our environment so there is no way this would ever work. Researching this problem on the internet I kept reading that the function isInNet() is known to not work with some versions of Java and it’s called a few times in our PAC file. Since we already know the PAC file is processed serially I thought if I sent WebEx traffic to the proxy before calling isInNet() in the script that would solve my problem and testing proved that had been the culprit all along. Here is an example PAC file that’s also been re-worked a bit by my coding genius of a boss that solved this issue:

function FindProxyForURL(url, host) {
	if (isPlainHostName(host))
	{
		return "DIRECT";
	}
	host = host.toLowerCase();
// Work around bug in unknown piece of MacOSX or cisco Meeting Center
	if (shExpMatch(host, "*.webex.com"))
	{
		return "PROXY proxy.example.local:8080";
	}
// If specific URL needs to bypass proxy, send traffic direct.
	if ( shExpMatch(host, "*.example.local") ||
	     host == "jtv.com" ||
	     host == "127.0.0.1")
	{
		return "DIRECT";
	}
// If IP address is internal or hostname resolves to internal IP, send direct.
	var resolved_ip = dnsResolve(host);
	if (
		isInNet(host, "10.0.0.0",  "255.0.0.0") ||
		isInNet(resolved_ip, "192.168.0.0",  "255.255.0.0")
	   )
	{
		return "DIRECT";
	}
// All other traffic uses below proxies, in fail-over order.
	return "PROXY proxy.example.local:8080";
}

After making this change all of our WebEx/Proxy issues were solved which for me was much cause for celebration since this had been an issue for 6 years that I, a dedicated Windows guy, had blamed on the MAC for not being fully Enterprise ready but as it turns in out in this particular case that’s not the issue. It is worth mentioning that as with most Java applications only Basic proxy authentication is supported so if you’re in an environment does not allow authentication packets to be sent in clear text (which I hope that’s the case for everyone) you must create a proxy rule that allows traffic to *.webex.com to pass without requiring authentication else you will get the dreaded authentication loop. I can also confirm this fix also works for Windows clients as well and there is no need for the ISA/TMG firewall client any longer to overcome this issue.

I sincerely hope this helps others in the community that have been battling this issue; I have yet to see any single post that puts all of this together in one place specifically as it relates to WebEx; only pleas for help from users having the same issue.

-Kevin N.

Posted in Systems & Infrastructure | 4 Comments

Introduction to Java Enterprise Edition 6

Java Enterprise Edition (EE) started out as a way to replace Common Gateway Interface
(CGI) using the Servlet API in the late 90′s. The Servlet technologies promised developers a much easier and standardized way to create dynamic content on web sites. The problem was that Servlets were server code and didn’t offer a clean way to build the user interface. Sun then released Java Server Pages (JSP) which made it a little easier to separate the view from server code and provided an answer to Microsoft’s Active Server Pages (ASP) technology.

Java became the technology to use on the server side in the late 90′s which made companies like IBM and Oracle take notice. These companies worked with Sun to make Java more enterprise ready with features like ACID transactions, messaging and security. Java EE officially became a specification using Servlets and JSP as the first APIs. The specification grew quickly and became more complex attempting to encompass years of enterprise computing knowledge. Expensive application servers were created to run the applications, but creating these applications became cumbersome and the cost of entry to create an enterprise application exploded. Lighter weight technologies like the Spring framework were created to make development easier and cheaper. Java EE became a dirty word in most development circles and seemingly disappeared from most developers radars.

The latest Java EE specification (6) now makes application development a breeze.
Technologies like Enterprise Java Beans (EJB) version 3.1, Java Persistence (JPA) version 2.0, Java API for XML-Based Web Services (JAX-WS) version 2.2 and Contexts and Dependency Injection for Java (CDI) version 1.0 now make Java EE the easiest, most powerful version to date. Using these technologies, developers can easily begin building powerful enterprise applications. The addition of free application containers like GlassFish and JBoss remove the cost barrier that made startup prohibitive.

The Enterprise Java Beans (EJB) 3.1 specification has been updated to allow annotation
based bean identification reducing the amount XML that has to be written. Annotations are used to identify a bean, inject the bean and provide a JNDI name. Example 1 shows a class that has been annotated as a Stateless session bean and has another bean injected. Notice the mappedName attribute that provides the JNDI name. AOP style programming is also supported using the @Interceptors annotation (XML configuration also available) allowing developers the ability to wrap code around classes or method calls. The major draw back of EJB 3.1 dependency injection continues to be lack of POJO support forcing the developer to make all classes EJB beans.

Example 1

@Stateless(mappedName = "beans/component/MySessionBean")
@Local
@Remote
public class MySessionBean
{
   @EJB(mappedName = "beans/component/MyOtherSessionBean")
   private MyOtherSessionBean myOtherSessionBean;
   //Methods added here....
}

The Contexts and Dependency Injection for Java (CDI) specification is the missing link
for Java EE to help tie EJBs and POJOs together. Session beans are powerful in that they can be monitored and managed through the container, but not every object requires this overhead. Utility classes such as validation and logging do not make sense as beans but are still an important part of the application. Using the CDI API, these objects can be injected using the @Inject annotation. Example 2 provides an example of a factory that provides the logger object and a bean that consumes it.

Example 2

@Singleton
public class LoggingFactory
{
   @Produces
   @Named(value = "Logger")
   public Logger getLogger(InjectionPoint point)
   {
      String beanName = point.getBean().getBeanClass().getName();
      Logger.getLogger(beanName);
   }
}

@Stateless
public class MyLoggingBean
{
   @Inject
   @Named(value = "Logger")
   private Logger logger;
}

JPA 2.0 is a nice ORM layer and an alternative to the Entity bean in the EJB specification. JPA can work solely using annotations, XML files or a mixture of both. Example 3 shows a simple annotated entity with an id field that is generated using a sequence. Note the @NamedQuery annotation that provides a query allowing the EntityManager to search against the poName field. The query does not select fields to pull from the database table like standard SQL, but instead performs a selection on the object. Also note that the where clause references an object property instead of a table column.

Example 3

@Entity
@Table(name=”my_table”)
@NamedQuery(name="PersistentObject.findByName", query="SELECT persistentObject
            FROM PersistentObject persistentObject WHERE persistentObject.poName = :name")
public class PersistentObject
{
   @Id
   @Column(name="PO_ID")
   @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PO_SEQ")
   @SequenceGenerator(name = "PO_SEQ", sequenceName = "po_seq", allocationSize = 1)
   private Integer poId;

   @Column(name="PO_NAME")
   private String poName;

   public Integer getPoId() { return poId; }
   public void setPoId(Integer id) { this.poId = id; }
   public String getPoName() { return poName; }
   public void setPoName(String name) { this.poName = name; }
}

Example 4 shows a Session bean with an injected EntityManager, a method that uses the
id field and EntityManager to find that entity and a method that changes the name. The example assumes that the calls are being made in a transactional system. Queries that are not based on the primary key can be stored in the entity using the @NamedQuery annotation or put into an external XML file.

Example 4

@Stateless(mappedName = "beans/component/MyPersistentService")
public class MyPersistentService
{
   @PersistenceContext(unitName = "my-db")
   private EntityManager em;
   public PersistentObject getPO(Integer id)
   {
      return em.find(PersistentObject .class, id);
   }
   public void changePOName(String name, Integer id)
   {
      PersistentObject po = em.find(PersistentObject .class, id);
      po.setPoName(name);
   }
}

The JAX-WS 2.2 specification provides annotation based web service visibility into java
applications. Instead of hand crafting the WSDL and XSD files, a developer can simply create a class and add annotations which will automatically create the contract. JAX-WS allows the developer to begin with a few annotations and then add more annotations to gain greater control over the generated WSDL and XSD contracts. Example 5 shows a simple stateless session bean that has been annotated as a web service. A single method exists with annotations to indicate that the method should be exposed in the WSDL as well as annotations to indicate the name of the return value and parameter.

Example 5

@WebService(name = "MyWebService", serviceName = "MyWebService", targetNamespace = "mine",
            portName = "MyWebService WS", endpointInterface = "com.mine.MyWebServiceBeanEndpoint")
@Stateless(mappedName = "ws/mine/MyWebService")
public class MyWebServiceBean implements MyWebServiceBeanEndpoint
{
   @EJB(mappedName = "beans/component/MyPersistentService")
   private MyPersistentService myPersistentService;

   @WebMethod
   @WebResult(name = "po")
   public PersistentObject getPO(@WebParam(name = "id") Integer id)
   {
      myPersistentService.getPO(id);
   }
}

Java EE has grown into a robust set of technologies that allow developers to quickly and
easily build enterprise applications, but to run the applications a developer still needs an
application container. The GlassFish server version 3.1.x is an open source Java EE version 6 container that provides advanced management features and has zero start up costs. GlassFish features a command line utility (asadmin) for managing the server and applications as well as a web console that provides a visual user interface. GlassFish is also the Java EE 6 reference implementation.

Java EE has come a long way since it was first introduced. Pressure from open source
frameworks have forced continual improvements in each specification that allow developers easier ways to provide enterprise applications at a more rapid pace, lower cost and with better results. A developer now has the option of starting a new application using just the basic features of Java EE and the embedded container then as the application grows larger, move to a server based container like GlassFish, JBoss, WebLogic or WebSphere. Java EE may have lost a step in the developers conscious, but with the latest specification it is ready to be placed back at the top of the list of frameworks being evaluated for new projects.

Written by David F.

Posted in Software | Tagged , , , | 3 Comments