Package de.sub.goobi.helper.ldap

Source Code of de.sub.goobi.helper.ldap.Ldap

package de.sub.goobi.helper.ldap;

/**
* This file is part of the Goobi Application - a Workflow tool for the support of mass digitization.
*
* Visit the websites for more information.
*         - http://www.goobi.org
*         - http://launchpad.net/goobi-production
*         - http://gdz.sub.uni-goettingen.de
*       - http://www.intranda.com
*       - http://digiverso.com
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions
* of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to
* link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and
* conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this
* library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.StartTlsRequest;
import javax.naming.ldap.StartTlsResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;

import de.sub.goobi.beans.Benutzer;
import de.sub.goobi.config.ConfigMain;
import de.sub.goobi.helper.FilesystemHelper;
import de.sub.goobi.helper.Helper;
import dubious.sub.goobi.helper.encryption.MD4;

public class Ldap {
  private static final Logger myLogger = Logger.getLogger(Ldap.class);

  public Ldap() {

  }

  private String getUserDN(Benutzer inBenutzer) {
    String userDN = inBenutzer.getLdapGruppe().getUserDN();
    userDN = userDN.replaceAll("\\{login\\}", inBenutzer.getLogin());
    if (inBenutzer.getLdaplogin() != null) {
      userDN = userDN.replaceAll("\\{ldaplogin\\}", inBenutzer.getLdaplogin());
    }
    userDN = userDN.replaceAll("\\{firstname\\}", inBenutzer.getVorname());
    userDN = userDN.replaceAll("\\{lastname\\}", inBenutzer.getNachname());
    return userDN;
  }

  /**
   * create new user in LDAP-directory
   *
   * @param inBenutzer
   * @param inPasswort
   * @throws NamingException
   * @throws NoSuchAlgorithmException
   * @throws InterruptedException
   * @throws IOException
   */
  public void createNewUser(Benutzer inBenutzer, String inPasswort) throws NamingException, NoSuchAlgorithmException, IOException,
      InterruptedException {

    if (!ConfigMain.getBooleanParameter("ldap_readonly", false)) {
      Hashtable<String, String> env = LdapConnectionSettings();
      env.put(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
      env.put(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));

      LdapUser dr = new LdapUser();
      dr.configure(inBenutzer, inPasswort, getNextUidNumber());
      DirContext ctx = new InitialDirContext(env);
      ctx.bind(getUserDN(inBenutzer), dr);
      ctx.close();
      setNextUidNumber();
      Helper.setMeldung(null, Helper.getTranslation("ldapWritten") + " " + inBenutzer.getNachVorname(), "");
      /*
       * -------------------------------- check if HomeDir exists, else create it --------------------------------
       */
      myLogger.debug("HomeVerzeichnis pruefen");
      String homePath = getUserHomeDirectory(inBenutzer);
      if (!new File(homePath).exists()) {
        myLogger.debug("HomeVerzeichnis existiert noch nicht");
                FilesystemHelper.createDirectoryForUser(homePath, inBenutzer.getLogin());
                myLogger.debug("HomeVerzeichnis angelegt");
      } else {
        myLogger.debug("HomeVerzeichnis existiert schon");
      }
    } else {
      Helper.setMeldung(null, Helper.getTranslation("ldapIsReadOnly"));
    }
  }

  /**
   * Check if connection with login and password possible
   *
   * @param inBenutzer
   * @param inPasswort
   * @return Login correct or not
   */
  public boolean isUserPasswordCorrect(Benutzer inBenutzer, String inPasswort) {
    myLogger.debug("start login session with ldap");
    Hashtable<String, String> env = LdapConnectionSettings();

    // Start TLS
    if (ConfigMain.getBooleanParameter("ldap_useTLS", false)) {
      myLogger.debug("use TLS for auth");
      env = new Hashtable<String, String>();
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
      env.put(Context.PROVIDER_URL, ConfigMain.getParameter("ldap_url"));
      env.put("java.naming.ldap.version", "3");
      LdapContext ctx = null;
      StartTlsResponse tls = null;
      try {
        ctx = new InitialLdapContext(env, null);

        // Authentication must be performed over a secure channel
        tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
        tls.negotiate();

        // Authenticate via SASL EXTERNAL mechanism using client X.509
        // certificate contained in JVM keystore
        ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
        ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, getUserDN(inBenutzer));
        ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, inPasswort);
        ctx.reconnect(null);
        return true;
        // Perform search for privileged attributes under authenticated context

      } catch (IOException e) {
        myLogger.error("TLS negotiation error:", e);
        return false;
      } catch (NamingException e) {
        myLogger.error("JNDI error:", e);
        return false;
      } finally {
        if (tls != null) {
          try {
            // Tear down TLS connection
            tls.close();
          } catch (IOException e) {
          }
        }
        if (ctx != null) {
          try {
            // Close LDAP connection
            ctx.close();
          } catch (NamingException e) {
          }
        }
      }
    } else {
      myLogger.debug("don't use TLS for auth");
      if (ConfigMain.getBooleanParameter("useSimpleAuthentification", false)) {
        env.put(Context.SECURITY_AUTHENTICATION, "none");
        // TODO auf passwort testen
      } else {
        env.put(Context.SECURITY_PRINCIPAL, getUserDN(inBenutzer));
        env.put(Context.SECURITY_CREDENTIALS, inPasswort);
      }
      myLogger.debug("ldap environment set");

      try {
        myLogger.debug("start classic ldap authentification");
        myLogger.debug("user DN is " + getUserDN(inBenutzer));

        if (ConfigMain.getParameter("ldap_AttributeToTest") == null) {
          myLogger.debug("ldap attribute to test is null");
          new InitialDirContext(env);
          return true;
        } else {
          myLogger.debug("ldap attribute to test is not null");
          DirContext ctx = new InitialDirContext(env);

          Attributes attrs = ctx.getAttributes(getUserDN(inBenutzer));
          Attribute la = attrs.get(ConfigMain.getParameter("ldap_AttributeToTest"));
          myLogger.debug("ldap attributes set");
          String test = (String) la.get(0);
          if (test.equals(ConfigMain.getParameter("ldap_ValueOfAttribute"))) {
            myLogger.debug("ldap ok");
            ctx.close();
            return true;
          } else {
            myLogger.debug("ldap not ok");
            ctx.close();
            return false;
          }
        }
      } catch (NamingException e) {
        myLogger.debug("login not allowed for " + inBenutzer.getLogin(), e);
        return false;
      }
    }
  }

  /**
   * retrieve home directory of given user
   *
   * @param inBenutzer
   * @return path as string
   */
  public String getUserHomeDirectory(Benutzer inBenutzer) {
    if (ConfigMain.getBooleanParameter("useLocalDirectory", false)) {
      return ConfigMain.getParameter("dir_Users") + inBenutzer.getLogin();
    }
    Hashtable<String, String> env = LdapConnectionSettings();
    if (ConfigMain.getBooleanParameter("ldap_useTLS", false)) {

      env = new Hashtable<String, String>();
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
      env.put(Context.PROVIDER_URL, ConfigMain.getParameter("ldap_url"));
      env.put("java.naming.ldap.version", "3");
      LdapContext ctx = null;
      StartTlsResponse tls = null;
      try {
        ctx = new InitialLdapContext(env, null);

        // Authentication must be performed over a secure channel
        tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
        tls.negotiate();

        // Authenticate via SASL EXTERNAL mechanism using client X.509
        // certificate contained in JVM keystore
        ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
        ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
        ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));

        ctx.reconnect(null);

        Attributes attrs = ctx.getAttributes(getUserDN(inBenutzer));
        Attribute la = attrs.get("homeDirectory");
        return (String) la.get(0);

        // Perform search for privileged attributes under authenticated context

      } catch (IOException e) {
        myLogger.error("TLS negotiation error:", e);

        return ConfigMain.getParameter("dir_Users") + inBenutzer.getLogin();
      } catch (NamingException e) {

        myLogger.error("JNDI error:", e);

        return ConfigMain.getParameter("dir_Users") + inBenutzer.getLogin();
      } finally {
        if (tls != null) {
          try {
            // Tear down TLS connection
            tls.close();
          } catch (IOException e) {
          }
        }
        if (ctx != null) {
          try {
            // Close LDAP connection
            ctx.close();
          } catch (NamingException e) {
          }
        }
      }
    } else if (ConfigMain.getBooleanParameter("useSimpleAuthentification", false)) {
      env.put(Context.SECURITY_AUTHENTICATION, "none");
    } else {
      env.put(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
      env.put(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));

    }
    DirContext ctx;
    String rueckgabe = "";
    try {
      ctx = new InitialDirContext(env);
      Attributes attrs = ctx.getAttributes(getUserDN(inBenutzer));
      Attribute la = attrs.get("homeDirectory");
      rueckgabe = (String) la.get(0);
      ctx.close();
    } catch (NamingException e) {
      myLogger.error(e);
    }
    return rueckgabe;
  }

  /**
   * check if User already exists on system
   *
   * @param inBenutzer
   * @return path as string
   */
  public boolean isUserAlreadyExists(String inLogin) {
    Hashtable<String, String> env = LdapConnectionSettings();
    env.put(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
    env.put(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));
    DirContext ctx;
    boolean rueckgabe = false;
    try {
      ctx = new InitialDirContext(env);
      Attributes matchAttrs = new BasicAttributes(true);
      NamingEnumeration<SearchResult> answer = ctx.search("ou=users,dc=gdz,dc=sub,dc=uni-goettingen,dc=de", matchAttrs);
      rueckgabe = answer.hasMoreElements();

      while (answer.hasMore()) {
        SearchResult sr = answer.next();
        myLogger.debug(">>>" + sr.getName());
        Attributes attrs = sr.getAttributes();
        String givenName = " ";
        String surName = " ";
        String mail = " ";
        String cn = " ";
        String hd = " ";
        try {
          givenName = attrs.get("givenName").toString();
        } catch (Exception err) {
          givenName = " ";
        }
        try {
          surName = attrs.get("sn").toString();
        } catch (Exception e2) {
          surName = " ";
        }
        try {
          mail = attrs.get("mail").toString();
        } catch (Exception e3) {
          mail = " ";
        }
        try {
          cn = attrs.get("cn").toString();
        } catch (Exception e4) {
          cn = " ";
        }
        try {
          hd = attrs.get("homeDirectory").toString();
        } catch (Exception e4) {
          hd = " ";
        }
        myLogger.debug(givenName);
        myLogger.debug(surName);
        myLogger.debug(mail);
        myLogger.debug(cn);
        myLogger.debug(hd);

      }

      ctx.close();
    } catch (NamingException e) {
      myLogger.error(e);
    }
    return rueckgabe;
  }

  /**
   * Get next free uidNumber
   *
   * @return next free uidNumber
   * @throws NamingException
   */
  private String getNextUidNumber() {
    Hashtable<String, String> env = LdapConnectionSettings();
    env.put(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
    env.put(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));
    DirContext ctx;
    String rueckgabe = "";
    try {
      ctx = new InitialDirContext(env);
      Attributes attrs = ctx.getAttributes(ConfigMain.getParameter("ldap_nextFreeUnixId"));
      Attribute la = attrs.get("uidNumber");
      rueckgabe = (String) la.get(0);
      ctx.close();
    } catch (NamingException e) {
      myLogger.error(e);
      Helper.setFehlerMeldung(e.getMessage());
    }
    return rueckgabe;
  }

  /**
   * Set next free uidNumber
   *
   * @throws NamingException
   */
  private void setNextUidNumber() {
    Hashtable<String, String> env = LdapConnectionSettings();
    env.put(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
    env.put(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));
    DirContext ctx;

    try {
      ctx = new InitialDirContext(env);
      Attributes attrs = ctx.getAttributes(ConfigMain.getParameter("ldap_nextFreeUnixId"));
      Attribute la = attrs.get("uidNumber");
      String oldValue = (String) la.get(0);
      int bla = Integer.parseInt(oldValue) + 1;

      BasicAttribute attrNeu = new BasicAttribute("uidNumber", String.valueOf(bla));
      ModificationItem[] mods = new ModificationItem[1];
      mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attrNeu);
      ctx.modifyAttributes(ConfigMain.getParameter("ldap_nextFreeUnixId"), mods);

      ctx.close();
    } catch (NamingException e) {
      myLogger.error(e);
    }

  }

  /**
   * change password of given user, needs old password for authentification
   *
   * @param inUser
   * @param inOldPassword
   * @param inNewPassword
   * @return boolean about result of change
   * @throws NoSuchAlgorithmException
   */
  public boolean changeUserPassword(Benutzer inBenutzer, String inOldPassword, String inNewPassword) throws NoSuchAlgorithmException {
    Hashtable<String, String> env = LdapConnectionSettings();
    if (!ConfigMain.getBooleanParameter("ldap_readonly", false)) {
      env.put(Context.SECURITY_PRINCIPAL, ConfigMain.getParameter("ldap_adminLogin"));
      env.put(Context.SECURITY_CREDENTIALS, ConfigMain.getParameter("ldap_adminPassword"));

      try {
        DirContext ctx = new InitialDirContext(env);

   
        /*
         * -------------------------------- Encryption of password and Base64-Encoding --------------------------------
         */
        MessageDigest md = MessageDigest.getInstance(ConfigMain.getParameter("ldap_encryption", "SHA"));
        md.update(inNewPassword.getBytes());
        String digestBase64 = new String(Base64.encodeBase64(md.digest()));
        ModificationItem[] mods = new ModificationItem[4];

        /*
         * -------------------------------- UserPasswort-Attribut ändern --------------------------------
         */
        BasicAttribute userpassword = new BasicAttribute("userPassword", "{" + ConfigMain.getParameter("ldap_encryption", "SHA") + "}"
            + digestBase64);

        /*
         * -------------------------------- LanMgr-Passwort-Attribut ändern --------------------------------
         */
        BasicAttribute lanmgrpassword = null;
        try {
          lanmgrpassword = new BasicAttribute("sambaLMPassword", LdapUser.toHexString(LdapUser.lmHash(inNewPassword)));
          // TODO: Don't catch super class exception, make sure that the password isn't logged here
        } catch (Exception e) {
          myLogger.error(e);
        }

        /*
         * -------------------------------- NTLM-Passwort-Attribut ändern --------------------------------
         */
        BasicAttribute ntlmpassword = null;
        try {
          byte hmm[] = MD4.mdfour(inNewPassword.getBytes("UnicodeLittleUnmarked"));
          ntlmpassword = new BasicAttribute("sambaNTPassword", LdapUser.toHexString(hmm));
        } catch (UnsupportedEncodingException e) {
          // TODO: Make sure that the password isn't logged here
          myLogger.error(e);
        }

        BasicAttribute sambaPwdLastSet = new BasicAttribute("sambaPwdLastSet", String.valueOf(System.currentTimeMillis() / 1000l));

        mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, userpassword);
        mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, lanmgrpassword);
        mods[2] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, ntlmpassword);
        mods[3] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, sambaPwdLastSet);
        ctx.modifyAttributes(getUserDN(inBenutzer), mods);

        // Close the context when we're done
        ctx.close();
        return true;
      } catch (NamingException e) {
        myLogger.debug("Benutzeranmeldung nicht korrekt oder Passwortänderung nicht möglich", e);
        return false;
      }
    }
    return false;
  }

  private Hashtable<String, String> LdapConnectionSettings() {
    // Set up environment for creating initial context
    Hashtable<String, String> env = new Hashtable<String, String>(11);
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ConfigMain.getParameter("ldap_url"));
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    /* wenn die Verbindung über ssl laufen soll */
    if (ConfigMain.getBooleanParameter("ldap_sslconnection")) {
      String keystorepath = ConfigMain.getParameter("ldap_keystore");
      String keystorepasswd = ConfigMain.getParameter("ldap_keystore_password");

      // add all necessary certificates first
      loadCertificates(keystorepath, keystorepasswd);

      // set properties, so that the current keystore is used for SSL
      System.setProperty("javax.net.ssl.keyStore", keystorepath);
      System.setProperty("javax.net.ssl.trustStore", keystorepath);
      System.setProperty("javax.net.ssl.keyStorePassword", keystorepasswd);
      env.put(Context.SECURITY_PROTOCOL, "ssl");
    }
    return env;
  }

  private void loadCertificates(String path, String passwd) {
    /* wenn die Zertifikate noch nicht im Keystore sind, jetzt einlesen */
    File myPfad = new File(path);
    if (!myPfad.exists()) {
      try {
        FileOutputStream ksos = new FileOutputStream(path);
        // TODO: Rename parameters to something more meaningful, this is quite specific for the GDZ
        FileInputStream cacertFile = new FileInputStream(ConfigMain.getParameter("ldap_cert_root"));
        FileInputStream certFile2 = new FileInputStream(ConfigMain.getParameter("ldap_cert_pdc"));

        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cacert = (X509Certificate) cf.generateCertificate(cacertFile);
        X509Certificate servercert = (X509Certificate) cf.generateCertificate(certFile2);

        KeyStore ks = KeyStore.getInstance("jks");
        char[] password = passwd.toCharArray();

        // TODO: Let this method really load a keystore if configured
        // initalize the keystore, if file is available, load the keystore
        ks.load(null);

        ks.setCertificateEntry("ROOTCERT", cacert);
        ks.setCertificateEntry("PDC", servercert);

        ks.store(ksos, password);
        ksos.close();
      } catch (Exception e) {
        myLogger.error(e);
      }

    }
  }

}
TOP

Related Classes of de.sub.goobi.helper.ldap.Ldap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.