Java tutorial
/** * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jasig.portal.portlets.account; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import javax.portlet.PortletMode; import javax.portlet.WindowState; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.portal.EntityIdentifier; import org.jasig.portal.groups.IGroupMember; import org.jasig.portal.i18n.ILocaleStore; import org.jasig.portal.i18n.LocaleManager; import org.jasig.portal.layout.dlm.remoting.IGroupListHelper; import org.jasig.portal.layout.dlm.remoting.JsonEntityBean; import org.jasig.portal.persondir.ILocalAccountDao; import org.jasig.portal.persondir.ILocalAccountPerson; import org.jasig.portal.portletpublishing.xml.Preference; import org.jasig.portal.portlets.StringListAttribute; import org.jasig.portal.security.IAuthorizationPrincipal; import org.jasig.portal.security.IPerson; import org.jasig.portal.security.IPersonManager; import org.jasig.portal.security.IPortalPasswordService; import org.jasig.portal.services.AuthorizationService; import org.jasig.portal.services.GroupService; import org.jasig.portal.url.IPortalUrlBuilder; import org.jasig.portal.url.IPortalUrlProvider; import org.jasig.portal.url.IPortletUrlBuilder; import org.jasig.portal.url.UrlType; import org.jasig.services.persondir.IPersonAttributes; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.mail.MailException; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupDir; @Component("userAccountHelper") public class UserAccountHelper { protected final Log log = LogFactory.getLog(getClass()); private String templateDir = "properties/templates"; private String passwordResetTemplate = "passwordReset"; private ILocaleStore localeStore; private ILocalAccountDao accountDao; private IPortalPasswordService passwordService; private List<Preference> accountEditAttributes; private JavaMailSenderImpl mailSender; private IPortalUrlProvider urlProvider; private MessageSource messageSource; private String portalEmailAddress; private IPersonManager personManager; private IGroupListHelper groupListHelper; @Autowired public void setLocaleStore(ILocaleStore localeStore) { this.localeStore = localeStore; } @Autowired public void setLocalAccountDao(ILocalAccountDao accountDao) { this.accountDao = accountDao; } @Autowired public void setPortalPasswordService(IPortalPasswordService passwordService) { this.passwordService = passwordService; } @Resource(name = "accountEditAttributes") public void setAccountEditAttributes(List<Preference> accountEditAttributes) { this.accountEditAttributes = Collections.unmodifiableList(accountEditAttributes); } @Autowired public void setMailSender(JavaMailSenderImpl mailSender) { this.mailSender = mailSender; } @Autowired public void setPortalUrlProvider(IPortalUrlProvider urlProvider) { this.urlProvider = urlProvider; } @Autowired public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } @Resource(name = "portalEmailAddress") public void setPortalEmailAddress(String portalEmailAddress) { this.portalEmailAddress = portalEmailAddress; } @Autowired public void setPersonManager(IPersonManager personManager) { this.personManager = personManager; } @Autowired public void setGroupListHelper(IGroupListHelper groupListHelper) { this.groupListHelper = groupListHelper; } public PersonForm getNewAccountForm() { PersonForm form = new PersonForm(accountEditAttributes); Set<String> attributeNames = accountDao.getCurrentAttributeNames(); for (String name : attributeNames) { form.getAttributes().put(name, new StringListAttribute(Collections.<String>emptyList())); } return form; } public PersonForm getForm(String username) { ILocalAccountPerson person = accountDao.getPerson(username); PersonForm form = new PersonForm(accountEditAttributes); form.setUsername(person.getName()); form.setId(person.getId()); Set<String> attributeNames = accountDao.getCurrentAttributeNames(); for (String name : attributeNames) { List<String> values = new ArrayList<String>(); List<Object> attrValues = person.getAttributeValues(name); if (attrValues != null) { for (Object value : person.getAttributeValues(name)) { values.add((String) value); } } form.getAttributes().put(name, new StringListAttribute(values)); } return form; } protected boolean isLocalAccount(String username) { ILocalAccountPerson person = accountDao.getPerson(username); if (person != null) { return true; } else { return false; } } public List<JsonEntityBean> getParentGroups(String target) { IGroupMember member = GroupService.getEntity(target, IPerson.class); @SuppressWarnings("unchecked") Iterator<IGroupMember> iterator = (Iterator<IGroupMember>) member.getAllContainingGroups(); List<JsonEntityBean> parents = new ArrayList<JsonEntityBean>(); while (iterator.hasNext()) { parents.add(groupListHelper.getEntity(iterator.next())); } Collections.sort(parents); return parents; } public boolean canEditUser(IPerson currentUser, String target) { // first check to see if this is a local user if (!isLocalAccount(target)) { return false; } EntityIdentifier ei = currentUser.getEntityIdentifier(); IAuthorizationPrincipal ap = AuthorizationService.instance().newPrincipal(ei.getKey(), ei.getType()); // if the target represents the current user, determine if they can // edit their own account if (currentUser.getName().equals(target) && ap.hasPermission("UP_USERS", "EDIT_USER", "SELF")) { return true; } // otherwise determine if the user has permission to edit the account else if (ap.hasPermission("UP_USERS", "EDIT_USER", target)) { return true; } else { return false; } } /** * Returns the collection of attributes that the specified currentUser can * edit. * * @param currentUser * @return */ public List<Preference> getEditableUserAttributes(IPerson currentUser) { EntityIdentifier ei = currentUser.getEntityIdentifier(); IAuthorizationPrincipal ap = AuthorizationService.instance().newPrincipal(ei.getKey(), ei.getType()); List<Preference> allowedAttributes = new ArrayList<Preference>(); for (Preference attr : accountEditAttributes) { if (ap.hasPermission("UP_USERS", "EDIT_USER_ATTRIBUTE", attr.getName())) { allowedAttributes.add(attr); } } return allowedAttributes; } public List<GroupedPersonAttribute> groupPersonAttributes(final IPersonAttributes user, final HttpServletRequest request) { // get the locale for the current user final Locale locale = getCurrentUserLocale(request); // construct a list of grouped user attributes for the specified user final List<GroupedPersonAttribute> displayAttributes = new ArrayList<GroupedPersonAttribute>(); for (Map.Entry<String, List<Object>> attr : user.getAttributes().entrySet()) { // get the display name for this user attribute final String displayName = messageSource.getMessage("attribute.displayName.".concat(attr.getKey()), new Object[] {}, attr.getKey(), locale); boolean found = false; // if this display name and value is already in the list, add this // new attribute name to that group for (GroupedPersonAttribute displayAttribute : displayAttributes) { if (displayAttribute.getDisplayName().equals(displayName) && attr.getValue().equals(displayAttribute.getValues())) { displayAttribute.getAttributeNames().add(attr.getKey()); found = true; break; } } // otherwise add a new group if (!found) { final GroupedPersonAttribute displayAttribute = new GroupedPersonAttribute(displayName, attr.getValue(), attr.getKey()); displayAttributes.add(displayAttribute); } } Collections.sort(displayAttributes, new GroupedPersonAttributeByNameComparator()); return displayAttributes; } public boolean canDeleteUser(IPerson currentUser, String target) { // first check to see if this is a local user if (!isLocalAccount(target)) { return false; } EntityIdentifier ei = currentUser.getEntityIdentifier(); IAuthorizationPrincipal ap = AuthorizationService.instance().newPrincipal(ei.getKey(), ei.getType()); // TODO create new user editing permission return (ap.hasPermission("UP_USERS", "DELETE_USER", target)); } public void deleteAccount(IPerson currentUser, String target) { if (!canDeleteUser(currentUser, target)) { throw new RuntimeException("Current user " + currentUser.getName() + " does not have permissions to update person " + target); } ILocalAccountPerson person = accountDao.getPerson(target); accountDao.deleteAccount(person); log.info("Account " + person.getName() + " successfully deleted"); } public void updateAccount(IPerson currentUser, PersonForm form) { ILocalAccountPerson account; // if this is a new user, create an account object with the specified // username if (form.getId() < 0) { account = accountDao.getPerson(form.getUsername()); if (account == null) { /* * Should there be a permissions check to verify * the user is allowed to create new users? */ account = accountDao.createPerson(form.getUsername()); } } // otherwise, get the existing account from the database else { account = accountDao.getPerson(form.getId()); } /* * SANITY CHECK #1: Is the user permitted to modify this account? * (Presumably this check was already made when the page was rendered, * but re-checking alleviates danger from cleverly-crafted HTTP * requests.) */ if (!canEditUser(currentUser, account.getName())) { throw new RuntimeException("Current user " + currentUser.getName() + " does not have permissions to update person " + account.getName()); } // Used w/ check #2 EntityIdentifier ei = currentUser.getEntityIdentifier(); IAuthorizationPrincipal ap = AuthorizationService.instance().newPrincipal(ei.getKey(), ei.getType()); // update the account attributes to match those specified in the form List<Preference> editableAttributes = getEditableUserAttributes(currentUser); for (Preference editableAttribute : editableAttributes) { String attributeName = editableAttribute.getName(); /* * SANITY CHECK #2: Should never fail since getEditableUserAttributes should return only * editable attribute names, but do this anyway just in case. */ if (!ap.hasPermission("UP_USERS", "EDIT_USER_ATTRIBUTE", attributeName)) { throw new RuntimeException("Current user " + currentUser.getName() + " does not have permissions to edit attribute " + attributeName); } if (form.getAttributes().get(attributeName) == null || form.getAttributes().get(attributeName).isBlank()) { account.removeAttribute(attributeName); } else { account.setAttribute(attributeName, form.getAttributes().get(attributeName).getValue()); } } // if a new password has been specified, update the account password if (StringUtils.isNotBlank(form.getPassword())) { account.setPassword(passwordService.encryptPassword(form.getPassword())); account.setLastPasswordChange(new Date()); account.removeAttribute("loginToken"); } accountDao.updateAccount(account); log.info("Account " + account.getName() + " successfully updated"); } public String getRandomToken() { String token = RandomStringUtils.randomAlphanumeric(20); return token; } public boolean validateLoginToken(String username, String password) { ILocalAccountPerson person = accountDao.getPerson(username); if (person != null) { Object recordedToken = person.getAttributeValue("loginToken"); if (recordedToken != null && recordedToken.equals(password)) { return true; } } return false; } public void sendLoginToken(HttpServletRequest request, ILocalAccountPerson account) { IPerson person = personManager.getPerson(request); final Locale[] userLocales = localeStore.getUserLocales(person); LocaleManager localeManager = new LocaleManager(person, userLocales); Locale locale = localeManager.getLocales()[0]; IPortalUrlBuilder builder = urlProvider.getPortalUrlBuilderByPortletFName(request, "reset-password", UrlType.RENDER); IPortletUrlBuilder portletUrlBuilder = builder.getTargetedPortletUrlBuilder(); portletUrlBuilder.addParameter("username", account.getName()); portletUrlBuilder.addParameter("loginToken", (String) account.getAttributeValue("loginToken")); portletUrlBuilder.setPortletMode(PortletMode.VIEW); portletUrlBuilder.setWindowState(WindowState.MAXIMIZED); StringBuffer url = new StringBuffer(); url.append(request.getScheme()); url.append("://").append(request.getServerName()); int port = request.getServerPort(); if (port != 80 && port != 443) { url.append(":").append(port); } url.append(builder.getUrlString()); log.debug("Sending password reset instructions to user with url " + url.toString()); String emailAddress = (String) account.getAttributeValue("mail"); final STGroup group = new STGroupDir(templateDir, '$', '$'); final ST template = group.getInstanceOf(passwordResetTemplate); template.add("displayName", person.getAttribute("displayName")); template.add("url", url.toString()); MimeMessage message = mailSender.createMimeMessage(); String body = template.render(); try { MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setTo(emailAddress); helper.setText(body, true); helper.setSubject(messageSource.getMessage("reset.your.password", new Object[] {}, locale)); helper.setFrom(portalEmailAddress, messageSource.getMessage("portal.name", new Object[] {}, locale)); log.debug("Sending message to " + emailAddress + " from " + Arrays.toString(message.getFrom()) + " subject " + message.getSubject()); this.mailSender.send(message); } catch (MailException e) { log.error("Unable to send password reset email ", e); } catch (MessagingException e) { log.error("Unable to send password reset email ", e); } catch (UnsupportedEncodingException e) { log.error("Unable to send password reset email ", e); } } protected Locale getCurrentUserLocale(final HttpServletRequest request) { final IPerson person = personManager.getPerson(request); final Locale[] userLocales = localeStore.getUserLocales(person); final LocaleManager localeManager = new LocaleManager(person, userLocales); final Locale locale = localeManager.getLocales()[0]; return locale; } }