Skip to content

Commit ba17898

Browse files
authored
Merge pull request #128 from EUSurvey/ESURVEY-6660
Esurvey 6660
2 parents 6cd9f5b + 3610c78 commit ba17898

File tree

10 files changed

+132
-59
lines changed

10 files changed

+132
-59
lines changed

src/main/java/com/ec/survey/controller/AddressBookController.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ec.survey.controller;
22

3+
import com.ec.survey.exception.ForbiddenURLException;
34
import com.ec.survey.exception.MessageException;
45
import com.ec.survey.model.Paging;
56
import com.ec.survey.model.ParticipationGroup;
@@ -70,7 +71,6 @@ public class AddressBookController extends BasicController {
7071
@SuppressWarnings("unchecked")
7172
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
7273
public ModelAndView attendees(HttpServletRequest request) throws Exception {
73-
7474
User user = sessionService.getCurrentUser(request);
7575
int ownerId;
7676
if (user.getGlobalPrivileges().get(GlobalPrivilege.ContactManagement) == 2)
@@ -132,9 +132,7 @@ public ModelAndView attendees(HttpServletRequest request) throws Exception {
132132

133133
if (request.getParameter("added") != null)
134134
{
135-
Attendee addedContact = attendeeService.get(Integer.parseInt(request.getParameter("added")));
136135
result.addObject("added", true);
137-
result.addObject("addedContact", addedContact);
138136
} else if (request.getParameter("edited") != null && request.getParameter("edited").length() > 0)
139137
{
140138
if (!request.getParameter("edited").equalsIgnoreCase("batch"))
@@ -1316,12 +1314,9 @@ public String delete(@RequestParam("id") String id, HttpServletRequest request)
13161314
@SuppressWarnings("unchecked")
13171315
@RequestMapping( value = "/editAttendee/{id}", method = {RequestMethod.GET, RequestMethod.HEAD})
13181316
public ModelAndView edit(@PathVariable("id") String id, HttpServletRequest request) throws Exception {
1319-
13201317
Attendee attendee = attendeeService.get(Integer.parseInt(id));
1321-
13221318
Paging<Attendee> paging = (Paging<Attendee>) request.getSession().getAttribute("attendees-paging");
13231319
HashMap<String, String> filter = (HashMap<String, String>) request.getSession().getAttribute("attendees-filter");
1324-
13251320
User user = sessionService.getCurrentUser(request);
13261321

13271322
int ownerId;
@@ -1330,8 +1325,13 @@ public ModelAndView edit(@PathVariable("id") String id, HttpServletRequest reque
13301325
{
13311326
ownerId = -1;
13321327
} else {
1333-
ownerId = user.getId();
1334-
}
1328+
ownerId = user.getId();
1329+
if (attendee.getOwnerId() != ownerId) {
1330+
if (!attendeeService.getAccessibleAttendees(ownerId, null).contains(attendee.getId())) {
1331+
throw new ForbiddenURLException();
1332+
}
1333+
}
1334+
}
13351335

13361336
paging.setItems(attendeeService.getAttendees(ownerId, filter, paging.getCurrentPage(), paging.getItemsPerPage()));
13371337

src/main/java/com/ec/survey/controller/SettingsController.java

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ec.survey.controller;
22

3+
import com.ec.survey.exception.ForbiddenURLException;
34
import com.ec.survey.model.administration.GlobalPrivilege;
45
import com.ec.survey.model.administration.User;
56
import com.ec.survey.model.attendees.Attendee;
@@ -29,6 +30,7 @@
2930
import javax.servlet.http.HttpServletRequest;
3031
import javax.servlet.http.HttpServletResponse;
3132
import java.util.ArrayList;
33+
import java.util.Date;
3234
import java.util.HashMap;
3335
import java.util.List;
3436
import java.util.Locale;
@@ -48,7 +50,7 @@ public class SettingsController extends BasicController {
4850

4951
@Resource(name="attendeeService")
5052
private AttendeeService attendeeService;
51-
53+
5254
@Autowired private LocaleResolver localeResolver;
5355

5456
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
@@ -285,19 +287,42 @@ public ModelAndView shareEdit(@PathVariable String pid, HttpServletRequest reque
285287
}
286288

287289
@RequestMapping(value = "/userExists", headers="Accept=*/*", method=RequestMethod.GET)
288-
public @ResponseBody boolean userExists(HttpServletRequest request, HttpServletResponse response ) {
290+
public @ResponseBody boolean userExists(HttpServletRequest request, HttpServletResponse response )
291+
throws NotAgreedToTosException, WeakAuthenticationException, ForbiddenURLException {
289292
HashMap<String,String[]> parameters = Ucs2Utf8.requestToHashMap(request);
290-
291-
String login = parameters.get("login")[0];
292-
293-
User user;
294-
try {
295-
user = administrationService.getUserForLogin(login);
296-
} catch (Exception e) {
297-
return false;
293+
User userInRequest = sessionService.getCurrentUser(request);
294+
User user = administrationService.getUser(userInRequest.getId());
295+
Date now = new Date();
296+
Date lastAttemptMoment = new Date();
297+
if (user.getUserExistsAttemptDate() != null) {
298+
lastAttemptMoment = user.getUserExistsAttemptDate();
299+
} else {
300+
user.setUserExistsAttemptDate(now);
298301
}
299302

300-
return user != null;
303+
long lastAttemptMomentPlusOneHourLong = lastAttemptMoment.getTime() + 1000L * 60L * 60L;
304+
Date lastAttemptMomentPlusOneHour = new Date(lastAttemptMomentPlusOneHourLong);
305+
int numberOfAttemptsInOneHour = user.getUserExistsAttempts();
306+
if (now.after(lastAttemptMomentPlusOneHour)) {
307+
// reinit
308+
numberOfAttemptsInOneHour = 1;
309+
user.setUserExistsAttempts(numberOfAttemptsInOneHour);
310+
user.setUserExistsAttemptDate(now);
311+
} else {
312+
// adding
313+
numberOfAttemptsInOneHour += 1;
314+
user.setUserExistsAttempts(numberOfAttemptsInOneHour);
315+
if (numberOfAttemptsInOneHour > 30) {
316+
throw new ForbiddenURLException();
317+
// not saving the user since this would overload the Users table
318+
}
319+
}
320+
administrationService.updateUser(user);
321+
sessionService.setCurrentUser(request, user);
322+
323+
String login = parameters.get("login")[0];
324+
User searchedUser = administrationService.getUserForLogin(login);
325+
return searchedUser != null;
301326
}
302327

303328
@RequestMapping(value = "/createStaticShare", method = RequestMethod.POST)

src/main/java/com/ec/survey/model/administration/User.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public class User implements java.io.Serializable {
4646
private Date validationCodeGeneration;
4747
private List<String> departments = new ArrayList<>();
4848
private int badLoginAttempts = 0;
49+
private int userExistsAttempts = 0;
50+
private Date userExistsAttemptDate;
4951
private boolean agreedToToS;
5052
private Integer lastEditedSurvey;
5153
private boolean canCreateSurveys = true;
@@ -271,6 +273,22 @@ public int getBadLoginAttempts() {
271273
public void setBadLoginAttempts(Integer badLoginAttempts) {
272274
this.badLoginAttempts = badLoginAttempts != null ? badLoginAttempts : 0;
273275
}
276+
277+
@Column(name = "USER_EXISTS_ATTEMPS")
278+
public int getUserExistsAttempts() {
279+
return this.userExistsAttempts;
280+
}
281+
public void setUserExistsAttempts(Integer userExistsAttempts) {
282+
this.userExistsAttempts = userExistsAttempts != null ? userExistsAttempts : 0;
283+
}
284+
285+
@Column(name = "USER_EXISTS_ATTEMPT_DATE")
286+
public Date getUserExistsAttemptDate() {
287+
return userExistsAttemptDate;
288+
}
289+
public void setUserExistsAttemptDate(Date userExistsAttemptDate) {
290+
this.userExistsAttemptDate = userExistsAttemptDate;
291+
}
274292

275293
@Column(name = "USER_TOS")
276294
public boolean isAgreedToToS() {

src/main/java/com/ec/survey/service/AttendeeService.java

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -175,22 +175,38 @@ public int getNumberOfAttendees(Integer ownerId, HashMap<String, String> attribu
175175

176176
return ConversionTools.getValue(query.uniqueResult());
177177
}
178+
179+
@Transactional(readOnly = true)
180+
@SuppressWarnings("unchecked")
181+
public List<Integer> getAccessibleAttendees(Integer ownerId, HashMap<String,String> attributeFilter) throws Exception {
182+
Session session = sessionFactory.getCurrentSession();
183+
184+
HashMap<String, Object> parameters = new HashMap<>();
185+
String sql = getSql(session, ownerId, attributeFilter, parameters, false);
186+
187+
SQLQuery query = session.createSQLQuery("SELECT a.ATTENDEE_ID " + sql);
188+
sqlQueryService.setParameters(query, parameters);
189+
190+
@SuppressWarnings("rawtypes")
191+
List res = query.list();
192+
return res;
193+
}
178194

179-
private String getSql(Session session, Integer ownerId, Map<String, String> hashMap, HashMap<String, Object> oQueryParameters, boolean onlywritableshares) {
195+
private String getSql(Session session, Integer ownerId, Map<String, String> attributeFilter, HashMap<String, Object> oQueryParameters, boolean onlywritableshares) {
180196

181197
StringBuilder sql = new StringBuilder("FROM ATTENDEE a");
182198

183-
if (hashMap != null && hashMap.size() > 0)
199+
if (attributeFilter != null && attributeFilter.size() > 0)
184200
{
185-
for (String key : hashMap.keySet())
201+
for (String key : attributeFilter.keySet())
186202
{
187-
if (!key.equalsIgnoreCase("name") && !key.equalsIgnoreCase("email") && !key.equalsIgnoreCase("owner") && !key.equalsIgnoreCase("_csrf") && !key.startsWith("visibleAttendee") && hashMap.get(key) != null && hashMap.get(key).trim().length() > 0)
203+
if (!key.equalsIgnoreCase("name") && !key.equalsIgnoreCase("email") && !key.equalsIgnoreCase("owner") && !key.equalsIgnoreCase("_csrf") && !key.startsWith("visibleAttendee") && attributeFilter.get(key) != null && attributeFilter.get(key).trim().length() > 0)
188204
{
189205
sql.append(" LEFT OUTER JOIN ATTRIBUTE at ON at.ATTE_ID = a.ATTENDEE_ID ");
190206
break;
191207
}
192208
}
193-
if (hashMap.containsKey("owner") && hashMap.get("owner") != null && hashMap.get("owner").length() > 0)
209+
if (attributeFilter.containsKey("owner") && attributeFilter.get("owner") != null && attributeFilter.get("owner").length() > 0)
194210
{
195211
sql.append(" JOIN USERS u ON u.USER_ID = a.OWNER_ID ");
196212
}
@@ -212,15 +228,15 @@ private String getSql(Session session, Integer ownerId, Map<String, String> hash
212228

213229
sql.append(" AND a.ATTENDEE_HIDDEN IS NULL");
214230

215-
if (hashMap != null && hashMap.size() > 0)
231+
if (attributeFilter != null && attributeFilter.size() > 0)
216232
{
217233
int counter = 0;
218-
for (String key : hashMap.keySet())
234+
for (String key : attributeFilter.keySet())
219235
{
220236
if (!key.equalsIgnoreCase("name") && !key.equalsIgnoreCase("email") && !key.equalsIgnoreCase("owner"))
221237
try {
222238
int intKey = Integer.parseInt(key);
223-
String value = hashMap.get(key).trim();
239+
String value = attributeFilter.get(key).trim();
224240

225241
if (value.length() > 0)
226242
{
@@ -234,22 +250,22 @@ private String getSql(Session session, Integer ownerId, Map<String, String> hash
234250
}
235251
}
236252

237-
if (hashMap.containsKey("name") && hashMap.get("name") != null && hashMap.get("name").length() > 0)
253+
if (attributeFilter.containsKey("name") && attributeFilter.get("name") != null && attributeFilter.get("name").length() > 0)
238254
{
239255
sql.append(" AND a.ATTENDEE_NAME like :name");
240-
oQueryParameters.put("name", "%" + hashMap.get("name") + "%");
256+
oQueryParameters.put("name", "%" + attributeFilter.get("name") + "%");
241257
}
242258

243-
if (hashMap.containsKey("email") && hashMap.get("email") != null && hashMap.get("email").length() > 0)
259+
if (attributeFilter.containsKey("email") && attributeFilter.get("email") != null && attributeFilter.get("email").length() > 0)
244260
{
245261
sql.append(" AND a.ATTENDEE_EMAIL like :email");
246-
oQueryParameters.put("email", "%" + hashMap.get("email") + "%");
262+
oQueryParameters.put("email", "%" + attributeFilter.get("email") + "%");
247263
}
248264

249-
if (hashMap.containsKey("owner") && hashMap.get("owner") != null && hashMap.get("owner").length() > 0)
265+
if (attributeFilter.containsKey("owner") && attributeFilter.get("owner") != null && attributeFilter.get("owner").length() > 0)
250266
{
251267
sql.append(" AND (u.USER_DISPLAYNAME like :owner OR u.USER_LOGIN like :owner)");
252-
oQueryParameters.put("owner", "%" + hashMap.get("owner") + "%");
268+
oQueryParameters.put("owner", "%" + attributeFilter.get("owner") + "%");
253269
}
254270
}
255271

src/main/webapp/WEB-INF/classes/messages_en.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ error.nouserselected = Please select a user
142142
error.OwnerNotValid = The selected owner is not a valid user
143143
error.PasswordWeak = Please choose a password between 8 and 16 characters with at least one digit and one non-alphanumeric character (e.g. !?$%...).
144144
error.PleaseReload = There was a problem. Please reload the page.
145+
error.UsersTooOftenAddressBook = You have exceeded the number of contact edits you may perform per hour.
146+
error.UsersTooOftenShares = You have exceeded the number of shares you may perform per hour.
145147
error.RequestTranslation = Request for translation failed
146148
error.ResetCodeInvalid = You did not provide a valid password reset code!
147149
error.ResetCodeOutdated = This password reset code is not valid anymore! Please request a new one.

src/main/webapp/WEB-INF/views/addressbook/addressbook-batch.jsp

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,29 +89,31 @@
8989
</c:if>
9090

9191
<c:forEach items="${attributeNames}" var="attributeName">
92-
<tr>
93-
<td><esapi:encodeForHTML>${attributeName.name}</esapi:encodeForHTML><input type="hidden" class="existingbatchkey" value="<esapi:encodeForHTMLAttribute>${attributeName.name}</esapi:encodeForHTMLAttribute>" /></td>
94-
<td style="width: 250px;"><select class="form-control" onchange="checkAttributeSelection(this)"
95-
name="attribute<esapi:encodeForHTMLAttribute>${attributeName.id}</esapi:encodeForHTMLAttribute>">
96-
<option value="0" selected="selected">
97-
<spring:message code="label.KeepValue" />
98-
</option>
99-
<option value="-1">
100-
<spring:message code="label.ClearValue" />
101-
</option>
102-
<option value="-2">
103-
<spring:message code="label.NewValue" />
104-
</option>
105-
106-
<c:if test="${attributeValues.get(attributeName.id).size() > 0}">
107-
<option disabled="disabled">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</option>
108-
</c:if>
109-
110-
<c:forEach items="${attributeValues.get(attributeName.id)}" var="value">
111-
<option><esapi:encodeForHTML>${value}</esapi:encodeForHTML></option>
112-
</c:forEach>
113-
</select></td>
114-
</tr>
92+
<c:if test="${attributeName.name != 'Owner'}">
93+
<tr>
94+
<td><esapi:encodeForHTML>${attributeName.name}</esapi:encodeForHTML><input type="hidden" class="existingbatchkey" value="<esapi:encodeForHTMLAttribute>${attributeName.name}</esapi:encodeForHTMLAttribute>" /></td>
95+
<td style="width: 250px;"><select class="form-control" onchange="checkAttributeSelection(this)"
96+
name="attribute<esapi:encodeForHTMLAttribute>${attributeName.id}</esapi:encodeForHTMLAttribute>">
97+
<option value="0" selected="selected">
98+
<spring:message code="label.KeepValue" />
99+
</option>
100+
<option value="-1">
101+
<spring:message code="label.ClearValue" />
102+
</option>
103+
<option value="-2">
104+
<spring:message code="label.NewValue" />
105+
</option>
106+
107+
<c:if test="${attributeValues.get(attributeName.id).size() > 0}">
108+
<option disabled="disabled">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</option>
109+
</c:if>
110+
111+
<c:forEach items="${attributeValues.get(attributeName.id)}" var="value">
112+
<option><esapi:encodeForHTML>${value}</esapi:encodeForHTML></option>
113+
</c:forEach>
114+
</select></td>
115+
</tr>
116+
</c:if>
115117
</c:forEach>
116118

117119
</tbody>

src/main/webapp/WEB-INF/views/addressbook/addressbook.jsp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<script type="text/javascript" src="${contextpath}/resources/js/configure.js?version=<%@include file="../version.txt" %>"></script>
1717
<script type="text/javascript" src="${contextpath}/resources/js/jquery.stickytableheaders.js?version=<%@include file="../version.txt" %>"></script>
1818
<script type="text/javascript" src="${contextpath}/resources/js/fileuploader.js?version=<%@include file="../version.txt" %>"></script>
19+
<script type="text/javascript" src="${contextpath}/resources/js/menu.js?version=<%@include file="../version.txt" %>"></script>
1920

2021
<style>
2122
#sortable { list-style-type: none; margin: 0; padding: 0; width: 190px; }
@@ -35,6 +36,7 @@
3536

3637
<script type="text/javascript">
3738
var labelRemoveAttribute = '<spring:message code="label.RemoveAttribute" />';
39+
var usersTooOftenAddressBook = '<spring:message code="error.UsersTooOftenAddressBook" />';
3840
3941
$(function() {
4042
$("#addressbook-menu-tab").addClass("active");
@@ -881,7 +883,7 @@
881883

882884
<c:if test="${added != null}">
883885
<script type="text/javascript">
884-
showInfo('<spring:message code="label.Contact" />&nbsp;<esapi:encodeForHTML>${addedContact.name}</esapi:encodeForHTML>&nbsp;<spring:message code="message.AttendeeAdded" />');
886+
showInfo('<spring:message code="label.Contact" />&nbsp;<spring:message code="message.AttendeeAdded" />');
885887
</script>
886888
</c:if>
887889

src/main/webapp/WEB-INF/views/settings/shares.jsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<script type="text/javascript" src="${contextpath}/resources/js/shares.js?version=<%@include file="../version.txt" %>"></script>
1414

1515
<script type="text/javascript">
16+
var usersTooOftenShares = '<spring:message code="error.UsersTooOftenShares" />';
1617
$(function() {
1718
$("#settings-menu-tab").addClass("active");
1819
$("#shares-button").removeClass("InactiveLinkButton").addClass("ActiveLinkButton");

src/main/webapp/resources/js/addressbook.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -775,17 +775,21 @@ function checkOwnerAndSubmit()
775775
ok = false;
776776
}
777777
}
778-
778+
779779
if (owner != null && owner.trim().length > 0)
780780
{
781781
$.ajax({
782782
type:'GET',
783+
async: false,
783784
url: contextpath + "/settings/userExists",
784785
data: "login=" + owner,
785786
dataType: 'json',
786787
cache: false,
788+
error: function() {
789+
ok = false;
790+
showError(usersTooOftenAddressBook);
791+
},
787792
success: function( exists ) {
788-
789793
if (exists == true)
790794
{
791795
ok = true;

src/main/webapp/resources/js/shares.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,9 @@
441441
data: "login=" + recipient,
442442
dataType: 'json',
443443
cache: false,
444+
error: function() {
445+
showError(usersTooOftenShares);
446+
},
444447
success: function( exists ) {
445448

446449
if (exists == true)

0 commit comments

Comments
 (0)