1   package com.atlassian.user.impl.hibernate;
2   
3   import com.atlassian.user.*;
4   import com.atlassian.user.impl.DuplicateEntityException;
5   import com.atlassian.user.impl.RepositoryException;
6   import com.atlassian.user.impl.hibernate.repository.HibernateRepository;
7   import com.atlassian.user.repository.RepositoryIdentifier;
8   import com.atlassian.user.search.page.DefaultPager;
9   import com.atlassian.user.search.page.Pager;
10  import com.atlassian.user.security.password.Credential;
11  import com.atlassian.user.security.password.PasswordEncryptor;
12  import com.atlassian.user.util.Assert;
13  import net.sf.hibernate.HibernateException;
14  import net.sf.hibernate.Query;
15  import net.sf.hibernate.Session;
16  import org.springframework.dao.DataAccessException;
17  import org.springframework.orm.hibernate.HibernateCallback;
18  import org.springframework.orm.hibernate.SessionFactoryUtils;
19  import org.springframework.orm.hibernate.support.HibernateDaoSupport;
20  
21  import java.util.List;
22  import java.util.Set;
23  
24  public class HibernateUserManager extends HibernateDaoSupport implements UserManager
25  {
26      private static final String USERNAME_FIELD = "username";
27      public static final String ENTITYID_FIELD = "entityid";
28  
29      private final RepositoryIdentifier identifier;
30      private final PasswordEncryptor passwordEncryptor;
31  
32      public HibernateUserManager(RepositoryIdentifier identifier, HibernateRepository repository, PasswordEncryptor passwordEncryptor)
33      {
34          this.identifier = identifier;
35          this.passwordEncryptor = passwordEncryptor;
36          setSessionFactory(repository.getSessionFactory());
37      }
38  
39      public Pager<User> getUsers() throws EntityException
40      {
41          try
42          {
43              return new DefaultPager<User>(getUsersFromHibernate());
44          }
45          catch (DataAccessException e)
46          {
47              throw new RepositoryException(e);
48          }
49      }
50  
51      public Pager<String> getUserNames() throws EntityException
52      {
53          try
54          {
55              return new DefaultPager<String>(getUsernamesFromHibernate());
56          }
57          catch (DataAccessException e)
58          {
59              throw new RepositoryException(e);
60          }
61      }
62  
63      /**
64       * @return an {@link User} if one could be found, otherwise null.
65       * @throws EntityException representing the exception which prohibited looking for or retrieving the user.
66       */
67      public User getUser(final String username) throws EntityException
68      {
69          return internalGetUser(username);
70      }
71  
72      public User createUser(String username) throws EntityException
73      {
74          validateNewUserName(username);
75  
76          User user = new DefaultHibernateUser(username);
77          getHibernateTemplate().save(user);
78  
79          return user;
80      }
81  
82      public User createUser(User userTemplate, Credential credential) throws EntityException
83      {
84          validateNewUserName(userTemplate.getName());
85  
86          DefaultHibernateUser user = new DefaultHibernateUser(userTemplate.getName());
87          user.setFullName(userTemplate.getFullName());
88          user.setEmail(userTemplate.getEmail());
89          user.setPassword(passwordEncryptor.getEncryptedValue(credential));
90          getHibernateTemplate().save(user);
91  
92          return user;
93      }
94  
95      private void validateNewUserName(String name) throws EntityException
96      {
97          if (name == null)
98              throw new IllegalArgumentException("Username cannot be null.");
99  
100         User existingUser = getUser(name);
101         if (existingUser != null)
102             throw new DuplicateEntityException("User with name [" + name + "] already exists in this repository (" + identifier.getName() + ")");
103     }
104 
105     /**
106      * Encrypts the plain password, sets it on the user, and saves the user.
107      */
108     public void alterPassword(User user, String password) throws EntityException
109     {
110         DefaultHibernateUser foundUser = internalGetUser(user.getName());
111         if (foundUser == null)
112             throw new EntityException("This repository [" + identifier.getName() + "] does not handle user [" + user.getName() + "]");
113 
114         String encryptedPassword = passwordEncryptor.encrypt(password);
115         foundUser.setPassword(encryptedPassword);
116         getHibernateTemplate().saveOrUpdate(foundUser);
117     }
118 
119     public void saveUser(User user) throws EntityException
120     {
121         Assert.notNull(user, "User must not be null");
122         DefaultHibernateUser persistedUser = internalGetUser(user.getName());
123         if (persistedUser == null)
124                 throw new EntityException("This repository [" + identifier + "] does not handle user [" + user.getName() + "]");
125 
126         persistedUser.setFullName(user.getFullName());
127         persistedUser.setEmail(user.getEmail());
128         getHibernateTemplate().saveOrUpdate(persistedUser);
129     }
130 
131     /**
132      * Removes the specified group, if it is present.
133      *
134      * @throws EntityException if an exception which prohibited removal
135      */
136     public void removeUser(User user) throws EntityException
137     {
138         final DefaultHibernateUser foundUser = internalGetUser(user.getName());
139         if (foundUser == null)
140             throw new IllegalArgumentException("User can not be found in this user manager: [" + user + "]");
141 
142         List<DefaultHibernateGroup> groups = getGroupsForLocalUser(foundUser);
143         if (groups != null)
144         {
145             foundUser.setGroups(null);
146 
147             for (DefaultHibernateGroup group : groups)
148             {
149                 Set members = group.getLocalMembers();
150 
151                 if (members != null)
152                     members.remove(foundUser);
153 
154                 getHibernateTemplate().saveOrUpdate(group);
155             }
156         }
157 
158         getHibernateTemplate().delete(foundUser);
159     }
160 
161     @SuppressWarnings({"unchecked"})
162     private DefaultHibernateUser internalGetUser(final String username) throws RepositoryException
163     {
164         Assert.notNull(username, "User must not be null");
165         List<DefaultHibernateUser> result;
166         try
167         {
168             result = getHibernateTemplate().executeFind(new HibernateCallback()
169             {
170                 public Object doInHibernate(Session session) throws HibernateException
171                 {
172                     Query query = session.getNamedQuery("atluser.user_find");
173                     SessionFactoryUtils.applyTransactionTimeout(query, getSessionFactory());
174                     query.setCacheable(true);
175                     query.setParameter(USERNAME_FIELD, username);
176                     return query.list();
177                 }
178             });
179         }
180         catch (DataAccessException e)
181         {
182             throw new RepositoryException(e);
183         }
184 
185         return result.isEmpty() ? null : result.get(0);
186     }
187 
188     public boolean isReadOnly(User user) throws EntityException
189     {
190         return false;
191     }
192 
193     /**
194      * @return a {@link com.atlassian.user.security.password.PasswordEncryptor} which handles the encrypytion of passwords for users managed by this
195      *         object.
196      * @throws UnsupportedOperationException - for {@link com.atlassian.user.UserManager} objects which do not create {@link com.atlassian.user.User} objects.
197      */
198     @SuppressWarnings({"UnusedDeclaration"})
199     public PasswordEncryptor getPasswordEncryptor(User user) throws EntityException
200     {
201         return passwordEncryptor;
202     }
203 
204 
205     /**
206      * @return the {@link com.atlassian.user.repository.RepositoryIdentifier} which is managed by this instance.
207      */
208     public RepositoryIdentifier getIdentifier()
209     {
210         return identifier;
211     }
212 
213     public RepositoryIdentifier getRepository(Entity entity) throws EntityException
214     {
215         return getUser(entity.getName()) == null ? null : identifier;
216     }
217 
218     /**
219      * Used to detemine whether an entity can be added (eg, can call {@link com.atlassian.user.UserManager#createUser(String)} or {@link com.atlassian.user.GroupManager#createGroup(String)}
220      */
221     public boolean isCreative()
222     {
223         return true;
224     }
225 
226     @SuppressWarnings({"unchecked"})
227     private List<User> getUsersFromHibernate()
228     {
229         List<User> result;
230         result = getHibernateTemplate().executeFind(new HibernateCallback()
231         {
232             public Object doInHibernate(Session session) throws HibernateException
233             {
234                 Query queryObject = session.getNamedQuery("atluser.user_findAll");
235                 SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
236 
237                 return queryObject.list();
238             }
239         });
240         return result;
241     }
242 
243     @SuppressWarnings("unchecked")
244     private List<String> getUsernamesFromHibernate()
245     {
246         List result;
247         result = getHibernateTemplate().executeFind(new HibernateCallback()
248         {
249             public Object doInHibernate(Session session) throws HibernateException
250             {
251                 Query queryObject = session.getNamedQuery("atluser.user_findAllUserNames");
252                 SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
253 
254                 return queryObject.list();
255             }
256         });
257         return result;
258     }
259 
260     @SuppressWarnings("unchecked")
261     private List<DefaultHibernateGroup> getGroupsForLocalUser(final DefaultHibernateUser user) throws RepositoryException
262     {
263         Assert.notNull(user, "User must not be null");
264 
265         try
266         {
267             return getHibernateTemplate().executeFind(new HibernateCallback()
268             {
269                 public Object doInHibernate(Session session) throws HibernateException
270                 {
271                     Query queryObject = session.getNamedQuery("atluser.group_getGroupsForUser");
272                     SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
273                     queryObject.setLong(ENTITYID_FIELD, user.getId());
274                     queryObject.setCacheable(true);
275                     return queryObject.list();
276                 }
277             });
278         }
279         catch (DataAccessException e)
280         {
281             throw new RepositoryException(e);
282         }
283     }
284 }