001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.administration;
018:
019: import java.io.FileReader;
020: import java.io.StringWriter;
021: import java.security.Principal;
022: import java.security.PrivilegedAction;
023: import java.util.Collection;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.prefs.Preferences;
029:
030: import javax.portlet.PortletConfig;
031: import javax.portlet.PortletRequest;
032: import javax.portlet.PortletResponse;
033:
034: import org.apache.commons.configuration.Configuration;
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037: import org.apache.jetspeed.Jetspeed;
038: import org.apache.jetspeed.PortalReservedParameters;
039: import org.apache.jetspeed.exception.JetspeedException;
040: import org.apache.jetspeed.om.folder.Folder;
041: import org.apache.jetspeed.om.folder.FolderNotFoundException;
042: import org.apache.jetspeed.om.folder.InvalidFolderException;
043: import org.apache.jetspeed.page.PageManager;
044: import org.apache.jetspeed.page.document.NodeException;
045: import org.apache.jetspeed.prefs.PreferencesProvider;
046: import org.apache.jetspeed.prefs.om.Node;
047: import org.apache.jetspeed.profiler.Profiler;
048: import org.apache.jetspeed.profiler.rules.ProfilingRule;
049: import org.apache.jetspeed.request.RequestContext;
050: import org.apache.jetspeed.security.GroupManager;
051: import org.apache.jetspeed.security.JSSubject;
052: import org.apache.jetspeed.security.RoleManager;
053: import org.apache.jetspeed.security.SecurityHelper;
054: import org.apache.jetspeed.security.User;
055: import org.apache.jetspeed.security.UserManager;
056: import org.apache.jetspeed.security.UserPrincipal;
057: import org.apache.velocity.VelocityContext;
058: import org.apache.velocity.app.VelocityEngine;
059: import org.springframework.mail.MailException;
060: import org.springframework.mail.SimpleMailMessage;
061: import org.springframework.mail.javamail.JavaMailSender;
062:
063: /**
064: * PortalAdministrationImpl
065: * Implements aggregate portal administration functions:
066: * - Emails
067: * - Registration
068: * - Password Generation
069: * -
070: *
071: * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
072: * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
073: * @version $Id: $
074: */
075:
076: public class PortalAdministrationImpl implements PortalAdministration {
077: private final static Log log = LogFactory
078: .getLog(PortalAdministrationImpl.class);
079:
080: /** administration services */
081: protected Configuration config;
082: protected UserManager userManager;
083: protected RoleManager roleManager;
084: protected GroupManager groupManager;
085: protected PageManager pageManager;
086: private PreferencesProvider preferences;
087: protected Profiler profiler;
088: protected JavaMailSender mailSender;
089: protected VelocityEngine velocityEngine;
090: protected AdminUtil adminUtil;
091:
092: /** list of default roles for a registered user */
093: protected List defaultRoles;
094: /** list of default groups for a registered user */
095: protected List defaultGroups;
096: /** map of default profiling rules for a registered user */
097: protected Map defaultRules;
098: /** name of PSML Folder Template to clone from when registering new user */
099: protected String folderTemplate;
100: /** default administrative user */
101: protected String adminUser;
102:
103: public PortalAdministrationImpl(UserManager userManager,
104: RoleManager roleManager, GroupManager groupManager,
105: PageManager pageManager, PreferencesProvider preferences,
106: Profiler profiler, JavaMailSender mailSender,
107: VelocityEngine velocityEngine) {
108: this .userManager = userManager;
109: this .roleManager = roleManager;
110: this .groupManager = groupManager;
111: this .pageManager = pageManager;
112: this .preferences = preferences;
113: this .profiler = profiler;
114: this .mailSender = mailSender;
115: this .velocityEngine = velocityEngine;
116: this .adminUtil = new AdminUtil();
117: }
118:
119: public void start() {
120: this .config = (Configuration) Jetspeed.getComponentManager()
121: .getComponent("portal_configuration");
122:
123: this .defaultRoles = config
124: .getList(PortalConfigurationConstants.REGISTRATION_ROLES_DEFAULT);
125: this .defaultGroups = config
126: .getList(PortalConfigurationConstants.REGISTRATION_GROUPS_DEFAULT);
127:
128: Object[] profileRuleNames = config
129: .getList(
130: PortalConfigurationConstants.PROFILER_RULE_NAMES_DEFAULT)
131: .toArray();
132: Object[] profileRuleValues = config
133: .getList(
134: PortalConfigurationConstants.PROFILER_RULE_VALUES_DEFAULT)
135: .toArray();
136: defaultRules = new HashMap();
137: if (profileRuleNames != null && profileRuleValues != null) {
138: for (int ix = 0; ix < ((profileRuleNames.length < profileRuleValues.length) ? profileRuleNames.length
139: : profileRuleValues.length); ix++) {
140: defaultRules.put(profileRuleNames[ix],
141: profileRuleValues[ix]);
142: }
143: }
144: this .folderTemplate = config
145: .getString(PortalConfigurationConstants.PSML_TEMPLATE_FOLDER);
146: this .adminUser = config
147: .getString(PortalConfigurationConstants.USERS_DEFAULT_ADMIN);
148:
149: }
150:
151: public void registerUser(String userName, String password)
152: throws RegistrationException {
153: registerUser(userName, password, (List) null, null, null, null,
154: null);
155: }
156:
157: public void registerUser(String userName, String password,
158: List roles, List groups, Map userInfo, Map rules,
159: String folderTemplate) throws RegistrationException {
160: registerUser(userName, password, roles, groups, userInfo,
161: rules, folderTemplate, null);
162: }
163:
164: /* (non-Javadoc)
165: * @see org.apache.jetspeed.administration.PortalAdministration#registerUser(java.lang.String, java.lang.String, java.util.Map, java.awt.List, java.awt.List, java.lang.String)
166: */
167: public void registerUser(String userName, String password,
168: List roles, List groups, Map userInfo, Map rules,
169: String folderTemplate, String subsite)
170: throws RegistrationException {
171: try {
172: // create the user
173: userManager.addUser(userName, password);
174: User user = userManager.getUser(userName);
175:
176: // assign roles to user
177: if (roles == null || roles.isEmpty()) {
178: roles = this .defaultRoles;
179: }
180: if (roles != null) {
181: Iterator roleList = roles.iterator();
182: while (roleList.hasNext()) {
183: String role = (String) roleList.next();
184: if (role.trim().length() > 0)
185: roleManager.addRoleToUser(userName, role);
186: }
187: }
188:
189: // assign groups to user
190: if (groups == null || groups.isEmpty()) {
191: groups = this .defaultGroups;
192: }
193: if (groups != null) {
194: Iterator groupsList = groups.iterator();
195: while (groupsList.hasNext()) {
196: String group = (String) groupsList.next();
197: if (group.trim().length() > 0) {
198: groupManager.addUserToGroup(userName, group);
199: }
200: }
201: }
202:
203: // assign user attributes to user
204: if (userInfo != null) {
205: Iterator info = userInfo.entrySet().iterator();
206: while (info.hasNext()) {
207: Map.Entry entry = (Map.Entry) info.next();
208: user.getUserAttributes().put(
209: (String) entry.getKey(),
210: (String) entry.getValue());
211: }
212: }
213:
214: // assign profiling rules to user
215: if (rules == null || rules.isEmpty()) {
216: rules = this .defaultRules;
217: }
218: if (rules != null) {
219: Iterator ruleEntries = rules.entrySet().iterator();
220: while (ruleEntries.hasNext()) {
221: Map.Entry entry = (Map.Entry) ruleEntries.next();
222: ProfilingRule rule = profiler
223: .getRule((String) entry.getValue());
224: if (rule != null) {
225: Principal principal = SecurityHelper
226: .getBestPrincipal(user.getSubject(),
227: UserPrincipal.class);
228: profiler.setRuleForPrincipal(principal, rule,
229: (String) entry.getKey());
230: }
231: }
232: }
233:
234: if (folderTemplate == null) {
235: folderTemplate = this .folderTemplate;
236: }
237:
238: if (subsite == null) {
239: subsite = Folder.USER_FOLDER + userName;
240: } else {
241: subsite = subsite + Folder.USER_FOLDER + userName;
242: }
243:
244: // This next chunk of code is the fancy way to force the creation of the user
245: // template pages to be created with subject equal to the new user
246: // otherwise it would be created as guest, and guest does not have enough privs.
247: final String innerFolderTemplate = folderTemplate;
248: final String innerSubsite = subsite;
249: final PageManager innerPageManager = pageManager;
250: final String innerUserName = userName;
251: final User innerUser = user;
252: User powerUser = userManager.getUser(this .adminUser);
253: JetspeedException pe = (JetspeedException) JSSubject
254: .doAsPrivileged(powerUser.getSubject(),
255: new PrivilegedAction() {
256: public Object run() {
257: try {
258: if (innerSubsite != null) {
259: Preferences attributes = innerUser
260: .getUserAttributes();
261: attributes
262: .put(
263: User.USER_INFO_SUBSITE,
264: innerSubsite);
265: }
266: // create user's home folder
267: // deep copy from the default folder template tree, creating a deep-copy of the template
268: // in the new user's folder tree
269: Folder source = innerPageManager
270: .getFolder(innerFolderTemplate);
271:
272: innerPageManager
273: .deepCopyFolder(source,
274: innerSubsite,
275: innerUserName);
276: Folder newFolder = pageManager
277: .getFolder(innerSubsite);
278: newFolder
279: .setTitle("Home Folder");
280: newFolder.setShortTitle("Home");
281:
282: return null;
283: } catch (FolderNotFoundException e1) {
284: return e1;
285: } catch (InvalidFolderException e1) {
286: return e1;
287: } catch (NodeException e1) {
288: return e1;
289: }
290: }
291: }, null);
292:
293: if (pe != null) {
294: // rollback user creation and cascade roles, groups, etc
295: try {
296: if (userManager.getUser(userName) != null) {
297: userManager.removeUser(userName);
298: }
299: } catch (Exception e) {
300: log
301: .error("Registration Error: Failed to rollback user "
302: + userName);
303: }
304: log
305: .error("Registration Error: Failed to create user folders for "
306: + userName + ", " + pe.toString());
307: throw pe;
308: }
309:
310: } catch (Exception e) {
311: log
312: .error("Registration Error: Failed to create registered user "
313: + userName + ", " + e.toString());
314: throw new RegistrationException(e);
315: }
316: }
317:
318: /* (non-Javadoc)
319: * @see org.apache.jetspeed.administration.PortalAdministration#generatePassword()
320: */
321: public String generatePassword() {
322: return adminUtil.generatePassword();
323: }
324:
325: /* (non-Javadoc)
326: * @see org.apache.jetspeed.administration.PortalAdministration#sendPassword(java.lang.String)
327: */
328: public void sendEmail(PortletConfig portletConfig,
329: String emailAddress, String localizedSubject,
330: String localizedTemplatePath, Map userAttributes)
331: throws AdministrationEmailException {
332:
333: String from = config
334: .getString(PortalConfigurationConstants.EMAIL_SENDER);
335: String subject = localizedSubject;
336: String to = emailAddress;
337: String text = mergeEmailTemplate(portletConfig, userAttributes,
338: "map", localizedTemplatePath);
339: sendEmail(from, subject, to, text);
340:
341: }
342:
343: /**
344: * @param from
345: * @param subject
346: * @param to
347: * @param text
348: * @throws AdministrationEmailException
349: */
350: public void sendEmail(String from, String subject, String to,
351: String text) throws AdministrationEmailException {
352: SimpleMailMessage msg = new SimpleMailMessage();
353: if (from == null) {
354: from = "jetspeed-admin@apache.org";
355: }
356: msg.setFrom(from);
357: if (subject == null) {
358: subject = "message from jetspeed";
359: }
360: msg.setSubject(subject);
361: msg.setTo(to);
362: msg.setText(text);
363: try {
364: mailSender.send(msg);
365: } catch (MailException ex) {
366: throw new AdministrationEmailException(
367: "Failed to send forgotten password email to user with email address because "
368: + ex.getMessage()); //+ user.getEmail());
369: }
370: }
371:
372: public String mergeEmailTemplate(PortletConfig portletConfig,
373: Map attributes, String attributesName, String template)
374: throws AdministrationEmailException {
375: VelocityContext context = new VelocityContext();
376: context.put(attributesName, attributes);
377: StringWriter writer = new StringWriter();
378:
379: try {
380: String realTemplatePath = portletConfig.getPortletContext()
381: .getRealPath(template);
382: FileReader templateReader = new FileReader(realTemplatePath);
383: velocityEngine.evaluate(context, writer,
384: "UserEmailProcessor", templateReader);
385: } catch (Exception e) {
386: throw new AdministrationEmailException(
387: "Failed to generate email text for email template "
388: + template, e);
389: }
390:
391: String buffer = writer.getBuffer().toString();
392:
393: return buffer;
394: }
395:
396: private static final String USER_NOT_FOUND_FROM_EMAIL = "User not found for Email address: ";
397:
398: public User lookupUserFromEmail(String email)
399: throws AdministrationEmailException {
400: Collection result = preferences.lookupPreference("userinfo",
401: "user.business-info.online.email", email);
402: if (result.size() == 0) {
403: throw new AdministrationEmailException(
404: USER_NOT_FOUND_FROM_EMAIL + email);
405: }
406: Iterator nodes = result.iterator();
407: Node node = (Node) nodes.next();
408: String nodePath = node.getFullPath();
409: if (nodePath == null) {
410: throw new AdministrationEmailException(
411: USER_NOT_FOUND_FROM_EMAIL + email);
412: }
413: String[] paths = nodePath.split("/");
414: if (paths == null || paths.length != 4) {
415: throw new AdministrationEmailException(
416: USER_NOT_FOUND_FROM_EMAIL + email);
417: }
418: String userName = paths[2];
419: try {
420: return userManager.getUser(userName);
421: } catch (Exception e) {
422: throw new AdministrationEmailException(
423: USER_NOT_FOUND_FROM_EMAIL + email);
424: }
425: }
426:
427: /**
428: * Helper for admin portlets to generate portal urls
429: */
430: public String getPortalURL(PortletRequest request,
431: PortletResponse response, String path) {
432: // get internal request context
433: RequestContext context = (RequestContext) request
434: .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
435: String baseUrl = context.getPortalURL().getBaseURL();
436: String jetspeedPath = adminUtil.concatenatePaths(baseUrl,
437: context.getPortalURL().getBasePath());
438: if (path == null)
439: return jetspeedPath;
440: return adminUtil.concatenatePaths(jetspeedPath, response
441: .encodeURL(path));
442: }
443:
444: Map forgottenPasswordData = new HashMap();
445:
446: /* (non-Javadoc)
447: * @see org.apache.jetspeed.administration.PortalAdministration#getNewLoginInfo(java.lang.String)
448: */
449: public Map getNewLoginInfo(String guid) {
450: synchronized (forgottenPasswordData) {
451: return (Map) forgottenPasswordData.get(guid);
452: }
453: }
454:
455: /* (non-Javadoc)
456: * @see org.apache.jetspeed.administration.PortalAdministration#setNewLoginInfo(java.lang.String, org.apache.jetspeed.administration.PortalAdministration.ResetPasswordInfo)
457: */
458: public void putNewLoginInfo(String guid, Map info) {
459: synchronized (forgottenPasswordData) {
460: forgottenPasswordData.put(guid, info);
461: }
462: }
463:
464: /* (non-Javadoc)
465: * @see org.apache.jetspeed.administration.PortalAdministration#removeNewLoginInfo(java.lang.String)
466: */
467: public void removeNewLoginInfo(String guid) {
468: synchronized (forgottenPasswordData) {
469: forgottenPasswordData.remove(guid);
470: }
471: }
472:
473: }
|