You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by ta...@apache.org on 2005/11/30 00:44:14 UTC

svn commit: r349840 - in /portals/jetspeed-2/trunk: ./ applications/j2-admin/ applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/ applications/j2-admin/src/webapp/WEB-INF/ applications/j2-admin/src/webapp/WEB-INF/view/userreg/ com...

Author: taylor
Date: Tue Nov 29 15:44:06 2005
New Revision: 349840

URL: http://svn.apache.org/viewcvs?rev=349840&view=rev
Log:
First pass at a UserRegistrationPortlet and ForgottenPassword portlet. There are a few features which are roughed in that need filling out and a few minor bugs.  
Only major change yet needed is updated temporary credential system for ForgottenPasswordPortlet.  
Change the default-page.psml which puts the user stuff down the right side, and the demo stuff down the left of a two-column layout.
You will need to update the mail sender host in assembly/administration.xml  in order to send emails.

Added:
    portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/
    portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswd.vm
    portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswdEmail.vm
    portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistration.vm
    portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistrationEmail.vm
    portals/jetspeed-2/trunk/components/portal/src/test/org/apache/jetspeed/administration/
    portals/jetspeed-2/trunk/components/portal/src/test/org/apache/jetspeed/administration/TestPortalAdministrationImpl.java
Modified:
    portals/jetspeed-2/trunk/applications/j2-admin/project.xml
    portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/ForgottenPasswordPortlet.java
    portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/UserRegistrationPortlet.java
    portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/portlet.xml
    portals/jetspeed-2/trunk/components/portal/project.xml
    portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/administration/PortalAdministrationImpl.java
    portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/administration/PortalAdministration.java
    portals/jetspeed-2/trunk/jetspeed-components.xml
    portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/administration.xml
    portals/jetspeed-2/trunk/src/webapp/WEB-INF/pages/default-page.psml

Modified: portals/jetspeed-2/trunk/applications/j2-admin/project.xml
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/project.xml?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/project.xml (original)
+++ portals/jetspeed-2/trunk/applications/j2-admin/project.xml Tue Nov 29 15:44:06 2005
@@ -149,6 +149,15 @@
         </properties>
     </dependency>
     <dependency>
+        <id>taglibs:standard</id>
+        <version>1.0.6</version>
+        <type>jar</type>
+        <properties>
+            <war.bundle>true</war.bundle>
+        </properties>
+    </dependency>
+
+    <dependency>
         <id>servletapi</id>
         <version>2.3</version>
         <type>jar</type>

Modified: portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/ForgottenPasswordPortlet.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/ForgottenPasswordPortlet.java?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/ForgottenPasswordPortlet.java (original)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/ForgottenPasswordPortlet.java Tue Nov 29 15:44:06 2005
@@ -17,6 +17,7 @@
 
 import java.io.IOException;
 import java.security.Principal;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -38,128 +39,219 @@
 import org.apache.jetspeed.administration.AdministrationEmailException;
 import org.apache.jetspeed.administration.PortalAdministration;
 import org.apache.jetspeed.security.PasswordCredential;
+import org.apache.jetspeed.security.SecurityException;
 import org.apache.jetspeed.security.User;
 import org.apache.jetspeed.security.UserManager;
 import org.apache.jetspeed.security.UserPrincipal;
 import org.apache.portals.bridges.velocity.AbstractVelocityMessagingPortlet;
-import org.apache.velocity.context.Context;
 import org.apache.portals.gems.util.ValidationHelper;
