Java in Notes/Domino Explained: Security 201


As of Notes 6.x the JVM installed with Notes/Domino is a real Java 2 virtual machine which means that you have greater control over how security is handled. As mentioned previously you cannot install your own SecurityManager but you have the possibility to grant or restrict which access third-party libraries get.

As mentioned in my post called “Managing external Java dependencies in Domino Designer” you have a directory called jvm/lib/ext under your binary Notes/Domino directory. This directory can be used to install third-party or custom libraries which will always be on the classpath of Notes/Domino. What you maybe did not know is that the libraries placed in this directory is granted all permissions which means that they can really wreak havok on your system if they are malicious.

The permissions granted to external JAR-files in Notes/Domino are controlled through two files that are located in the jvm/lib/security directory called java.security and java.policy. The java.security file is a property file for classes in the java.security package – there is no need to worry about this file unless you start installing custom cryptographic extensions or modify the ones that are installed by default. The other file, java.policy, is however very usable and it is here you can control which permissions individual libraries get. This file is used by the installed SecurityManager to decide which operations to allow.

Below is a snippet from the default java.policy file:

// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/*" {
	permission java.security.AllPermission;
};

// Notes java code gets all permissions
grant codeBase "file:${notes.binary}/*" {
	permission java.security.AllPermission;
};

As you can see above the java.security.AllPermission permission is granted to all the files in jvm/lib/ext and to all files in the binary Notes/Domino directory. You can refer to the Javadocs for indepth information on java.security.AllPermission but suffice it to say that it allows everything. The syntax of the java.policy file also allows you to grant permissions if a library is digitally signed (see below for a link to a page describing the syntax of the java.policy in detail).

The java.security.AllPermission is a lot of access to any given library and it shouldn’t be granted lightly. Consider the source of the library, who compiled it and what the library should do before granting access. As always only grant the access that is actually needed – don’t just give java.security.AllPermissions because it is easier…

java.security.AllPermission shouldn’t be granted lightly…
There are a host of other types of permissions that may be granted (see the sub-classes of java.security.Permission) incl. access to reading and writing specific files or directories to access to network resources etc. In fact the java.security.FilePermission is probably the permission most commonly used since it allows you to grant a library access to files in a specific directory. Using java.security.FilePermission you can distinguish between reading, writing and executing files.

This is a point where Java allows you much more fine grained control than LotusScript. In LotusScript you have access to I/O or you don’t – in Java you can actually control which files a library may work with.

That is all for now. The next and final installment on security will discuss how third-party libraries actually use the permissions granted to them by the SecurityManager.

Further reading

Java in Notes/Domino Explained: Security 101


As a Notes/Domino programmer you are probably familiar with the fact that the agent manager (AMgr) distinguishes between operations consider restricted and those considered unrestricted. Among restricted operations are those that access the file system, set the system clock etc. Whether an agent is allowed to use restricted operations are based on settings in two different locations:

  • Whether the signer is granted access to restricted operations on the Security tab of the server document.
  • Whether the agent is set to allow restricted operations on the second tab of the agent properties.

The default setting in the agent properties is not to allow access to restricted operations.

When running Java agents the access to restricted operations are governed by a SecurityManager “installed” (configured) when the JVM is initialized and before the NotesMain() method of the agent is invoked. Once a SecurityManager has been installed in the JVM (using the setSecurityManager() method of the java.lang.System class) a new one cannot be set. If you try a java.lang.SecurityException is thrown. This guarantees that the default installed SecurityManager cannot be replaced at runtime.

A SecurityManager is a class extending java.lang.SecurityManager. If a SecurityManager is installed in the JVM it is asked before a security sensitive operation is executed. The SecurityManager then has the option of overruling the execution of the operation by throwing a java.lang.SecurityException.

The following types of operations are controlled by the SecurityManager in agents:

  • The ability to read files on disk
  • The ability to write files on disk
  • The ability to access the network
  • The ability to work with class loaders
  • The ability to execute external programs
  • The ability to use Java classes calling with native code
  • The ability to access system properties

The Java API of Notes/Domino contains two different SecurityManagers – one for agents and one for servlets. The SecurityManager for agents is COM.ibm.JEmpower.applet.AppletSecurity and the SecurityManager for servlers is lotus.notes.AgentSecurityManager. Both inherit directly from java.lang.SecurityManager.

Looking into IBM Informix

As posted previously we’re researching a storage intensive relational database project at the office. I talked with the DB2 guys at IBM today and they asked me to look into Informix instead of DB2 since Informix has a BLOB (Binary Large OBject) support superior to DB2. In additional the fragment support for tables sounds like it’s something we could use to help “partition” the tables in date segments.

Anyone who has some “getting started” information for Informix? I figured the “dbaccess” command out but it would be nice with a tutorial or similar to get started.

The small differences between Notes and COM sometimes matters

Had an example of this today when porting some LotusScript in Notes to VBA using COM to access Notes. In Notes the GetAllDocmentsByKey function of the NotesView class can take an array of parameters, the array being of any datatype (String, Integer etc.). It turns out that this isn’t the case for COM access where the array must be a Variant array as shown below. If you supply a String array you’ll get an error at runtime.

// declarations
Dim session NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim dc As NotesDocumentCollection
Dim v(1) As Variant

// get session, database, views etc.
Set db = session.GetDatabase("server", "path")
Set view = db.GetView("someview")
...
...

