diff -Nur postgresql-jdbc-8.3-604.src.orig/doc/pgjdbc.xml postgresql-jdbc-8.3-604.src/doc/pgjdbc.xml
--- postgresql-jdbc-8.3-604.src.orig/doc/pgjdbc.xml	2008-01-08 07:56:26.000000000 +0100
+++ postgresql-jdbc-8.3-604.src/doc/pgjdbc.xml	2009-07-01 09:54:45.029843000 +0200
@@ -450,6 +450,17 @@
       </varlistentry>
 
       <varlistentry>
+       <term><varname>krbsrvname</varname> = <type>String</type></term>
+       <listitem>
+        <para>
+		Use the given string as Kerberos service name instead of
+		<literal>postgres</literal>. For more information see <xref
+		linkend="gss"/>.
+		</para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
        <term><varname>compatible</varname> = <type>String</type></term>
        <listitem>
         <para>
@@ -796,6 +807,247 @@
 
  </chapter>
 
+ <chapter id="gss">
+  <title>Using <acronym>GSS</acronym></title>
+   
+   <para>
+  The Generic Security Services Application Program Interface
+  (<acronym>GSS</acronym> <acronym>API</acronym> or
+  <acronym>GSSAPI</acronym>) enables the <acronym>JDBC</acronym> driver to
+  authenticate the user via Kerberos.
+   </para>
+
+   <para>
+  Kerberos makes a single sign on solution possible. It is a very secure
+  authentication method and needs only a few changes to the system. The
+  <acronym>JDBC</acronym> driver supports Linux- and Windows-clients and
+  possibly other systems which have <acronym>GSS</acronym>
+  <acronym>API</acronym> support in Java.
+   </para>
+
+   <note>
+     <para>
+  <productname>PostgreSQL</productname> supports different Kerberos
+  authentication types (Kerberos 4, Kerberos 5, <acronym>GSS API</acronym>
+  and <acronym>SSPI</acronym>). This chapter describes only Kerberos 5 with
+  the help of the <acronym>GSS API</acronym>.
+  </para>
+   </note>
+   
+   <sect1 id="gss-server">
+    <title>Server Configuration</title>
+
+    <para>
+  Please read the documentation of the server for further details on
+  configuring the <productname>PostgreSQL</productname> server for
+  Kerberos/GSSAPI. A very, very short description:
+    </para>
+
+  <para>
+  You have to create a service principal
+  (<literal>postgres/fqdn@REALM</literal>), extract its key to a keytab which
+  is readable by the user running the server. Some variables should be set in
+  the configuration file:
+  </para>
+
+  <programlisting>
+  krb_server_keyfile = '/path/to/keytab'
+  krb_server_hostname = 'fqdn-of-server'
+  </programlisting>
+
+  <para>
+  Normally you should not need to define these values. But on a multihomed
+  host it is better to define the hostname. The path to the keytab is
+  neccessary because normally you would not use the system's keytab (e.g.
+  <literal>/etc/krb5.keytab</literal>) which should only be readable by the
+  superuser.
+  </para>
+
+  <para>
+  In the <literal>pg_hba.conf</literal> you should enable
+  <literal>gss</literal>:
+  </para>
+
+  <programlisting>
+  # TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD
+  host    all         all         10.0.0.0/8            gss
+  </programlisting>
+   </sect1>  
+
+   <sect1 id="gss-client">
+    <title>Client Configuration</title>
+
+    <para>
+  You need to configure Kerberos on the client prior using the
+  <acronym>JDBC</acronym> driver.  This section describes the client
+  configuration on Linux and Windows.
+    </para>
+
+  <sect2 id="gss-client-linux">
+    <title>Linux</title>
+
+    <para>
+    The system has to be configured for Kerberos. Some distributions
+    integrate Kerberos very well, so there is nothing to do except of using
+    it. To configure it manually you need to setup the Kerberos
+    configuration file <literal>/etc/krb5.conf</literal>:
+    </para>
+
+    <programlisting>
+    [libdefaults]
+        default_realm = EXAMPLE.ORG
+
+    [realms]
+        EXAMPLE.ORG = {
+            kdc          = kerberos.example.org
+            admin_server = kerberos.example.org
+        }
+
+    [domain_realm]
+        .example.org = EXAMPLE.ORG
+    </programlisting>
+
+    <para>
+    This is a minimal <literal>krb5.conf</literal>. It contains the default
+    Kerberos realm (<literal>EXAMPLE.ORG</literal>) and which key
+    destribution center (<acronym>KDC</acronym>) and administration server
+    (<acronym>AS</acronym>) is responsible for this realm. For further
+    information you should take a look in the documentation of the Kerberos
+    implementation.
+    </para>
+
+    <para>
+    Afterwards you have to initialize the Kerberos environment by executing
+    kinit. With klist you can check, if everything is fine. It should
+    output something like this:
+    </para>
+
+    <programlisting>
+    cju@box:~/> klist
+    Ticket cache: FILE:/tmp/krb5cc_1003
+    Default principal: cju@EXAMPLE.ORG
+
+    Valid starting     Expires            Service principal
+    06/26/09 14:07:15  06/27/09 14:07:15  krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
+
+
+    Kerberos 4 ticket cache: /tmp/tkt1003
+    klist: You have no tickets cached
+    </programlisting>
+    
+    <para>
+    <literal>klist</literal> should show you a valid Ticket Granting Ticket
+    (<acronym>TGT</acronym>). You can now configure the
+    <acronym>JDBC</acronym> driver and use it.
+    </para>
+  </sect2>  
+
+  <sect2>
+    <title>Windows</title>
+
+    <para>
+    Windows 2000 Professional and Server, Windows XP and Windows 2003
+    Server support natively Kerberos as long as they are member of either a
+    Kerberos Realm or an Active Directory Domain.
+    </para>
+
+    <para>
+    Some changes are neccessary to use third-party software and especially
+    Java with Kerberos. To understand these changes, a descent knowledge of
+    the native Microsoft Kerberos implementation is useful:
+    </para>
+
+    <para>
+    Windows stores the credentials cache (<acronym>CC</acronym>) in memory
+    and protects this area against unauthorized applications. But it is
+    neccessary to allow applications access to the CC to implement a real
+    single sign on solution. In detail applications need access to a
+    current, valid <acronym>TGT</acronym> which is stored in the
+    <acronym>CC</acronym>.
+    </para>
+
+    <para>
+    Sun Java 1.6 should solve this problem by using the native Microsoft
+    libraries but in fact doesn't. Therefore the registry fix described in
+    described in <xref linkend="gss-ms-reg-w2k-w2k3-vista"/> and <xref
+    linkend="gss-ms-reg-xp"/> is needed.
+    </para>
+
+    <para>
+    You also need to create a Kerberos configuration file. On Windows it is
+    named <literal>krb5.ini</literal> and is searched for in the Windows system
+    directory (e.g. <literal>C:\Windows</literal>). An example configuration is
+    in <xref linkend="gss-client-linux"/>.
+    </para>
+
+    <sect3 id="gss-ms-reg-w2k-w2k3-vista">
+      <title>Windows 2000 SP4, 2003 Server and later or Vista</title>
+
+      <para>
+	  Add under
+	  <literal>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters</literal>
+	  the <literal>DWORD</literal> key <literal>AllowTGTSessionKey</literal>
+	  with the value <literal>1</literal>.
+      </para>
+
+      <programlisting>
+      HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
+      Value Name: AllowTGTSessionKey
+      Value Type: REG_DWORD
+      Value: 1
+      </programlisting>
+    </sect3>
+
+    <sect3 id="gss-ms-reg-xp">
+      <title>Windows XP</title>
+
+      <para>
+      Add under
+	  <literal>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos</literal>
+	  the <literal>DWORD</literal> key <literal>AllowTGTSessionKey</literal>
+	  with the value <literal>1</literal>.
+      </para>
+
+      <programlisting>
+      HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos
+      Value Name: AllowTGTSessionKey
+      Value Type: REG_DWORD
+      Value: 1
+      </programlisting>
+    </sect3>
+  </sect2>  
+  </sect1>  
+
+  <sect1 id="gss-jdbc">
+      <title>JDBC Configuration and Behaviour</title>
+
+    <para>
+    You can use the <acronym>JDBC</acronym> driver without supplying a user
+    name and password.  It will initialize the Kerberos environment,
+    extract the user name from the principal name of your
+    <acronym>TGT</acronym> (without realm and instance) and authenticate
+    with it.
+    </para>
+
+    <para>
+    If you supply a user name, the TGT with that user name is searched and
+    used. If it can not be found, an exception is thrown.
+    </para>
+
+    <para>
+    It is possible to define another service name for the Kerberos server
+    (default: <literal>postgres</literal>). This should not be neccessary.
+    </para>
+
+    <para>
+    The <acronym>JDBC</acronym> driver honors the setting of a keytab to
+    initialize the Kerberos stuff. If <literal>useKeyTab</literal> is not
+    defined or <literal>false</literal>, the driver tries to access the
+    credentials cache of the current user. For more information take a look
+    at the documentation of <classname>Krb5LoginModule</classname>.
+    </para>
+  </sect1>
+ </chapter>
 
   <chapter id="query">
    <title>Issuing a Query and Processing the Result</title>