+import org.apache.velocity.context.Context;
 
 /**
  * This portlet allows a logged on user to change its password.
  *
  * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
+ * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
  * @version $Id: $
  */
 public class ForgottenPasswordPortlet extends AbstractVelocityMessagingPortlet
 {
+
     private PortalAdministration admin;
-    private UserManager userManager;    
-    
+
+    private UserManager userManager;
+
     // Request Params 
     private static final String RP_EMAIL_ADDRESS = "email";
 
     // Messages 
     private static final String MSG_MESSAGE = "MSG";
-    
+    private static final String MSG_CHANGEDPW_MSG = "CH_PWD_MSD";
+
     // Context Variables
-    private static final String CTX_EMAIL_ADDRESS = "email";    
+    private static final String CTX_EMAIL_ADDRESS = "email";
+
     private static final String CTX_RETURN_URL = "returnURL";
+
     private static final String CTX_NEW_PASSWORD = "password";
+
     private static final String CTX_USER_NAME = "username";
+
     private static final String CTX_MESSAGE = "MSG";
 
+    private static final String CTX_CHANGEDPW_MSG = "updatedPWMsg";
+
     // Init Parameter Constants
-    private static final String IP_REDIRECT_PATH = "redirectPath";    
+    private static final String IP_REDIRECT_PATH = "redirectPath";
+
     private static final String IP_RETURN_URL = "returnURL";
-    private static final String IP_TEMPLATE = "template";
-    
+
+    private static final String IP_TEMPLATE = "emailTemplate";
+
     // Resource Bundle
     private static final String RB_EMAIL_SUBJECT = "email.subject.forgotten.password";
-    
+
     /** email template to use for merging */
     private String template;
+
     /** servlet path of the return url to be printed and href'd in email template */
     private String returnUrlPath;
+
     /** path where to redirect to after pressing submit on the form */
     private String redirectPath;
 
     /** localized emailSubject */
     private String emailSubject = null;
-    
+
+    //TODO do this in a DB
+    Map hackMap;
+
+    class UserPassword
+    {
+
+        String user;
+
+        String password;
+    }
+
     public void init(PortletConfig config) throws PortletException
     {
         super.init(config);
-        admin = (PortalAdministration) 
-                    getPortletContext().getAttribute(CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
-        if (null == admin)
-        {
-            throw new PortletException("Failed to find the Portal Administration on portlet initialization");
-        }
-        userManager = (UserManager) 
-            getPortletContext().getAttribute(CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
-        if (null == userManager)
-        {
-            throw new PortletException("Failed to find the User Manager on portlet initialization");
-        }        
-        
+        admin = (PortalAdministration) getPortletContext().getAttribute(
+                CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
+        if (null == admin) { throw new PortletException(
+                "Failed to find the Portal Administration on portlet initialization"); }
+        userManager = (UserManager) getPortletContext().getAttribute(
+                CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
+        if (null == userManager) { throw new PortletException(
+                "Failed to find the User Manager on portlet initialization"); }
+
         this.returnUrlPath = config.getInitParameter(IP_RETURN_URL);
         this.redirectPath = config.getInitParameter(IP_REDIRECT_PATH);
         this.template = config.getInitParameter(IP_TEMPLATE);
+
+        hackMap = new HashMap();
     }
-    
-    public void doView(RenderRequest request, RenderResponse response) 
-    throws PortletException, IOException
-    {
-        response.setContentType("text/html");                
-        Context context = getContext(request);        
-        String email = request.getParameter(RP_EMAIL_ADDRESS);        
+
+    private boolean isValidGUID(String guid)
+    {
+        // lookup the guid here 
+        UserPassword m = (UserPassword) hackMap.get(guid);
+        if (m != null) { return true; }
+        return false;
+    }
+
+    private boolean updatePasswordFromGUID(String guid)
+    {
+        UserPassword m = (UserPassword) hackMap.get(guid);
+        String userName = (String) m.user;
+        String newPassword = (String) m.password;
+
+        // Here's where a break should be.   The following code should be put into the RETURN portlet
+        try
+        {
+            userManager.setPassword(userName, null, newPassword);
+            userManager.setPasswordUpdateRequired(userName, true);
+            // if we got here stuff is changed... removed the key from the map
+            hackMap.remove(guid);
+        } catch (SecurityException e)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public void doView(RenderRequest request, RenderResponse response)
+            throws PortletException, IOException
+    {
+        response.setContentType("text/html");
+        Context context = getContext(request);
+        String email = request.getParameter(RP_EMAIL_ADDRESS);
+        String guid = request.getParameter("guid");
+
+        if (guid != null) 
+        {
+            if(isValidGUID(guid)) 
+            {
+                try
+                {
+                    updatePasswordFromGUID(guid);
+                    context
+                            .put(CTX_CHANGEDPW_MSG,
+                                    "Your password has been updated!  Please login using it!");
+                } catch (Exception e)
+                {
+                    context
+                            .put(CTX_CHANGEDPW_MSG,
+                                    "<font color=\"red\">unable to update your password, try again please</font>");
+                }
+            } else {
+                // invalid GUID
+                context
+                .put(CTX_CHANGEDPW_MSG,
+                        "<font color=\"red\">I'm sorry that change password link is invalid</font>");
+            }
+        } else {
+            // might be returning from initial request
+            context.put(CTX_CHANGEDPW_MSG,consumeRenderMessage(request, MSG_CHANGEDPW_MSG));
+        }
         context.put(CTX_EMAIL_ADDRESS, email);
-        context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));        
+        context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));
         super.doView(request, response);
     }
 
-    public void processAction(ActionRequest request, ActionResponse response) 
-        throws PortletException, IOException
+    public static String makeGUID(String user, String newpw)
+    {
+        // This is a quicky version
+        long num = (long) user.hashCode() + (long) newpw.hashCode(); //  Possible collisions here...
+        long d = new Date().getTime();
+        long val = num * d;
+        String retval = Long.toHexString(val);
+        return retval;
+    }
+
+    public void processAction(ActionRequest request, ActionResponse response)
+            throws PortletException, IOException
     {
         List errors = new LinkedList();
-                            
+
         String email = request.getParameter(RP_EMAIL_ADDRESS);
-        
+
         // validation
         if (!ValidationHelper.isEmailAddress(email, true, 80))
         {
             // TODO: get error message from localized resource
-            errors.add("Please enter a valid Email address.");  
+            errors.add("Please enter a valid Email address.");
         }
-        
-        
+
         if (errors.size() > 0)
         {
             publishRenderMessage(request, MSG_MESSAGE, errors);
             return;
         }
-        
+
         User user = null;
         try
         {
             user = admin.lookupUserFromEmail(email);
-        } 
-        catch (Exception e) 
+        } catch (Exception e)
         {
             // TODO: get message from localized messages
-            publishRenderMessage(request, MSG_MESSAGE, 
+            publishRenderMessage(
+                    request,
+                    MSG_MESSAGE,
                     makeMessage("Sorry but we could not find this email address on file. Are you sure you typed it in correctly?"));
             return;
         }
 
-        try 
+        try
         {
             String userName = getUserName(user);
-            String oldPassword = getPassword(user);
-            String newPassword = admin.generatePassword();             
-            userManager.setPassword(userName, oldPassword, newPassword);
-            userManager.setPasswordUpdateRequired(userName, true);
+
+            String newPassword = admin.generatePassword();
+
+            String urlGUID = makeGUID(userName, newPassword);
+
             Preferences pref = user.getUserAttributes();
             String[] keys = pref.keys();
             Map userAttributes = new HashMap();
@@ -173,62 +265,83 @@
                 }
             }
             // special attributes
-            userAttributes.put(CTX_RETURN_URL, generateReturnURL(request, response));
+            userAttributes.put(CTX_RETURN_URL, generateReturnURL(request,
+                    response, urlGUID));
             userAttributes.put(CTX_NEW_PASSWORD, newPassword);
             userAttributes.put(CTX_USER_NAME, userName);
-            
-            admin.sendEmail(email, getEmailSubject(request), this.template, userAttributes);
+            if (this.template == null) { throw new Exception(
+                    "email template not available"); }
+            admin.sendEmail(this.getPortletConfig(), email,
+                    getEmailSubject(request), this.template, userAttributes);
+
+            //TODO this is currently hacked with a hashmap... needs to move to either a DB table
+            // or to some sort of credential
+            UserPassword up = new UserPassword();
+            up.user = userName;
+            up.password = newPassword;
+            hackMap.put(urlGUID, up);
+
+            publishRenderMessage(
+                    request,
+                    MSG_CHANGEDPW_MSG,
+                    makeMessage("An email has been sent to you.  Please follow the link in the email"));
             
             response.sendRedirect(this.redirectPath);
-        }
-        catch (AdministrationEmailException e)
+        } catch (AdministrationEmailException e)
         {
-            publishRenderMessage(request, CTX_MESSAGE, 
-                    makeMessage(e.getMessage()));
-        }
-        catch (Exception e) 
+            publishRenderMessage(request, CTX_MESSAGE, makeMessage(e
+                    .getMessage()));
+        } catch (Exception e)
         {
-            publishRenderMessage(request, CTX_MESSAGE, makeMessage("Failed to send password: " + e.toString()));
+            publishRenderMessage(request, CTX_MESSAGE,
+                    makeMessage("Failed to send password: " + e.toString()));
         }
-        
+
     }
 
     protected String getEmailSubject(PortletRequest request)
     {
-        ResourceBundle resource = getPortletConfig().getResourceBundle(request.getLocale());
-        this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
+        ResourceBundle resource = getPortletConfig().getResourceBundle(
+                request.getLocale());
+        try
+        {
+            this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
+        } catch (Exception e)
+        {
+            //TODO  report missing resource somehow
+        }
         if (this.emailSubject == null)
-            this.emailSubject = "Password Notification";
+                this.emailSubject = "Password Notification";
         return this.emailSubject;
     }
-    
-    protected String generateReturnURL(ActionRequest request, ActionResponse response)
+
+    protected String generateReturnURL(ActionRequest request,
+            ActionResponse response, String urlGUID)
     {
-        // TODO: get the FULL PORTAL URL return address to login from init param        
-        return "http://TODO-FIXME" + this.returnUrlPath; 
+        return this.returnUrlPath + "?guid=" + urlGUID;
     }
-    
+
     protected String getUserName(User user)
     {
         Principal principal = null;
         Iterator principals = user.getSubject().getPrincipals().iterator();
         while (principals.hasNext())
-        {      
+        {
             Object o = principals.next();
             if (o instanceof UserPrincipal)
             {
-                principal = (Principal)o;
+                principal = (Principal) o;
                 return principal.toString();
             }
-                
+
         }
-        return null;        
+        return null;
     }
 
     protected String getPassword(User user)
     {
         PasswordCredential credential = null;
-        
+
         Set credentials = user.getSubject().getPrivateCredentials();
         Iterator iter = credentials.iterator();
         while (iter.hasNext())
@@ -236,13 +349,15 @@
             Object o = iter.next();
             if (o instanceof PasswordCredential)
             {
-                credential = (PasswordCredential)o;
-                return credential.toString();
+                credential = (PasswordCredential) o;
+                char[] charar = credential.getPassword();
+
+                return new String(charar);
             }
         }
-        return null;                
+        return null;
     }