// populate key array
v(0) = "key1"
v(1) = "key2"

// get by key
Set dc = view.GetAllDocumentsByKey(v, True)
Msgbox dc.Count

Being fair the difference is noted in the Designer help database.

Restrict access to Tomcat URL to select IP addresses

One of our customer applications has been plagued by massive amounts of requests from external IP adresses that really shouldn’t be using the URL’s. The connections caused the connection pool in the Tomcat instance behind Apache to deplete and hence no connections were available to legitimate users. Since the URL cannot be password protected we needed another way to restrict the access.

The solution is quite simple and only involved a couple of lines in the VirtualHost section of httpd.conf. The below RewriteRules restrict the access to the /search URL to the XX.YYY.ZZ.WW1, XX.YYY.ZZ.WW2 and XX.YYY.ZZ.WW3 addresses. All other URLs are available as normal. If you try to access the URL from another IP address than the ones specified you’ll get a 403 Forbidden HTTP response code back.

RewriteEngine    on
RewriteLog       /usr/local/apache2/logs/rewrite.log
RewriteLogLevel  0

# allow access to search only from select addresses
RewriteCond   %{REMOTE_ADDR}  XX.YYY.ZZ.WW1                        [OR]
RewriteCond   %{REMOTE_ADDR}  XX.YYY.ZZ.WW2                        [OR]
RewriteCond   %{REMOTE_ADDR}  XX.YYY.ZZ.WW3
RewriteRule   ^(/search.*)    $1                                   [PT,L]

# deny access to search from all other addresses
RewriteRule   ^/search.*      -                                    [F]

The real beautiful thing is that Tomcat is totally oblivious to the change and not a single line of code needed to be changed hence no need for software tests.

Beware of changing Domino Directory ACL

Be aware when changing the ACL of the Domino Directory since it may affect your users and the deployment of policies. Pay special attention when messing with the PolicyCreator and PolicyModifier roles or you may encounter the “The signer of the note must have Editor access and the PolicyCreator or PolicyModifier role to the Domino Directory” error message.

More information: SPR #TBOO5QNNDM.

DWA working in Firefox 1.5.0.2 (was: “Domino Web Access broken in Firefox 1.5?”)

As previously reported Domino Web Access seemed to have some problems running under Firefox 1.5 and I was not alone in having the issue. I just tried again today using Firefox 1.5.0.2 (the newest version from Mozilla) against Domino 7.0.1 (on Win32) and it was just fine. Don’t know if it’s the Firefox version or after upgradering from Domino 7.0 to Domino 7.0.1.

Anyone else experiencing the same thing?

Java in Notes/Domino Explained: Casting 101


To discuss and understand casting you must know that when you instantiate an object in Java you create an object on the heap and a reference to the object on the stack. In your Java agents you only have direct access to what’s on the stack which means that what you manipulate in your code are the references. Since you do not work with the objects on the heap directly the reference on the stack must tell the JVM which type of object is at the memory location pointed to on the heap.

Casting means taking an existing object reference and making it of another type. When most Java developers talk about casting they refer to “casting objects” which strictly speaking is wrong. It is however one of those things you learn to live with… 🙂

A simple example

As you might know every class in Java ultimatively inherits from java.lang.Object which means that a java.lang.Object reference can point to anything (much like a Variant in LotusScript). This means that you can always cast an object to java.lang.Object since it is a more generic type.

However you cannot store a java.lang.Object reference in a java.lang.String reference without casting since String is more specific than Object. As you can see I have to cast the obj reference to a String reference in line 3. If I don’t the code wont compile.

String sample1 = "This is my string..."; // create a String
Object obj     = sample1;                // store String in java.Object reference
String sample2 = (String)obj;            // we must cast to store an Object in a String
                                         // reference

To sum up you need to cast when refering to an object with a more specific reference than the current reference.

When casting references you may encounter the java.lang.ClassCastException which is an unchecked exception. This exception is the way the JVM can signal that you are doing an illegal cast for example casting a lotus.domino.Document to a lotus.domino.Database.

Knowing when it’s okay to cast

So how do you check if a cast is legal? Well apart from knowing which references you are dealing with you can use the instanceof keyword. The below example checks that the object really does inherit from lotus.domino.RichTextItem before casting:

// declarations
RichTextItem rt = null;
Item item = null;

// get document
Document doc = db.getDocumentByUnid("<some unid>");

// loop all items and put them into an ArrayList
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
   // get next element from the Vector (returns java.lang.Object)
   Object obj = items.elementAt(i);

   // is the item a RichTextItem?
   if (obj instanceof RichTextItem) {
      // yes it is - cast it as such
      rt = (RichTextItem)obj;
   } else {
      // nope - cast it as an Item
      item = (Item)obj;
   }
}

The above example is equivalent to the below code exept that I use the ClassCastException to find out that the cast is invalid.

// declarations
RichTextItem rt = null;
Item item = null;

// get document
Document doc = db.getDocumentByUnid("<some unid>");

// loop all items and put them into an ArrayList
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
   // get next element from the Vector (returns java.lang.Object)
   Object obj = items.elementAt(i);

   try {
      // try to cast as RichTextItem
      rt = (RichTextItem)obj;

      // coming here means that the item is a RichTextItem
      ...
   } catch (ClassCastException e) {
      // not a RichTextItem - cast it as an Item
      item = (Item)obj);
   }
}