diff -Nur postgresql-jdbc-8.3-604.src.orig/org/postgresql/core/v3/ConnectionFactoryImpl.java postgresql-jdbc-8.3-604.src/org/postgresql/core/v3/ConnectionFactoryImpl.java
--- postgresql-jdbc-8.3-604.src.orig/org/postgresql/core/v3/ConnectionFactoryImpl.java	2008-01-08 07:56:27.000000000 +0100
+++ postgresql-jdbc-8.3-604.src/org/postgresql/core/v3/ConnectionFactoryImpl.java	2009-07-01 13:32:08.211901000 +0200
@@ -24,6 +24,7 @@
 import org.postgresql.util.ServerErrorMessage;
 import org.postgresql.util.UnixCrypt;
 import org.postgresql.util.MD5Digest;
+import org.postgresql.util.GSSHelper;
 import org.postgresql.util.GT;
 
 /**
@@ -39,6 +40,12 @@
     private static final int AUTH_REQ_CRYPT = 4;
     private static final int AUTH_REQ_MD5 = 5;
     private static final int AUTH_REQ_SCM = 6;
+    private static final int AUTH_REQ_GSS = 7;      /* GSSAPI without wrap() */
+    private static final int AUTH_REQ_GSS_CONT = 8; /* Continue GSS exchanges */
+    private static final int AUTH_REQ_SSPI = 9;     /* SSPI negotiate without wrap() */
+
+    // helper-object for GSS-API stuff
+    private GSSHelper gssHelper = null;
 
     /** Marker exception; thrown when we want to fall back to using V2. */
     private static class UnsupportedProtocolException extends IOException {
@@ -80,6 +87,27 @@
             if (trySSL)
                 newStream = enableSSL(newStream, requireSSL, info, logger);
 
+            // try to initialize GSS API but don't fail here (we don't know if
+            // the server will ask us for GSS authentication...):
+            try
+            {
+                gssHelper = new GSSHelper(host, user, info, logger);
+
+                // if no user name was supplied, we'll take it from the
+                // currently logged in user
+                if (user == null || user.length() == 0)
+                {
+                    user = gssHelper.getUserName();
+                    if (logger.logDebug())
+                        logger.debug("using user name " + user); 
+                }
+            }
+            catch (PSQLException e)
+            {
+                if (logger.logDebug())
+                    logger.debug("failed to initialize GSS API: " + e.toString());
+            }
+            
             // Construct and send a startup packet.
             String[][] params = {
                                     { "user", user },
@@ -92,7 +120,7 @@
             sendStartupPacket(newStream, params, logger);
 
             // Do authentication (until AuthenticationOk).
-            doAuthentication(newStream, user, info.getProperty("password"), logger);
+            doAuthentication(newStream, info, user, info.getProperty("password"), logger);
 
             // Do final startup.
             ProtocolConnectionImpl protoConnection = new ProtocolConnectionImpl(newStream, user, database, info, logger);
@@ -244,8 +272,10 @@
         pgStream.flush();
     }
 
-    private void doAuthentication(PGStream pgStream, String user, String password, Logger logger) throws IOException, SQLException
+    private void doAuthentication(PGStream pgStream, Properties info, String user, String password, Logger logger) throws IOException, SQLException
     {
+        boolean usingGSS = false;
+
         // Now get the response from the backend, either an error message
         // or an authentication request
 
@@ -363,9 +393,73 @@
                         break;
                     }
 
+                case AUTH_REQ_GSS:
+                    {
+                        if (logger.logDebug()) 
+                            logger.debug(" <=BE AuthenticationReqGss");
+
+                        if (gssHelper == null)
+                            throw new PSQLException(
+                                    GT.tr(
+                                        "GSS authentication requested by server but GSS API not initialized."), 
+                                    PSQLState.CONNECTION_UNABLE_TO_CONNECT);
+
+                        usingGSS = true;
+
+                        byte[] token = null;
+                        token = gssHelper.establishContext(token);
+                        if (token != null) {
+                            if (logger.logDebug()) 
+                                logger.debug(" FE=> GSS token (" + token.length + " bytes)");
+                            pgStream.SendChar('p');
+                            pgStream.SendInteger4(token.length + 4);
+                            pgStream.Send(token);
+                            pgStream.flush();
+                        }
+
+                        break;
+                    }
+
+                case AUTH_REQ_GSS_CONT:
+                    {
+                        if (logger.logDebug())
+                            logger.debug(" <=BE AuthenticationReqGssCont");
+
+                        if (gssHelper == null)
+                            throw new PSQLException(
+                                    GT.tr(
+                                        "GSS authentication continuation requested but GSS API not initialized."), 
+                                    PSQLState.CONNECTION_UNABLE_TO_CONNECT);
+
+                        // token length = msg_len - sizeof(msg_len) - sizeof(auth_type)
+                        byte[] token = new byte[l_msgLen - 8];
+                        pgStream.Receive(token, 0, token.length);
+
+                        if (logger.logDebug())
+                            logger.debug(" <=BE GSS token (" + token.length + " bytes)");
+
+                        token = gssHelper.establishContext(token);
+                        if (token != null) {
+                            if (logger.logDebug()) 
+                                logger.debug( " FE=> GSS token (" + token.length + " bytes)");
+                            pgStream.SendChar('p');
+                            pgStream.SendInteger4(token.length + 4);
+                            pgStream.Send(token);
+                            pgStream.flush();
+                        }
+
+                        break;
+                    }
+
                 case AUTH_REQ_OK:
                     if (logger.logDebug())
                         logger.debug(" <=BE AuthenticationOk");
+                        
+                    // throw an exception if the GSS API context is not completely established 
+                    if (usingGSS && !gssHelper.isContextEstablished())
+                    {
+                        throw new PSQLException(GT.tr("The GSS context between server and client is not fully established. Maybe the server is compromised."), PSQLState.CONNECTION_FAILURE);
+                    }
 
                     return ; // We're done.
 
diff -Nur postgresql-jdbc-8.3-604.src.orig/org/postgresql/util/GSSHelper.java postgresql-jdbc-8.3-604.src/org/postgresql/util/GSSHelper.java
--- postgresql-jdbc-8.3-604.src.orig/org/postgresql/util/GSSHelper.java	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-jdbc-8.3-604.src/org/postgresql/util/GSSHelper.java	2009-07-01 15:05:51.123096000 +0200
@@ -0,0 +1,296 @@
+/*-------------------------------------------------------------------------
+ * GSSHelper.java
+ *
+ * Author: Christian Jung <christian.jung@saarstahl.com> 
+ */
+package org.postgresql.util;
+
+import com.sun.security.auth.module.Krb5LoginModule;
+import java.lang.RuntimeException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.LoginException;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import org.postgresql.core.Logger;
+import org.postgresql.util.GT;
+import org.postgresql.util.PSQLException;
+import org.postgresql.util.PSQLState;
+
+/**
+ * This class implements methods used for the GSS API authentication protocol
+ * on a PostgreSQL.
+ *
+ * @author Christian Jung (christian.jung@saarstahl.com)
+ */
+public class GSSHelper extends Object
+{
+    // constants:
+    private static final String PG_KRB_SRV_NAM = "postgres";
+    private static final org.ietf.jgss.Oid OID_KRB5_MECH;
+
+    // initialize complex class objects:
+    static 
+    {
+        try 
+        {
+            OID_KRB5_MECH = new org.ietf.jgss.Oid(
+                    "1.2.840.113554.1.2.2");
+        }
+        catch (GSSException e) 
+        {
+            throw new RuntimeException(e);
+        }    
+    }
+
+    private Subject    subject = null;             // object which stores the private credentials of the local user
+    private GSSContext context = null;             // GSS context
+    private String     userPrincipalName = null;   // principal name of the local user
+    private String     krbServiceName = null;      // service-part of server's principal name
+    private String     fqdn = null;                // full qualified domain name of the server
+
+    
+    /**
+     * Creates a new GSSHelper object. 
+     *
+     * It is used in the ConnectionFactory implementation. The constructor
+     * intializes the Kerberos credentials cache and the GSS API layer needed
+     * to authenticate via GSS.
+     *
+     * @param host hostname of the server to be connected to
+     * @param user user name (may be null, a Kerberos principal or a Postgres user)
+     * @param info driver configuration
+     * @param logger logger which will be used to log
+	 * @exception PSQLException on error. All exceptions which are catched in
+	 * the constructor are passed as the cause of the PSQLException.
+     */
+    public GSSHelper(String host, String user, Properties info, Logger logger) throws PSQLException
+    {
+        krbServiceName = info.getProperty("krbsrvname", PG_KRB_SRV_NAM);
+
+        subject = new Subject();
+
+        Map<String, String> krb5LoginOptions = new HashMap<String, String>();
+        krb5LoginOptions.put("doNotPrompt", "true");
+        // set useTicketCache only if useKeyTab is "false"
+        if (System.getProperty("useKeyTab", "false").equalsIgnoreCase("false") &&
+            info.getProperty("useKeyTab", "false").equalsIgnoreCase("false"))
+            krb5LoginOptions.put("useTicketCache", "true");
+
+        // initialize kerberos stuff:
+        try 
+        {
+            Krb5LoginModule krb5Login = new Krb5LoginModule();
+            krb5Login.initialize(subject, null, null, krb5LoginOptions);
+            krb5Login.login();
+            krb5Login.commit();
+        }
+        catch (LoginException e)
+        {
+            throw new PSQLException(
+                    GT.tr("failed to initialize kerberos environment ({0})",
+                        e.toString()), PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
+        }
+
+        // check if we have a valid TGT:
+        Set privateCredentials = subject.getPrivateCredentials(KerberosTicket.class);
+        KerberosTicket krb5Tgt = null;
+        for (Iterator i = privateCredentials.iterator(); i.hasNext();)
+        {
+            KerberosTicket ticket = (KerberosTicket)i.next();
+
+            if (ticket.isInitial() && ticket.isCurrent())
+            {
+                if (logger.logDebug())
+                    logger.debug("found valid TGT of user " + ticket.getClient().getName());
+
+                // check if the TGT is from the supplied user:
+                if (user != null && user.length() > 0)
+                {
+                    String principalName = new StringTokenizer(
+                            ticket.getClient().getName().toLowerCase(), "/@").nextToken();
+
+                    if (!user.toLowerCase().equals(principalName))
+                    {
+                        logger.info("TGT principal name does not match requested user");
+                        continue;
+                    }    
+                }
+            
+                krb5Tgt = ticket;
+                break;
+            }    
+        }
+
+        if (krb5Tgt == null) 
+            throw new PSQLException(
+                    GT.tr("no valid TGT found"),
+                    PSQLState.CONNECTION_UNABLE_TO_CONNECT);
+
+        userPrincipalName = krb5Tgt.getClient().getName();
+        
+        // get the full qualified domain name of the database server
+        try
+        {
+            fqdn = InetAddress.getByName(host).getCanonicalHostName();
+        }
+        catch (UnknownHostException e)
+        {
+            throw new PSQLException(
+                    GT.tr("failed to get full qualified domain name of {0}", host), 
+                    PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
+        }
+
+        // intialize the GSS API
+        try 
+        {
+            context = (GSSContext)Subject.doAsPrivileged(
+                subject, 
+                new PrivilegedExceptionAction()
+                {
+                    public Object run() throws GSSException 
+                    {
+                        GSSManager manager = GSSManager.getInstance();
+
+                        GSSName gssPeerName = manager.createName(
+                                krbServiceName + "@" + fqdn, 
+                                GSSName.NT_HOSTBASED_SERVICE);
+                        
+                        GSSName gssUserName = manager.createName(
+                                userPrincipalName, 
+                                GSSName.NT_USER_NAME);
+
+                        GSSCredential userCredential = manager.createCredential(
+                                gssUserName,
+                                GSSCredential.DEFAULT_LIFETIME,
+                                OID_KRB5_MECH, 
+                                GSSCredential.INITIATE_ONLY);
+
+                        return manager.createContext(
+                                gssPeerName,
+                                OID_KRB5_MECH,
+                                userCredential,
+                                GSSContext.DEFAULT_LIFETIME);
+                    }            
+                }, null);
+
+            // enable mutual authentication:
+            context.requestMutualAuth(true);
+
+            // disable confidentiality and integrity checking after
+            // context establishment (this is not needed in our case)
+            context.requestConf(false);
+            context.requestInteg(false);
+        }
+        catch (GSSException e) 
+        {
+            throw new PSQLException(
+                    GT.tr("GSS API initialization failed: {0}", e.toString()), 
+                    PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
+        }
+        catch (PrivilegedActionException e) 
+        {
+            GSSException cause = (GSSException)e.getCause();
+
+            throw new PSQLException(
+                    GT.tr("GSS API initialization failed: {0}", cause.toString()), 
+                    PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
+        }
+    }
+
+
+    private byte[] token;
+    /**
+     * Establish the GSS API context between client an server.
+     *
+     * An authentication via GSS API is done by exchanging tokens between
+     * client and server until all authentication issues are met. In our case
+     * these are normally only two tokens. One to the server and one from the
+     * server (mutual authentication).
+     *
+     * The first call of this method may be done with null or an empty byte
+     * array as token. Successive calls have to be made with the token send
+     * from the server.
+     *
+     * @param in token received from the server, null or empty byte array
+     * @return token which has to be send to the server
+	 * @exception PSQLException on error. All exceptions which are catched in
+	 * this method are passed as the cause of the PSQLException.
+     */
+    public byte[] establishContext( byte[] in ) throws PSQLException
+    {
+        token = (in == null ? new byte[0] : in);
+        
+        try
+        {
+            Subject.doAsPrivileged(subject, new PrivilegedExceptionAction() 
+            {
+                public Object run() throws GSSException 
+                {
+                    if (!context.isEstablished())
+                        token = context.initSecContext(token, 0, token.length);
+
+                    return (token == null ? 0 : token.length);
+                }
+            }, null);
+        }
+        catch (PrivilegedActionException e)
+        {
+            GSSException cause = (GSSException)e.getCause();
+
+            throw new PSQLException(
+                    GT.tr("GSS error occured: {0}", cause.toString()), 
+                    PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
+        }
+
+        return token;
+    }
+
+
+    /**
+     * Returns whether the GSS context between server and client is
+     * established.
+     *
+     * @return true if the context is established otherwise false
+     */
+    public boolean isContextEstablished()
+    {
+        return (context != null ? context.isEstablished() : false);
+    }    
+
+    
+    /**
+     * Returns the Postgres user name of local principal name.
+     * 
+     * The user name is derived from the principal name by stripping any
+     * instance and realm from it.
+     *
+     * 'cju/admin@EXAMPLE.ORG' is converted to 'cju' for example.
+     *
+     * @return Postgres user name
+     */
+    public String getUserName()
+    {
+        if (userPrincipalName == null)
+            return null;
+
+        // return only the user from the principal name (analogous to
+        // C-function pg_an_to_ln())
+        return new StringTokenizer(userPrincipalName, "/@").nextToken();
+
+    }
+}
