From 841933daec4f92d73f999337422fab52c1030b1f Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Mon, 23 Mar 2009 13:54:44 +0000
Subject: [PATCH] Fixes for these issues:

---
 opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java |  210 ++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 147 insertions(+), 63 deletions(-)

diff --git a/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
index 75b29c7..08727bf 100644
--- a/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.extensions;
 
@@ -52,7 +52,9 @@
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslException;
 
+import org.ietf.jgss.GSSException;
 import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.meta.
   GSSAPISASLMechanismHandlerCfgDefn.QualityOfProtection;
@@ -129,27 +131,14 @@
   @Override()
   public void initializeSASLMechanismHandler(
       GSSAPISASLMechanismHandlerCfg configuration) throws ConfigException,
-      InitializationException
-  {
-    configuration.addGSSAPIChangeListener(this);
-    this.configuration = configuration;
-    configEntryDN = configuration.dn();
-    try
-    {
-      DN identityMapperDN = configuration.getIdentityMapperDN();
-      identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
-      serverFQDN = getFQDN(configuration);
-      Message msg = INFO_GSSAPI_SERVER_FQDN.get(serverFQDN);
-      logError(msg);
-      saslProps = new HashMap<String, String>();
-      saslProps.put(Sasl.QOP, getQOP(configuration));
-      saslProps.put(Sasl.REUSE, "false");
-      String configFileName = configureLoginConfFile(configuration);
-      System.setProperty(JAAS_PROPERTY_CONFIG_FILE, configFileName);
-      System.setProperty(JAAS_PROPERTY_SUBJECT_CREDS_ONLY, "false");
-      getKdcRealm(configuration);
+      InitializationException {
+    try {
+      initialize(configuration);
       DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_GSSAPI, this);
-      login();
+      configuration.addGSSAPIChangeListener(this);
+      this.configuration = configuration;
+      Message msg = INFO_GSSAPI_STARTED.get();
+      logError(msg);
     }
     catch (UnknownHostException unhe)
     {
@@ -305,8 +294,8 @@
    *           If the configuration file cannot be created.
    */
   private String configureLoginConfFile(
-      GSSAPISASLMechanismHandlerCfg configuration) throws IOException
-  {
+      GSSAPISASLMechanismHandlerCfg configuration)
+  throws IOException, InitializationException {
     String configFileName;
     File tempFile = File.createTempFile("login", "conf");
     configFileName = tempFile.getAbsolutePath();
@@ -315,27 +304,28 @@
     w.write(getClass().getName() + " {");
     w.newLine();
     w.write("  com.sun.security.auth.module.Krb5LoginModule required "
-        + "storeKey=true useKeyTab=true ");
-    String keyTabFile = configuration.getKeytab();
-    if (keyTabFile != null)
-    {
-      w.write("keyTab=\"" + keyTabFile + "\" ");
+        + "storeKey=true useKeyTab=true doNotPrompt=true ");
+    String keyTabFilePath = configuration.getKeytab();
+    if(keyTabFilePath == null) {
+      String home = System.getProperty("user.home");
+      String sep = System.getProperty("file.separator");
+      keyTabFilePath = home+sep+"krb5.keytab";
     }
+    File keyTabFile = new File(keyTabFilePath);
+    if(!keyTabFile.exists()) {
+      Message msg = ERR_SASL_GSSAPI_KEYTAB_INVALID.get(keyTabFilePath);
+      throw new InitializationException(msg);
+    }
+    w.write("keyTab=\"" + keyTabFile + "\" ");
     StringBuilder principal = new StringBuilder();
     String principalName = configuration.getPrincipalName();
     String realm = configuration.getRealm();
     if (principalName != null)
-    {
       principal.append("principal=\"" + principalName);
-    }
     else
-    {
       principal.append("principal=\"ldap/" + serverFQDN);
-    }
     if (realm != null)
-    {
       principal.append("@" + realm);
-    }
     w.write(principal.toString());
     Message msg = INFO_GSSAPI_PRINCIPAL_NAME.get(principal.toString());
     logError(msg);
@@ -354,14 +344,23 @@
    * {@inheritDoc}
    */
   @Override()
-  public void finalizeSASLMechanismHandler()
-  {
+  public void finalizeSASLMechanismHandler() {
     logout();
+    if(configuration != null)
     configuration.removeGSSAPIChangeListener(this);
     DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_GSSAPI);
+    clearProperties();
+    Message msg = INFO_GSSAPI_STOPPED.get();
+    logError(msg);
   }
 
 
+private void clearProperties() {
+  System.clearProperty(KRBV_PROPERTY_KDC);
+  System.clearProperty(KRBV_PROPERTY_REALM);
+  System.clearProperty(JAAS_PROPERTY_CONFIG_FILE);
+  System.clearProperty(JAAS_PROPERTY_SUBJECT_CREDS_ONLY);
+}
 
   /**
    * {@inheritDoc}
@@ -379,10 +378,8 @@
     }
     ClientConnection clientConn = bindOp.getClientConnection();
     SASLContext saslContext = (SASLContext) clientConn.getSASLAuthStateInfo();
-    if (saslContext == null)
-    {
-      try
-      {
+    if (saslContext == null) {
+      try {
         //If the connection is secure already (i.e., TLS), then make the
         //receive buffers sizes match.
         if(clientConn.isSecure()) {
@@ -396,15 +393,18 @@
           saslContext = SASLContext.createSASLContext(saslProps, serverFQDN,
                                   SASL_MECHANISM_GSSAPI, identityMapper);
         }
-      }
-      catch (SaslException ex)
-      {
+      } catch (SaslException ex) {
         if (debugEnabled())
-        {
           TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        Message msg;
+        GSSException gex = (GSSException) ex.getCause();
+        if(gex != null) {
+          msg = ERR_SASL_CONTEXT_CREATE_ERROR.get(SASL_MECHANISM_GSSAPI,
+              getGSSExceptionMessage(gex));
+        } else {
+          msg = ERR_SASL_CONTEXT_CREATE_ERROR.get(SASL_MECHANISM_GSSAPI,
+              getExceptionMessage(ex));
         }
-        Message msg = ERR_SASL_CONTEXT_CREATE_ERROR.get(SASL_MECHANISM_GSSAPI,
-            getExceptionMessage(ex));
         clientConn.setSASLAuthStateInfo(null);
         bindOp.setAuthFailureReason(msg);
         bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS);
@@ -415,6 +415,26 @@
   }
 
 
+  /**
+   * Get the underlying GSSException messages that really tell what the
+   * problem is. The major code is the GSS-API status and the minor is the
+   * mechanism specific error.
+   *
+   * @param gex The GSSExcption thrown.
+   *
+   * @return The message containing the major and (optional) minor codes and
+   *         strings.
+   */
+  public static Message getGSSExceptionMessage(GSSException gex) {
+    MessageBuilder message = new MessageBuilder();
+    message.append("major code (" + Integer.valueOf(gex.getMajor()).toString()
+                  + ") " +  gex.getMajorString());
+    if(gex.getMinor() != 0)
+      message.append(", minor code (" +
+                      Integer.valueOf(gex.getMinor()).toString()
+                       +  ") "  + gex.getMinorString());
+    return message.toMessage();
+  }
 
   /**
    * Retrieves the user account for the user associated with the
@@ -472,9 +492,9 @@
   public boolean isConfigurationAcceptable(
       SASLMechanismHandlerCfg configuration, List<Message> unacceptableReasons)
   {
-    GSSAPISASLMechanismHandlerCfg config =
+    GSSAPISASLMechanismHandlerCfg newConfig =
       (GSSAPISASLMechanismHandlerCfg) configuration;
-    return isConfigurationChangeAcceptable(config, unacceptableReasons);
+    return isConfigurationChangeAcceptable(newConfig, unacceptableReasons);
   }
 
 
@@ -483,10 +503,56 @@
    * {@inheritDoc}
    */
   public boolean isConfigurationChangeAcceptable(
-      GSSAPISASLMechanismHandlerCfg configuration,
-      List<Message> unacceptableReasons)
-  {
-    return true;
+      GSSAPISASLMechanismHandlerCfg newConfiguration,
+      List<Message> unacceptableReasons) {
+    boolean returnCode = true;
+    boolean newStateEnabled = newConfiguration.isEnabled();
+    boolean oldStateEnabled = false;
+    if(this.configuration != null)
+      oldStateEnabled = configuration.isEnabled();
+    if(newStateEnabled) {
+      try {
+       if(oldStateEnabled)
+         finalizeSASLMechanismHandler();
+       initialize(newConfiguration);
+       finalizeSASLMechanismHandler();
+      } catch (InitializationException ex) {
+        if (debugEnabled())
+          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        Message message = ex.getMessageObject();
+        unacceptableReasons.add(message);
+        clearProperties();
+        returnCode = false;
+      } catch (UnknownHostException ex) {
+        if (debugEnabled())
+          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        Message message = ERR_SASL_CANNOT_GET_SERVER_FQDN.get(String
+            .valueOf(configEntryDN), getExceptionMessage(ex));
+        unacceptableReasons.add(message);
+        clearProperties();
+        returnCode = false;
+      } catch (IOException ex) {
+        if (debugEnabled())
+          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        Message message = ERR_SASLGSSAPI_CANNOT_CREATE_JAAS_CONFIG
+            .get(getExceptionMessage(ex));
+        unacceptableReasons.add(message);
+        clearProperties();
+        returnCode = false;
+      } catch (LoginException ex) {
+        if (debugEnabled())
+          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        Message message = ERR_SASLGSSAPI_CANNOT_CREATE_LOGIN_CONTEXT
+            .get(getExceptionMessage(ex));
+        unacceptableReasons.add(message);
+        clearProperties();
+        returnCode = false;
+      }
+    } else {
+      if(oldStateEnabled)
+       this.finalizeSASLMechanismHandler();
+    }
+    return returnCode;
   }
 
 
@@ -495,23 +561,41 @@
    * {@inheritDoc}
    */
   public ConfigChangeResult applyConfigurationChange(
-      GSSAPISASLMechanismHandlerCfg configuration)
-  {
+      GSSAPISASLMechanismHandlerCfg configuration) {
     ResultCode resultCode = ResultCode.SUCCESS;
     boolean adminActionRequired = false;
     ArrayList<Message> messages = new ArrayList<Message>();
-    DN identityMapperDN = configuration.getIdentityMapperDN();
-    IdentityMapper<?> newIdentityMapper = DirectoryServer
-        .getIdentityMapper(identityMapperDN);
-    identityMapper = newIdentityMapper;
-    saslProps = new HashMap<String, String>();
-    saslProps.put(Sasl.QOP, getQOP(configuration));
-    saslProps.put(Sasl.REUSE, "false");
-    this.configuration = configuration;
     return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
 
-
+/**
+ * Try to initialize the GSSAPI mechanism handler with the specified config.
+ *
+ * @param config The configuration to use.
+ *
+ * @throws UnknownHostException If a host name does not resolve.
+ * @throws IOException If there was a problem creating the login file.
+ * @throws LoginException If the context could not login.
+ * @throws InitializationException If the keytab file does not exist.
+ */
+private void initialize(GSSAPISASLMechanismHandlerCfg config)
+throws UnknownHostException, IOException,
+       LoginException, InitializationException {
+    configEntryDN = config.dn();
+    DN identityMapperDN = config.getIdentityMapperDN();
+    identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+    serverFQDN = getFQDN(config);
+    Message msg = INFO_GSSAPI_SERVER_FQDN.get(serverFQDN);
+    logError(msg);
+    saslProps = new HashMap<String, String>();
+    saslProps.put(Sasl.QOP, getQOP(config));
+    saslProps.put(Sasl.REUSE, "false");
+    String configFileName = configureLoginConfFile(config);
+    System.setProperty(JAAS_PROPERTY_CONFIG_FILE, configFileName);
+    System.setProperty(JAAS_PROPERTY_SUBJECT_CREDS_ONLY, "false");
+    getKdcRealm(config);
+    login();
+}
 
   /**
    * Retrieves the QOP (quality-of-protection) from the specified

--
Gitblit v1.10.0