View Javadoc

1   /**
2    * 2007, Digitalis Informatica. All rights reserved. Distribuicao e Gestao de Informatica, Lda. Estrada de Paco de Arcos
3    * num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999 http://www.digitalis.pt
4    */
5   package pt.digitalis.utils.ldap.impl.ad;
6   
7   import java.io.UnsupportedEncodingException;
8   import java.util.ArrayList;
9   import java.util.List;
10  
11  import javax.naming.directory.Attributes;
12  import javax.naming.directory.BasicAttribute;
13  import javax.naming.directory.DirContext;
14  import javax.naming.directory.ModificationItem;
15  
16  import pt.digitalis.utils.ldap.LDAPUser;
17  import pt.digitalis.utils.ldap.exception.LDAPOperationException;
18  import pt.digitalis.utils.ldap.exception.LDAPOperationReadOnlyException;
19  import pt.digitalis.utils.ldap.impl.AbstractLDAPUtils;
20  
21  /**
22   * LDAP Utils implementation for Active Directory (AD).
23   * 
24   * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a><br/>
25   * @author Luis Pinto <a href="lpinto@digitalis.pt">lpinto@digitalis.pt</a><br/>
26   * @created Apr 01, 2008
27   */
28  @SuppressWarnings("unused")
29  public class LDAPUtilsActiveDirectoryImpl extends AbstractLDAPUtils {
30  
31      /** AD's "account disabled" account option. */
32      final static private int UF_ACCOUNTDISABLE = 0x0002;
33  
34      /** AD's "account enabled" account option. */
35      final static private int UF_ACCOUNTENABLE = 0x0001;
36  
37      /** AD's "password don't expire" account option. */
38      final static private int UF_DONT_EXPIRE_PASSWD = 0x10000;
39  
40      /** AD's "normal account" account option. */
41      final static private int UF_NORMAL_ACCOUNT = 0x0200;
42  
43      /** AD's "password can't change" account option. */
44      final static private int UF_PASSWD_CANT_CHANGE = 0x0040;
45  
46      /** AD's "password not required" account option. */
47      final static private int UF_PASSWD_NOTREQD = 0x0020;
48  
49      /** AD's "password expired" account option. */
50      final static private int UF_PASSWORD_EXPIRED = 0x800000;
51  
52      /** the unchangeable attributes */
53      final static List<String> unchangeableAttributes = new ArrayList<String>();
54  
55      /** AD's "user control value" attribute value. */
56      final static private String USER_CONTROL_VALUE = Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWD_NOTREQD
57              + UF_DONT_EXPIRE_PASSWD + UF_ACCOUNTENABLE);
58  
59      static
60      {
61          unchangeableAttributes.add("USNCHANGED");
62          unchangeableAttributes.add("WHENCHANGED");
63  
64      }
65  
66      /**
67       * For the AD implementation an entity's DN is composed of the common name and the parent group's DN, excluding the
68       * group´s CN.<br>
69       * <br>
70       * Example:<br>
71       * <br>
72       * <br>
73       * - User login name: 'user1' <br>
74       * <br>
75       * - Main group's DN: cn=group1,ou=group1,dc=dc1,dc=dc2 <br>
76       * <br>
77       * - User's DN: cn=user1,ou=group1,dc=dc1,dc=dc2 <br>
78       * 
79       * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#calculateDistinguishedName(java.lang.String,
80       *      java.lang.String)
81       */
82      @Override
83      protected String calculateDistinguishedName(String commonName, String mainGroupDN) throws LDAPOperationException
84      {
85  
86          if (commonName == null)
87              throw new LDAPOperationException(
88                      "The supplied CN was null! Cannot calculate the entity's DN without a valid CN...");
89          if (mainGroupDN == null)
90          {
91              throw new LDAPOperationException(
92                      "The supplied parent group name was null!! Cannot calculate the entity's DN without a valid parent group name...");
93          }
94  
95          // Create user CN part
96          StringBuffer newDistinguishedName = new StringBuffer(AbstractLDAPUtils.CN_TAG + commonName);
97  
98          // Get group DN
99          StringBuffer groupDistinguishedName = new StringBuffer(mainGroupDN);
100 
101         // Discard group's CN
102         groupDistinguishedName.trimToSize();
103         groupDistinguishedName.replace(0, groupDistinguishedName.capacity(),
104                 groupDistinguishedName.substring(groupDistinguishedName.indexOf(",")));
105 
106         // Append the group's DN to user's DN
107         newDistinguishedName.append(groupDistinguishedName);
108 
109         // Return result
110         return newDistinguishedName.toString();
111     }
112 
113     /**
114      * @see pt.digitalis.utils.ldap.ILDAPUtils#changePassword(java.lang.String, java.lang.String)
115      */
116     @Override
117     public void changePassword(String loginName, String newPassword) throws LDAPOperationException
118     {
119         if (this.isReadOnly())
120             throw new LDAPOperationReadOnlyException();
121 
122         // Define encoding to use for password
123         final String ENCODING = "UTF-16LE";
124 
125         // Setting the password for the user
126         try
127         {
128             // Quote the password
129             String newQuotedPassword = "\"" + newPassword + "\"";
130             // Set the encoding
131             byte[] newUnicodePassword = newQuotedPassword.getBytes(ENCODING);
132 
133             // Define the attribute to change
134             // ModificationItem[] mods = new ModificationItem[2];
135             ModificationItem[] mods = new ModificationItem[1];
136             mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd",
137                     newUnicodePassword));
138             // mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl",
139             // Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWORD_EXPIRED)));
140 
141             super.modifyAttributes(findUserByLogin(loginName).getDistinguishedName(), mods, true);
142 
143         }
144         catch (UnsupportedEncodingException unsupportedEncodingException)
145         {
146             throw new LDAPOperationException(ENCODING + " encoding not suppported!", unsupportedEncodingException);
147         }
148     }
149 
150     /**
151      * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#getAttributesForUserAddition(pt.digitalis.utils.ldap.LDAPUser)
152      */
153     @Override
154     protected Attributes getAttributesForUserAddition(LDAPUser newUser) throws LDAPOperationException
155     {
156 
157         Attributes attrs = super.getAttributesForUserAddition(newUser);
158         attrs.put(getUserControlAttributeName(), LDAPUtilsActiveDirectoryImpl.USER_CONTROL_VALUE);
159 
160         String result = "";
161         String baseDn = getConfigurations().getBaseSearchDN();
162         String[] baseDnArray = baseDn.split(",");
163 
164         for (String content: baseDnArray)
165         {
166             if (content.toUpperCase().startsWith("DC"))
167             {
168                 if ("".equals(result))
169                 {
170                     result = content.split("=")[1];
171                 }
172                 else
173                 {
174                     result += "." + content.split("=")[1];
175                 }
176             }
177         }
178 
179         if ("".equals(result))
180         {
181             result = newUser.getLoginName();
182         }
183         else
184         {
185             result = newUser.getLoginName() + "@" + result;
186         }
187 
188         /*
189          * This attribute contains the UPN that is an Internet-style login name for a user based on the Internet
190          * standard RFC 822. The UPN is shorter than the distinguished name and easier to remember. By convention, this
191          * should map to the user e-mail name. The value set for this attribute is equal to the length of the user's ID
192          * and the domain name. Source: http://msdn.microsoft.com/en-us/library/ms680857%28VS.85%29.aspx
193          */
194         attrs.put("userPrincipalName", result);
195 
196         return attrs;
197     }
198 
199     /**
200      * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#getGroupClassName()
201      */
202     @Override
203     protected String getGroupClassName()
204     {
205         return "group";
206     }
207 
208     /**
209      * The LDAP attribute 'desktopProfile' was chosen to store the group's parent group information since there is no
210      * attribute on the so-called LDAP standard for the this information, and such information is needed for this
211      * implementation. VALIDATE: Luis: is this the appropriate attribute?
212      * 
213      * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#getGroupParentGroupAttributeName()
214      */
215     @Override
216     public String getGroupParentGroupAttributeName()
217     {
218         return "desktopProfile";
219     }
220 
221     /**
222      * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#getMailAttributeName()
223      */
224     @Override
225     public String getMailAttributeName()
226     {
227         return "mail";
228     }
229 
230     /**
231      * @see pt.digitalis.utils.ldap.ILDAPUtils#getUnchangeableLDAPAttributes()
232      */
233     public List<String> getUnchangeableLDAPAttributes()
234     {
235         return unchangeableAttributes;
236     }
237 
238     /**
239      * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#getUserClassName()
240      */
241     @Override
242     protected String getUserClassName()
243     {
244         return "user";
245     }
246 
247     /**
248      * Returns the standard LDAP name for the 'user account control' attribute. To be overridden on the different LDAP
249      * implementations. This method must NOT be qualified with 'final' and/or 'static' to preserve polymorphic behavior.
250      * 
251      * @return the standard LDAP name for the 'user account control' attribute
252      */
253     protected String getUserControlAttributeName()
254     {
255         return "userAccountControl";
256     }
257 
258     /**
259      * @see pt.digitalis.utils.ldap.impl.AbstractLDAPUtils#getUserLoginAttributeName()
260      */
261     @Override
262     public String getUserLoginAttributeName()
263     {
264         return "sAMAccountName";
265     }
266 }