-    
+
     protected List makeMessage(String msg)
     {
         List errors = new LinkedList();

Modified: portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/UserRegistrationPortlet.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/UserRegistrationPortlet.java?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/UserRegistrationPortlet.java (original)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/java/org/apache/jetspeed/portlets/registration/UserRegistrationPortlet.java Tue Nov 29 15:44:06 2005
@@ -16,6 +16,7 @@
 package org.apache.jetspeed.portlets.registration;
 
 import java.io.IOException;
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -33,222 +34,440 @@
 import javax.portlet.RenderResponse;
 
 import org.apache.jetspeed.CommonPortletServices;
+import org.apache.jetspeed.administration.AdministrationEmailException;
 import org.apache.jetspeed.administration.PortalAdministration;
 import org.apache.jetspeed.security.SecurityException;
 import org.apache.jetspeed.security.User;
 import org.apache.jetspeed.security.UserManager;
+import org.apache.portals.bridges.frameworks.model.ModelBean;
 import org.apache.portals.bridges.velocity.AbstractVelocityMessagingPortlet;
+import org.apache.portals.gems.util.ValidationHelper;
 import org.apache.velocity.context.Context;
 
 /**
  * This portlet allows a logged on user to change its password.
  *
  * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
+ * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
  * @version $Id: $
  */
 public class UserRegistrationPortlet extends AbstractVelocityMessagingPortlet
 {
+
     private PortalAdministration admin;
+
     private UserManager userManager;
- 
+
+    // commonly USED attributes
+
+    private static final String USER_ATTRIBUTE_EMAIL = "user.business-info.online.email";
 
     // Messages 
-    private static final String MSG_MESSAGE = "MSG";    
+    private static final String MSG_MESSAGE = "MSG";
+
     private static final String MSG_USERINFO = "user";
-    
+
+    private static final String MSG_REGED_USER_MSG = "registeredUserMsg";
+
     // Init Parameters
     private static final String IP_ROLES = "roles"; // comma separated    
+
     private static final String IP_GROUPS = "groups"; // comma separated
-    private static final String IP_TEMPLATE = "template";
+
+    private static final String IP_EMAIL_TEMPLATE = "emailTemplate";
+
     private static final String IP_RULES_NAMES = "rulesNames";
+
     private static final String IP_RULES_VALUES = "rulesValues";
-    private static final String IP_REDIRECT_PATH = "redirectPath";    
+
+    private static final String IP_REDIRECT_PATH = "redirectPath";
+
     private static final String IP_RETURN_URL = "returnURL";
-    
+
+    private static final String IP_OPTION_EMAILS_SYSTEM_UNIQUE = "Option_Emails_System_Unique";
+
+    private static final String IP_OPTION_GENERATE_PASSWORDS = "Option_Generate_Passwords";
+
+    private static final String IP_OPTION_USE_EMAIL_AS_USERNAME = "Option_Use_Email_As_Username";
+
     // Context Variables
     private static final String CTX_RETURN_URL = "returnURL";
+
     private static final String CTX_MESSAGE = "MSG";
-    private static final String CTX_USERINFO = "user";    
-    
+
+    private static final String CTX_USERINFO = "user";
+
+    private static final String CTX_REGED_USER_MSG = "registeredUserMsg";
+
+    private static final String CTX_OPTION_GENERATE_PASSWORDS = "CTX_Option_Generate_Passwords";
+
+    private static final String CTX_OPTION_USE_EMAIL_AS_USERNAME = "CTX_Option_Use_Email_As_Username";
+
     // Resource Bundle
     private static final String RB_EMAIL_SUBJECT = "email.subject.registration";
-    
+
     /** email template to use for merging */
-    private String template;
+    private String emailTemplate;
 
     /** localized emailSubject */
     private String emailSubject = null;
-    
+
     /** path where to redirect to after pressing submit on the form */
     private String redirectPath;
 
     /** servlet path of the return url to be printed and href'd in email template */
     private String returnUrlPath;
-    
+
     /** roles */
     private List roles;
-    
+
     /** groups */
     private List groups;
-    
+
     /** profile rules */
     private Map rules;
-    
+
+    /** will force the passwords to be generated instead of picked by the user */
+    private boolean optionForceGeneratedPasswords = false;
+
+    /** will use cause the portlet to use a user request username instead otherwise forces emailaddress */
+    private boolean optionForceEmailAsUsername = true;
+
+    /** will check to make sure the email address is unique to the system */
+    private boolean optionForceEmailsToBeSystemUnique = true;
+
     public void init(PortletConfig config) throws PortletException
     {
         super.init(config);
-        admin = (PortalAdministration) 
-                    getPortletContext().getAttribute(CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
-        if (null == admin)
-        {
-            throw new PortletException("Failed to find the Portal Administration on portlet initialization");
-        }
-        userManager = (UserManager)  
-        getPortletContext().getAttribute(CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
-        if (null == userManager)
-        { 
-            throw new PortletException("Failed to find the User Manager on portlet initialization");
-        } 
-        
+        admin = (PortalAdministration) getPortletContext().getAttribute(
+                CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
+        if (null == admin) { throw new PortletException(
+                "Failed to find the Portal Administration on portlet initialization"); }
+        userManager = (UserManager) getPortletContext().getAttribute(
+                CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
+        if (null == userManager) { throw new PortletException(
+                "Failed to find the User Manager on portlet initialization"); }
+
         // roles
         this.roles = getInitParameterList(config, IP_ROLES);
-        
+
         // groups
         this.groups = getInitParameterList(config, IP_GROUPS);
-        
+
         // rules (name,value pairs)
         List names = getInitParameterList(config, IP_RULES_NAMES);
         List values = getInitParameterList(config, IP_RULES_VALUES);
         rules = new HashMap();
-        for (int ix = 0; ix < ((names.size() < values.size()) ? names.size() : values.size()); ix++)
+        for (int ix = 0; ix < ((names.size() < values.size()) ? names.size()
+                : values.size()); ix++)
         {
             rules.put(names.get(ix), values.get(ix));
         }
-   
+
+        this.emailTemplate = config.getInitParameter(IP_EMAIL_TEMPLATE);
+
         // user attributes ? 
-        
-        this.template = config.getInitParameter(IP_TEMPLATE);
-        this.redirectPath = config.getInitParameter(IP_REDIRECT_PATH);
-        this.returnUrlPath = config.getInitParameter(IP_RETURN_URL);        
-    }
-    
-    public void doView(RenderRequest request,
-                       RenderResponse response) 
-        throws PortletException, IOException 
-    {
-        response.setContentType("text/html");                
-        Context context = getContext(request);        
-        context.put(CTX_USERINFO, this.receiveRenderMessage(request, MSG_USERINFO));
-        context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));        
-        super.doView(request, response);                
+
+        this.optionForceEmailsToBeSystemUnique = Boolean.getBoolean(config
+                .getInitParameter(IP_OPTION_EMAILS_SYSTEM_UNIQUE));
+        this.optionForceGeneratedPasswords = Boolean.getBoolean(config
+                .getInitParameter(IP_OPTION_GENERATE_PASSWORDS));
+        this.optionForceEmailAsUsername = Boolean.getBoolean(config
+                .getInitParameter(IP_OPTION_USE_EMAIL_AS_USERNAME));
+        if (this.optionForceEmailAsUsername)
+        {
+            // just to be sure
+            this.optionForceEmailsToBeSystemUnique = true;
+        }
+    }
+
+    public void doView(RenderRequest request, RenderResponse response)
+            throws PortletException, IOException
+    {
+        response.setContentType("text/html");
+        Context context = getContext(request);
+        context.put(CTX_USERINFO, this.receiveRenderMessage(request,
+                MSG_USERINFO));
+        context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));
+        
+        // if this is non-null, then we know that we registered
+        context.put(CTX_REGED_USER_MSG, consumeRenderMessage(request,
+                MSG_REGED_USER_MSG));
+
+        // next two control the existence of some of the fields in the form
+        if (this.optionForceEmailAsUsername)
+        {
+            context.put(CTX_OPTION_USE_EMAIL_AS_USERNAME, "TRUE");
+        }
+        if (this.optionForceGeneratedPasswords)
+        {
+            context.put(CTX_OPTION_GENERATE_PASSWORDS, "TRUE");
+        }
+
+        super.doView(request, response);
+    }
+
+    private Object getBeanFromSession(PortletRequest request, ModelBean mb)
+    {
+        return request.getPortletSession().getAttribute(makeModelBeanKey(mb));
     }
-    
+
+    private void clearBeanFromSession(PortletRequest request, ModelBean mb)
+    {
+        System.out.println("Clearing bean " + makeModelBeanKey(mb));
+        request.getPortletSession().removeAttribute(makeModelBeanKey(mb));
+    }
+
+    private void putBeanInSession(PortletRequest request, ModelBean mb,
+            Object bean)
+    {
+        if (bean instanceof Serializable)
+        {
+            request.getPortletSession()
+                    .setAttribute(makeModelBeanKey(mb), bean);
+        }
+    }
+
+    private String makeModelBeanKey(ModelBean mb)
+    {
+        return "ModelBean:" + mb.getBeanName();
+    }
+
+    /*   
+     protected Object formToBean(ActionRequest request, String view, ModelBean mb) throws PortletException
+     {
+
+     // try to get the bean from the session first
+     Object bean = getBeanFromSession(request, mb);
+     if (bean == null)
+     {
+     bean = model.createBean(mb);
+     if (bean == null) { throw new PortletException("Portlet Action error in creating bean for view: " + view); }
+     putBeanInSession(request, mb, bean);
+     }
+
+     Map params = request.getParameterMap();
+     try
+     {
+     BeanUtils.populate(bean, params);
+     }
+     catch (Exception e)
+     {
+     throw new PortletException("Portlet Action error in  populating bean: " + mb.getBeanName(), e);
+     }
+     return bean;
+     }
+     */
+
+    protected static String[] formValues =
+    { "user.name.family", "user.name.given", "user.business-info.online.email",
+            "user.name", "password", "verifyPassword", "user.department",
+            "user.employer"};
+
     public void processAction(ActionRequest actionRequest,
-            ActionResponse actionResponse) throws PortletException, IOException 
+            ActionResponse actionResponse) throws PortletException, IOException
     {
         List errors = new LinkedList();
-        
-        // TODO: determine which PLT.D Information to register with
-        String familyName = actionRequest.getParameter("user.name.family");
-        String givenName = actionRequest.getParameter("user.name.given");     
-        String email = actionRequest.getParameter("user.email");
-        
-        String userName = actionRequest.getParameter("user.name");
-        String password = actionRequest.getParameter("password");
-        String verifyPassword = actionRequest.getParameter("verifyPassword");
 
-        // TODO: Validation
-        
-        // Could have two modes (init param or pref) of user name creation:
-        //  1. use email address
-        //  2. request user id
-        // Could have two modes (init param or pref) of password creation
-        //  1. generate new password automatically
-        //  2. enter a new password and verify
-        
-        // TODO: add select user attributes to map
+        Map userAttributes = new HashMap();
+
         Map userInfo = new HashMap();
-        
-        boolean requestUserId = true;
-        if (requestUserId)
+
+        for (int i = 0; i < formValues.length; i++)
+        {
+            String key = formValues[i];
+            String value = actionRequest.getParameter(key);
+            if (value != null)
+            {
+                userInfo.put(key, value);
+                if (key.startsWith("user."))
+                {
+                    // we'll assume that these map back to PLT.D  values
+                    userAttributes.put(key, value);
+                }
+            }
+        }
+
+        if (!ValidationHelper.isAny((String) userInfo.get("user.name.given"),
+                true, 25))
+        {
+            // TODO: get error message from localized resource
+            errors.add("You must enter a first name");
+        }
+        if (!ValidationHelper.isAny((String) userInfo.get("user.name.family"),
+                true, 25))
+        {
+            // TODO: get error message from localized resource
+            errors.add("You must enter a last name");
+        }
+        if (!ValidationHelper.isAny((String) userInfo.get("user.name"), true,
+                25))
+        {
+            // TODO: get error message from localized resource
+            errors.add("You must enter a username");
+        }
+        if (!ValidationHelper.isEmailAddress((String) userInfo
+                .get(USER_ATTRIBUTE_EMAIL), true, 80))
         {
-            boolean userIdExistsFlag = true;
+            // TODO: get error message from localized resource
+            errors.add("Please enter a valid Email address.");
+        }
+        if (!this.optionForceGeneratedPasswords)
+        {
+            if (!ValidationHelper.isAny((String) userInfo.get("password"),
+                    true, 25))
+            {
+                // TODO: get error message from localized resource
+                errors.add("You must enter a password");
+            }
+        }
+
+        if (optionForceEmailAsUsername)
+        {
+            // force user.name to be same as email
+            userInfo.put("user.name", userInfo.get(USER_ATTRIBUTE_EMAIL));
+        }
+
+        boolean userIdExistsFlag = true;
+        try
+        {
+            User user = userManager.getUser((String) userInfo.get("user.name"));
+        } catch (SecurityException e)
+        {
+            userIdExistsFlag = false;
+        }
+        //
+        if (userIdExistsFlag)
+        {
+            // TODO: localize messages
+            errors
+                    .add("Requested User ID already exists.  Please select another User Id.");
+            publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
+            return;
+        }
+        if (optionForceEmailsToBeSystemUnique)
+        {
+            boolean emailExistsFlag = true;
+            User user = null;
             try
             {
-                User user = userManager.getUser(userName);
-            } 
-            catch (SecurityException e) 
+                user = admin.lookupUserFromEmail((String) userInfo
+                        .get(USER_ATTRIBUTE_EMAIL));
+            } catch (AdministrationEmailException e1)
             {
-                userIdExistsFlag = false;
+                emailExistsFlag = false;
             }
-    //
-            if (userIdExistsFlag) 
+            if ((emailExistsFlag) || (user != null))
             {
                 // TODO: localize messages
-                errors.add("Requested User ID already exists.  Please select another User Id.");
+                errors
+                        .add("The requested email address is already being used in the system.  If you already have an account, consider using the forgotten password portlet to retreive your password");
                 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
                 return;
             }
+
         }
-        
-        try 
+
+        try
         {
-            boolean generatePasswordOption = true;
-            if (generatePasswordOption)
+            if (optionForceGeneratedPasswords)
             {
-                password = admin.generatePassword();
+                String password = admin.generatePassword();
+                userInfo.put("user.password", password);
+            } else
+            {
+                if (userInfo.get("password").equals(
+                        userInfo.get("verifyPassword")))
+                {
+
+                } else
+                {
+                    //                  TODO: localize messages
+                    errors
+                            .add("The two passwords do not match, please re-type them");
+                    publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
+                    return;
+                }
             }
-            
-            admin.registerUser(userName, 
-                               password, 
-                               this.roles, 
-                               this.groups, 
-                               userInfo, 
-                               rules, 
-                               template);
-          
-            // special attributes
-            userInfo.put(CTX_RETURN_URL, generateReturnURL(actionRequest, actionResponse));
-            
-            admin.sendEmail(email, getEmailSubject(actionRequest), this.template, userInfo);
-            
+        } catch (Exception e)
+        {
+            // TODO: localize messages
+            errors.add("Failed to add user. " + e.toString());
+            publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
+        }
+        // make sure no errors have occurred
+        if (errors.size() > 0)
+        {
+            publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
+        }
+
+        // Ok, we think we're good to go, let's create the user!
+        try
+        {
+            admin.registerUser((String) userInfo.get("user.name"),
+                    (String) userInfo.get("password"), this.roles, this.groups,
+                    userAttributes, // note use of only PLT.D  values here.
+                    rules, null); // passing in null causes use of default template
+
+            String urlGUID = ForgottenPasswordPortlet.makeGUID(
+                    (String) userInfo.get("user.name"), (String) userInfo
+                            .get("password"));
+
+            userInfo.put(CTX_RETURN_URL, generateReturnURL(actionRequest,
+                    actionResponse, urlGUID));
+
+            if (this.emailTemplate == null) { throw new Exception(
+                    "email template not available"); }
+
+            admin.sendEmail(getPortletConfig(), (String) userInfo
+                    .get(USER_ATTRIBUTE_EMAIL), getEmailSubject(actionRequest),
+                    this.emailTemplate, userInfo);
+
+            publishRenderMessage(actionRequest, MSG_REGED_USER_MSG,
+                    "You have completed the user registration process.  Please login above");
+
             actionResponse.sendRedirect(this.redirectPath);
 
-        } 
-        catch (Exception e) 
+        } catch (Exception e)
         {
             // TODO: localize messages
             errors.add("Failed to add user. " + e.toString());
-            publishRenderMessage(actionRequest, MSG_MESSAGE, errors);            
+            publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
         }
     }
