1   package com.atlassian.user.impl.osuser;
2   
3   import com.atlassian.user.Entity;
4   import com.atlassian.user.EntityException;
5   import com.atlassian.user.User;
6   import com.atlassian.user.UserManager;
7   import com.atlassian.user.impl.RepositoryException;
8   import com.atlassian.user.repository.RepositoryIdentifier;
9   import com.atlassian.user.search.EntityNameAlphaComparator;
10  import com.atlassian.user.search.page.DefaultPager;
11  import com.atlassian.user.search.page.Pager;
12  import com.atlassian.user.security.password.Credential;
13  import com.atlassian.user.util.Assert;
14  import com.opensymphony.module.propertyset.PropertySet;
15  import com.opensymphony.user.ImmutableException;
16  import com.opensymphony.user.provider.CredentialsProvider;
17  
18  import java.util.*;
19  
20  /**
21   * An adaptor class for {@link CredentialsProvider} and some of the higher level operations of {@link com.opensymphony.user.UserManager}
22   * <p/>
23   * The rule is to use the credentialsProvider and/or profileProvider (for propertySets) for most things. Store() operations
24   * must be called on the entity itself.
25   */
26  public class OSUUserManager extends OSUEntityManager implements UserManager
27  {
28      private final OSUAccessor accessor;
29  
30      public OSUUserManager(RepositoryIdentifier repository, OSUAccessor accessor)
31      {
32          super(repository);
33          this.accessor = accessor;
34      }
35  
36      public Pager<User> getUsers()
37      {
38          Collection<String> userNames = getUserNamesInternal();
39          SortedSet<User> atlassianUsers = new TreeSet<User>(new EntityNameAlphaComparator());
40  
41          for (String username : userNames)
42          {
43              OSUUser user = getWrappedOSUUser(username);
44              if (user != null)
45                  atlassianUsers.add(user);
46          }
47  
48          return new DefaultPager<User>(atlassianUsers);
49      }
50  
51      public Pager<String> getUserNames() throws EntityException
52      {
53          return new DefaultPager<String>(getUserNamesInternal());
54      }
55  
56      public User getUser(String username)
57      {
58          return getWrappedOSUUser(username);
59      }
60  
61      private OSUUser getWrappedOSUUser(String username)
62      {
63          com.opensymphony.user.User opensymphonyUser = getOpenSymphonyUser(username);
64          return opensymphonyUser == null ? null : new OSUUser(opensymphonyUser);
65      }
66  
67      private com.opensymphony.user.User getOpenSymphonyUser(String username)
68      {
69          String lcUsername = username.toLowerCase();
70          if (accessor.getCredentialsProvider().handles(lcUsername))
71              return new com.opensymphony.user.User(username.toLowerCase(), accessor);
72          else
73              return null;
74      }
75  
76      public User createUser(String username) throws com.atlassian.user.EntityException
77      {
78          validateNewUserName(username);
79  
80          if (accessor.getCredentialsProvider().create(username))
81          {
82              accessor.getProfileProvider().create(username);
83              return getWrappedOSUUser(username);
84          }
85  
86          //this is a very poor condition to run into but what can be done about it?
87          throw new EntityException("Was unable to create user [" + username + "] but the credentials provider ["
88              + accessor.getCredentialsProvider().toString() + "] did not say why.");
89      }
90  
91      public User createUser(User userTemplate, Credential credential) throws EntityException, UnsupportedOperationException
92      {
93          String username = userTemplate.getName();
94          validateNewUserName(username);
95          if (credential.isEncrypted() && credential != Credential.NONE)
96              throw new IllegalArgumentException("OSUser passwords must not be encrypted");
97  
98          boolean created = accessor.getCredentialsProvider().create(username);
99          if (!created)
100             throw new RepositoryException("Couldn't create user [" + username + "] in credentials provider");
101 
102         accessor.getProfileProvider().create(username);
103         com.opensymphony.user.User user = new com.opensymphony.user.User(username.toLowerCase(), accessor);
104         user.setFullName(userTemplate.getFullName());
105         user.setEmail(userTemplate.getEmail());
106         try
107         {
108             if (credential != Credential.NONE && credential.getValue() != null)
109                 user.setPassword(credential.getValue());
110             user.store();
111         }
112         catch (ImmutableException e)
113         {
114             throw new RepositoryException(e);
115         }
116 
117         return new OSUUser(user);
118     }
119 
120     private void validateNewUserName(String username) throws com.atlassian.user.impl.DuplicateEntityException
121     {
122         boolean usernameHandled = accessor.getCredentialsProvider().handles(username);
123 
124         if (usernameHandled)
125             throw new com.atlassian.user.impl.DuplicateEntityException("User [" + username
126                 + "] already exists in credentialsProvider [" + accessor.getCredentialsProvider().toString() + "]");
127     }
128 
129     /**
130      * Encrypts the plain password, sets it on the user, and saves the user.
131      */
132     public void alterPassword(User user, String plainTextPass) throws EntityException
133     {
134         if (!(user instanceof OSUUser))
135             throw new EntityException("Unsupported user type: " + user);
136         
137         OSUUser osUser = (OSUUser) user;
138         osUser.setPassword(plainTextPass);
139         saveUser(osUser);
140     }
141 
142     public void removeUser(User user) throws EntityException
143     {
144         Assert.notNull(user, "User must not be null");
145         Assert.isInstanceOf(OSUUser.class, user);
146         Assert.isTrue(getUser(user.getName()) != null,
147             "User is not managed by this user manager: [" + user.getName() + "]");
148 
149         String userName = user.getName();
150 
151         // need to remove properties from a user as its deleted
152         // See: http://jira.atlassian.com/browse/USER-192
153         PropertySet propertySet = accessor.getProfileProvider().getPropertySet(userName);
154 
155         for (Object o : propertySet.getKeys())
156         {
157             String key = (String) o;
158             propertySet.remove(key);
159         }
160 
161         List<String> groupsOfUser = new ArrayList<String>(getGroupsContainingUserInternal(userName));
162 
163         for (String groupName : groupsOfUser)
164         {
165             accessor.getAccessProvider().removeFromGroup(userName, groupName);
166         }
167 
168         boolean result = accessor.getCredentialsProvider().remove(userName);
169 
170         if (!result)
171             throw new EntityException("Could not remove user!");
172 
173         accessor.getProfileProvider().remove(userName);
174     }
175 
176     public boolean isReadOnly(User user)
177     {
178         return getUser(user.getName()) == null;
179     }
180 
181     public void saveUser(User user) throws EntityException
182     {
183         Assert.notNull(user, "User must not be null");
184         com.opensymphony.user.User osUser = getOpenSymphonyUser(user.getName());
185         osUser.setFullName(user.getFullName());
186         osUser.setEmail(user.getEmail());
187 
188         try
189         {
190             osUser.store();
191         }
192         catch (ImmutableException e)
193         {
194             throw new RepositoryException(e);
195         }
196     }
197 
198     public RepositoryIdentifier getRepository(Entity entity) throws EntityException
199     {
200         return getUser(entity.getName()) == null ? null : repository;
201     }
202 
203     public OSUAccessor getAccessor()
204     {
205         return accessor;
206     }
207 
208     @SuppressWarnings({"unchecked"})
209     private List<String> getUserNamesInternal()
210     {
211         return accessor.getCredentialsProvider().list();
212     }
213 
214     @SuppressWarnings({"unchecked"})
215     private List<String> getGroupsContainingUserInternal(String userName)
216     {
217         return (List<String>) accessor.getAccessProvider().listGroupsContainingUser(userName);
218     }
219 }