BasicNtlmLogon.java

package sk.iway.iwcm.system.ntlm;

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapContext;

import org.apache.commons.collections.CollectionUtils;

import sk.iway.iwcm.Constants;
import sk.iway.iwcm.Logger;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.common.DocTools;
import sk.iway.iwcm.gallery.GalleryDB;
import sk.iway.iwcm.i18n.Prop;
import sk.iway.iwcm.io.IwcmFile;
import sk.iway.iwcm.io.IwcmOutputStream;
import sk.iway.iwcm.users.PermissionGroupBean;
import sk.iway.iwcm.users.PermissionGroupDB;
import sk.iway.iwcm.users.UserDetails;
import sk.iway.iwcm.users.UserGroupDetails;
import sk.iway.iwcm.users.UserGroupsDB;
import sk.iway.iwcm.users.UsersDB;

/**
 *  BasicNtlmLogon.java - univerzalne overenie pouzivatela v ActiveDirectory (LDAP)
 *
 *@Title        webjet7
 *@Company      Interway s.r.o. (www.interway.sk)
 *@Copyright    Interway s.r.o. (c) 2001-2012
 *@author       $Author: jeeff jeeff $
 *@version      $Revision: 1.3 $
 *@created      Date: 15.2.2012 13:54:31
 *@modified     $Date: 2004/08/16 06:26:11 $
 */
public class BasicNtlmLogon
{
	protected BasicNtlmLogon() {
		//utility class
	}
	/**
	 * LDAP dotaz pre autorizaciu v ActiveDirectory
	 * @param user
	 */
	public static void doLdapQuery(UserDetails user)
	{
		doLdapQuery(user, AuthenticationFilter.getLdapProvider(), AuthenticationFilter.getLdapUsername(), AuthenticationFilter.getLdapPassword());
	}

