diff -Nru eucalyptus-2.0+bzr1241/debian/changelog eucalyptus-2.0+bzr1241/debian/changelog --- eucalyptus-2.0+bzr1241/debian/changelog 2010-09-28 21:13:25.000000000 +0100 +++ eucalyptus-2.0+bzr1241/debian/changelog 2010-12-09 17:46:21.000000000 +0000 @@ -1,3 +1,15 @@ +eucalyptus (2.0+bzr1241-0ubuntu4.1) maverick-security; urgency=low + + * SECURITY UPDATE: An unauthenticated user to the admin web interface, + could reset a user password, without email confirmation. (LP: #675372). + - debian/patches/26-confirm-password-change.patch: Enable email as an + additional stage confirmation, when a password reset request is made. + Patch courtesy of upstream Eucalyptus. + - debian/eucalyptus-cloud.postinst: Remove the server side web ui cache + and restart eucalyptus. + + -- Dave Walker (Daviey) Thu, 18 Nov 2010 17:11:48 +0000 + eucalyptus (2.0+bzr1241-0ubuntu4) maverick; urgency=low * debian/eucalyptus-java-common.postinst: On upgrades from Lucid/10.04, diff -Nru eucalyptus-2.0+bzr1241/debian/eucalyptus-cloud.postinst eucalyptus-2.0+bzr1241/debian/eucalyptus-cloud.postinst --- eucalyptus-2.0+bzr1241/debian/eucalyptus-cloud.postinst 2010-09-16 17:32:59.000000000 +0100 +++ eucalyptus-2.0+bzr1241/debian/eucalyptus-cloud.postinst 2010-12-09 17:44:30.000000000 +0000 @@ -43,6 +43,14 @@ EOF fi fi + + if dpkg --compare-versions "$2" lt 2.0+bzr1241-0ubuntu4.1 + then + initctl stop eucalyptus || true + rm -rf /var/run/eucalyptus/webapp + initctl start eucalyptus || true + fi + fi #DEBHELPER# diff -Nru eucalyptus-2.0+bzr1241/debian/patches/26-confirm-password-change.patch eucalyptus-2.0+bzr1241/debian/patches/26-confirm-password-change.patch --- eucalyptus-2.0+bzr1241/debian/patches/26-confirm-password-change.patch 1970-01-01 01:00:00.000000000 +0100 +++ eucalyptus-2.0+bzr1241/debian/patches/26-confirm-password-change.patch 2010-11-19 17:27:12.000000000 +0000 @@ -0,0 +1,3374 @@ +Description: This patch ensures the password recovery function confirms by email, rather than allowing unauthenticated users to be able to change it. +Origin: Provided by upstream, attached as a patch to the bug report. +Bug: https://launchpad.net/bugs/675372 +Last-Update: 2010-11-18 + +--- a/clc/.project ++++ b/clc/.project +@@ -1,6 +1,6 @@ + + +- main ++ 2.0.0 + + + +--- a/clc/modules/www/conf/eucalyptus-web-default.properties ++++ b/clc/modules/www/conf/eucalyptus-web-default.properties +@@ -23,6 +23,7 @@ + + cloud-name = Your Eucalyptus cloud + ++enable-signups = yes + signup-greeting = Please, fill out the form: + + # specify which (optional) fields are requested on the signup form +@@ -45,7 +46,7 @@ + + password-recovery-subject = request to reset your Eucalyptus password + +-password-recovery-message = You or someone pretending to be you made a request to reset the password on a Eucalyptus elastic cloud system. Disregard this message if resetting the password was not your intention, but if it was, click the following link to confirm the change of password: ++password-recovery-message = You or someone pretending to be you made a request to reset the password on a Eucalyptus elastic cloud system. Disregard this message if resetting the password was not your intention, but if it was, click the following link to change of password: + + thanks-for-signup = Thank you for signing up! Your request has been forwarded to the cloud administrator. If your application is approved, you will receive an email message (at the address you specified) with instructions for activating your account. + +--- a/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/client/EucalyptusWebInterface.java ++++ b/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/client/EucalyptusWebInterface.java +@@ -131,6 +131,7 @@ + private static String admin_first_time_config_text; + private static String admin_email_change_text; + private static String admin_cloud_ip_setup_text; ++ private static boolean enable_signups; + private static boolean request_telephone; + private static boolean request_project_leader; + private static boolean request_affiliation; +@@ -264,6 +265,7 @@ + } + + /* optional parameters (booleans will be 'yes' if not specified) */ ++ enable_signups = str2bool((String)props.get("enable-signups")); + request_telephone = str2bool((String)props.get("request-telephone")); + request_project_leader = str2bool((String)props.get("request-project-leader")); + request_affiliation = str2bool((String)props.get("request-affiliation")); +@@ -382,7 +384,7 @@ + ClickListener RecoverButtonListener = new ClickListener() { + public void onClick( Widget sender ) + { +- displayPasswordRecoveryPage(); ++ displayInitiatePasswordRecoveryPage(); + } + }; + +@@ -419,8 +421,10 @@ + + HorizontalPanel hpanel = new HorizontalPanel(); + hpanel.setSpacing(2); +- hpanel.add( signup_button ); +- hpanel.add( new HTML(" " + MSG.forAccount() + "  |  ") ); ++ if (enable_signups) { ++ hpanel.add( signup_button ); ++ hpanel.add( new HTML(" " + MSG.forAccount() + "  |  ") ); ++ } + hpanel.add( recover_button ); + hpanel.add( new HTML(" " + MSG.thePassword()) ); + +@@ -873,23 +877,136 @@ + parent.add( wrapper ); + } + +- public void displayPasswordRecoveryPage() ++ public void displayInitiatePasswordRecoveryPage() + { +- label_box.setText ("Please, choose the new password"); ++ label_box.setText ("Enter the following to reset your password"); + label_box.setStyleName("euca-greeting-normal"); + +- final Grid g1 = new Grid ( 3, 3 ); ++ final Grid g1 = new Grid ( 2, 3 ); // rows, cols + g1.getColumnFormatter().setWidth(0, "230"); + g1.getColumnFormatter().setWidth(1, "180"); + g1.getColumnFormatter().setWidth(2, "180"); + int i = 0; + +- final int usernameOrEmail_row = i; +- g1.setWidget( i, 0, new Label( "Username OR email address:" ) ); ++ final int username_row = i; ++ g1.setWidget( i, 0, new Label( "Username:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox username_box = new TextBox(); ++ username_box.setWidth("180"); ++ g1.setWidget( i++, 1, username_box ); ++ ++ final int email_row = i; ++ g1.setWidget( i, 0, new Label( "Email address:" ) ); + g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); +- final TextBox usernameOrEmail_box = new TextBox(); +- usernameOrEmail_box.setWidth("180"); +- g1.setWidget( i++, 1, usernameOrEmail_box ); ++ final TextBox email_box = new TextBox(); ++ email_box.setWidth("180"); ++ g1.setWidget( i++, 1, email_box ); ++ ++ ClickListener RecoverButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ boolean formOk = true; ++ ++ for ( int j = 0; j < 2; j++ ) ++ { ++ g1.clearCell( j, 2 ); // clear previous right-hand-side annotations ++ } ++ ++ // perform checks ++ if ( username_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Username is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( username_row, 2, l); ++ formOk = false; ++ } ++ if ( username_box.getText().matches(".*[ \t]+.*") ) { ++ Label l = new Label ("Username cannot have spaces, sorry!"); ++ l.setStyleName ("euca-error-hint"); ++ g1.setWidget (username_row, 2, l); ++ formOk = false; ++ } ++ if ( ! email_box.getText().contains("@") ) ++ { ++ Label l = new Label( "Valid email is mandatory!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( email_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( formOk ) ++ { ++ label_box.setText( "Checking with the server..." ); ++ label_box.setStyleName("euca-greeting-pending"); ++ ++ UserInfoWeb user = new UserInfoWeb( ++ username_box.getText(), ++ "", // don't care about real name ++ email_box.getText(), ++ null ); // null => reset requested ++ EucalyptusWebBackend.App.getInstance().recoverPassword( ++ user, ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ displayDialog( "Thank you!", ( String ) result ); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ String m = caught.getMessage(); ++ displayErrorPage(m); ++ } ++ } ++ ); ++ ++ } ++ else ++ { ++ label_box.setText( "Please, fix the errors and resubmit:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ }; ++ ++ Button submit_button = new Button ( "Recover Password", RecoverButtonListener ); ++ Button cancel_button = new Button ( "Cancel", DefaultPageButtonListener ); ++ VerticalPanel mpanel = new VerticalPanel(); ++ mpanel.add( g1 ); ++ ++ HorizontalPanel bpanel = new HorizontalPanel(); ++ bpanel.add( submit_button ); ++ bpanel.add( new HTML( "  or  " ) ); ++ bpanel.add( cancel_button ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ vpanel.add (label_box); ++ vpanel.add (mpanel); ++ vpanel.add (bpanel); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( wrapper ); ++ } ++ ++ public void displayCompletePasswordRecoveryPage(final String code) ++ { ++ label_box.setText ("Please, choose the new password"); ++ label_box.setStyleName("euca-greeting-normal"); ++ ++ final Grid g1 = new Grid ( 2, 3 ); // rows, cols ++ g1.getColumnFormatter().setWidth(0, "230"); ++ g1.getColumnFormatter().setWidth(1, "180"); ++ g1.getColumnFormatter().setWidth(2, "180"); ++ int i = 0; + + final int password1_row = i; + g1.setWidget( i, 0, new Label( "New password:" ) ); +@@ -910,26 +1027,10 @@ + { + boolean formOk = true; + +- for ( int j = 0; j < 3; j++ ) +- { +- g1.clearCell( j, 2 ); /* clear previous right-hand-side annotations */ +- } +- +- /* perform checks */ +- if ( usernameOrEmail_box.getText().length() < 1 ) ++ for ( int j = 0; j < 2; j++ ) + { +- Label l = new Label( "Username is empty!" ); +- l.setStyleName("euca-error-hint"); +- g1.setWidget( usernameOrEmail_row, 2, l); +- formOk = false; ++ g1.clearCell( j, 2 ); // clear previous right-hand-side annotations + } +- /* no spaces in username */ +- if ( usernameOrEmail_box.getText().matches(".*[ \t]+.*") ) { +- Label l = new Label ("Username cannot have spaces, sorry!"); +- l.setStyleName ("euca-error-hint"); +- g1.setWidget (usernameOrEmail_row, 2, l); +- formOk = false; +- } + + if ( cleartextPassword1_box.getText().length() < minPasswordLength ) + { +@@ -945,24 +1046,15 @@ + g1.setWidget( password2_row, 2, l ); + formOk = false; + } +- if ( cleartextPassword1_box.getText().toLowerCase().matches(".*" + +- usernameOrEmail_box.getText().toLowerCase() + ".*")) { +- Label l = new Label ( "Password may not contain the username!"); +- l.setStyleName("euca-error-hint"); +- g1.setWidget( password1_row, 2, l ); +- formOk = false; +- } + + if ( formOk ) + { + label_box.setText( "Checking with the server..." ); + label_box.setStyleName("euca-greeting-pending"); + +- UserInfoWeb user = new UserInfoWeb( +- usernameOrEmail_box.getText(), +- "", /* don't care about the name */ +- usernameOrEmail_box.getText(), /* same as login */ +- GWTUtils.md5(cleartextPassword1_box.getText()) ); ++ UserInfoWeb user = new UserInfoWeb(); ++ user.setConfirmationCode(code); ++ user.setPassword(GWTUtils.md5(cleartextPassword1_box.getText())); + EucalyptusWebBackend.App.getInstance().recoverPassword( + user, + new AsyncCallback() { +@@ -988,7 +1080,7 @@ + } + }; + +- Button submit_button = new Button ( "Recover Password", RecoverButtonListener ); ++ Button submit_button = new Button ( "Change Password", RecoverButtonListener ); + Button cancel_button = new Button ( "Cancel", DefaultPageButtonListener ); + VerticalPanel mpanel = new VerticalPanel(); + mpanel.add( g1 ); +@@ -1182,14 +1274,18 @@ + else if ( action.equals( "confirm" ) + || action.equals ("recover") ) + { +- String confirmationCode = ( String ) urlParams.get( "code" ); +- if ( confirmationCode == null ) ++ String code = ( String ) urlParams.get( "code" ); ++ if ( code == null ) + { + displayErrorPage( "Confirmation code not specified" ); + } + else + { +- attemptAction( action, confirmationCode ); ++ if (action.equals( "confirm" )) { ++ attemptAction( action, code ); ++ } else if (action.equals( "recover")) { ++ displayCompletePasswordRecoveryPage(code); ++ } + } + } + else +@@ -1217,7 +1313,7 @@ + if (loggedInUser!=null) { + if ( loggedInUser.isAdministrator().booleanValue() ) + { +- if (loggedInUser.getEmail().equalsIgnoreCase( "" ) ) { ++ if (loggedInUser.getEmail().equalsIgnoreCase( UserInfoWeb.BOGUS_ENTRY ) ) { + displayFirstTimeConfiguration(); + } else { + displayBarAndTabs(message); +@@ -1964,7 +2060,7 @@ + } + public void onFailure( Throwable caught ) + { +- loggedInUser.setEmail( "" ); ++ loggedInUser.setEmail( UserInfoWeb.BOGUS_ENTRY ); + displayLoginErrorPage( caught.getMessage() ); + } + }); +@@ -2773,7 +2869,7 @@ + } + public void onFailure( Throwable caught ) + { +- loggedInUser.setEmail( "" ); ++ loggedInUser.setEmail( UserInfoWeb.BOGUS_ENTRY ); + String m = caught.getMessage(); + label_box.setText( m ); + label_box.setStyleName("euca-greeting-warning"); +--- /dev/null ++++ b/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/client/EucalyptusWebInterface.java.orig +@@ -0,0 +1,2817 @@ ++/******************************************************************************* ++*Copyright (c) 2009 Eucalyptus Systems, Inc. ++* ++* This program is free software: you can redistribute it and/or modify ++* it under the terms of the GNU General Public License as published by ++* the Free Software Foundation, only version 3 of the License. ++* ++* ++* This file is distributed in the hope that it will be useful, but WITHOUT ++* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++* for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program. If not, see . ++* ++* Please contact Eucalyptus Systems, Inc., 130 Castilian ++* Dr., Goleta, CA 93101 USA or visit ++* if you need additional information or have any questions. ++* ++* This file may incorporate work covered under the following copyright and ++* permission notice: ++* ++* Software License Agreement (BSD License) ++* ++* Copyright (c) 2008, Regents of the University of California ++* All rights reserved. ++* ++* Redistribution and use of this software in source and binary forms, with ++* or without modification, are permitted provided that the following ++* conditions are met: ++* ++* Redistributions of source code must retain the above copyright notice, ++* this list of conditions and the following disclaimer. ++* ++* Redistributions in binary form must reproduce the above copyright ++* notice, this list of conditions and the following disclaimer in the ++* documentation and/or other materials provided with the distribution. ++* ++* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER ++* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF ++* THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE ++* LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS ++* SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING ++* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA ++* BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN ++* THE REGENTS’ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT ++* OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR ++* WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH ++* ANY SUCH LICENSES OR RIGHTS. ++*******************************************************************************/ ++/* ++ * Author: Dmitrii Zagorodnov dmitrii@cs.ucsb.edu ++ */ ++ ++package edu.ucsb.eucalyptus.admin.client; ++ ++import com.google.gwt.core.client.EntryPoint; ++import com.google.gwt.core.client.GWT; ++import com.google.gwt.http.client.URL; ++import com.google.gwt.user.client.Cookies; ++import com.google.gwt.user.client.History; ++import com.google.gwt.user.client.Window; ++import com.google.gwt.user.client.rpc.AsyncCallback; ++import com.google.gwt.user.client.ui.*; ++import com.google.gwt.event.dom.client.ClickHandler; ++import com.google.gwt.event.dom.client.ClickEvent; ++import edu.ucsb.eucalyptus.admin.client.extensions.store.ImageStoreClient; ++import edu.ucsb.eucalyptus.admin.client.extensions.store.ImageStoreWidget; ++import edu.ucsb.eucalyptus.admin.client.extensions.store.FrameWidget; ++import java.util.Date; ++import java.util.HashMap; ++import java.util.List; ++ ++/******************************************************************************* ++ * Copyright (c) 2009 Eucalyptus Systems, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, only version 3 of the License. ++ * ++ * ++ * This file is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program. If not, see . ++ * ++ * Please contact Eucalyptus Systems, Inc., 130 Castilian ++ * Dr., Goleta, CA 93101 USA or visit ++ * if you need additional information or have any questions. ++ * ++ * This file may incorporate work covered under the following copyright and ++ * permission notice: ++ * ++ * SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING ++ * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA ++ * BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN ++ * THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT ++ * OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR ++ * WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH ++ * ANY SUCH LICENSES OR RIGHTS. ++ ******************************************************************************/ ++ ++public class EucalyptusWebInterface implements EntryPoint { ++ ++ private static final AppMessages MSG = (AppMessages) GWT.create(AppMessages.class); ++ ++ private static String cookie_name = "eucalyptus-session-id"; ++ private static int minPasswordLength = 5; /* TODO: put into config? */ ++ ++ /* configuration parameters to be set from the server */ ++ private static Boolean server_ready = new Boolean(false); ++ private static String signup_greeting; ++ private static String version; ++ private static String cloud_name; ++ private static String certificate_download_text; ++ private static String rest_credentials_text; ++ private static String user_account_text; ++ private static String admin_first_time_config_text; ++ private static String admin_email_change_text; ++ private static String admin_cloud_ip_setup_text; ++ private static boolean request_telephone; ++ private static boolean request_project_leader; ++ private static boolean request_affiliation; ++ private static boolean request_project_description; ++ private static boolean show_cloud_registration; ++ private static String cloud_registration_text; ++ private static Image logo = null; ++ private static Image textless_logo = null; ++ private static String rightscale_base_url = null; ++ private static String rightscaleUrl = null; ++ private static String extensions = null; ++ ++ /* global variables */ ++ private static HashMap props; ++ private static HashMap urlParams; ++ private static String sessionId; ++ private static String currentAction; ++ private static UserInfoWeb loggedInUser; ++ private static CloudInfoWeb cloudInfo; ++ private static TabBar allTabs; ++ private static int currentTabIndex = 0; ++ private static int credsTabIndex = -1; ++ private static int imgTabIndex = -1; ++ private static int usrTabIndex = -1; ++ private static int confTabIndex = -1; ++ private static int downTabIndex = -1; ++ private static int storeTabIndex = -1; ++ private static int servicesTabIndex = -1; ++ private static boolean sortUsersLastFirst = true; ++ ++ /* UI selections remembered for future use */ ++ private static boolean previousSkipConfirmation = false; // do not skip email confirmation by default ++ ++ /* globally visible UI widgets */ ++ private Label label_box = new Label(); ++ private CheckBox check_box = new CheckBox("", false); ++ private Label remember_label = new Label(MSG.rememberMe()); ++ private static Label statusMessage = new Label(); ++ ++ public void onModuleLoad() ++ { ++ sessionId = Cookies.getCookie( cookie_name ); ++ urlParams = GWTUtils.parseParamString( GWTUtils.getParamString() ); ++ ++ /* if specified, 'page' will tell us which tab to select */ ++ String page = ( String ) urlParams.get( "page" ); ++ if (page!=null) { currentTabIndex = Integer.parseInt(page); } ++ ++ currentAction = ( String ) urlParams.get( "action" ); ++ ++ displayStatusPage("Loading data from server..."); ++ EucalyptusWebBackend.App.getInstance().getProperties( ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ props = ( HashMap ) result; ++ try { ++ load_props(); /* verify properties */ ++ ++ /* these don't need sessions */ ++ if ( currentAction!=null && (currentAction.equals ("confirm") ++ || currentAction.equals ("recover")) ) { ++ executeAction( currentAction ); ++ ++ } else { ++ /* if we have don't have sessionId saved in a cookie */ ++ if ( sessionId == null ) ++ { ++ displayLoginPage(); ++ } ++ else /* we have a cookie - try using it */ ++ { ++ check_box.setChecked(true); ++ attemptLogin(); ++ } ++ } ++ } catch (Exception e) { ++ displayErrorPageFinal ("Internal error (1): " + e.getMessage()); ++ } ++ } ++ public void onFailure( Throwable caught ) ++ { ++ displayErrorPageFinal ("Internal error (2): " + caught.getMessage()); ++ } ++ } ++ ); ++ } ++ ++ void load_props() throws Exception ++ { ++ if (props == null) { ++ throw new Exception("Invalid server configuration"); ++ } ++ version = (String)props.get("version"); ++ cloud_name = (String)props.get("cloud-name"); ++ signup_greeting = (String)props.get("signup-greeting"); ++ certificate_download_text = (String)props.get("certificate-download-text"); ++ rest_credentials_text = (String)props.get("rest-credentials-text"); ++ user_account_text = (String)props.get("user-account-text"); ++ admin_first_time_config_text = (String)props.get("admin-first-time-config-text"); ++ admin_email_change_text = (String)props.get("admin-email-change-text"); ++ admin_cloud_ip_setup_text = (String)props.get("admin-cloud-ip-setup-text"); ++ server_ready = (Boolean)props.get("ready"); ++ ++ if (server_ready==null) { ++ throw new Exception("Internal server error (cannot determine server readiness)"); ++ } ++ if (cloud_name==null) { ++ throw new Exception("Server configuration is missing 'cloud-name' value"); ++ } ++ if (signup_greeting==null) { ++ throw new Exception("Server configuration is missing 'signup-greeting' value"); ++ } ++ if (certificate_download_text==null) { ++ throw new Exception("Server configuration is missing 'certificate-dowload-text' value"); ++ } ++ if (rest_credentials_text==null) { ++ throw new Exception("Server configuration is missing 'rest-credentials-text' value"); ++ } ++ if (user_account_text==null) { ++ throw new Exception("Server configuration is missing 'user-account-text' value"); ++ } ++ if (admin_first_time_config_text==null) { ++ throw new Exception("Server configuration is missing 'admin-first-time-config-text' value"); ++ } ++ if (admin_email_change_text==null) { ++ throw new Exception("Server configuration is missing 'admin-email-change-text' value"); ++ } ++ if (admin_cloud_ip_setup_text==null) { ++ throw new Exception("Server configuration is missing 'admin-cloud-ip-setup-text' value"); ++ } ++ ++ /* optional parameters (booleans will be 'yes' if not specified) */ ++ request_telephone = str2bool((String)props.get("request-telephone")); ++ request_project_leader = str2bool((String)props.get("request-project-leader")); ++ request_affiliation = str2bool((String)props.get("request-affiliation")); ++ request_project_description = str2bool((String)props.get("request-project-description")); ++ String file = (String)props.get("logo-file"); ++ if (file!=null) { ++ logo = new Image(file); ++ } ++ file = (String)props.get("logo-textless-file"); ++ if (file!=null) { ++ textless_logo = new Image(file); ++ } ++ ++ show_cloud_registration = str2bool((String)props.get("show-cloud-registration")); ++ cloud_registration_text = (String)props.get("cloud-registration-text"); ++ rightscale_base_url = (String)props.get("rightscale-registration-base-url"); ++ if (cloud_registration_text==null || rightscale_base_url==null) { ++ show_cloud_registration = false; ++ } ++ extensions = (String)props.get("extensions"); ++ ++ } ++ ++ private boolean str2bool(String s) ++ { ++ if (s==null) { ++ return true; ++ } ++ if (s.equalsIgnoreCase("no") ++ || s.equalsIgnoreCase("n") ++ || s.equalsIgnoreCase("0")) { ++ return false; ++ } else { ++ return true; ++ } ++ } ++ ++ public void displayLoginPage() ++ { ++ if ( currentAction == null ) { ++ displayLoginPage(MSG.pleaseSignIn() + ":"); ++ } else { ++ if ( currentAction.equals( "approve" ) ++ || currentAction.equals( "reject" ) ++ || currentAction.equals( "disable" ) ++ || currentAction.equals( "delete" )) { ++ displayLoginPage("Please, log into Eucalyptus to " + currentAction + " the user"); ++ ++ } else if ( currentAction.equals( "delete_image")) { ++ displayLoginPage("Please, log into Eucalyptus to delete the image"); ++ ++ } else if ( currentAction.equals( "confirm" ) ) { ++ displayLoginPage("Please, log into Eucalyptus to confirm your acccount"); ++ ++ } else { /* unknown action - will be caught upon login */ ++ displayLoginPage(MSG.pleaseSignIn() + ":"); ++ } ++ label_box.setStyleName ("euca-greeting-warning"); /* highlight the message */ ++ } ++ } ++ ++ public void displayLoginPage(String greeting) ++ { ++ History.newItem("login"); ++ label_box.setText( greeting ); ++ label_box.setStyleName("euca-greeting-normal"); ++ final TextBox login_box = new TextBox(); ++ login_box.setFocus(true); // this box gets focus first ++ final PasswordTextBox pass_box = new PasswordTextBox(); ++ ++ ClickListener LoginButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ /* perform checks */ ++ if ( login_box.getText().length() < 1 ) ++ { ++ displayLoginErrorPage("Username is empty!"); ++ return; ++ } ++ if ( pass_box.getText().length() < 1 ) ++ { ++ displayLoginErrorPage("Password is empty!"); ++ return; ++ } ++ ++ label_box.setText("Contacting the server..."); ++ label_box.setStyleName("euca-greeting-pending"); ++ EucalyptusWebBackend.App.getInstance().getNewSessionID( ++ login_box.getText(), ++ GWTUtils.md5(pass_box.getText()), ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ sessionId = ( String ) result; ++ long expiresMs = System.currentTimeMillis() + (7 * 24 * 60 * 60 * 1000); /* week */ ++ Date expires = new Date(expiresMs); ++ if (check_box.isChecked()) { ++ Cookies.setCookie( cookie_name, sessionId, expires); ++ } else { ++ /* this cookie should expire at the end of the session */ ++ /* TODO: does this work right in all browsers? */ ++ Cookies.setCookie( cookie_name, sessionId, new Date(0)); ++ } ++ attemptLogin(); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ displayLoginErrorPage((String)caught.getMessage()); ++ } ++ } ++ ); ++ } ++ }; ++ ++ ClickListener RecoverButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ displayPasswordRecoveryPage(); ++ } ++ }; ++ ++ Button submit_button = new Button( MSG.signInButton(), LoginButtonListener ); ++ Hyperlink signup_button = new Hyperlink( MSG.applyButton(), "apply" ); ++ signup_button.addClickListener( AddUserButtonListener ); ++ Hyperlink recover_button = new Hyperlink( MSG.recoverButton(), "recover" ); ++ recover_button.addClickListener( RecoverButtonListener ); ++ remember_label.setStyleName("euca-remember-text"); ++ ++ /* enable login by pressing Enter */ ++ EucalyptusKeyboardListener sl = new EucalyptusKeyboardListener(submit_button); ++ submit_button.addKeyboardListener(sl); ++ login_box.addKeyboardListener(sl); ++ pass_box.addKeyboardListener(sl); ++ ++ Grid g = new Grid( 4, 2 ); ++ g.setCellSpacing(4); ++ g.setWidget(0, 0, new Label(MSG.usernameField()+":")); ++ g.getCellFormatter().setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ g.setWidget(1, 0, new Label(MSG.passwordField()+":")); ++ g.getCellFormatter().setHorizontalAlignment(1, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ g.setWidget(0, 1, login_box ); ++ g.setWidget(1, 1, pass_box ); ++ g.setWidget(2, 0, check_box); ++ g.getCellFormatter().setHorizontalAlignment(2, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ g.setWidget(2, 1, remember_label); ++ g.setWidget(3, 1, submit_button); ++ VerticalPanel panel = new VerticalPanel(); ++ panel.add (g); ++ panel.setStyleName("euca-login-panel"); ++ panel.setCellHorizontalAlignment(g, HasHorizontalAlignment.ALIGN_CENTER); ++ panel.setCellVerticalAlignment(g, HasVerticalAlignment.ALIGN_MIDDLE); ++ ++ HorizontalPanel hpanel = new HorizontalPanel(); ++ hpanel.setSpacing(2); ++ hpanel.add( signup_button ); ++ hpanel.add( new HTML(" " + MSG.forAccount() + "  |  ") ); ++ hpanel.add( recover_button ); ++ hpanel.add( new HTML(" " + MSG.thePassword()) ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ if (version!=null) { ++ Label version_label = new Label ("Version " + version); ++ version_label.setStyleName ("euca-small-text"); ++ vpanel.add (version_label); ++ } ++ vpanel.add (label_box); ++ vpanel.add (panel); ++ if (server_ready.booleanValue()) { ++ vpanel.add (hpanel); ++ } ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( wrapper ); ++ } ++ ++ public void displayLoginErrorPage ( String message ) ++ { ++ if (message.equals("Earlier session not found") || ++ message.equals("Earlier session expired")) { ++ displayLoginPage(); ++ } else { ++ displayLoginPage("Error: " + message); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ ++ /* this handles sign-ups, adding of users by admin, and editing of users */ ++ public void displayUserRecordPage( Panel parent, UserInfoWeb userToEdit) ++ { ++ final String oldPassword; ++ final boolean admin; ++ final boolean newUser; ++ final boolean showSkipConfirmed; ++ boolean isAdminChecked = false; // not admin by default ++ boolean skipConfirmationChecked = previousSkipConfirmation; ++ ++ if (loggedInUser != null ++ && loggedInUser.isAdministrator()) { ++ admin = true; ++ } else { ++ admin = false; ++ } ++ if (userToEdit==null) { ++ newUser = true; ++ showSkipConfirmed = true; ++ userToEdit = new UserInfoWeb(); ++ oldPassword = ""; ++ if ( admin ) { ++ label_box.setText ("Please, fill out the form to add a user"); ++ } else { ++ label_box.setText ( signup_greeting ); // Please, fill out the form: ++ } ++ } else { ++ newUser = false; ++ oldPassword = userToEdit.getPassword(); ++ isAdminChecked = userToEdit.isAdministrator(); ++ showSkipConfirmed = !userToEdit.isConfirmed(); ++ skipConfirmationChecked = userToEdit.isConfirmed(); ++ ++ String status; ++ if (!userToEdit.isApproved()) { ++ status = "unapproved"; ++ } else if (!userToEdit.isEnabled()) { ++ status = "disabled"; ++ } else if (!userToEdit.isConfirmed()) { ++ status = "unconfirmed"; ++ } else { ++ status = "active"; ++ } ++ if (userToEdit.isAdministrator()) { ++ status += " & admin"; ++ } ++ label_box.setText ("Editing information for user '" + userToEdit.getUserName() +"' (" + status + ")" ); ++ } ++ label_box.setStyleName("euca-greeting-normal"); ++ ++ int rowsMandatory = 5; ++ if (admin) { ++ rowsMandatory++; // for admin checkbox ++ if (showSkipConfirmed) { ++ rowsMandatory++; // for skip confirmation checkbox ++ } ++ } ++ final Grid g1 = new Grid ( rowsMandatory, 3 ); ++ g1.getColumnFormatter().setWidth(0, "180"); ++ g1.getColumnFormatter().setWidth(1, "180"); ++ g1.getColumnFormatter().setWidth(2, "180"); ++ int i = 0; ++ ++ final Label label_mandatory = new Label( "Mandatory fields:" ); ++ label_mandatory.setStyleName("euca-section-header"); ++ ++ final int userName_row = i; ++ g1.setWidget( i, 0, new Label( "Username:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox userName_box = new TextBox(); ++ userName_box.setText (userToEdit.getUserName()); ++ userName_box.setWidth("180"); ++ if ( ! newUser ) { ++ userName_box.setEnabled (false); ++ } ++ g1.setWidget( i++, 1, userName_box ); ++ ++ // optional row ++ final CheckBox userIsAdmin = new CheckBox("Administrator"); ++ userIsAdmin.setChecked(isAdminChecked); ++ userIsAdmin.setStyleName("euca-remember-text"); ++ if (admin) { ++ g1.setWidget ( i++, 1, userIsAdmin); ++ } ++ ++ final int password1_row = i; ++ g1.setWidget( i, 0, new Label( "Password:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox cleartextPassword1_box = new PasswordTextBox(); ++ cleartextPassword1_box.setText (userToEdit.getPassword()); ++ cleartextPassword1_box.setWidth ("180"); ++ if ( (! admin && ! newUser ) || userToEdit.isAdministrator().booleanValue()) { ++ cleartextPassword1_box.setEnabled (false); ++ } ++ g1.setWidget( i++, 1, cleartextPassword1_box ); ++ ++ final int password2_row = i; ++ g1.setWidget( i, 0, new Label( "Password, again:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox cleartextPassword2_box = new PasswordTextBox(); ++ cleartextPassword2_box.setText (userToEdit.getPassword()); ++ cleartextPassword2_box.setWidth("180"); ++ if ( ( ! admin && ! newUser ) || userToEdit.isAdministrator().booleanValue()) { ++ cleartextPassword2_box.setEnabled (false); ++ } ++ g1.setWidget( i++, 1, cleartextPassword2_box ); ++ ++ final int realName_row = i; ++ g1.setWidget( i, 0, new Label( "Full Name:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox realName_box = new TextBox(); ++ realName_box.setText (userToEdit.getRealName()); ++ realName_box.setWidth("180"); ++ g1.setWidget( i++, 1, realName_box ); ++ ++ final int emailAddress_row = i; ++ g1.setWidget( i, 0, new Label( "Email address:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox emailAddress_box = new TextBox(); ++ emailAddress_box.setText (userToEdit.getEmail()); ++ emailAddress_box.setWidth("180"); ++ g1.setWidget( i++, 1, emailAddress_box ); ++ ++ // optional row ++ final CheckBox skipConfirmation = new CheckBox("Skip email confirmation"); ++ skipConfirmation.setChecked(skipConfirmationChecked); ++ skipConfirmation.setStyleName("euca-remember-text"); ++ if (admin && showSkipConfirmed) { ++ g1.setWidget ( i++, 1, skipConfirmation); ++ } ++ ++ /* these widgets are allocated, but not necessarily used */ ++ final Grid g2 = new Grid(); ++ final Label label_optional = new Label( "Optional fields:" ); ++ label_optional.setStyleName("euca-section-header"); ++ final TextBox telephoneNumber_box = new TextBox(); ++ final TextBox projectPIName_box = new TextBox(); ++ final TextBox affiliation_box = new TextBox(); ++ final TextArea projectDescription_box = new TextArea(); ++ ++ int extra_fields = 0; ++ if (request_telephone) { extra_fields++; } ++ if (request_project_leader) { extra_fields++; } ++ if (request_affiliation) { extra_fields++; } ++ if (request_project_description) { extra_fields++; } ++ ++ if (extra_fields > 0) { ++ g2.resize(extra_fields, 2); ++ g2.getColumnFormatter().setWidth(0, "180"); ++ g2.getColumnFormatter().setWidth(1, "360"); ++ i = 0; ++ ++ if (request_telephone) { ++ g2.setWidget( i, 0, new Label( "Telephone Number:" )); ++ g2.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ telephoneNumber_box.setWidth("180"); ++ telephoneNumber_box.setText (userToEdit.getTelephoneNumber()); ++ g2.setWidget( i++, 1, telephoneNumber_box ); ++ } ++ ++ if (request_project_leader) { ++ g2.setWidget( i, 0, new Label( "Project Leader:" ) ); ++ g2.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ projectPIName_box.setText (userToEdit.getProjectPIName()); ++ projectPIName_box.setWidth("180"); ++ g2.setWidget( i++, 1, projectPIName_box ); ++ } ++ ++ if (request_affiliation) { ++ g2.setWidget( i, 0, new Label( "Affiliation:" ) ); ++ g2.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ affiliation_box.setText (userToEdit.getAffiliation()); ++ affiliation_box.setWidth("360"); ++ g2.setWidget( i++, 1, affiliation_box ); ++ } ++ ++ if (request_project_description) { ++ g2.setWidget( i, 0, new Label( "Project Description:" ) ); ++ g2.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ projectDescription_box.setText (userToEdit.getProjectDescription()); ++ projectDescription_box.setWidth("360"); ++ projectDescription_box.setHeight("50"); ++ g2.setWidget( i++, 1, projectDescription_box ); ++ } ++ } ++ ++ ClickListener SignupButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ boolean formOk = true; ++ ++ for ( int j = 0; j < 4; j++ ) ++ { ++ g1.clearCell( j, 2 ); /* clear previous right-hand-side annotations */ ++ } ++ ++ // perform checks ++ if ( userName_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Username is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( userName_row, 2, l); ++ formOk = false; ++ } else { ++ // do this in the else-clause so the empty username doesn't match here ++ if ( cleartextPassword1_box.getText().toLowerCase().matches(".*" + ++ userName_box.getText().toLowerCase() + ".*")) { ++ Label l = new Label ( "Password may not contain the username!"); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password1_row, 2, l ); ++ formOk = false; ++ } ++ } ++ ++ if ( userName_box.getText().matches(".*[^\\w\\-\\.@]+.*") ) { ++ Label l = new Label ("Invalid characters in the username!"); ++ l.setStyleName ("euca-error-hint"); ++ g1.setWidget (userName_row, 2, l); ++ formOk = false; ++ } ++ ++ if ( userName_box.getText().length() > 30) ++ { ++ Label l = new Label( "Username is too long, sorry!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( userName_row, 2, l); ++ formOk = false; ++ } ++ ++ if ( cleartextPassword1_box.getText().length() < minPasswordLength ) ++ { ++ Label l = new Label( "Password must be at least " + minPasswordLength + " characters long!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password1_row, 2, l ); ++ formOk = false; ++ } ++ if ( !cleartextPassword1_box.getText().equals( cleartextPassword2_box.getText() ) ) ++ { ++ Label l = new Label( "Passwords do not match!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password2_row, 2, l ); ++ formOk = false; ++ } ++ if ( realName_box.getText().equalsIgnoreCase(cleartextPassword1_box.getText()) ++ || userName_box.getText().equalsIgnoreCase(cleartextPassword1_box.getText())) { ++ Label l = new Label ( "Password may not be your name or username!"); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password1_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( realName_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Name is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( realName_row, 2, l ); ++ formOk = false; ++ } ++ if ( emailAddress_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Email address is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( emailAddress_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( formOk ) ++ { ++ label_box.setText( "Checking with the server..." ); ++ label_box.setStyleName("euca-greeting-pending"); ++ String enteredPassword = cleartextPassword1_box.getText(); ++ String encryptedPassword = GWTUtils.md5(enteredPassword); ++ if ( enteredPassword.equals(oldPassword)) { ++ encryptedPassword = enteredPassword; // it was not changed in the edit ++ } ++ final UserInfoWeb userToSave = new UserInfoWeb( ++ userName_box.getText(), ++ realName_box.getText(), ++ emailAddress_box.getText(), ++ encryptedPassword); ++ if ( admin ) { ++ userToSave.setAdministrator( userIsAdmin.isChecked()); ++ if ( showSkipConfirmed ) { ++ previousSkipConfirmation = skipConfirmation.isChecked(); // remember value for the future ++ userToSave.setConfirmed(previousSkipConfirmation); ++ } ++ } ++ if ( telephoneNumber_box.getText().length() > 0 ) ++ { ++ userToSave.setTelephoneNumber( telephoneNumber_box.getText() ); ++ } ++ if ( affiliation_box.getText().length() > 0 ) ++ { ++ userToSave.setAffiliation( affiliation_box.getText() ); ++ } ++ if ( projectDescription_box.getText().length() > 0 ) ++ { ++ userToSave.setProjectDescription( projectDescription_box.getText() ); ++ } ++ if ( projectPIName_box.getText().length() > 0 ) ++ { ++ userToSave.setProjectPIName( projectPIName_box.getText() ); ++ } ++ if (newUser) { ++ EucalyptusWebBackend.App.getInstance().addUserRecord( ++ sessionId, /* will be null if anonymous user signs up */ ++ userToSave, ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ displayDialog( "Thank you!", ( String ) result ); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ String m = caught.getMessage(); ++ if ( m.equals( "User already exists" ) ) ++ { ++ g1.setWidget( userName_row, 2, new Label( "Username is taken!" ) ); ++ label_box.setText( "Please, fix the error and resubmit:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } else { ++ displayErrorPage(m); ++ } ++ } ++ } ++ ); ++ } else { ++ EucalyptusWebBackend.App.getInstance().updateUserRecord( ++ sessionId, ++ userToSave, ++ new AsyncCallback() { ++ public void onSuccess(Object result) { ++ if (loggedInUser.getUserName().equals(userToSave.getUserName())) { ++ loggedInUser.setRealName(userToSave.getRealName()); ++ loggedInUser.setEmail(userToSave.getEmail()); ++ loggedInUser.setPassword(userToSave.getPassword()); ++ loggedInUser.setTelephoneNumber(userToSave.getTelephoneNumber()); ++ loggedInUser.setAffiliation(userToSave.getAffiliation()); ++ loggedInUser.setProjectDescription(userToSave.getProjectDescription()); ++ loggedInUser.setProjectPIName(userToSave.getProjectPIName()); ++ displayDialog("", (String) result); ++ ++ } else { // admin updating a user ++ displayBarAndTabs(""); ++ statusMessage.setText( ( String ) result ); ++ } ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ String m = caught.getMessage(); ++ displayErrorPage(m); ++ } ++ } ++ ); ++ } ++ } ++ else ++ { ++ label_box.setText( "Please, fix the errors and resubmit:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ }; ++ ++ Button submit_button; ++ if (newUser) { ++ if (admin) { ++ submit_button = new Button ( "Add user", SignupButtonListener); ++ } else { ++ submit_button = new Button ( "Sign up", SignupButtonListener); ++ } ++ } else { ++ submit_button = new Button ( "Update Record", SignupButtonListener ); ++ } ++ ++ Button cancel_button = new Button( "Cancel", DefaultPageButtonListener ); ++ VerticalPanel mpanel = new VerticalPanel(); ++ mpanel.add( label_mandatory ); ++ mpanel.add( g1 ); ++ ++ VerticalPanel opanel = new VerticalPanel(); ++ if (extra_fields > 0) { ++ opanel.add( label_optional ); ++ opanel.add( g2 ); ++ } ++ ++ HorizontalPanel bpanel = new HorizontalPanel(); ++ bpanel.add( submit_button ); ++ bpanel.add( new HTML( "  or  " ) ); ++ bpanel.add( cancel_button ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ vpanel.add(new HTML("
")); ++ if (logo!=null) { addLogoWithText(vpanel); vpanel.add(new HTML("
"));}; ++ vpanel.add (label_box); ++ vpanel.add (mpanel); ++ vpanel.add (opanel); ++ vpanel.add (bpanel); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++// wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ parent.clear(); ++ parent.add( wrapper ); ++ } ++ ++ public void displayPasswordRecoveryPage() ++ { ++ label_box.setText ("Please, choose the new password"); ++ label_box.setStyleName("euca-greeting-normal"); ++ ++ final Grid g1 = new Grid ( 3, 3 ); ++ g1.getColumnFormatter().setWidth(0, "230"); ++ g1.getColumnFormatter().setWidth(1, "180"); ++ g1.getColumnFormatter().setWidth(2, "180"); ++ int i = 0; ++ ++ final int usernameOrEmail_row = i; ++ g1.setWidget( i, 0, new Label( "Username OR email address:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox usernameOrEmail_box = new TextBox(); ++ usernameOrEmail_box.setWidth("180"); ++ g1.setWidget( i++, 1, usernameOrEmail_box ); ++ ++ final int password1_row = i; ++ g1.setWidget( i, 0, new Label( "New password:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox cleartextPassword1_box = new PasswordTextBox(); ++ cleartextPassword1_box.setWidth("180"); ++ g1.setWidget( i++, 1, cleartextPassword1_box ); ++ ++ final int password2_row = i; ++ g1.setWidget( i, 0, new Label( "The password, again:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox cleartextPassword2_box = new PasswordTextBox(); ++ cleartextPassword2_box.setWidth("180"); ++ g1.setWidget( i++, 1, cleartextPassword2_box ); ++ ++ ClickListener RecoverButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ boolean formOk = true; ++ ++ for ( int j = 0; j < 3; j++ ) ++ { ++ g1.clearCell( j, 2 ); /* clear previous right-hand-side annotations */ ++ } ++ ++ /* perform checks */ ++ if ( usernameOrEmail_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Username is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( usernameOrEmail_row, 2, l); ++ formOk = false; ++ } ++ /* no spaces in username */ ++ if ( usernameOrEmail_box.getText().matches(".*[ \t]+.*") ) { ++ Label l = new Label ("Username cannot have spaces, sorry!"); ++ l.setStyleName ("euca-error-hint"); ++ g1.setWidget (usernameOrEmail_row, 2, l); ++ formOk = false; ++ } ++ ++ if ( cleartextPassword1_box.getText().length() < minPasswordLength ) ++ { ++ Label l = new Label( "Password must be at least " + minPasswordLength + " characters long!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password1_row, 2, l ); ++ formOk = false; ++ } ++ if ( !cleartextPassword1_box.getText().equals( cleartextPassword2_box.getText() ) ) ++ { ++ Label l = new Label( "Passwords do not match!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password2_row, 2, l ); ++ formOk = false; ++ } ++ if ( cleartextPassword1_box.getText().toLowerCase().matches(".*" + ++ usernameOrEmail_box.getText().toLowerCase() + ".*")) { ++ Label l = new Label ( "Password may not contain the username!"); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( password1_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( formOk ) ++ { ++ label_box.setText( "Checking with the server..." ); ++ label_box.setStyleName("euca-greeting-pending"); ++ ++ UserInfoWeb user = new UserInfoWeb( ++ usernameOrEmail_box.getText(), ++ "", /* don't care about the name */ ++ usernameOrEmail_box.getText(), /* same as login */ ++ GWTUtils.md5(cleartextPassword1_box.getText()) ); ++ EucalyptusWebBackend.App.getInstance().recoverPassword( ++ user, ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ displayDialog( "Thank you!", ( String ) result ); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ String m = caught.getMessage(); ++ displayErrorPage(m); ++ } ++ } ++ ); ++ ++ } ++ else ++ { ++ label_box.setText( "Please, fix the errors and resubmit:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ }; ++ ++ Button submit_button = new Button ( "Recover Password", RecoverButtonListener ); ++ Button cancel_button = new Button ( "Cancel", DefaultPageButtonListener ); ++ VerticalPanel mpanel = new VerticalPanel(); ++ mpanel.add( g1 ); ++ ++ HorizontalPanel bpanel = new HorizontalPanel(); ++ bpanel.add( submit_button ); ++ bpanel.add( new HTML( "  or  " ) ); ++ bpanel.add( cancel_button ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ vpanel.add (label_box); ++ vpanel.add (mpanel); ++ vpanel.add (bpanel); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( wrapper ); ++ } ++ ++ private Button displayDialog ( String greeting, String message ) ++ { ++ return displayDialog (greeting, message, null); ++ } ++ ++ private Button displayDialog ( String greeting, String message, Button firstButton ) ++ { ++ if ( message==null || message.equalsIgnoreCase("") ) { ++ message = "Server is not accessible!"; // TODO: any other reasons why message would be empty? ++ } ++ label_box.setText( greeting ); ++ label_box.setStyleName("euca-greeting-normal"); ++ Label m = new Label ( message ); ++ m.setWidth("300"); ++ ++ VerticalPanel panel = new VerticalPanel(); ++ panel.add(m); ++ panel.setStyleName("euca-login-panel"); ++ panel.setCellHorizontalAlignment(m, HasHorizontalAlignment.ALIGN_CENTER); ++ panel.setCellVerticalAlignment(m, HasVerticalAlignment.ALIGN_MIDDLE); ++ Button ok_button = new Button( "Ok", DefaultPageButtonListener ); ++ ++ HorizontalPanel hpanel = new HorizontalPanel(); ++ hpanel.setSpacing (10); ++ if (firstButton!=null) { ++ hpanel.add (firstButton); ++ } ++ hpanel.add (ok_button); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ vpanel.add (label_box); ++ vpanel.add (panel); ++ vpanel.add (hpanel); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( wrapper ); ++ ++ return ok_button; ++ } ++ ++ public void attemptLogin() ++ { ++ displayStatusPage("Logging into the server..."); ++ EucalyptusWebBackend.App.getInstance().getUserRecord( ++ sessionId, ++ null, /* get user record associated with this sessionId */ ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ loggedInUser = ( UserInfoWeb ) ( (List) result).get(0); ++ if ( currentAction == null ) { ++ displayDefaultPage (""); ++ } else { ++ executeAction( currentAction ); ++ } ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ if (caught.getMessage().equals("Password expired")) { ++ displayPasswordChangePage( true ); ++ } else { ++ displayLoginErrorPage( caught.getMessage() ); ++ } ++ } ++ } ++ ); ++ } ++ ++ public void attemptAction( String action, String param ) ++ { ++ displayStatusPage( "Contacting the server..." ); ++ EucalyptusWebBackend.App.getInstance().performAction( ++ sessionId, ++ action, ++ param, ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ displayMessagePage( ( String ) result ); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ displayErrorPage( caught.getMessage() ); ++ } ++ } ++ ); ++ } ++ ++ public void attemptActionNoReload( String action, String param, final VerticalPanel parent ) ++ { ++ statusMessage.setText( "Contacting the server..." ); ++ EucalyptusWebBackend.App.getInstance().performAction( ++ sessionId, ++ action, ++ param, ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ displayBarAndTabs(""); ++ statusMessage.setText( ( String ) result ); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ displayErrorPage( caught.getMessage() ); ++ } ++ } ++ ); ++ } ++ ++ public void executeAction( String action ) ++ { ++ /* NOTE: some of the checks are repeated by the server, ++ * this is just to avoid unnecessary RPCs */ ++ if ( action.equals ( "approve" ) ++ || action.equals ( "reject" ) ++ || action.equals ( "delete" ) ++ || action.equals ( "disable" ) ++ || action.equals ( "enable" ) ) ++ { ++ String userName = ( String ) urlParams.get( "user" ); ++ if ( !loggedInUser.isAdministrator().booleanValue() ) ++ { ++ displayErrorPage( "Administrative privileges required" ); ++ } ++ else if ( userName == null ) ++ { ++ displayErrorPage( "Username not specified" ); ++ } ++ else ++ { ++ attemptAction( action, userName ); ++ } ++ } ++ else if ( action.equals ( "delete_image") ++ || action.equals ( "disable_image") ++ || action.equals ( "enable_image") ) ++ { ++ String imageId = ( String ) urlParams.get ("id"); ++ if ( !loggedInUser.isAdministrator().booleanValue() ) ++ { ++ displayErrorPage( "Administrative privileges required" ); ++ } ++ else if ( imageId == null ) ++ { ++ displayErrorPage( "Image ID not specified" ); ++ } ++ else ++ { ++ attemptAction( action, imageId ); ++ } ++ } ++ else if ( action.equals( "confirm" ) ++ || action.equals ("recover") ) ++ { ++ String confirmationCode = ( String ) urlParams.get( "code" ); ++ if ( confirmationCode == null ) ++ { ++ displayErrorPage( "Confirmation code not specified" ); ++ } ++ else ++ { ++ attemptAction( action, confirmationCode ); ++ } ++ } ++ else ++ { ++ displayErrorPage( "Action '" + action + "' not recognized" ); ++ } ++ } ++ ++ public void displayDefaultPage (String message) ++ { ++ displayStatusPage("Loading default page..."); ++ ++ /* If there is an action encoded in the URL, then redirect to ++ * a URL without that action, so it is not repeated upon a reload ++ * However, reserve the currently selected tab in URL. ++ */ ++ if (currentAction!=null) { ++ String extra = ""; ++ if (currentTabIndex!=0) { ++ extra = "?page=" + currentTabIndex; ++ } ++ GWTUtils.redirect (GWT.getModuleBaseURL() + extra); ++ } ++ ++ if (loggedInUser!=null) { ++ if ( loggedInUser.isAdministrator().booleanValue() ) ++ { ++ if (loggedInUser.getEmail().equalsIgnoreCase( "" ) ) { ++ displayFirstTimeConfiguration(); ++ } else { ++ displayBarAndTabs(message); ++ } ++ } ++ else ++ { ++ displayBarAndTabs(message); ++ } ++ } else { ++ displayLoginPage(); ++ } ++ } ++ ++ ClickListener AddUserButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ displayUserRecordPage (RootPanel.get(), null); ++ } ++ }; ++ ++ ClickListener DefaultPageButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ displayDefaultPage (""); ++ } ++ }; ++ ++ public void displayErrorPage( String message ) ++ { ++ displayDialog("Error!", message); ++ label_box.setStyleName("euca-greeting-error"); ++ } ++ ++ public void displayErrorPageFinal( String message ) ++ { ++ Button ok_button = displayDialog("Error!", message); ++ label_box.setStyleName("euca-greeting-error"); ++ ok_button.setVisible(false); ++ } ++ ++ public void displayMessagePage( String message ) ++ { ++ displayDialog("", message); ++ label_box.setStyleName("euca-greeting-normal"); ++ } ++ ++ ClickListener LogoutButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ EucalyptusWebBackend.App.getInstance().logoutSession( ++ sessionId, ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ displayLoginPage(); ++ } ++ ++ public void onFailure( Throwable caught ) ++ { ++ displayLoginPage(); ++ } ++ } ++ ); ++ sessionId = null; /* invalidate sessionId */ ++ loggedInUser = null; /* invalidate user */ ++ Cookies.removeCookie( cookie_name ); // TODO: this isn't working for some reason ++ } ++ }; ++ ++ public void displayBarAndTabs(String message) ++ { ++ /* top bar */ ++ displayStatusPage("Drawing the tabs..."); ++ ++ HorizontalPanel top_bar = new HorizontalPanel(); ++ top_bar.getElement().setClassName("euca-top-bar"); ++ ++ HorizontalPanel name_panel = new HorizontalPanel(); ++ name_panel.getElement().setClassName("euca-top-bar-left"); ++ name_panel.setSpacing (5); ++ name_panel.add (new HTML(Theme.draw_header())); ++ top_bar.add (name_panel); ++ ++ top_bar.setCellHorizontalAlignment(name_panel, HorizontalPanel.ALIGN_LEFT); ++ top_bar.setCellVerticalAlignment(name_panel, HorizontalPanel.ALIGN_TOP); // michael left this as MIDDLE ++ ++ HorizontalPanel upanel = new HorizontalPanel(); ++ upanel.getElement().setClassName("euca-top-bar-right"); ++ Label user_name = new HTML("Logged in as " ++ + loggedInUser.getUserName() ++ + "  |  "); ++ Hyperlink logout_button = new Hyperlink("Logout", "logout"); ++ logout_button.addClickListener(LogoutButtonListener); ++ upanel.add(user_name); ++ upanel.add(logout_button); ++ top_bar.add(upanel); ++ top_bar.setCellHorizontalAlignment(upanel, HorizontalPanel.ALIGN_RIGHT); ++ top_bar.setCellVerticalAlignment(upanel, HorizontalPanel.ALIGN_TOP); ++ ++ final HorizontalPanel messageBox = new HorizontalPanel(); ++ messageBox.setStyleName("euca-message-bar"); ++ messageBox.setSpacing(3); ++ messageBox.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); ++ messageBox.add (statusMessage); ++ statusMessage.setStyleName("euca-small-text"); ++ ++ final VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.setStyleName("euca-tab-contents"); ++// wrapper.setSize("100%", "80%"); ++// wrapper.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++// wrapper.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); ++ ++ // set up tab layout so that *TabIndex variables are set in the beginning ++ int nTabs = 0; ++ allTabs = new TabBar(); ++ ++ ++ allTabs.addTab ("Credentials"); credsTabIndex = nTabs++; ++ allTabs.addTab ("Images"); imgTabIndex = nTabs++; ++ /////allTabs.addTab ("Instances"); instTabIndex = nTabs++; ++ if (loggedInUser.isAdministrator().booleanValue()) { ++ if (extensions != null && extensions.contains("store")) { ++ allTabs.addTab ("Store"); storeTabIndex = nTabs++; ++ } ++ allTabs.addTab ("Users"); usrTabIndex = nTabs++; ++ allTabs.addTab ("Configuration"); confTabIndex = nTabs++; ++ allTabs.addTab ("Services"); servicesTabIndex = nTabs++; ++ allTabs.addTab ("Extras"); downTabIndex = nTabs++; ++ } ++ // can happen if admin user re-logs in as regular without reloading ++ if (currentTabIndex > (nTabs-1) ) { ++ currentTabIndex = 0; ++ } ++ allTabs.addTabListener(new TabListener() { ++ public void onTabSelected(SourcesTabEvents sender, int tabIndex) { ++ String error = "This tab is not implemented yet, sorry!"; ++ statusMessage.setText(""); ++ wrapper.clear(); ++ currentTabIndex = tabIndex; ++ if (tabIndex==credsTabIndex) { displayCredentialsTab(wrapper); } ++ else if (tabIndex==imgTabIndex) { displayImagesTab(wrapper); } ++ else if (tabIndex==usrTabIndex) { displayUsersTab(wrapper); } ++ else if (tabIndex==confTabIndex) { displayConfTab(wrapper); } ++ else if (tabIndex==downTabIndex) { displayDownloadsTab(wrapper); } ++ else if (tabIndex==storeTabIndex) { displayStoreTab(wrapper); } ++ else if (tabIndex==servicesTabIndex) { displayServicesTab(wrapper); } ++ else { displayErrorPage("Invalid tab!"); } ++ } ++ public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) { ++ return true; /* here we could do checking for clicks on disabled tabs */ ++ } ++ }); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( top_bar ); ++ RootPanel.get().add( allTabs ); ++ RootPanel.get().add( messageBox ); ++ RootPanel.get().add( wrapper ); ++ allTabs.selectTab(currentTabIndex); ++ } ++ ++ private Image addLogoWithText(CellPanel name_panel) { ++ logo.getElement().setAttribute("alt", cloud_name); ++ name_panel.add(logo); ++ return logo; ++ } ++ ++ private void addTextlessLogoAndHeading(HorizontalPanel name_panel) { ++ Label welcome = new Label( cloud_name); ++ if (textless_logo!=null) { ++ name_panel.add (textless_logo); ++ } ++ name_panel.add(welcome); ++ name_panel.setCellVerticalAlignment(welcome, HorizontalPanel.ALIGN_MIDDLE); ++ } ++ ++ public void displayCredentialsTab (final VerticalPanel parent) ++ { ++ EucalyptusWebBackend.App.getInstance().getCloudInfo( ++ sessionId, ++ false, // do not check external IP for now ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ cloudInfo = ( CloudInfoWeb ) result; ++ actuallyDisplayCredentialsTab (parent); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ displayErrorPage( caught.getMessage() ); ++ } ++ } ++ ); ++ } ++ ++ private class RightscaleDialog extends DialogBox { ++ ++ private boolean cancelled; ++ ++ public RightscaleDialog () { ++ ++ cancelled = false; ++ setHTML ("   Checking the external IP address..."); ++ ++ final Button okButton = new Button("OK", ++ new ClickListener() { ++ public void onClick(Widget sender) { ++ RightscaleDialog.this.hide(); ++ if (rightscaleUrl!=null) { ++ Window.open (rightscaleUrl, "_blank", ""); ++ } ++ } ++ }); ++ okButton.setEnabled (false); ++ Button cancelButton = new Button("Cancel", ++ new ClickListener() { ++ public void onClick(Widget sender) { ++ RightscaleDialog.this.hide(); ++ cancelled = true; ++ } ++ }); ++ ++ HorizontalPanel buttonPanel = new HorizontalPanel(); ++ buttonPanel.add (okButton); ++ buttonPanel.add (cancelButton); ++ setWidget (buttonPanel); ++ ++ EucalyptusWebBackend.App.getInstance().getCloudInfo( ++ sessionId, ++ true, // DO check external IP ++ new AsyncCallback () { ++ public void onSuccess( Object result ) ++ { ++ if (cancelled) { ++ return; ++ } ++ cloudInfo = ( CloudInfoWeb ) result; ++ String ex = cloudInfo.getExternalHostPort(); ++ String in = cloudInfo.getInternalHostPort(); ++ String text = ""; ++ String ip; ++ ++ if (ex==null) { ++ ip = in; ++ text = "Warning: RightScale could not discover the external IP address of your cloud. Hence, the pre-filled cloud URL may be incorrect. Check your firewall settings.

"; ++ ++ } else if (!ex.equals(in)) { ++ ip = ex; ++ text = "Warning: The external cloud IP discovered by Rightscale (" + ex + ") is different from the IP found by Eucalyptus (" + in + "). Hence, the pre-filled cloud URL may be incorrect. Check your firewall settings.

"; ++ ++ } else { ++ ip = ex; ++ } ++ String callbackUrl = "https://" ++ + ip ++ + cloudInfo.getServicePath(); ++ rightscaleUrl = rightscale_base_url ++ + GWTUtils.escape (callbackUrl) // URL.encode() wasn't quite right ++ + "®istration_version=1.0&retry=1&secret_token=" ++ + GWTUtils.escape (cloudInfo.getCloudId()); ++ String pre = "

Cloud registration

You are about to open a new window to Rightscale's Web site, on which you will be able to complete registraton.

"; ++ setHTML (pre + text); ++ okButton.setEnabled (true); ++ center(); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ displayErrorPage( caught.getMessage() ); ++ } ++ } ++ ); ++ } ++ } ++ ++ private class LandscapeDialog extends DialogBox { ++ ++ private boolean cancelled = false; ++ private String landscapeUrl = null; ++ ++ public LandscapeDialog () { ++ ++ cancelled = false; ++ setHTML("   Checking the external IP address..."); ++ ++ final Button okButton = new Button("OK", ++ new ClickListener() { ++ public void onClick(Widget sender) { ++ LandscapeDialog.this.hide(); ++ if (landscapeUrl!=null) { ++ Window.open(landscapeUrl, "_blank", ""); ++ } ++ } ++ }); ++ okButton.setEnabled (false); ++ Button cancelButton = new Button("Cancel", ++ new ClickListener() { ++ public void onClick(Widget sender) { ++ LandscapeDialog.this.hide(); ++ cancelled = true; ++ } ++ }); ++ ++ HorizontalPanel buttonPanel = new HorizontalPanel(); ++ buttonPanel.add (okButton); ++ buttonPanel.add (cancelButton); ++ setWidget (buttonPanel); ++ ++ EucalyptusWebBackend.App.getInstance().getCloudInfo( ++ sessionId, ++ true, // DO check external IP ++ new AsyncCallback () { ++ public void onSuccess( Object result ) ++ { ++ if (cancelled) { ++ return; ++ } ++ cloudInfo = (CloudInfoWeb) result; ++ String ex = cloudInfo.getExternalHostPort(); ++ String in = cloudInfo.getInternalHostPort(); ++ String text = ""; ++ String ip; ++ ++ if (ex==null) { ++ ip = in; ++ text = "Warning: The external IP address of your cloud could not be discovered. Hence, the pre-filled cloud URL may be incorrect. Check your firewall settings.

"; ++ } else if (!ex.equals(in)) { ++ ip = ex; ++ text = "Warning: The external cloud IP discovered (" + ex + ") is different from the IP found by Eucalyptus (" + in + "). Hence, the pre-filled cloud URL may be incorrect. Check your firewall settings.

"; ++ } else { ++ ip = ex; ++ } ++ String callbackUrl = "https://" ++ + ip ++ + cloudInfo.getServicePath(); ++ // XXX Should really use the info-url instead ++ String ec2Url = "http://" ++ + ip ++ + "/services/Eucalyptus"; ++ landscapeUrl = ++ "https://landscape.canonical.com/register-cloud" ++ + "?endpoint=" ++ + GWTUtils.escape(ec2Url) ++ + "&info-url=" ++ + GWTUtils.escape(callbackUrl) ++ + "&cloud-id=" ++ + GWTUtils.escape(cloudInfo.getCloudId()); ++ String pre = "

Cloud registration

You are about to open a new window to Landscape's web site, on which you will be able to complete the registraton.

"; ++ setHTML(pre + text); ++ okButton.setEnabled(true); ++ center(); ++ } ++ public void onFailure(Throwable caught) ++ { ++ displayErrorPage(caught.getMessage()); ++ } ++ } ++ ); ++ } ++ } ++ ++ public void actuallyDisplayCredentialsTab (VerticalPanel parent) ++ { ++ History.newItem("credentials"); ++ ++ VerticalPanel credspanel = new VerticalPanel (); ++ credspanel.setSpacing(5); ++ parent.add (credspanel); ++ credspanel.getElement().setClassName ("euca-tab-with-text"); ++ ++ VerticalPanel ppanel = new VerticalPanel(); ++ ppanel.add (new HTML ("

User account Information

")); ++ ++ Grid userGrid = new Grid(3,2); ++ userGrid.setText(0, 0, "Login:"); ++ userGrid.setHTML(0, 1, "" + loggedInUser.getUserName() +""); ++ userGrid.setText(1, 0, "Name:"); ++ userGrid.setHTML(1, 1, "" + loggedInUser.getRealName() +""); ++ userGrid.setText(2, 0, "Email:"); ++ userGrid.setHTML(2, 1, "" + loggedInUser.getEmail() +""); ++ ppanel.add(userGrid); ++ ppanel.add (new HTML ("

" + user_account_text + "

")); ++ ppanel.setStyleName("euca-text"); ++ ppanel.addStyleName("content"); ++ ++ Button passwordButton = new Button ( "Change Password", ++ new ClickListener() { ++ public void onClick(Widget sender) { ++ displayPasswordChangePage (false); ++ } ++ }); ++ Button editButton = new Button ( "Edit Account Information", ++ new ClickListener() { ++ public void onClick (Widget sender) { ++ displayUserRecordPage (RootPanel.get(), loggedInUser); ++ } ++ }); ++ ppanel.setSpacing( 0 ); ++ ppanel.add(editButton); ++ ppanel.add(passwordButton); ++ ++ VerticalPanel cpanel = new VerticalPanel(); ++ cpanel.add ( new HTML (certificate_download_text) ); ++ cpanel.setStyleName( "euca-text" ); ++ cpanel.addStyleName("content"); ++ Button certButton = new Button ("Download Credentials", new ClickListener() { ++ public void onClick (Widget sender) { ++ Window.open(GWT.getModuleBaseURL() + ++ "getX509?user=" + loggedInUser.getUserName() + ++ "&keyValue=" + loggedInUser.getUserName() + ++ "&code=" + loggedInUser.getToken(), ++ "_self", ""); ++ } ++ }); ++ ++ VerticalPanel rpanel = new VerticalPanel(); ++ rpanel.setSpacing (0); ++ HTML credentials_html = new HTML (rest_credentials_text); ++ credentials_html.setStyleName("content"); ++ rpanel.add( credentials_html ); ++ Grid g0 = new Grid (2, 2); ++ g0.setWidget (0, 0, new HTML ("Query ID:")); ++ final HTML queryId = new HTML ("" + loggedInUser.getQueryId() + ""); ++ queryId.setVisible (false); ++ g0.setWidget (0, 1, queryId); ++ g0.setWidget (1, 0, new HTML ("Secret Key:")); ++ final HTML secretKey = new HTML ("" + loggedInUser.getSecretKey() + ""); ++ secretKey.setVisible (false); ++ g0.setWidget (1, 1, secretKey); ++ rpanel.add (g0); ++ rpanel.setStyleName( "euca-text" ); ++ final Button secretButton = new Button ( "Show keys" ); ++ secretButton.addClickListener(new ClickListener() { ++ public void onClick(Widget sender) { ++ if (secretKey.isVisible()) { ++ secretKey.setVisible(false); ++ queryId.setVisible(false); ++ secretButton.setText ("Show keys"); ++ } else { ++ secretKey.setVisible(true); ++ queryId.setVisible(true); ++ secretButton.setText ("Hide keys"); ++ } ++ } ++ }); ++ ++ int gridRows = 3; ++ if (loggedInUser.isAdministrator() && show_cloud_registration) { ++ gridRows++; ++ } ++ credspanel.add(ppanel); ++ ++ credspanel.add(cpanel); ++ credspanel.add(certButton); ++ credspanel.add(rpanel); ++ credspanel.add(secretButton); ++ ++// final Grid g = new Grid( gridRows, 2 ); ++// g.getColumnFormatter().setWidth(0, "400"); ++// g.getColumnFormatter().setWidth(1, "200"); ++// g.setCellSpacing( 30 ); ++// ++// g.setWidget( 0, 0, ppanel ); g.getCellFormatter().setVerticalAlignment(0, 0, HasVerticalAlignment.ALIGN_TOP); ++// // g.setWidget( 0, 1, ppanel2); g.getCellFormatter().setVerticalAlignment(0, 1, HasVerticalAlignment.ALIGN_TOP); ++// ++// g.setWidget( 1, 0, cpanel ); g.getCellFormatter().setVerticalAlignment(1, 0, HasVerticalAlignment.ALIGN_TOP); ++// g.setWidget( 1, 1, certButton ); g.getCellFormatter().setVerticalAlignment(1, 1, HasVerticalAlignment.ALIGN_TOP); ++// ++// g.setWidget( 2, 0, rpanel ); g.getCellFormatter().setVerticalAlignment(2, 0, HasVerticalAlignment.ALIGN_TOP); ++// g.setWidget( 2, 1, secretButton ); g.getCellFormatter().setVerticalAlignment(2, 1, HasVerticalAlignment.ALIGN_TOP); ++ ++/* ++ if (loggedInUser.isAdministrator() && show_cloud_registration) { ++ VerticalPanel cloud_panel = new VerticalPanel(); ++ cloud_panel.setSpacing (0); ++ cloud_panel.add( new HTML (cloud_registration_text) ); ++ Grid g1 = new Grid (2, 2); ++ g1.setWidget (0, 0, new HTML ("Cloud URL:")); ++ final HTML cloudUrl = new HTML ("https://" ++ + cloudInfo.getInternalHostPort() ++ + cloudInfo.getServicePath() ++ + ""); ++ g1.setWidget (0, 1, cloudUrl); ++ g1.setWidget (1, 0, new HTML ("Cloud ID:")); ++ final HTML cloudId = new HTML ("" ++ + cloudInfo.getCloudId() ++ + ""); ++ g1.setWidget (1, 1, cloudId); ++ cloud_panel.add (g1); ++ cloud_panel.setStyleName( "euca-text" ); ++ final Button cloudButton = new Button ( "Register" ); ++ cloudButton.addClickListener(new ClickListener() { ++ public void onClick(Widget sender) { ++ new RightscaleDialog().center(); ++ } ++ }); ++// g.setWidget (3, 0, cloud_panel ); ++// g.getCellFormatter().setVerticalAlignment(3, 0, HasVerticalAlignment.ALIGN_TOP); ++ credspanel.add(cloud_panel); ++ VerticalPanel vp = new VerticalPanel(); ++ vp.setSpacing (0); ++ HorizontalPanel hp = new HorizontalPanel(); ++ hp.setSpacing (0); ++ hp.add (cloudButton); ++ hp.add (new HTML ("with")); ++ Image logo = new Image ("themes/share/rightscale-logo-blue.gif"); ++ logo.setStyleName("euca-inline-image"); ++ hp.add (logo); ++ vp.add (hp); ++// g.setWidget( 3, 1, vp ); ++// g.getCellFormatter().setVerticalAlignment(3, 1, HasVerticalAlignment.ALIGN_TOP); ++ credspanel.add(vp); ++ } ++ */ ++ ++ //credspanel.add(g); ++ } ++ ++ public void displayErrorTab(VerticalPanel parent, String message) ++ { ++ parent.add(new Label(message)); ++ } ++ ++ public void displayTestingTab(VerticalPanel parent) ++ { ++ parent.add(new Label("truth = [" + props.get("truth") + "]")); ++ } ++ ++ public void displayStatusPage(String message) ++ { ++ label_box.setText( message ); ++ label_box.setStyleName("euca-greeting-pending"); ++ ++ final VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ wrapper.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); ++ wrapper.add(label_box); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add(wrapper); ++ } ++ ++ public void displayPasswordChangePage(boolean mustChange) ++ { ++ if (mustChange) { ++ label_box.setText( "You are required to change your password" ); ++ label_box.setStyleName("euca-greeting-error"); ++ } else { ++ label_box.setText( "Please, change your password" ); ++ label_box.setStyleName("euca-greeting-normal"); ++ } ++ final Grid g1 = new Grid ( 3, 3 ); ++ g1.getColumnFormatter().setWidth(0, "180"); ++ g1.getColumnFormatter().setWidth(1, "180"); ++ g1.getColumnFormatter().setWidth(2, "180"); ++ int i = 0; ++ ++ final int oldPassword_row = i; ++ g1.setWidget( i, 0, new Label( "Old password:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox oldPassword_box = new PasswordTextBox(); ++ oldPassword_box.setWidth("180"); ++ if (!mustChange) { // don't ask for old password if the change is involuntary ++ g1.setWidget( i++, 1, oldPassword_box ); ++ } ++ ++ final int newPassword1_row = i; ++ g1.setWidget( i, 0, new Label( "New password:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox newCleartextPassword1_box = new PasswordTextBox(); ++ newCleartextPassword1_box.setWidth("180"); ++ g1.setWidget( i++, 1, newCleartextPassword1_box ); ++ ++ final int newPassword2_row = i; ++ g1.setWidget( i, 0, new Label( "New password, again:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox newCleartextPassword2_box = new PasswordTextBox(); ++ newCleartextPassword2_box.setWidth("180"); ++ g1.setWidget( i++, 1, newCleartextPassword2_box ); ++ ++ ClickListener ChangeButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ boolean formOk = true; ++ ++ for ( int j = 0; j < 3; j++ ) ++ { ++ g1.clearCell( j, 2 ); // clear previous right-hand-side annotations ++ } ++ ++ // perform checks ++ if ( newCleartextPassword1_box.getText().length() < minPasswordLength ) ++ { ++ Label l = new Label( "Password is too short!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( newPassword1_row, 2, l ); ++ formOk = false; ++ } ++ if ( !newCleartextPassword1_box.getText().equals( newCleartextPassword2_box.getText() ) ) ++ { ++ Label l = new Label( "Passwords do not match!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( newPassword2_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( formOk ) ++ { ++ label_box.setText( "Checking with the server..." ); ++ label_box.setStyleName("euca-greeting-pending"); ++ ++ EucalyptusWebBackend.App.getInstance().changePassword( ++ sessionId, ++ GWTUtils.md5(oldPassword_box.getText()), ++ GWTUtils.md5(newCleartextPassword1_box.getText()), ++ new AsyncCallback() { ++ public void onSuccess( final String result ) ++ { ++ // password change succeded - pull in the new user record ++ label_box.setText( "Refreshing user data..." ); ++ EucalyptusWebBackend.App.getInstance().getUserRecord( ++ sessionId, ++ null, ++ new AsyncCallback>() { ++ public void onSuccess( List users ) ++ { ++ loggedInUser = users.get(0); ++ displayMessagePage ( ( String ) result ); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ displayLoginErrorPage( caught.getMessage() ); ++ } ++ }); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ String m = caught.getMessage(); ++ label_box.setText( m ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ ); ++ } ++ else ++ { ++ label_box.setText( "Please, fix the errors and try again:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ }; ++ ++ Button change_button = new Button( "Change password", ChangeButtonListener ); ++ Button cancel_button = new Button( "Cancel", DefaultPageButtonListener ); ++ ++ HorizontalPanel bpanel = new HorizontalPanel(); ++ bpanel.add( change_button ); ++ if (!mustChange) { ++ bpanel.add( new HTML( "  or  " ) ); ++ bpanel.add( cancel_button ); ++ } ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ vpanel.add (label_box); ++ vpanel.add (g1); ++ vpanel.add (bpanel); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( wrapper ); ++ } ++ ++ ++ public void displayAdminEmailChangePage() ++ { ++ label_box.setText( "One more thing!" ); ++ label_box.setStyleName("euca-greeting-error"); ++ ++ final Grid g1 = new Grid ( 2, 3 ); ++ g1.getColumnFormatter().setWidth(0, "180"); ++ g1.getColumnFormatter().setWidth(1, "180"); ++ g1.getColumnFormatter().setWidth(2, "180"); ++ int i = 0; ++ ++ g1.setWidget( i, 0, new Label( "Email address:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox emailAddress1_box = new TextBox(); ++ emailAddress1_box.setWidth("180"); ++ g1.setWidget( i++, 1, emailAddress1_box ); ++ ++ g1.setWidget( i, 0, new Label( "The address, again:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox emailAddress2_box = new TextBox(); ++ emailAddress2_box.setWidth("180"); ++ g1.setWidget( i++, 1, emailAddress2_box ); ++ ++ ClickListener ChangeButtonListener = new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ boolean formOk = true; ++ ++ for ( int j = 0; j < 2; j++ ) ++ { ++ g1.clearCell( j, 2 ); /* clear previous right-hand-side annotations */ ++ } ++ ++ /* perform checks */ ++ if ( emailAddress1_box.getText().length() < 3 ) ++ { ++ Label l = new Label( "Invalid address!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( 0, 2, l ); ++ formOk = false; ++ } ++ if ( !emailAddress1_box.getText().equals( emailAddress2_box.getText() ) ) ++ { ++ Label l = new Label( "Addresses do not match!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( 1, 2, l ); ++ formOk = false; ++ } ++ ++ if ( formOk ) ++ { ++ loggedInUser.setEmail( emailAddress1_box.getText() ); ++ label_box.setText( "Checking with the server..." ); ++ label_box.setStyleName("euca-greeting-pending"); ++ EucalyptusWebBackend.App.getInstance().updateUserRecord( ++ sessionId, ++ loggedInUser, ++ new AsyncCallback() { ++ public void onSuccess( final Object result ) ++ { ++ displayWalrusURLChangePage (); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ loggedInUser.setEmail( "" ); ++ displayLoginErrorPage( caught.getMessage() ); ++ } ++ }); ++ } ++ else ++ { ++ label_box.setText( "Please, fix the errors and try again:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ } ++ }; ++ ++ Button change_button = new Button( "Change address", ChangeButtonListener ); ++ HTML message = new HTML (admin_email_change_text); ++ message.setWidth( "460" ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++// vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ vpanel.add (label_box); ++ vpanel.add (message); ++ vpanel.add (g1); ++ vpanel.add (change_button); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); // michael commented out ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add( wrapper ); ++ } ++ ++ public static SystemConfigWeb conf = new SystemConfigWeb (); ++ public void displayWalrusURLChangePage() ++ { ++ label_box.setText( "One last thing! Really!!!" ); ++ label_box.setStyleName("euca-greeting-error"); ++ ++ HorizontalPanel hpanel = new HorizontalPanel(); ++ hpanel.add (new Label ("Walrus URL:")); ++ final TextBox box = new TextBox (); ++ box.setVisibleLength (55); ++ hpanel.add (box); ++ ++ EucalyptusWebBackend.App.getInstance().getSystemConfig(sessionId, ++ new AsyncCallback( ) { ++ public void onSuccess ( final Object result ) { ++ conf = (SystemConfigWeb) result; ++ box.setText (conf.getCloudHost()); ++ } ++ public void onFailure ( Throwable caught ) { } ++ } ++ ); ++ ++ Button change_button = new Button( "Confirm URL", ++ new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ conf.setCloudHost(box.getText()); ++ EucalyptusWebBackend.App.getInstance().setSystemConfig(sessionId, ++ conf, ++ new AsyncCallback() { ++ public void onSuccess ( final Object result ) { ++ currentTabIndex = 3; // TODO: change this to confTabIndex ++ displayDefaultPage (""); ++ } ++ public void onFailure ( Throwable caught ) { ++ displayErrorPage ("Failed to save the URL (check 'Configuration' tab)."); ++ } ++ } ++ ); ++ } ++ } ++ ); ++ HTML message = new HTML (admin_cloud_ip_setup_text); ++ message.setWidth( "460" ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ if (logo!=null) { vpanel.add (logo); } ++ vpanel.add (label_box); ++ vpanel.add (message); ++ vpanel.add (hpanel); ++ vpanel.add (change_button); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add (wrapper); ++ } ++ ++ public void displayUsersTab(final VerticalPanel parent) ++ { ++ History.newItem("users"); ++ final HTML msg = new HTML("Contacting the server..."); ++ EucalyptusWebBackend.App.getInstance().getUserRecord( ++ sessionId, ++ "*", /* we want all user records */ ++ new AsyncCallback() { ++ public void onSuccess( Object result ) ++ { ++ List usersList = (List)result; ++ displayUsersList (usersList, parent); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ displayErrorPage (caught.getMessage()); ++ } ++ }); ++ ++ parent.add(msg); ++ } ++ ++ public void displayImagesTab (final VerticalPanel parent) ++ { ++ History.newItem("images"); ++ final HTML msg = new HTML ("Contacting the server..."); ++ EucalyptusWebBackend.App.getInstance().getImageInfo( ++ sessionId, ++ loggedInUser.getUserName(), ++ new AsyncCallback() { ++ public void onSuccess (Object result) ++ { ++ List imagesList = (List)result; ++ displayImagesList (imagesList, parent); ++ } ++ public void onFailure (Throwable caught) ++ { ++ displayErrorPage (caught.getMessage()); ++ } ++ }); ++ ++ parent.add(msg); ++ } ++ ++ private class EucalyptusDialog extends DialogBox { ++ ++ private boolean cancelled; ++ ++ public EucalyptusDialog (String mainMsg, String extraMsg, Button okButton) { ++ ++ super(true); ++ cancelled = false; ++ setHTML (mainMsg); ++ Button cancelButton = new Button ("Cancel", new ClickListener() { ++ public void onClick(Widget sender) { ++ EucalyptusDialog.this.hide(); ++ cancelled = true; ++ } ++ }); ++ HorizontalPanel buttonPanel = new HorizontalPanel(); ++ buttonPanel.add (okButton); ++ buttonPanel.add (cancelButton); ++ setWidget (buttonPanel); ++ center(); ++ } ++ } ++ ++ public void displayConfirmDeletePage( final String userName ) ++ { ++ Button deleteButton = new Button ("Delete", new ClickListener() { ++ public void onClick(Widget sender) { ++ GWTUtils.redirect (GWT.getModuleBaseURL() ++ + "?action=delete" ++ + "&user=" + userName ++ + "&page=" + currentTabIndex); ++ } ++ }); ++ ++ Button okButton = displayDialog ("Sure?", ++ "Do you want to delete user '" + userName + "'?", deleteButton); ++ okButton.setText ("Cancel"); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ ++ public void displayConfirmDeletePageNoReload ( final String userName, final VerticalPanel parent ) ++ { ++ Button deleteButton = new Button ("Delete", new ClickListener() { ++ public void onClick(Widget sender) { ++ attemptActionNoReload("delete", userName, parent); ++ } ++ }); ++ ++ Button okButton = displayDialog ("Sure?", ++ "Do you want to delete user '" + userName + "'?", deleteButton); ++ okButton.setText ("Cancel"); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ ++ private HTML userActionButton (String action, UserInfoWeb user) ++ { ++ return new HTML ("" + action + ""); ++ } ++ ++ private HTML userActionButtonNoReload (final String action, final UserInfoWeb user, final VerticalPanel parent) ++ { ++ HTML link = new HTML (action); ++ link.setStyleName("euca-action-link"); ++ link.addClickListener(new ClickListener() { ++ public void onClick (Widget sender) { ++ attemptActionNoReload(action.toLowerCase(), user.getUserName(), parent); ++ } ++ }); ++ return link; ++ } ++ ++ class EditCallback implements ClickListener { ++ ++ private EucalyptusWebInterface parent; ++ private UserInfoWeb u; ++ ++ EditCallback ( final EucalyptusWebInterface parent, UserInfoWeb u ) ++ { ++ this.parent = parent; ++ this.u = u; ++ } ++ ++ public void onClick( final Widget widget ) ++ { ++ displayUserRecordPage (RootPanel.get(), u); ++ } ++ } ++ ++ public void displayUsersList(final List usersList, final VerticalPanel parent) ++ { ++ String sortSymbol = "↓"; // HTML down arrow ++ if (sortUsersLastFirst) { ++ sortSymbol = "↑"; // HTML up arrow ++ } ++ parent.clear(); ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(5); ++ parent.add(new HTML("

Users

")); ++ parent.add(vpanel); ++ int nusers = usersList.size(); ++ if (nusers>0) { ++ Anchor sort_button = new Anchor( sortSymbol, true); ++ sort_button.setStyleName ("euca-small-text"); ++ sort_button.addClickListener( new ClickListener() { ++ public void onClick(Widget sender) { ++ sortUsersLastFirst = !sortUsersLastFirst; ++ displayUsersList (usersList, parent); ++ } ++ }); ++ ++ final Grid g = new Grid(nusers + 1, 6); ++ g.setStyleName("euca-table"); ++ g.setCellPadding(6); ++ g.setWidget(0, 0, sort_button); ++ g.setWidget(0, 1, new Label("Username")); ++ g.setWidget(0, 2, new Label("Email")); ++ g.setWidget(0, 3, new Label("Name")); ++ g.setWidget(0, 4, new Label("Status")); ++ g.setWidget(0, 5, new Label("Actions")); ++ g.getRowFormatter().setStyleName(0, "euca-table-heading-row"); ++ ++ for (int i=0; i" + action + ""); ++ } ++ ++ public void displayImagesList(List imagesList, final VerticalPanel parent) ++ { ++ parent.clear(); ++ int nimages = imagesList.size(); ++ boolean showActions = false; ++ if (loggedInUser.isAdministrator().booleanValue()) { ++ showActions = true; ++ } ++ ++ ++ if (nimages>0) { ++ final Grid g = new Grid(nimages + 1, 6); ++ g.setStyleName("euca-table"); ++ g.setCellPadding(6); ++ g.setWidget(0, 0, new Label("Id")); ++ g.setWidget(0, 1, new Label("Name")); ++ g.setWidget(0, 2, new Label("Kernel")); ++ g.setWidget(0, 3, new Label("Ramdisk")); ++ g.setWidget(0, 4, new Label("State")); ++ if ( showActions ) ++ g.setWidget(0, 5, new Label("Actions")); ++ g.getRowFormatter().setStyleName(0, "euca-table-heading-row"); ++ ++ for (int i=0; iFor UEC documentation, community pages and the " + ++ "UEC user mailing list please see the Ubuntu site:

" + ++ "")); ++ servicesPanel.add(new SectionWidget( ++ "Training", ++ "

The Ubuntu Enterprise Cloud training course covers every " + ++ "aspect of running your own cloud. Including installing, " + ++ "configuring and optimising the infrastructure, along with " + ++ "setting up and managing virtual machines for your " + ++ "applications. To learn about the UEC course, and our other " + ++ "Ubuntu courses please see:

" + ++ "")); ++ servicesPanel.add(new SectionWidget( ++ "Eucalyptus", ++ "

The UEC is powered by Eucalyptus, an open-source cloud " + ++ "computing platform with support for popular hypervisor and " + ++ "cloud computing interfaces. Eucalyptus enables users to " + ++ "easily implement on-premise and hybrid clouds that leverage " + ++ "both internal and external resources.

" + ++ "

For open-source downloads, documentation and user forums " + ++ "please visit:

" + ++ "" + ++ "

For enterprise support, professional services and " + ++ "additional Eucalyptus products please visit:" + ++ "

")); ++ ++ HTMLPanel landscapePanel = new HTMLPanel( ++ "

Landscape is " + ++ "a systems management service that provides package management, " + ++ "security alerts, custom script automation and monitoring. " + ++ "With Landscape you can see and manage all of your Cloud " + ++ "environment.

" + ++ "

If you already have an account with Landscape, you can " + ++ "register this cloud now:

" + ++ ""); ++ ++ Anchor landscapeAnchor = Anchor.wrap( ++ landscapePanel.getElementById("ls-anchor")); ++ ++ landscapeAnchor.addClickHandler(new ClickHandler() { ++ public void onClick(ClickEvent event) { ++ event.preventDefault(); ++ new LandscapeDialog().center(); ++ } ++ }); ++ ++ servicesPanel.add(new SectionWidget( ++ "Landscape", ++ landscapePanel ++ )); ++ ++ if (loggedInUser.isAdministrator() && show_cloud_registration) { ++ HTMLPanel rightScalePanel = new HTMLPanel( ++ "

Your Eucalyptus cloud can also be registered with " + ++ "RightScale, " + ++ "providing you and your users with an easy-to-use interface " + ++ "to both EC2 and your Eucalyptus cloud. The following two " + ++ "parameters will be necessary for registration:

" + ++ "
" + ++ "

Cloud URL:

" + ++ "

Cloud ID:

" + ++ "
" + ++ "

If you already have an account with RightScale, you can " + ++ "register this cloud now:

" + ++ ""); ++ ++ rightScalePanel.add(new InlineLabel( ++ "https://" + ++ cloudInfo.getInternalHostPort() + ++ cloudInfo.getServicePath() ++ ), "rs-cloud-url"); ++ ++ rightScalePanel.add(new InlineLabel( ++ cloudInfo.getCloudId() ++ ), "rs-cloud-id"); ++ ++ Anchor rightScaleAnchor = Anchor.wrap( ++ rightScalePanel.getElementById("rs-anchor")); ++ ++ rightScaleAnchor.addClickHandler(new ClickHandler() { ++ public void onClick(ClickEvent event) { ++ event.preventDefault(); ++ new RightscaleDialog().center(); ++ } ++ }); ++ ++ servicesPanel.add(new SectionWidget( ++ "RightScale", ++ rightScalePanel ++ )); ++ } ++ ++ servicesPanel.add(new SectionWidget( ++ "Support", ++ "

With commercial support you have the certainty that your " + ++ "bugs and issues will be responded to promptly. Canonical " + ++ "provides business day and 24/7 for Ubuntu Enterprise Cloud. " + ++ "For more details on the service please see:

" + ++ "")); ++ ++ parent.clear(); ++ parent.add(servicesPanel); ++ } ++ ++ public void displayFirstTimeConfiguration() ++ { ++ displayStatusPage("Loading first-time configuration page..."); ++ ++ VerticalPanel gpanel = new VerticalPanel(); ++ gpanel.setSpacing(25); ++ gpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ ++ // password grid ++ ++ final Grid g1 = new Grid ( 2, 3 ); ++ g1.getColumnFormatter().setWidth(0, "240"); ++ g1.getColumnFormatter().setWidth(1, "180"); ++ g1.getColumnFormatter().setWidth(2, "180"); ++ int i = 0; ++ ++ final int newPassword1_row = i; ++ g1.setWidget( i, 0, new Label( "Administrator's new password:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox newCleartextPassword1_box = new PasswordTextBox(); ++ newCleartextPassword1_box.setFocus(true); // this box gets focus first ++ newCleartextPassword1_box.setWidth("180"); ++ g1.setWidget( i++, 1, newCleartextPassword1_box ); ++ ++ final int newPassword2_row = i; ++ g1.setWidget( i, 0, new Label( "The password, again:" ) ); ++ g1.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final PasswordTextBox newCleartextPassword2_box = new PasswordTextBox(); ++ newCleartextPassword2_box.setWidth("180"); ++ g1.setWidget( i++, 1, newCleartextPassword2_box ); ++ ++ gpanel.add(g1); ++ ++ // email address grid ++ ++ final Grid g2 = new Grid ( 1, 3 ); ++ g2.getColumnFormatter().setWidth(0, "240"); ++ g2.getColumnFormatter().setWidth(1, "180"); ++ g2.getColumnFormatter().setWidth(2, "180"); ++ i = 0; ++ ++ final int emailAddress_row = i; ++ g2.setWidget( i, 0, new Label( "Administrator's email address:" ) ); ++ g2.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox emailAddress_box = new TextBox(); ++ emailAddress_box.setWidth("180"); ++ g2.setWidget( i++, 1, emailAddress_box ); ++ ++ VerticalPanel epanel = new VerticalPanel(); ++ epanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ epanel.setSpacing(5); ++ epanel.add(g2); ++ HTML emailChangeMsg = new HTML( admin_email_change_text ); ++ emailChangeMsg.setWidth ("300"); ++ emailChangeMsg.setStyleName("euca-small-text"); ++ epanel.add(emailChangeMsg); ++ gpanel.add(epanel); ++ ++ // cloud URL grid ++ ++ final Grid g3 = new Grid ( 1, 3 ); ++ g3.getColumnFormatter().setWidth(0, "240"); ++ g3.getColumnFormatter().setWidth(1, "180"); ++ g3.getColumnFormatter().setWidth(2, "180"); ++ i = 0; ++ ++ final int cloudUrl_row = i; ++ g3.setWidget( i, 0, new Label( "Cloud Host:" ) ); ++ g3.getCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_RIGHT); ++ final TextBox cloudUrl_box = new TextBox(); ++ cloudUrl_box.setWidth("180"); ++ g3.setWidget( i++, 1, cloudUrl_box ); ++ ++ VerticalPanel cpanel = new VerticalPanel(); ++ cpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ cpanel.setSpacing(5); ++ cpanel.add(g3); ++ HTML cloudUrlMsg = new HTML ( admin_cloud_ip_setup_text ); ++ cloudUrlMsg.setWidth ("300"); ++ cloudUrlMsg.setStyleName("euca-small-text"); ++ cpanel.add (cloudUrlMsg); ++ gpanel.add(cpanel); ++ ++ // pull in guessed cloud URL ++ ++ EucalyptusWebBackend.App.getInstance().getSystemConfig(sessionId, ++ new AsyncCallback( ) { ++ public void onSuccess ( final Object result ) { ++ conf = (SystemConfigWeb) result; ++ cloudUrl_box.setText (conf.getCloudHost()); ++ } ++ public void onFailure ( Throwable caught ) { } ++ } ++ ); ++ ++ // user clicked submit ++ ++ Button change_button = new Button( "Submit", ++ new ClickListener() { ++ public void onClick( Widget sender ) ++ { ++ boolean formOk = true; ++ ++ ++ g1.clearCell( 0, 2 ); // clear previous right-hand-side annotations ++ g1.clearCell( 1, 2 ); // clear previous right-hand-side annotations ++ g2.clearCell( 0, 2 ); // clear previous right-hand-side annotations ++ g3.clearCell( 0, 2 ); // clear previous right-hand-side annotations ++ ++ ++ // perform checks ++ ++ if ( newCleartextPassword1_box.getText().length() < minPasswordLength ) ++ { ++ Label l = new Label( "Password is too short!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( newPassword1_row, 2, l ); ++ formOk = false; ++ } ++ if ( !newCleartextPassword1_box.getText().equals( newCleartextPassword2_box.getText() ) ) ++ { ++ Label l = new Label( "Passwords do not match!" ); ++ l.setStyleName("euca-error-hint"); ++ g1.setWidget( newPassword2_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( emailAddress_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Email address is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g2.setWidget( emailAddress_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( cloudUrl_box.getText().length() < 1 ) ++ { ++ Label l = new Label( "Cloud URL is empty!" ); ++ l.setStyleName("euca-error-hint"); ++ g3.setWidget( cloudUrl_row, 2, l ); ++ formOk = false; ++ } ++ ++ if ( !formOk ) ++ { ++ label_box.setText( "Please, fix the errors and try again:" ); ++ label_box.setStyleName("euca-greeting-warning"); ++ return; ++ } ++ ++ label_box.setText( "Checking with the server..." ); ++ label_box.setStyleName("euca-greeting-pending"); ++ ++ loggedInUser.setEmail( emailAddress_box.getText() ); ++ loggedInUser.setPassword(GWTUtils.md5(newCleartextPassword1_box.getText())); ++ ++ EucalyptusWebBackend.App.getInstance().updateUserRecord( ++ sessionId, ++ loggedInUser, ++ new AsyncCallback() { ++ public void onSuccess( final Object result ) ++ { ++ // password change succeded - pull in the new user record ++ label_box.setText( "Refreshing user data..." ); ++ EucalyptusWebBackend.App.getInstance().getUserRecord( ++ sessionId, ++ null, ++ new AsyncCallback() { ++ public void onSuccess( Object result2 ) ++ { ++ loggedInUser = ( UserInfoWeb ) ( (List) result2).get(0); ++ ++ // update cloud URL ++ conf.setCloudHost(cloudUrl_box.getText()); ++ EucalyptusWebBackend.App.getInstance().setSystemConfig(sessionId, ++ conf, ++ new AsyncCallback() { ++ public void onSuccess ( final Object result ) { ++ currentTabIndex = 3; // TODO: change this to confTabIndex when it's available ++ displayDefaultPage (""); ++ } ++ public void onFailure ( Throwable caught ) { ++ displayErrorPage ("Failed to save the cloud URL (check 'Configuration' tab)."); ++ } ++ } ++ ); ++ ++ } ++ public void onFailure( Throwable caught ) ++ { ++ displayLoginErrorPage( caught.getMessage() ); ++ } ++ }); ++ } ++ public void onFailure( Throwable caught ) ++ { ++ loggedInUser.setEmail( "" ); ++ String m = caught.getMessage(); ++ label_box.setText( m ); ++ label_box.setStyleName("euca-greeting-warning"); ++ } ++ }); ++ } ++ } ++ ); ++ ++ EucalyptusKeyboardListener sl = new EucalyptusKeyboardListener(change_button); ++ change_button.addKeyboardListener(sl); ++ newCleartextPassword1_box.addKeyboardListener(sl); ++ newCleartextPassword2_box.addKeyboardListener(sl); ++ emailAddress_box.addKeyboardListener(sl); ++ cloudUrl_box.addKeyboardListener(sl); ++ ++ HTML message = new HTML (admin_first_time_config_text); ++ message.setWidth( "600" ); ++ ++ VerticalPanel vpanel = new VerticalPanel(); ++ vpanel.setSpacing(15); ++ vpanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); ++ ++ if (logo!=null) { vpanel.add (logo); } ++ label_box.setText( "First-time Configuration" ); ++ label_box.setStyleName("euca-greeting-normal"); ++ vpanel.add (label_box); ++ vpanel.add (message); ++ vpanel.add (gpanel); ++ vpanel.add (change_button); ++ ++ VerticalPanel wrapper = new VerticalPanel(); ++ wrapper.add (vpanel); ++ wrapper.setSize("100%", "100%"); ++ wrapper.setCellHorizontalAlignment(vpanel, VerticalPanel.ALIGN_CENTER); ++ wrapper.setCellVerticalAlignment(vpanel, VerticalPanel.ALIGN_MIDDLE); // michael commented out ++ ++ RootPanel.get().clear(); ++ RootPanel.get().add (wrapper); ++ } ++} +--- a/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/client/UserInfoWeb.java ++++ b/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/client/UserInfoWeb.java +@@ -101,6 +101,8 @@ + private String queryId; + private String secretKey; + ++ public static String BOGUS_ENTRY = "n/a"; // mirrors value in UserInfo ++ + // displayUserRecordPage relies on empty strings and isAdministrator set + public UserInfoWeb() { + this.userName = ""; +--- a/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/server/EucalyptusManagement.java ++++ b/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/server/EucalyptusManagement.java +@@ -191,7 +191,6 @@ + user = Users.addUser( webUser.getUserName( ), webUser.isAdministrator( ), webUser.isEnabled( ) ); + try { + UserInfo userInfo = Composites.updateNew( webUser, UserInfo.class ); +- userInfo.setConfirmationCode( Crypto.generateSessionToken( webUser.getUserName() ) ); + try { + NetworkGroupUtil.createUserNetworkRulesGroup( userInfo.getUserName( ), NetworkRulesGroup.NETWORK_DEFAULT_NAME, "default group" ); + } catch ( EucalyptusCloudException e1 ) { +--- a/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/server/EucalyptusWebBackendImpl.java ++++ b/clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/server/EucalyptusWebBackendImpl.java +@@ -69,6 +69,7 @@ + import com.eucalyptus.auth.Groups; + import com.eucalyptus.auth.UserInfo; + import com.eucalyptus.auth.Users; ++import com.eucalyptus.auth.crypto.Crypto; + import com.eucalyptus.auth.principal.User; + import com.eucalyptus.bootstrap.HttpServerBootstrapper; + import com.eucalyptus.component.Component; +@@ -131,6 +132,7 @@ + private static Properties props = new Properties(); + private static long session_timeout_ms = 1000 * 60 * 60 * 24 * 14L; /* 2 weeks (TODO: put into config?) */ + private static long pass_expiration_ms = 1000 * 60 * 60 * 24 * 365L; /* 1 year (TODO: put into config?) */ ++ private static long recovery_expiration_ms = 1000 * 60 * 30; // 30 minutes (TODO: put into config?) + + /* parameters to be read from config file */ + private static String thanks_for_signup; +@@ -287,6 +289,7 @@ + SessionInfo session = verifySession (sessionId); + UserInfoWeb requestingUser = verifyUser (session, session.getUserId(), true); + if ( !requestingUser.isAdministrator().booleanValue()) { ++ user.setAdministrator(false); // in case someone is trying to be sneaky + throw new SerializableException("Administrative privileges required"); + } else { + admin = true; +@@ -296,6 +299,7 @@ + /* add the user */ + long now = System.currentTimeMillis(); + user.setPasswordExpires( new Long(now + pass_expiration_ms) ); ++ user.setConfirmationCode( Crypto.generateSessionToken( user.getUserName() ) ); + EucalyptusManagement.addWebUser(user); + + String response; +@@ -316,7 +320,7 @@ + return response; + } + +- private String notifyUserRecovery(UserInfoWeb user) ++ private void notifyUserRecovery(UserInfoWeb user) + { + try { + String http_eucalyptus = ServletUtils.getRequestUrl(getThreadLocalRequest()); +@@ -337,10 +341,7 @@ + LOG.error ("Confirmation code for user '" + user.getUserName() + + "' and address " + user.getEmail() + + " is " + user.getConfirmationCode()); +- +- return "Internal problem (failed to notify " + user.getEmail() + " by email)"; + } +- return "Notified '" + user.getUserName() + "' by email, thank you."; + } + + public String recoverPassword ( UserInfoWeb web_user ) +@@ -350,17 +351,43 @@ + throw new SerializableException("Invalid RPC arguments"); + } + +- UserInfoWeb db_user; +- try { +- /* try login first */ +- db_user = EucalyptusManagement.getWebUser(web_user.getUserName()); +- } catch (Exception e) { +- /* try email then */ +- db_user = EucalyptusManagement.getWebUserByEmail(web_user.getEmail()); ++ String response; ++ if (web_user.getPassword()==null) { // someone is initiating password recovery ++ try { ++ UserInfoWeb db_user = EucalyptusManagement.getWebUser(web_user.getUserName()); ++ if (db_user.getEmail().equalsIgnoreCase(web_user.getEmail())) { ++ long expires = System.currentTimeMillis() + recovery_expiration_ms; ++ db_user.setConfirmationCode(String.format("%015d", expires) + Crypto.generateSessionToken( db_user.getUserName() ) ); ++ EucalyptusManagement.commitWebUser(db_user); ++ notifyUserRecovery(db_user); ++ } ++ } catch (Exception e) { } // pretend all is well regardless of the outcome ++ response = "Please, check your email for further instructions."; ++ ++ } else { // someone is trying to change the password ++ String code = web_user.getConfirmationCode(); ++ if (code==null) { ++ throw new SerializableException("Insufficient parameters"); ++ } ++ UserInfoWeb db_user; ++ try { ++ db_user = EucalyptusManagement.getWebUserByCode(code); ++ long expires = Long.parseLong(code.substring(0, 15)); ++ long now = System.currentTimeMillis(); ++ if (now > expires) { ++ throw new SerializableException("Recovery attempt expired"); ++ } ++ db_user.setConfirmationCode("-unset-"); // so the code cannot be reused ++ db_user.setPassword (web_user.getPassword()); ++ db_user.setPasswordExpires( new Long(now + pass_expiration_ms) ); ++ EucalyptusManagement.commitWebUser(db_user); ++ } catch (Exception e) { ++ throw new SerializableException("Incorrect code"); ++ } ++ ++ response = "Your password has been reset."; + } +- db_user.setPassword (web_user.getPassword()); +- EucalyptusManagement.commitWebUser(db_user); +- return notifyUserRecovery(db_user); ++ return response; + } + + /* ensure the sessionId is (still) valid */ +@@ -503,22 +530,19 @@ + if (action.equals("recover") || + action.equals("confirm")) { + UserInfoWeb user = EucalyptusManagement.getWebUserByCode(param); +- String response; ++ String response = "OK"; + + if (action.equals("confirm")) { + if ( user != null ) { + user.setConfirmed(true); +- } +- if (user != null) { ++ user.setConfirmationCode("-unset-"); // so the code cannot be reused + EucalyptusManagement.commitWebUser(user); + } + response = "Your account is now active."; +- } else { +- if (user != null) { +- user.setPassword (user.getPassword()); +- long now = System.currentTimeMillis(); +- user.setPasswordExpires( new Long(now + pass_expiration_ms) ); +- EucalyptusManagement.commitWebUser(user); ++ ++ } else if (action.equals("recover")) { // this is just a way to verify that the code is valid (TODO: remove?) ++ if (user == null) { ++ throw new SerializableException("Invalid code"); + } + response = "Your password has been reset."; + } +@@ -702,31 +726,42 @@ + && ! callerRecord.getUserName().equals(userName)) { + throw new SerializableException ("Operation restricted to owner and administrator"); + } +- +- // set expiration for admin setting password for the first time +- if (oldRecord.isAdministrator() && oldRecord.getEmail().equalsIgnoreCase(UserInfo.BOGUS_ENTRY)) { +- long now = System.currentTimeMillis(); +- oldRecord.setPasswordExpires( new Long(now + pass_expiration_ms) ); +- } +- +- /* TODO: Any checks? */ ++ ++ // only an admin should be able to change this settings ++ if (callerRecord.isAdministrator()) { ++ ++ // set password and expiration for admin when logging in for the first time ++ if (oldRecord.getEmail().equalsIgnoreCase(UserInfo.BOGUS_ENTRY)) { ++ long now = System.currentTimeMillis(); ++ oldRecord.setPasswordExpires( new Long(now + pass_expiration_ms) ); ++ oldRecord.setPassword (newRecord.getPassword()); ++ } ++ ++ // admin can reset pwd of another user, but ++ // to reset his own password he has to use ++ // "change password" functionality ++ if(!callerRecord.getUserName().equals(userName)) ++ oldRecord.setPassword (newRecord.getPassword()); ++ ++ if(oldRecord.isAdministrator() != newRecord.isAdministrator()) ++ oldRecord.setAdministrator(newRecord.isAdministrator()); ++ if(oldRecord.isEnabled() != newRecord.isEnabled()) ++ oldRecord.setEnabled(newRecord.isEnabled( )); ++ // once confirmed, cannot be unconfirmed; also, confirmation implies approval and enablement ++ if (!oldRecord.isConfirmed() && newRecord.isConfirmed()) { ++ oldRecord.setConfirmed(true); ++ oldRecord.setEnabled(true); ++ oldRecord.setApproved(true); ++ } ++ } ++ + oldRecord.setRealName (newRecord.getRealName()); + oldRecord.setEmail (newRecord.getEmail()); +- oldRecord.setPassword (newRecord.getPassword()); + oldRecord.setTelephoneNumber (newRecord.getTelephoneNumber()); + oldRecord.setAffiliation (newRecord.getAffiliation()); + oldRecord.setProjectDescription (newRecord.getProjectDescription()); + oldRecord.setProjectPIName (newRecord.getProjectPIName()); +- oldRecord.setAdministrator(newRecord.isAdministrator()); +- oldRecord.setEnabled(newRecord.isEnabled( )); +- +- // once confirmed, cannot be unconfirmed; also, confirmation implies approval and enablement +- if (!oldRecord.isConfirmed() && newRecord.isConfirmed()) { +- oldRecord.setConfirmed(true); +- oldRecord.setEnabled(true); +- oldRecord.setApproved(true); +- } +- ++ + EucalyptusManagement.commitWebUser( oldRecord ); + + return "Account of user '" + userName + "' was updated"; diff -Nru eucalyptus-2.0+bzr1241/debian/patches/series eucalyptus-2.0+bzr1241/debian/patches/series --- eucalyptus-2.0+bzr1241/debian/patches/series 2010-09-16 17:32:59.000000000 +0100 +++ eucalyptus-2.0+bzr1241/debian/patches/series 2010-11-19 17:27:11.000000000 +0000 @@ -13,3 +13,4 @@ 23-add-munin-monitor.patch 24-label-metadata-ip.patch 25-uec-logo-png.patch +26-confirm-password-change.patch