| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. The ASF 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. For additional information regarding |
| * copyright in this work, please see the NOTICE file in the top level |
| * directory of this distribution. |
| */ |
| |
| package org.apache.roller.weblogger.ui.struts2.core; |
| |
| import java.util.TimeZone; |
| import java.util.UUID; |
| import javax.servlet.http.HttpServletRequest; |
| import org.apache.commons.lang3.CharSetUtils; |
| import org.apache.commons.lang3.RandomStringUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.roller.weblogger.WebloggerException; |
| import org.apache.roller.weblogger.business.WebloggerFactory; |
| import org.apache.roller.weblogger.business.UserManager; |
| import org.apache.roller.weblogger.config.AuthMethod; |
| import org.apache.roller.weblogger.config.WebloggerConfig; |
| import org.apache.roller.weblogger.config.WebloggerRuntimeConfig; |
| import org.apache.roller.weblogger.pojos.User; |
| import org.apache.roller.weblogger.ui.core.RollerSession; |
| import org.apache.roller.weblogger.ui.core.security.CustomUserRegistry; |
| import org.apache.roller.weblogger.ui.struts2.util.UIAction; |
| import org.apache.roller.weblogger.util.MailUtil; |
| import org.apache.struts2.convention.annotation.AllowedMethods; |
| import org.apache.struts2.interceptor.ServletRequestAware; |
| import org.apache.struts2.interceptor.validation.SkipValidation; |
| |
| |
| /** |
| * Actions for registering a new user. This page is activated in Roller in two ways, |
| * by explicitly selecting the "Register" button on the Main Menu, or if |
| * upon a non-Roller DB login (say, LDAP) if the user does not exist in the |
| * Roller DB. In the latter case, this page is activated from login-redirect.jsp file. |
| * |
| * @see org.apache.roller.weblogger.ui.struts2.core.Login |
| */ |
| // TODO: make this work @AllowedMethods({"execute","save","activate"}) |
| public class Register extends UIAction implements ServletRequestAware { |
| |
| private static Log log = LogFactory.getLog(Register.class); |
| private static final String DISABLED_RETURN_CODE = "disabled"; |
| public static final String DEFAULT_ALLOWED_CHARS = "A-Za-z0-9"; |
| |
| // this is a no-no, we should not need this |
| private HttpServletRequest servletRequest = null; |
| |
| private AuthMethod authMethod = WebloggerConfig.getAuthMethod(); |
| |
| private String activationStatus = null; |
| |
| private String activationCode = null; |
| private ProfileBean bean = new ProfileBean(); |
| |
| public Register() { |
| this.pageTitle = "newUser.addNewUser"; |
| } |
| |
| // override default security, we do not require an authenticated user |
| public boolean isUserRequired() { |
| return false; |
| } |
| |
| // override default security, we do not require an action weblog |
| public boolean isWeblogRequired() { |
| return false; |
| } |
| |
| public String getAuthMethod() { |
| return authMethod.name(); |
| } |
| |
| @SkipValidation |
| public String execute() { |
| |
| // if registration is disabled, then don't allow registration |
| try { |
| if (!WebloggerRuntimeConfig.getBooleanProperty("users.registration.enabled") |
| // unless there are 0 users (need to allow creation of first user) |
| && WebloggerFactory.getWeblogger().getUserManager().getUserCount() != 0) { |
| addError("Register.disabled"); |
| return DISABLED_RETURN_CODE; |
| } |
| } catch (Exception e) { |
| log.error("Error checking user count", e); |
| addError("generic.error.check.logs"); |
| return DISABLED_RETURN_CODE; |
| } |
| |
| // For new user default to locale set in browser |
| bean.setLocale(getServletRequest().getLocale().toString()); |
| |
| // For new user default to timezone of server |
| bean.setTimeZone(TimeZone.getDefault().getID()); |
| |
| /* TODO: when Spring Security 2.1 is release comment out this stuff, |
| * which pre-populates the user bean with info from OpenID provider. |
| * |
| Collection attrsCollect = (Collection)WebloggerFactory.getWeblogger() |
| .getUserManager().userAttributes.get(UserAttribute.Attributes.openidUrl.toString()); |
| |
| if (attrsCollect != null) { |
| ArrayList attrs = new ArrayList(attrsCollect); |
| for (OpenIDUserAttribute attr : attrs) { |
| if (attr.getName().equals(OpenIDUserAttribute.Attributes.country.toString())) { |
| getBean().setLocale(UIUtils.getLocale(attr.getValue())); |
| } |
| if (attr.getName().equals(OpenIDUserAttribute.Attributes.email.toString())) { |
| getBean().setEmailAddress(attr.getValue()); |
| } |
| if (attr.getName().equals(OpenIDUserAttribute.Attributes.fullname.toString())) { |
| getBean().setFullName(attr.getValue()); |
| } |
| if (attr.getName().equals(OpenIDUserAttribute.Attributes.nickname.toString())) { |
| getBean().setUserName(attr.getValue()); |
| } |
| if (attr.getName().equals(OpenIDUserAttribute.Attributes.timezone.toString())) { |
| getBean().setTimeZone(UIUtils.getTimeZone(attr.getValue())); |
| } |
| if (attr.getName().equals(OpenIDUserAttribute.Attributes.openidname.toString())) { |
| getBean().setOpenidUrl(attr.getValue()); |
| } |
| |
| } |
| }*/ |
| |
| try { |
| |
| if (WebloggerConfig.getAuthMethod() == AuthMethod.LDAP) { |
| // See if user is already logged in via Spring Security |
| User fromSSOUser = CustomUserRegistry.getUserDetailsFromAuthentication(getServletRequest()); |
| if (fromSSOUser != null) { |
| // Copy user details from Spring Security, including LDAP attributes |
| getBean().copyFrom(fromSSOUser); |
| } |
| } else if (WebloggerConfig.getAuthMethod() == AuthMethod.CMA) { |
| // See if user is already logged in via CMA |
| if (getServletRequest().getUserPrincipal() != null) { |
| // Only detail we get is username, sadly no LDAP attributes |
| getBean().setUserName(getServletRequest().getUserPrincipal().getName()); |
| getBean().setScreenName(getServletRequest().getUserPrincipal().getName()); |
| } |
| } |
| |
| } catch (Exception ex) { |
| log.error("Error reading SSO user data", ex); |
| addError("error.editing.user", ex.toString()); |
| } |
| |
| return INPUT; |
| } |
| |
| |
| public String save() { |
| |
| // if registration is disabled, then don't allow registration |
| try { |
| if (!WebloggerRuntimeConfig.getBooleanProperty("users.registration.enabled") |
| // unless there are 0 users (need to allow creation of first user) |
| && WebloggerFactory.getWeblogger().getUserManager().getUserCount() != 0) { |
| return DISABLED_RETURN_CODE; |
| } |
| } catch (Exception e) { |
| log.error("Error checking user count", e); |
| return DISABLED_RETURN_CODE; |
| } |
| |
| myValidate(); |
| |
| if (!hasActionErrors()) { |
| try { |
| |
| UserManager mgr = WebloggerFactory.getWeblogger().getUserManager(); |
| |
| // copy form data into new user pojo |
| User ud = new User(); |
| // copyTo skips password |
| getBean().copyTo(ud); |
| ud.setUserName(getBean().getUserName()); |
| ud.setDateCreated(new java.util.Date()); |
| ud.setEnabled(Boolean.TRUE); |
| |
| // If user set both password and passwordConfirm then reset password |
| if (!StringUtils.isEmpty(getBean().getPasswordText()) && |
| !StringUtils.isEmpty(getBean().getPasswordConfirm())) { |
| ud.resetPassword(getBean().getPasswordText()); |
| } |
| |
| // are we using email activation? |
| boolean activationEnabled = WebloggerRuntimeConfig.getBooleanProperty( |
| "user.account.email.activation"); |
| if (activationEnabled) { |
| // User account will be enabled after the activation process |
| ud.setEnabled(Boolean.FALSE); |
| |
| // Create & save the activation data |
| String inActivationCode = UUID.randomUUID().toString(); |
| |
| inActivationCode = retryActivationCode(mgr, inActivationCode); |
| ud.setActivationCode(inActivationCode); |
| } |
| |
| String openidurl = getBean().getOpenIdUrl(); |
| if (openidurl != null) { |
| if (openidurl.endsWith("/")) { |
| openidurl = openidurl.substring(0, openidurl.length() - 1); |
| } |
| ud.setOpenIdUrl(openidurl); |
| } |
| |
| // save new user |
| mgr.addUser(ud); |
| |
| WebloggerFactory.getWeblogger().flush(); |
| |
| // now send activation email if necessary |
| sendActivationMailIfNeeded(ud, activationEnabled); |
| |
| // Invalidate session, otherwise new user who was originally |
| // authenticated via LDAP/SSO will remain logged in but |
| // without a valid Roller role. |
| getServletRequest().getSession().removeAttribute(RollerSession.ROLLER_SESSION); |
| getServletRequest().getSession().invalidate(); |
| |
| // set a special page title |
| setPageTitle("welcome.title"); |
| |
| return SUCCESS; |
| |
| } catch (WebloggerException ex) { |
| log.error("Error adding new user", ex); |
| addError("generic.error.check.logs"); |
| } |
| } |
| |
| return INPUT; |
| } |
| |
| private String retryActivationCode(UserManager mgr, String inActivationCode) throws WebloggerException { |
| if (mgr.getUserByActivationCode(inActivationCode) != null) { |
| // In the *extremely* unlikely event that we generate an |
| // activation code that is already use, we'll retry 3 times. |
| int numOfRetries = 3; |
| if (numOfRetries < 1) { |
| numOfRetries = 1; |
| } |
| for (int i = 0; i < numOfRetries; i++) { |
| inActivationCode = UUID.randomUUID().toString(); |
| if (mgr.getUserByActivationCode(inActivationCode) == null) { |
| break; |
| } else { |
| inActivationCode = null; |
| } |
| } |
| // In more unlikely event that three retries isn't enough |
| if (inActivationCode == null){ |
| throw new WebloggerException("error.add.user.activationCodeInUse"); |
| } |
| } |
| return inActivationCode; |
| } |
| |
| private void sendActivationMailIfNeeded(User ud, boolean activationEnabled) { |
| if (activationEnabled && ud.getActivationCode() != null) { |
| try { |
| // send activation mail to the user |
| MailUtil.sendUserActivationEmail(ud); |
| } catch (WebloggerException ex) { |
| log.error("Error sending activation email to - " + ud.getEmailAddress(), ex); |
| } |
| |
| setActivationStatus("pending"); |
| } |
| } |
| |
| |
| @SkipValidation |
| public String activate() { |
| |
| try { |
| UserManager mgr = WebloggerFactory.getWeblogger().getUserManager(); |
| |
| if (getActivationCode() == null) { |
| addError("error.activate.user.missingActivationCode"); |
| } else { |
| User user = mgr.getUserByActivationCode(getActivationCode()); |
| |
| if (user != null) { |
| // enable user account |
| user.setEnabled(Boolean.TRUE); |
| user.setActivationCode(null); |
| mgr.saveUser(user); |
| WebloggerFactory.getWeblogger().flush(); |
| |
| setActivationStatus("active"); |
| |
| } else { |
| addError("error.activate.user.invalidActivationCode"); |
| } |
| } |
| |
| } catch (WebloggerException e) { |
| addError(e.getMessage()); |
| log.error("ERROR in activateUser", e); |
| } |
| |
| if (hasActionErrors()) { |
| setActivationStatus("error"); |
| } |
| |
| // set a special page title |
| setPageTitle("welcome.title"); |
| |
| return SUCCESS; |
| } |
| |
| |
| public void myValidate() { |
| |
| // if using external auth, we don't want to error on empty password/username from HTML form. |
| boolean usingSSO = authMethod == AuthMethod.LDAP || authMethod == AuthMethod.CMA; |
| if (usingSSO) { |
| // store an unused marker in the Roller DB for the passphrase in |
| // the LDAP or CMA cases, as actual passwords are stored externally |
| String unusedPassword = WebloggerConfig.getProperty("users.passwords.externalAuthValue", "<externalAuth>"); |
| |
| // Preserve username and password, Spring Security case |
| preserveUsernameAndPassword(unusedPassword); |
| } |
| |
| String allowed = WebloggerConfig.getProperty("username.allowedChars"); |
| if (allowed == null || allowed.trim().length() == 0) { |
| allowed = DEFAULT_ALLOWED_CHARS; |
| } |
| |
| // check that username only contains safe characters |
| String safe = CharSetUtils.keep(getBean().getUserName(), allowed); |
| if (!safe.equals(getBean().getUserName()) ) { |
| addError("error.add.user.badUserName"); |
| } |
| |
| // check password, it is required if OpenID and SSO are disabled |
| if (AuthMethod.ROLLERDB.name().equals(getAuthMethod()) |
| && StringUtils.isEmpty(getBean().getPasswordText())) { |
| addError("error.add.user.passwordEmpty"); |
| return; |
| } |
| |
| // User.password does not allow null, so generate one |
| if (getAuthMethod().equals(AuthMethod.OPENID.name()) || |
| (getAuthMethod().equals(AuthMethod.DB_OPENID.name()) && !StringUtils.isEmpty(getBean().getOpenIdUrl()))) { |
| String randomString = RandomStringUtils.randomAlphanumeric(255); |
| getBean().setPasswordText(randomString); |
| getBean().setPasswordConfirm(randomString); |
| } |
| |
| // check that passwords match |
| if (!getBean().getPasswordText().equals(getBean().getPasswordConfirm())) { |
| addError("userRegister.error.mismatchedPasswords"); |
| } |
| |
| // check that username is not taken |
| checkUsername(); |
| |
| // check that OpenID, if provided, is not taken |
| checkOpenID(); |
| } |
| |
| private void preserveUsernameAndPassword(String unusedPassword) { |
| User fromSSOUser = CustomUserRegistry.getUserDetailsFromAuthentication(getServletRequest()); |
| if (fromSSOUser != null) { |
| getBean().setPasswordText(unusedPassword); |
| getBean().setPasswordConfirm(unusedPassword); |
| getBean().setUserName(fromSSOUser.getUserName()); |
| } |
| |
| // Preserve username and password, CMA case |
| else if (getServletRequest().getUserPrincipal() != null) { |
| getBean().setUserName(getServletRequest().getUserPrincipal().getName()); |
| getBean().setPasswordText(unusedPassword); |
| getBean().setPasswordConfirm(unusedPassword); |
| } |
| } |
| |
| private void checkUsername() { |
| if (!StringUtils.isEmpty(getBean().getUserName())) { |
| try { |
| UserManager mgr = WebloggerFactory.getWeblogger().getUserManager(); |
| if (mgr.getUserByUserName(getBean().getUserName(), null) != null) { |
| addError("error.add.user.userNameInUse"); |
| // reset user name |
| getBean().setUserName(null); |
| } |
| } catch (WebloggerException ex) { |
| log.error("error checking for user", ex); |
| addError("generic.error.check.logs"); |
| } |
| } |
| } |
| |
| private void checkOpenID() { |
| if (!StringUtils.isEmpty(getBean().getOpenIdUrl())) { |
| try { |
| UserManager mgr = WebloggerFactory.getWeblogger().getUserManager(); |
| if (mgr.getUserByOpenIdUrl(getBean().getOpenIdUrl()) != null) { |
| addError("error.add.user.openIdInUse"); |
| // reset OpenID URL |
| getBean().setOpenIdUrl(null); |
| } |
| } catch (WebloggerException ex) { |
| log.error("error checking OpenID URL", ex); |
| addError("generic.error.check.logs"); |
| } |
| } |
| } |
| |
| |
| public HttpServletRequest getServletRequest() { |
| return servletRequest; |
| } |
| |
| public void setServletRequest(HttpServletRequest servletRequest) { |
| this.servletRequest = servletRequest; |
| } |
| |
| public ProfileBean getBean() { |
| return bean; |
| } |
| |
| public void setBean(ProfileBean bean) { |
| this.bean = bean; |
| } |
| |
| public String getActivationStatus() { |
| return activationStatus; |
| } |
| |
| public void setActivationStatus(String activationStatus) { |
| this.activationStatus = activationStatus; |
| } |
| |
| public String getActivationCode() { |
| return activationCode; |
| } |
| |
| public void setActivationCode(String activationCode) { |
| this.activationCode = activationCode; |
| } |
| |
| } |