-    
+
     protected String getEmailSubject(PortletRequest request)
     {
-        ResourceBundle resource = getPortletConfig().getResourceBundle(request.getLocale());
-        this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
+        ResourceBundle resource = getPortletConfig().getResourceBundle(
+                request.getLocale());
+        try
+        {
+            this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
+        } catch (java.util.MissingResourceException mre)
+        {
+            this.emailSubject = null;
+        }
         if (this.emailSubject == null)
-            this.emailSubject = "Registration Confirmation";
+                this.emailSubject = "Registration Confirmation";
         return this.emailSubject;
     }
 
     protected List getInitParameterList(PortletConfig config, String ipName)
     {
         String temp = config.getInitParameter(ipName);
-        if (temp == null)
-            return new ArrayList();
-        
+        if (temp == null) return new ArrayList();
+
         String[] temps = temp.split("\\,");
         for (int ix = 0; ix < temps.length; ix++)
-            temps[ix] = temps[ix].trim();        
-        
-        return Arrays.asList(temps);        
+            temps[ix] = temps[ix].trim();
+
+        return Arrays.asList(temps);
     }
-    
-    protected String generateReturnURL(ActionRequest request, ActionResponse response)
+
+    protected String generateReturnURL(ActionRequest request,
+            ActionResponse response, String urlGUID)
     {
-        // TODO: get the FULL PORTAL URL return address to login from init param        
-        return "http://TODO-FIXME" + this.returnUrlPath; 
+        return this.returnUrlPath + "?newUserGUID=" + urlGUID;
     }
