1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.security.app.dialog.action;
35
36 import static info.magnolia.cms.security.MgnlUserManager.*;
37 import static info.magnolia.cms.security.SecurityConstants.*;
38
39 import info.magnolia.cms.security.SecuritySupport;
40 import info.magnolia.cms.security.SilentSessionOp;
41 import info.magnolia.cms.security.User;
42 import info.magnolia.cms.security.UserManager;
43 import info.magnolia.context.MgnlContext;
44 import info.magnolia.jcr.util.NodeUtil;
45 import info.magnolia.jcr.util.PropertyUtil;
46 import info.magnolia.repository.RepositoryConstants;
47 import info.magnolia.security.app.util.UsersWorkspaceUtil;
48 import info.magnolia.ui.admincentral.dialog.action.SaveDialogAction;
49 import info.magnolia.ui.api.action.ActionExecutionException;
50 import info.magnolia.ui.form.EditorCallback;
51 import info.magnolia.ui.form.EditorValidator;
52 import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
53 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
54 import info.magnolia.ui.vaadin.integration.jcr.ModelConstants;
55
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Collection;
59 import java.util.List;
60
61 import javax.jcr.Node;
62 import javax.jcr.RepositoryException;
63 import javax.jcr.Session;
64 import javax.jcr.Value;
65 import javax.jcr.ValueFactory;
66
67 import org.apache.commons.lang3.StringUtils;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 import com.vaadin.data.Item;
72
73
74
75
76 public class SaveUserDialogAction extends SaveDialogAction<SaveUserDialogActionDefinition> {
77
78 private static final Logger log = LoggerFactory.getLogger(SaveUserDialogAction.class);
79
80 private SecuritySupport securitySupport;
81 private final List<String> protectedProperties = Arrays.asList(PROPERTY_PASSWORD, "name", NODE_GROUPS, NODE_ROLES);
82
83 public SaveUserDialogAction(SaveUserDialogActionDefinition definition, Item item, EditorValidator validator, EditorCallback callback, SecuritySupport securitySupport) {
84 super(definition, item, validator, callback);
85 this.securitySupport = securitySupport;
86 }
87
88 @Override
89 public void execute() throws ActionExecutionException {
90
91 validator.showValidation(true);
92 if (validator.isValid()) {
93
94 final JcrNodeAdapter nodeAdapter = (JcrNodeAdapter) item;
95 createOrUpdateUser(nodeAdapter);
96 callback.onSuccess(getDefinition().getName());
97
98 } else {
99
100 }
101 }
102
103 private void createOrUpdateUser(final JcrNodeAdapter userItem) throws ActionExecutionException {
104 try {
105 String userManagerRealm = getDefinition().getUserManagerRealm();
106 if (StringUtils.isBlank(userManagerRealm)){
107 log.debug("userManagerRealm property is not defined -> will try to get realm from node path");
108 userManagerRealm = resolveUserManagerRealm(userItem);
109 }
110 UserManager userManager = securitySupport.getUserManager(userManagerRealm);
111 if (userManager == null){
112 throw new ActionExecutionException("User cannot be created. No user manager with realm name " + userManagerRealm + " is defined.");
113 }
114
115 String newUserName = (String) userItem.getItemProperty(ModelConstants.JCR_NAME).getValue();
116 String newPassword = (String) userItem.getItemProperty(PROPERTY_PASSWORD).getValue();
117
118 User user;
119 Session session = userItem.getJcrItem().getSession();
120 final Node userNode;
121 if (userItem instanceof JcrNewNodeAdapter) {
122
123
124 Node parentNode = userItem.getJcrItem();
125 String parentPath = parentNode.getPath();
126
127 if ("/".equals(parentPath)) {
128 throw new ActionExecutionException("Users cannot be created directly under root");
129 }
130
131
132 parentNode.getSession().checkPermission(parentNode.getPath(), Session.ACTION_ADD_NODE);
133
134 user = userManager.createUser(parentPath, newUserName, newPassword);
135 userNode = session.getNodeByIdentifier(user.getIdentifier());
136 } else {
137 userNode = userItem.getJcrItem();
138 String existingUserName = userNode.getName();
139 user = userManager.getUser(existingUserName);
140
141 if (!StringUtils.equals(existingUserName, newUserName)) {
142 String pathBefore = userNode.getPath();
143 NodeUtil.renameNode(userNode, newUserName);
144 userNode.setProperty("name", newUserName);
145 UsersWorkspaceUtil.updateAcls(userNode, pathBefore);
146 }
147
148 String existingPasswordHash = user.getProperty(PROPERTY_PASSWORD);
149 if (!StringUtils.equals(newPassword, existingPasswordHash)) {
150 userManager.setProperty(user, PROPERTY_PASSWORD, newPassword);
151 }
152 }
153
154 final Collection<String> groups = resolveItemsNamesFromIdentifiers((Collection<String>) userItem.getItemProperty(NODE_GROUPS).getValue(), RepositoryConstants.USER_GROUPS);
155 log.debug("Assigning user the following groups [{}]", groups);
156 storeGroupsCollection(userManager, user, groups);
157
158 final Collection<String> roles = resolveItemsNamesFromIdentifiers((Collection<String>) userItem.getItemProperty(NODE_ROLES).getValue(), RepositoryConstants.USER_ROLES);
159 log.debug("Assigning user the following roles [{}]", roles);
160 storeRolesCollection(userManager, user, roles);
161
162 Collection<?> userProperties = userItem.getItemPropertyIds();
163 ValueFactory valueFactory = session.getValueFactory();
164 for (Object propertyName : userProperties) {
165 if (!protectedProperties.contains(propertyName)) {
166 Value propertyValue = PropertyUtil.createValue(userItem.getItemProperty(propertyName).getValue(), valueFactory);
167 userManager.setProperty(user, propertyName.toString(), propertyValue);
168 }
169 }
170
171 userItem.updateChildren(userNode);
172
173 session.save();
174
175 } catch (final RepositoryException e) {
176 throw new ActionExecutionException(e);
177 }
178 }
179
180 private String resolveUserManagerRealm(final JcrNodeAdapter userItem) throws RepositoryException{
181 String userPath = userItem.getJcrItem().getPath();
182 if (userItem instanceof JcrNewNodeAdapter && !"/".equals(userPath)) {
183
184 userPath += "/";
185 }
186 return StringUtils.substringBetween(userPath, "/");
187 }
188
189 private void storeGroupsCollection(UserManager userManager, User user, Collection<String> newGroups){
190 Collection<String> oldGroups = new ArrayList<String>();
191 for (String group : user.getGroups()) {
192 oldGroups.add(group);
193 }
194 for(String newGroup : newGroups) {
195 userManager.addGroup(user, newGroup);
196 oldGroups.remove(newGroup);
197 }
198 for(String oldGroup : oldGroups) {
199 userManager.removeGroup(user, oldGroup);
200 }
201 }
202
203 private void storeRolesCollection(UserManager userManager, User user, Collection<String> newRoles){
204 Collection<String> oldRoles = new ArrayList<String>();
205 for (String role : user.getRoles()) {
206 oldRoles.add(role);
207 }
208 for(String newRole : newRoles) {
209 userManager.addRole(user, newRole);
210 oldRoles.remove(newRole);
211 }
212 for(String oldRole : oldRoles) {
213 userManager.removeRole(user, oldRole);
214 }
215 }
216
217 private Collection<String> resolveItemsNamesFromIdentifiers(Collection<String> itemsIdentifiers, String repository){
218 final Collection<String> itemsNames = new ArrayList<String>();
219 for (final String itemIdentifier : itemsIdentifiers) {
220 MgnlContext.doInSystemContext(new SilentSessionOp<Void>(repository) {
221
222 @Override
223 public Void doExec(Session session) {
224 try {
225 final String itemName = session.getNodeByIdentifier(itemIdentifier).getName();
226 itemsNames.add(itemName);
227 } catch (RepositoryException e) {
228 log.error("Can't resolve group/role with uuid: " + itemIdentifier);
229 log.debug(e.getMessage());
230 }
231 return null;
232 }
233 });
234 }
235 return itemsNames;
236 }
237
238 }