	/**
	 * LDAP dotaz pre autorizaciu
	 * @param user
	 * @param ldapProviderUrl
	 * @param ldapUsername
	 * @param ldapPassword
	 */
	@SuppressWarnings("unchecked")
	public static void doLdapQuery(UserDetails user, String ldapProviderUrl, String ldapUsername, String ldapPassword)
	{
		DirContext ctx = null;

		try
		{
			Logger.debug(BasicNtlmLogon.class, "Logging user: "+ user.getLogin());

			Hashtable<String, Object> env = new Hashtable<>(); //NOSONAR

			String ldapDomainAppend = Constants.getString("ldapDomainAppend");

			boolean ldapUseSslProtocol = Constants.getBoolean("ldapUseSslProtocol");
			if(ldapUseSslProtocol) env.put(Context.SECURITY_PROTOCOL, "ssl");
			env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
			env.put(Context.STATE_FACTORIES, "PersonStateFactory");
			env.put(Context.OBJECT_FACTORIES, "PersonObjectFactory");
			env.put(Context.PROVIDER_URL, ldapProviderUrl);  // SET YOUR SERVER AND STARTING CONTEXT HERE
			String ldapSecurityPrincipalDn = Constants.getString("ldapSecurityPrincipalDn"); //napr. cn=!USERNAME!,dc=ad,dc=interway,dc=sk
			if(Tools.isEmpty(ldapSecurityPrincipalDn)) ldapSecurityPrincipalDn = ldapUsername+ldapDomainAppend;
			else ldapSecurityPrincipalDn = Tools.replace(ldapSecurityPrincipalDn, "!USERNAME!", ldapUsername+ldapDomainAppend);
			env.put(Context.SECURITY_PRINCIPAL, ldapSecurityPrincipalDn); //"cn=Administrator, o=oracle.local");  // SET USER THAT CAN SEARCH AND MODIFY FULL NAME HERE
			env.put(Context.SECURITY_CREDENTIALS, ldapPassword);  // SET PASSWORD HERE
			env.put(Context.REFERRAL, "follow");
			env.put(Context.LANGUAGE, "sk-SK");
			env.put(LdapContext.CONTROL_FACTORIES, "com.sun.jndi.ldap.ControlFactory");

			Logger.debug(BasicNtlmLogon.class, "ldap: ldapProviderUrl="+ldapProviderUrl+" ldapSecurityPrincipalDn="+ldapSecurityPrincipalDn+" ldapUsername="+ldapUsername+ldapDomainAppend);

			ctx = new InitialDirContext(env);

			// Specify the search filter to match all users with no full name
			String filter = Constants.getString("ldapFilter");  //"(&(objectClass=Person) (&(sAMAccountName="+user.getLogin()+")))"; // "DC=oracle, (&(objectClass=Person) (&(sn=priezvisko)))";
			filter = Tools.replace(filter, "!USERNAME!", user.getLogin()+ldapDomainAppend);

			// limit returned attributes to those we care about
			//String[] attrIDs = {"sn", "givenName", "mail"};
			SearchControls ctls = new SearchControls();
			//ctls.setReturningAttributes(attrIDs);
			// comment out next line to limit to one container otherwise it'll walk down the tree
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);

			String[] retAttrs = Tools.getTokens(Constants.getString("basicNtlmLogonAttrs"), ",");
			ctls.setReturningAttributes(retAttrs);

			// Search for objects using filter and controls
			NamingEnumeration<SearchResult> answer = ctx.search("", filter, ctls);

			StringBuilder ldapGroups = new StringBuilder();
			// cycle through result set
			if (answer.hasMore())
			{
				SearchResult sr = answer.next();
				Attributes attrs = sr.getAttributes();

				//DEBUG: treba vymazat
				/*
				NamingEnumeration allAttrs = attrs.getAll();
				Logger.debug(BasicNtlmLogon.class,"POCET: " + attrs.size());
				while (allAttrs.hasMoreElements())
				{
					Attribute a = (Attribute)allAttrs.next();
					Logger.debug(BasicNtlmLogon.class,"ENUM: " + a);
				}
				*/

				String origFirstName = user.getFirstName();
				String origLastName = user.getLastName();

				if (isAtrAvailable(retAttrs, "mail")) user.setEmail(NtlmLogonAction.getAtrValue(attrs, "mail", user.getEmail()));
				//user.setTitle(NtlmLogonAction.getAtrValue(attrs, "title", user.getTitle()));

				if (isAtrAvailable(retAttrs, "cn"))
				{
					String cn = NtlmLogonAction.getAtrValue(attrs, "cn", null);
					if (Tools.isNotEmpty(cn) && cn.indexOf(",")!=-1)
					{
						try
						{
							user.setTitle(cn.substring(cn.indexOf(",")).trim());
						}
						catch (Exception e)
						{
							sk.iway.iwcm.Logger.error(e);
						}
					}
				}

				if (isAtrAvailable(retAttrs, "givenName")) user.setFirstName(NtlmLogonAction.getAtrValue(attrs, "givenName", user.getFirstName()));
				if (isAtrAvailable(retAttrs, "sn")) user.setLastName(NtlmLogonAction.getAtrValue(attrs, "sn", user.getLastName()));
				if (isAtrAvailable(retAttrs, "streetAddress")) user.setAdress(NtlmLogonAction.getAtrValue(attrs, "streetAddress", user.getAdress()));
				if (isAtrAvailable(retAttrs, "l")) user.setCity(NtlmLogonAction.getAtrValue(attrs, "l", user.getCity()));
				if (isAtrAvailable(retAttrs, "postalCode")) user.setPSC(NtlmLogonAction.getAtrValue(attrs, "postalCode", user.getPSC()));
				if (isAtrAvailable(retAttrs, "co")) user.setCountry(NtlmLogonAction.getAtrValue(attrs, "co", user.getCountry()));
				if (isAtrAvailable(retAttrs, "company")) user.setCompany(NtlmLogonAction.getAtrValue(attrs, "company", user.getCompany()));
				if (isAtrAvailable(retAttrs, "telephoneNumber")) user.setPhone(NtlmLogonAction.getAtrValue(attrs, "telephoneNumber", user.getPhone()));

				if (Tools.isEmpty(user.getLastName())) user.setLastName(origLastName);
				if (Tools.isEmpty(user.getFirstName())) user.setFirstName(origFirstName);

				if (isAtrAvailable(retAttrs, "department")) user.setFieldC(NtlmLogonAction.getAtrValue(attrs, "department", user.getFieldC()));
				if (isAtrAvailable(retAttrs, "description")) user.setSignature(NtlmLogonAction.getAtrValue(attrs, "description", user.getSignature()));
				if (isAtrAvailable(retAttrs, "title")) user.setPosition(NtlmLogonAction.getAtrValue(attrs, "title", user.getPosition()));

				//CNUserName = NtlmLogonAction.getAtrValue(attrs, "cn", "");

				//ldapGroups = NtlmLogonAction.getAtrValue(attrs, "memberOf", null) + ", ";

				if (isAtrAvailable(retAttrs, "memberOf"))
				{
					Attribute memberOf = attrs.get("memberOf");
					if (memberOf != null)
					{
						NamingEnumeration<?> all = memberOf.getAll();
						while (all.hasMoreElements())
						{
							Object o = all.next();

							if (o == null) continue;

							Logger.debug(BasicNtlmLogon.class, "memberOf: "+o.toString());

							if (ldapGroups.length()>0) ldapGroups.append("\n");
							ldapGroups.append(o.toString());
						}
					}
				}

				if (isAtrAvailable(retAttrs, "distinguishedName"))
				{
					//: OU=2,OU=1,OU=mzpsr,DC=mzp,DC=enviro,DC=gov,DC=sk
					//distinguishedName: CN=Cerovska,OU=2,OU=1,OU=mzpsr,DC=mzp,DC=enviro,DC=gov,DC=sk
					String distinguishedName = NtlmLogonAction.getAtrValue(attrs, "distinguishedName", null);
					try
					{
						//ziskaj info o adresari v ktorom je
						String ldapDNSuffix = Constants.getString("ldapDNSuffix");
						if (Tools.isNotEmpty(ldapDNSuffix) && Tools.isNotEmpty(distinguishedName))
						{
							int start = distinguishedName.indexOf(",");
							int end = distinguishedName.indexOf(ldapDNSuffix);
							if (start > 0 && end > start)
							{
								String groupDN = distinguishedName.substring(start+1, end-1);
								Logger.debug(BasicNtlmLogon.class, "Getting groupDN="+groupDN);
								Attributes groupAtrs = ctx.getAttributes(groupDN);
								if (groupAtrs != null)
								{
									String description = NtlmLogonAction.getAtrValue(groupAtrs, "description", null);
									if (Tools.isNotEmpty(description))
									{
										user.setFieldA(description);
									}
								}
							}
						}
					}
					catch (Exception e)
					{
						sk.iway.iwcm.Logger.error(e);
					}
				}

				if (Constants.getBoolean("passwordUseHash"))
				{
					user.setPassword(user.getLogin());
				}

				if (isAtrAvailable(retAttrs, "thumbnailPhoto"))
				{
					Attribute photo = attrs.get("thumbnailPhoto");
					Logger.debug(BasicNtlmLogon.class, "thumbnailPhoto="+photo);
					if (photo != null)
					{
						byte[] photoBytes = (byte[])photo.get();
						Logger.debug(BasicNtlmLogon.class, "photoBytes.length="+photoBytes.length);
						if (photoBytes.length > 100)
						{
							String BASE_DIR = "/images/gallery/user/";
							String photoURL = BASE_DIR+ DocTools.removeChars(user.getLogin(), true)+".jpg";

							Logger.debug(BasicNtlmLogon.class, "Saving user photo: "+photoURL);

							IwcmFile photoFile = new IwcmFile(Tools.getRealPath(photoURL));
							if(!photoFile.exists())
							{
								//zapis do suboru
								IwcmOutputStream ios = new IwcmOutputStream(photoFile);
								ios.write(photoBytes);
								ios.close();

								//zmaz o_ a s_ fotku
								IwcmFile oPhotoFile = new IwcmFile(Tools.getRealPath(GalleryDB.getImagePathOriginal(photoURL)));
								if (oPhotoFile.exists()) oPhotoFile.delete();

								IwcmFile sPhotoFile = new IwcmFile(Tools.getRealPath(GalleryDB.getImagePathSmall(photoURL)));
								if (sPhotoFile.exists()) sPhotoFile.delete();

								//resizni
								Prop prop = Prop.getInstance();
								Dimension[] dims = GalleryDB.getDimension(BASE_DIR);
								GalleryDB.resizePictureImpl(dims, photoFile.getAbsolutePath(), null, prop, GalleryDB.getResizeMode(BASE_DIR));
							}
							else
							{
								Logger.debug(BasicNtlmLogon.class, "User photo: "+photoURL + " already exists, using existing file");
							}
							user.setPhoto(photoURL);
						}
					}
				}
				if (Tools.isNotEmpty(Constants.getString("ntlmDefaultUserPhoto")) && Tools.isEmpty(user.getPhoto()))
				{
					user.setPhoto(Constants.getString("ntlmDefaultUserPhoto"));
				}

				// eDir returns "attribute name : attribute value on get method so strip off up to ": "
				//attrs.put("fullName", givenName.substring(givenName.indexOf(':')+2) + ' ' + surName.substring(surName.indexOf(':')+2));
				//ctx.modifyAttributes(sr.getName(), DirContext.REPLACE_ATTRIBUTE, attrs);
			}
			else
			{
				user.setLogin(null);
				return;
			}

			// Close the context when we're done
			ctx.close();
			ctx = null;

			//moznost mat viac administratorskych AD skupin
			String[] ntlmAdminGroupNames = Tools.getTokens(Constants.getString("NTLMAdminGroupName"), ",");
			if (ntlmAdminGroupNames != null && ntlmAdminGroupNames.length > 0)
			{
				user.setAdmin(false);
				for(String groupName : ntlmAdminGroupNames)
				{
					if (ldapGroups.indexOf("CN="+groupName+",")!=-1)
					{
						Logger.debug(BasicNtlmLogon.class,"Je clenom skupiny '"+groupName+"', USER JE ADMIN");
						user.setAdmin(true);
						break;
					}
				}
				if(user.isAdmin() == false) Logger.debug(BasicNtlmLogon.class,"USER NIE JE ADMIN");
			}

			if (retAttrs.length>0)
			{
				Logger.debug(BasicNtlmLogon.class,"Nastavujem skupiny:\n"+ldapGroups.toString());

				//porovnavam najprv nazvy skupin prav
				List<PermissionGroupBean> permissionGroupsAll = (new PermissionGroupDB()).getAll();
				if(permissionGroupsAll != null)
				{
					List<PermissionGroupBean> permissionGroupsAfter = new ArrayList<>();

					for (PermissionGroupBean pg : permissionGroupsAll)
					{
						Logger.debug(BasicNtlmLogon.class, "testujem skupinu prav: " + pg.getTitle());
						if (ldapGroups.indexOf("CN=" + pg.getTitle() + ",") != -1)
						{
							Logger.debug(BasicNtlmLogon.class, "JE clenom skupiny prav");
							permissionGroupsAfter.add(pg);
						}
					}

					//potrebujem userId
					if(user.getUserId() < 1) UsersDB.saveUser(user);
					List<PermissionGroupBean> permissionGroupsBefore = UserGroupsDB.getPermissionGroupsFor(user.getUserId());
					for (PermissionGroupBean permGroup : (Collection<PermissionGroupBean>)CollectionUtils.subtract(permissionGroupsAfter, permissionGroupsBefore))
						UsersDB.addUserToPermissionGroup(user.getUserId(), permGroup.getUserPermGroupId());

					for (PermissionGroupBean permGroup : (Collection<PermissionGroupBean>)CollectionUtils.subtract(permissionGroupsBefore, permissionGroupsAfter))
						UsersDB.deleteUserFromPermissionGroup(user.getUserId(), permGroup.getUserPermGroupId());
				}

				//porovnavam aj pouzivatelske skupiny
				StringBuilder groupsString = new StringBuilder(Constants.getString("passwordProtectedAutoId"));
				for (UserGroupDetails ugd : UserGroupsDB.getInstance().getUserGroups())
				{
					Logger.debug(BasicNtlmLogon.class, "testujem pouzivatelsku skupinu: " + ugd.getUserGroupName());
					if (ldapGroups.indexOf("CN=" + ugd.getUserGroupName() + ",") != -1)
					{
						Logger.debug(BasicNtlmLogon.class, "je clenom pouzivatelskej skupiny");
						if (Tools.isNotEmpty(groupsString)) groupsString.append(",");
						groupsString.append("" + ugd.getUserGroupId());
					}
				}
				Logger.debug(BasicNtlmLogon.class,"nastavujem skupinyIDS: " + groupsString.toString());
				user.setUserGroupsIds(groupsString.toString());
			}
		}
		catch(Exception ne)
		{
			Logger.error(BasicNtlmLogon.class,ne.getMessage());
			sk.iway.iwcm.Logger.error(ne);
			user.setLogin(null);
		}
		finally
		{
			if (ctx != null)
			{
				try
				{
					ctx.close();
				}
				catch (Exception e2)
				{
				}
			}
		}
	}

	/**
	 * Otestuje, ci dany atribut mame nacitany (a mozeme ho nastavit)
	 * @param atrs
	 * @param name
	 * @return
	 */
	private static boolean isAtrAvailable(String[] atrs, String name)
	{
		if (atrs == null || atrs.length<1) return false;
		for (String atr : atrs)
		{
			if (atr.equals(name)) return true;
		}
		return false;
	}
}