-    
+
 }

Modified: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/portlet.xml
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/portlet.xml?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/portlet.xml (original)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/portlet.xml Tue Nov 29 15:44:06 2005
@@ -839,5 +839,115 @@
     </portlet-info>
   </portlet>
 
+  <portlet id="ForgottenPasswordPortlet">
+    <init-param>
+        <description>This parameter sets the template used in view mode.</description>
+        <name>ViewPage</name>
+            <value>/WEB-INF/view/userreg/forgottenPasswd.vm</value>
+     </init-param>
+     <init-param>
+        <description>This parameter sets the template used to send the Email for Forgotten password</description>
+        <name>emailTemplate</name>
+            <value>/WEB-INF/view/userreg/forgottenPasswdEmail.vm</value>
+     </init-param>   
+     <init-param>
+        <description>This parameter sets the url to which folks will return after they receive an email</description>
+        <name>returnURL</name>
+            <value>http://localhost:8080/jetspeed/portal/something.vm</value>
+     </init-param>   
+     <init-param>
+        <description>This parameter sets the URL to which people will go after they successfully complete their form for forgotten password</description>
+        <name>redirectPath</name>
+            <value>http://localhost:8080/jetspeed/portal/</value>
+     </init-param>   
+
+    <portlet-name>ForgottenPasswordPortlet</portlet-name>
+    <display-name>Forgotten Password Portlet</display-name>
+    <description>Provides users with the ability to request a new password to be sent to their email address</description>
+    <portlet-class>org.apache.jetspeed.portlets.registration.ForgottenPasswordPortlet</portlet-class>
+    <expiration-cache>-1</expiration-cache>
+    <supports>
+      <mime-type>text/html</mime-type>
+      <portlet-mode>VIEW</portlet-mode>
+    </supports>
+    <supported-locale>en</supported-locale>
+    <portlet-info>
+      <title>Forgotten Password</title>
+      <short-title>Forgotten Password</short-title>
+      <keywords>password, forgotten, lost, passwd </keywords>
+    </portlet-info>
+  </portlet>
+
+    <portlet id="ForgottenPasswordReturnPortlet">
+    <init-param>
+        <description>This parameter sets the template used in view mode.</description>
+        <name>ViewPage</name>
+            <value>/WEB-INF/view/userreg/forgottenPasswdReturn.vm</value>
+     </init-param>
+    <portlet-name>ForgottenPasswordReturnPortlet</portlet-name>
+    <display-name>Forgotten Password Return Portlet</display-name>
+    <description>Provides users with the ability to click and update their password after email</description>
+    <portlet-class>org.apache.jetspeed.portlets.registration.ForgottenPasswordPortlet</portlet-class>
+    <expiration-cache>-1</expiration-cache>
+    <supports>
+      <mime-type>text/html</mime-type>
+      <portlet-mode>VIEW</portlet-mode>
+    </supports>
+    <supported-locale>en</supported-locale>
+    <portlet-info>
+      <title>Forgotten Password Return</title>
+      <short-title>forgot PS return</short-title>
+      <keywords> </keywords>
+    </portlet-info>
+  </portlet>
+  
+      
+    <portlet id="UserRegistrationPortlet">
+    <init-param>
+        <description>This parameter sets the template used in view mode.</description>
+        <name>ViewPage</name>
+            <value>/WEB-INF/view/userreg/userRegistration.vm</value>
+     </init-param>
+      
+      <init-param>
+        <description>This option will generate a new password for each user registration</description>
+        <name>Option_Generate_Passwords</name>
+            <value>false</value>
+      </init-param>   
+      <init-param>
+        <description>This option will force email address to be system wide unique</description>
+        <name>Option_Emails_System_Unique</name>
+            <value>true</value>
+      </init-param>   
+      <init-param>
+        <description>This option will use the email address as the username</description>
+        <name>Option_Use_Email_As_Username</name>
+            <value>false</value>
+      </init-param> 
+
+      <init-param>
+        <description>This is the template in which you setup an email to be sent after user exists</description>
+        <name>emailTemplate</name>
+            <value>/WEB-INF/view/userreg/userRegistrationEmail.vm</value>
+      </init-param> 
+      
+        
+       
+    <portlet-name>UserRegistrationPortlet</portlet-name>
+    <display-name>User Registration Portlet</display-name>
+    <description>Provides users with the ability register anew with the portal</description>
+    <portlet-class>org.apache.jetspeed.portlets.registration.UserRegistrationPortlet</portlet-class>
+    <expiration-cache>-1</expiration-cache>
+    <supports>
+      <mime-type>text/html</mime-type>
+      <portlet-mode>VIEW</portlet-mode>
+    </supports>
+    <supported-locale>en</supported-locale>
+    <portlet-info>
+      <title>User Registration </title>
+      <short-title>User Registration</short-title>
+      <keywords>password, register, signup, new user </keywords>
+    </portlet-info>
+  </portlet>
 </portlet-app>
 

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswd.vm
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswd.vm?rev=349840&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswd.vm (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswd.vm Tue Nov 29 15:44:06 2005
@@ -0,0 +1,23 @@
+<div id="ForgottenPassword"  class="portlet-section-text"> 
+	#if($updatedPWMsg)
+		<table>
+			<tr><td colspan="2" ><font color="green" size="+1" >$updatedPWMsg</font></td></tr>
+		</table>
+	#else
+	<form name="forgottenPasswordForm" action="$renderResponse.createActionURL()" method="post" >
+	<table>
+		<tr><td colspan="2" > 
+			If you have forgotten your password, we can create a new one and send it to you via your email address.
+			You must enter the exact same email address with which you originally registered. 
+			#if($MSG )
+	 			<br>
+	 			<font color="red">$!MSG</font>
+	 		#end	
+		</td></tr>
+		
+		<tr><td>email address:</td><td><input type="text" name="email" value="$!email" /></td></tr>
+		<tr><td colspan="2" > <input type="submit" value="Request New Password"  name="Request New Password" /> </td></tr>
+	</table>
+    </form>
+    #end
+</div>

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswdEmail.vm
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswdEmail.vm?rev=349840&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswdEmail.vm (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/forgottenPasswdEmail.vm Tue Nov 29 15:44:06 2005
@@ -0,0 +1,14 @@
+Hello  $!{map.get("user.name.given")} $!{map.get("user.name.family")}:
+
+Thank you for requesting a new password for your account. 
+The account username: $!{map.get("username")}
+The new password is : $!{map.get("password")}
+To activate the new password you MUST click on the following link:
+$!{map.get("returnURL")}
+If you have received this email in error, and do NOT want to update your password,
+please do NOT click on the link above, and your account will remain using your
+original password.
+
+Thanks,  
+
+The Jetspeed Team.

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistration.vm
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistration.vm?rev=349840&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistration.vm (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistration.vm Tue Nov 29 15:44:06 2005
@@ -0,0 +1,37 @@
+<div id="UserRegistration"  class="portlet-section-text"> 
+	#if($registeredUserMsg)
+		<table>
+			<tr><td colspan="2" ><font color="green" size="+1" >$registeredUserMsg</font></td></tr>
+		</table>
+	#else
+	<form name="userRegistrationForm" action="$renderResponse.createActionURL()" method="post" >
+	<table>
+		<tr><td colspan="2" > 
+			Welcome.  Please fill out the following form to become a registered user.
+			#if($MSG )
+	 			<br>
+	 			<font color="red">$!MSG</font>
+	 		#end	
+		</td></tr>
+		
+		#if($CTX_Option_Use_Email_As_Username)
+		#else
+		<tr><td>username:</td><td><input type="text" name="user.name" value="$!user.name" /></td></tr>
+		#end
+		<tr><td>first name:</td><td><input type="text" name="user.name.given" value="$!user.name.given" /></td></tr>
+		<tr><td>last name:</td><td><input type="text" name="user.name.family" value="$!user.name.family" /></td></tr>
+		<tr><td>department: <font color="blue" size="-2">(optional)</font></td><td><input type="text" name="user.department" value="$!user.department" /></td></tr>
+		<tr><td>employer: <font color="blue" size="-2">(optional)</font></td><td><input type="text" name="user.employer" value="$!user.employer" /></td></tr>
+		<tr><td>email address:</td><td><input type="text" name="user.business-info.online.email" value="$!user.business-info.online.email" /></td></tr>
+		
+		#if($CTX_Option_Generate_Passwords)
+		#else
+		<tr><td>password:</td><td><input type="password" name="password" value="" /></td></tr>
+		<tr><td>password (verify):</td><td><input type="password" name="verifyPassword" value="" /></td></tr>
+		#end
+		
+		<tr><td colspan="2" > <input type="submit" value="Register Me!" name="Register Me" /> </td></tr>
+	</table>
+    </form>
+    #end
+</div>

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistrationEmail.vm
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistrationEmail.vm?rev=349840&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistrationEmail.vm (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/WEB-INF/view/userreg/userRegistrationEmail.vm Tue Nov 29 15:44:06 2005
@@ -0,0 +1,5 @@
+This is a place holder for now.
+
+Hello $!{map.get("user.name.given")}
+
+Hopefully more interesting stuff will happen later.
\ No newline at end of file

Modified: portals/jetspeed-2/trunk/components/portal/project.xml
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/components/portal/project.xml?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/project.xml (original)
+++ portals/jetspeed-2/trunk/components/portal/project.xml Tue Nov 29 15:44:06 2005
@@ -36,7 +36,13 @@
       <version>${jetspeed.version}</version>
     </dependency>
  </dependencies>
-    
+   
+<dependencies>
+    <dependency>
+      <id>taglibs:random</id>
+      <version>1.0.2</version>
+    </dependency>
+ </dependencies> 
     <build>
         <sourceDirectory>src/java</sourceDirectory>
         <unitTestSourceDirectory>src/test</unitTestSourceDirectory>

Modified: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/administration/PortalAdministrationImpl.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/administration/PortalAdministrationImpl.java?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/administration/PortalAdministrationImpl.java (original)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/administration/PortalAdministrationImpl.java Tue Nov 29 15:44:06 2005
@@ -15,22 +15,31 @@
  */
 package org.apache.jetspeed.administration;
 
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
+import java.io.FileReader;
 import java.io.StringWriter;
 import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import javax.portlet.PortletConfig;
+import javax.security.auth.Subject;
+import javax.servlet.jsp.JspException;
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.jetspeed.Jetspeed;
+import org.apache.jetspeed.exception.JetspeedException;
 import org.apache.jetspeed.om.folder.Folder;
+import org.apache.jetspeed.om.folder.FolderNotFoundException;
+import org.apache.jetspeed.om.folder.InvalidFolderException;
 import org.apache.jetspeed.page.PageManager;
+import org.apache.jetspeed.page.PageNotUpdatedException;
+import org.apache.jetspeed.page.document.NodeException;
+import org.apache.jetspeed.pipeline.PipelineException;
 import org.apache.jetspeed.prefs.PreferencesProvider;
 import org.apache.jetspeed.prefs.om.Node;
 import org.apache.jetspeed.profiler.Profiler;
@@ -46,7 +55,7 @@
 import org.springframework.mail.MailException;
 import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
-
+import org.apache.taglibs.random.RandomStrg;
 
 /**
  * PortalAdministrationImpl
@@ -57,6 +66,7 @@
  *  - 
  * 
  * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
+ * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
  * @version $Id: $
  */
 
@@ -82,6 +92,17 @@
     /** name of PSML Folder Template to clone from when registering new user */
     protected String folderTemplate;
     
+    /** the list of characters from which a password can be generatored. */
+    protected static final char[] PASS_CHARS = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
+        // removed these for aesthetic purposes
+        //'!', '&',  '-', '_', '=',
+        // '*','@', '#', '$', '%', '^',
+        //'+',
+    
     public PortalAdministrationImpl( UserManager userManager,
                                      RoleManager roleManager,
                                      GroupManager groupManager, 
@@ -219,17 +240,52 @@
                 }
             }
             
-            // create user's home folder                        
-            // deep copy from the default folder template tree, creating a deep-copy of the template
-            // in the new user's folder tree
             if (folderTemplate == null)
             {
                 folderTemplate = this.folderTemplate; 
             }
-            Folder source = pageManager.getFolder(folderTemplate);
-            pageManager.deepCopyFolder(source, Folder.USER_FOLDER + userName);
+            
+            // This next chunk of code is the fancy way to force the creation of the user
+            // template pages to be created with subject equal to the new user
+            // otherwise it would be created as guest, and guest does not have enough privs.
+            final String innerFolderTemplate = folderTemplate;
+            final String innerUserName = userName;
+            final PageManager innerPageManager = pageManager;
+            User powerUser = userManager.getUser("admin");
+            JetspeedException pe = (JetspeedException) Subject.doAsPrivileged(powerUser.getSubject(), new PrivilegedAction()
+                {
+                    public Object run() 
+                    {
+                         try
+                        {
+//                           create user's home folder                        
+                             // deep copy from the default folder template tree, creating a deep-copy of the template
+                             // in the new user's folder tree
+                            Folder source = innerPageManager.getFolder(innerFolderTemplate);
+                            innerPageManager.deepCopyFolder(source, Folder.USER_FOLDER + innerUserName);
+                             
+                            return null;
+                        }
+                         catch (FolderNotFoundException e1) {
+                             return e1;
+                         } catch (InvalidFolderException e1){
+                             return e1;
+                         } catch (NodeException e1){
+                             return e1;
+                         } catch (PageNotUpdatedException e1) {
+                             return e1;
+                         } catch (JetspeedException e1) {
+                             return e1;
+                         }                     
+                    }
+                }, null);
+                
+            if(pe != null)
+            {
+                throw pe;
+            }
                         
-        } 
+        }
         catch (Exception e) 
         {
             throw new RegistrationException(e); 
@@ -242,28 +298,73 @@
      */
     public String generatePassword()
     {
-        // TODO: Find a replacement for Ostermiller's utility
-        // http://ostermiller.org/utils/RandPass.html
-        // almost screwed up and checked in a GPL licensed piece of code
-        // had to remove
-        return "secret";
+        RandomStrg rs = new RandomStrg();
+        
+        //TODO put in a more secure random number provider
+        //rs.setAlgorithm();   -- ideally call this for super security.  need rnd provider
+        
+        try
+        {
+            rs.generateRandomObject();
+        } catch (JspException e)
+        {
+            // this would only get thrown if we tried a secure random and the provider
+            // was not available.
+            e.printStackTrace();
+        }
+        rs.setLength(new Integer(12));
+        rs.setSingle(PASS_CHARS,PASS_CHARS.length);
+        ArrayList upper = new ArrayList();
+        ArrayList lower = new ArrayList();
+        //upper.add(new Character('A'));
+        //lower.add(new Character('B'));
+        rs.setRanges(upper,lower);
+        String retval = rs.getRandom();
+        
+        return retval;
     }
 
     /* (non-Javadoc)
      * @see org.apache.jetspeed.administration.PortalAdministration#sendPassword(java.lang.String)
      */
-    public void sendEmail(String emailAddress, 
+    public void sendEmail(PortletConfig  portletConfig,
+                          String emailAddress, 
                           String localizedSubject, 
                           String localizedTemplatePath,
                           Map userAttributes)                            
     throws AdministrationEmailException    
     {       
+        
+        String from = config.getString(PortalConfigurationConstants.EMAIL_SENDER);
+        String subject = localizedSubject;
+        String to = emailAddress;
+        String text = mergeEmailTemplate(portletConfig, userAttributes, "map", localizedTemplatePath);
+        sendEmail(from, subject, to, text);
+        
+    }
+    
+    /**
+     * @param from
+     * @param subject
+     * @param to
+     * @param text
+     * @throws AdministrationEmailException
+     */
+    public void sendEmail(String from, String subject, String to, String text) throws AdministrationEmailException
+    {
         SimpleMailMessage msg = new SimpleMailMessage();
-        msg.setFrom(config.getString(PortalConfigurationConstants.EMAIL_SENDER));
-        msg.setSubject(localizedSubject);
-        msg.setTo(emailAddress);
-        msg.setText(mergeEmailTemplate(userAttributes, "map", localizedTemplatePath));
-
+        if(from == null) 
+        {
+            from = "jetspeedAdministrator@bluesunrise.com";
+        }
+        msg.setFrom(from);
+        if(subject == null) 
+        {
+            subject = "message from jetspeed";
+        }
+        msg.setSubject(subject);
+        msg.setTo(to);
+        msg.setText(text);
         try
         {
             mailSender.send(msg);
@@ -271,34 +372,23 @@
         catch (MailException ex)
         {
             throw new AdministrationEmailException(
-                    "Failed to send forgotten password email to user with email address "
+                    "Failed to send forgotten password email to user with email address because "+ex.getMessage()
                             ); //+ user.getEmail());
         }
     }
     
-    public void sendEmail(String recipient,
-            String localizedSubject,
-            String message)
-    throws AdministrationEmailException
-    {
-        
-    }
-    
-    
-    public String mergeEmailTemplate(Map attributes, String attributesName, String template)
+    public String mergeEmailTemplate(PortletConfig  portletConfig, Map attributes, String attributesName, String template)
     throws AdministrationEmailException
     {
         VelocityContext context = new VelocityContext();
         context.put(attributesName, attributes);
-        
         StringWriter writer = new StringWriter();
-        final InputStream templateResource = this.getClass()
-                .getResourceAsStream(template);
-        Reader templateReader = new InputStreamReader(templateResource);
+        
         try
         {
-            velocityEngine.evaluate(context, writer, "UserEmailProcessor",
-                    templateReader);
+            String realTemplatePath = portletConfig.getPortletContext().getRealPath(template);
+            FileReader templateReader = new FileReader(realTemplatePath);
+            velocityEngine.evaluate(context, writer, "UserEmailProcessor", templateReader);
         } catch (Exception e)
         {
             throw new AdministrationEmailException(
@@ -316,7 +406,7 @@
     public User lookupUserFromEmail(String email)
         throws AdministrationEmailException    
     {
-        Collection result = preferences.lookupPreference("userinfo", "user.email", email);
+        Collection result = preferences.lookupPreference("userinfo", "user.business-info.online.email", email);
         if (result.size() == 0)
         {
             throw new AdministrationEmailException(USER_NOT_FOUND_FROM_EMAIL + email);

Added: portals/jetspeed-2/trunk/components/portal/src/test/org/apache/jetspeed/administration/TestPortalAdministrationImpl.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/components/portal/src/test/org/apache/jetspeed/administration/TestPortalAdministrationImpl.java?rev=349840&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/test/org/apache/jetspeed/administration/TestPortalAdministrationImpl.java (added)
+++ portals/jetspeed-2/trunk/components/portal/src/test/org/apache/jetspeed/administration/TestPortalAdministrationImpl.java Tue Nov 29 15:44:06 2005
@@ -0,0 +1,78 @@
+package org.apache.jetspeed.administration;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.jetspeed.aggregator.TestWorkerMonitor;
+
+
+public class TestPortalAdministrationImpl extends  TestCase
+
+{
+
+    
+    public static void main(String args[])
+    {
+        junit.awtui.TestRunner.main(new String[] { TestWorkerMonitor.class.getName()});
+    }
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        
+        
+        
+    }
+    
+    public static Test suite()
+    {
+        // All methods starting with "test" will be executed in the test suite.
+        return new TestSuite(TestPortalAdministrationImpl.class);
+    }
+
+    private static final int JOB_COUNT = 2;
+    
+    public void testPasswordGen() throws Exception
+    {
+        PortalAdministrationImpl pai = new PortalAdministrationImpl(null,null,null,null,null,null,null,null);
+        String newPassword = pai.generatePassword();
+        assertNotNull("new password was NULL!!!",newPassword);
+        assertTrue("password is not long enough",(newPassword.length() > 4) );
+        
+    }
+    
+    public void xtestSendEmail() throws Exception {
+        PortalAdministrationImpl pai = new PortalAdministrationImpl(null,null,null,null,null,null,null,null);
+        pai.sendEmail("chris@bluesunrise.com","this is a unittest","chris@bluesunrise.com","this is the content of the message");
+        
+    }
+    
+    // this needs too much init to test easily right now
+    public void xtestRegUser() throws Exception
+    {
+        PortalAdministrationImpl pai = new PortalAdministrationImpl(null,null,null,null,null,null,null,null);
+        String user = "user"+(Math.abs(new Date().getTime()));
+        String password = "password";
+        List emptyList = new ArrayList();
+        Map emptyMap = new HashMap();
+        Map userAttributes = new HashMap();
+        String emailTemplate = "";
+        pai.registerUser(user, 
+                password, 
+                emptyList, 
+                emptyList, 
+               userAttributes,              // note use of only PLT.D  values here.
+               emptyMap, 
+               emailTemplate);
+        
+    }
+    
+
+}

Modified: portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/administration/PortalAdministration.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/administration/PortalAdministration.java?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/administration/PortalAdministration.java (original)
+++ portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/administration/PortalAdministration.java Tue Nov 29 15:44:06 2005
@@ -18,6 +18,7 @@
 import java.util.List;
 import java.util.Map;
 
+import javax.portlet.PortletConfig;
 import org.apache.jetspeed.security.User;
 
 /**
@@ -82,7 +83,8 @@
      * @parm userAttributes map of user attributes
      * @throws AdministrationEmailException
      */
-    public void sendEmail(String emailAddress, 
+    public void sendEmail(PortletConfig portletConfig,
+                          String emailAddress, 
                           String localizedSubject, 
                           String templatePath,
                           Map userAttributes)

Modified: portals/jetspeed-2/trunk/jetspeed-components.xml
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/jetspeed-components.xml?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/jetspeed-components.xml (original)
+++ portals/jetspeed-2/trunk/jetspeed-components.xml Tue Nov 29 15:44:06 2005
@@ -23,7 +23,7 @@
 			<id>jetspeed-cm</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -33,7 +33,7 @@
 			<id>content-server</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -43,7 +43,7 @@
 			<id>jetspeed-components</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -53,7 +53,7 @@
 			<id>jetspeed-deploy-tools</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -63,7 +63,7 @@
 			<id>jetspeed-rdbms</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -73,7 +73,7 @@
 			<id>jetspeed-prefs</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -83,7 +83,7 @@
 			<id>jetspeed-search</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -93,7 +93,7 @@
 			<id>jetspeed-security</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -103,7 +103,7 @@
 			<id>jetspeed-registry</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -112,7 +112,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-id-generator</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -121,7 +121,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-file-cache</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -130,7 +130,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-api</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>false</war.bundle>
@@ -139,7 +139,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-commons</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>false</war.bundle>
@@ -148,7 +148,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-locator</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -157,7 +157,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-capability</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -166,7 +166,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-profiler</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -175,7 +175,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-page-manager</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -185,7 +185,7 @@
 			<id>jetspeed-portal-site</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -194,7 +194,7 @@
 		<dependency>
 			<id>jetspeed2:jetspeed-portlet-factory</id>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -204,7 +204,7 @@
 			<id>jetspeed-sso</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -214,7 +214,7 @@
 			<id>jetspeed-statistics</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -224,7 +224,7 @@
 			<id>jetspeed-header-resource</id>
 			<groupId>jetspeed2</groupId>
 			<version>
-				${jetspeed.version}
+				2.0-dev
 			</version>
 			<properties>
 	           <war.bundle>true</war.bundle>
@@ -253,7 +253,15 @@
 	           <war.bundle>true</war.bundle>
 	        </properties>
 		</dependency>
-		
+		<dependency>
+        	<id>taglibs:random</id>
+        	<version>1.0.2</version>
+        	<type>jar</type>
+        	<properties>
+            	<war.bundle>true</war.bundle>
+        	</properties>
+    	</dependency>
+        
 		<!-- Velocity dependencies -->
 		<dependency>
 			<id>velocity</id>
@@ -275,7 +283,7 @@
 		<dependency>
 			<id>portals-bridges:portals-bridges-common</id>
 			<version>
-				${portals.bridges.common.version}
+				0.4-dev
 			</version>
 			<properties>
 				<war.bundle>false</war.bundle>
@@ -285,7 +293,7 @@
 			<id>portals-bridges-velocity</id>
 			<groupId>portals-bridges</groupId>
 			<version>
-				${portals.bridges.velocity.version}
+				0.4-dev
 			</version>
 			<properties>
 				<war.bundle>true</war.bundle>

Modified: portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/administration.xml
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/administration.xml?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/administration.xml (original)
+++ portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/administration.xml Tue Nov 29 15:44:06 2005
@@ -17,7 +17,7 @@
 -->
 <beans>
   <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
-    <property name="host"><value>localhost</value></property>
+    <property name="host"><value>mail.pacbell.net</value></property>
     <property name="username"><value></value></property>
     <property name="password"><value></value></property>
   </bean>

Modified: portals/jetspeed-2/trunk/src/webapp/WEB-INF/pages/default-page.psml
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/src/webapp/WEB-INF/pages/default-page.psml?rev=349840&r1=349839&r2=349840&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/src/webapp/WEB-INF/pages/default-page.psml (original)
+++ portals/jetspeed-2/trunk/src/webapp/WEB-INF/pages/default-page.psml Tue Nov 29 15:44:06 2005
@@ -29,31 +29,40 @@
   <fragment id="dp-1" type="layout" name="jetspeed-layouts::VelocityTwoColumns">
     <fragment id="dp-3" type="portlet" name="j2-admin::LocaleSelector">
       <property layout="TwoColumns" name="row" value="0" />
-      <property layout="TwoColumns" name="column" value="0" />
+      <property layout="TwoColumns" name="column" value="1" />
     </fragment>                                
     <fragment id="dp-12" type="portlet" name="j2-admin::LoginPortlet">
-      <property layout="TwoColumns" name="row" value="0" />
+      <property layout="TwoColumns" name="row" value="1" />
+      <property layout="TwoColumns" name="column" value="1" />
+    </fragment>                                
+    <fragment id="dp-22" type="portlet" name="j2-admin::ForgottenPasswordPortlet">
+      <property layout="TwoColumns" name="row" value="2" />
       <property layout="TwoColumns" name="column" value="1" />
     </fragment>                                
+    <fragment id="dp-23" type="portlet" name="j2-admin::UserRegistrationPortlet">
+      <property layout="TwoColumns" name="row" value="3" />
+      <property layout="TwoColumns" name="column" value="1" />
+    </fragment>                                
+    
     <fragment id="dp-7" type="portlet" name="demo::PickANumberPortlet" >
       <property layout="TwoColumns" name="row" value="1" />
       <property layout="TwoColumns" name="column" value="0" />
     </fragment>        
     <fragment id="dp-16" type="portlet" name="demo::RoleSecurityTest">
-      <property layout="TwoColumns" name="row" value="1" />
-      <property layout="TwoColumns" name="column" value="1" />
+      <property layout="TwoColumns" name="row" value="2" />
+      <property layout="TwoColumns" name="column" value="0" />
     </fragment>
     <fragment id="dp-9" type="portlet" name="demo::IFramePortlet" decorator="gray-gradient-noborder">
-      <property layout="TwoColumns" name="row" value="2" />
+      <property layout="TwoColumns" name="row" value="3" />
       <property layout="TwoColumns" name="column" value="0" />
     </fragment>
     <fragment id="dp-17" type="portlet" name="demo::UserInfoTest">
-      <property layout="TwoColumns" name="row" value="2" />
-      <property layout="TwoColumns" name="column" value="1" />
+      <property layout="TwoColumns" name="row" value="4" />
+      <property layout="TwoColumns" name="column" value="0" />
     </fragment>
     <fragment id="dp-18" type="portlet" name="demo::BookmarkPortlet">
-      <property layout="TwoColumns" name="row" value="3" />
-      <property layout="TwoColumns" name="column" value="1" />
+      <property layout="TwoColumns" name="row" value="5" />
+      <property layout="TwoColumns" name="column" value="0" />
     </fragment>
   </fragment>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org