Skip to content

Commit 402b5b0

Browse files
committed
Exporter: Encoded URLs
- it is now possible to specify which exporters allow encrypted URL authorizations (by default, only the iCalendar exports are allowed) - this can be configured using the unitime.export.authorizeEncodedQueries application property - it is now possible to specify whether URL encoding is enabled for anonymous access i.e., when disabled, events pages that allow for anonymous access (such as Lookup Examinations) will provide an unencrypted iCalendar URL when the user is not authenticated - this can be configured using the unitime.encode.anonymous application property, defaults to false
1 parent 538d4ad commit 402b5b0

25 files changed

Lines changed: 70 additions & 27 deletions

JavaSource/org/unitime/timetable/defaults/ApplicationProperty.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ public enum ApplicationProperty {
299299
@DefaultValue("true")
300300
@Description("Configuration: hash calendar queries to make the iCalendar URL short")
301301
UrlEncoderHashQueryWhenAsked("unitime.encode.hash"),
302+
303+
@Type(Boolean.class)
304+
@DefaultValue("false")
305+
@Description("Configuration: allow URL encoding for anonymous access (e.g., Lookup Examinations page can provide encrypted/hashed export URLs even when used without authentication).")
306+
UrlEncoderAnonymousAccess("unitime.encode.anonymous"),
302307

303308
@Description("JAAS authentication modules (deprecated)")
304309
@Deprecated
@@ -3867,6 +3872,12 @@ public enum ApplicationProperty {
38673872
@Description("Online Student Scheduling: use left join fetch when loading offerings")
38683873
@Since(4.9)
38693874
EnrollmentPrefetchOfferings("unitime.enrollment.prefetchOfferings"),
3875+
3876+
@DefaultValue(".*\\.ics")
3877+
@Description("Exporter: for the encoded export queries (/export?q= or /export?x=), the exporter (output parameter) must match this regular expression for authorization. " +
3878+
"This means that for matching exports, it is assumed that the export is run by the user for whom the encoded query was generated. By default, only iCalendar exports are allowed.")
3879+
@Since(4.9)
3880+
ExportAuthorizeEncodedQueries("unitime.export.authorizeEncodedQueries")
38703881
;
38713882

38723883
String iKey;

JavaSource/org/unitime/timetable/events/QueryEncoderBackend.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.unitime.timetable.model.Roles;
4747
import org.unitime.timetable.model.dao.HashedQueryDAO;
4848
import org.unitime.timetable.security.SessionContext;
49+
import org.unitime.timetable.security.context.AnonymousUserContext;
4950

5051
/**
5152
* @author Tomas Muller
@@ -55,9 +56,13 @@ public class QueryEncoderBackend implements GwtRpcImplementation<EncodeQueryRpcR
5556

5657
@Override
5758
public EncodeQueryRpcResponse execute(EncodeQueryRpcRequest request, SessionContext context) {
59+
if (!ApplicationProperty.UrlEncoderAnonymousAccess.isTrue() && (!context.isAuthenticated() || context.getUser() instanceof AnonymousUserContext))
60+
return new EncodeQueryRpcResponse().setSource(request.getQuery());
5861
String query = request.getQuery() +
5962
(context.getUser() == null ? "&user=" : "&user=" + context.getUser().getExternalUserId() +
6063
(context.getUser() == null || context.getUser().getCurrentAuthority() == null ? "&role=" + Roles.ROLE_ANONYMOUS : "&role=" + context.getUser().getCurrentAuthority().getRole()));
64+
if (query == null || query.isEmpty())
65+
return new EncodeQueryRpcResponse().setSource(request.getQuery());
6166
if (request.isHash() && ApplicationProperty.UrlEncoderHashQueryWhenAsked.isTrue()) {
6267
return new EncodeQueryRpcResponse(encode(query), hash(query));
6368
} else {

JavaSource/org/unitime/timetable/export/ExportServletHelper.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public ExportServletHelper(HttpServletRequest request, HttpServletResponse respo
7777
if (token != null && ApplicationProperty.ApiCanUseAPIToken.isTrue()) {
7878
uc = ((ApiToken)SpringApplicationContextHolder.getBean("apiToken")).getContext(getParameter("token"));
7979
if (uc != null) iContext = new CustomExportContext(request.getSession(), uc);
80-
} else if (isRequestEncoded()) {
80+
} else if (isRequestEncoded() && canAuthorizeEncodedQueries()) {
8181
String[] user = getParameterValues("user");
8282
String[] role = getParameterValues("role");
8383
if (user != null && user.length == 1 && user[0] != null && !user[0].isEmpty() &&
@@ -251,6 +251,14 @@ public boolean isRequestEncoded() {
251251
return iParams instanceof QParams;
252252
}
253253

254+
public boolean canAuthorizeEncodedQueries() {
255+
String output = getParameter("output");
256+
String regexp = ApplicationProperty.ExportAuthorizeEncodedQueries.value();
257+
if (output == null || output.isEmpty()) return false;
258+
if (regexp == null || regexp.isEmpty()) return true;
259+
return output.matches(regexp);
260+
}
261+
254262
public class CustomExportContext extends HttpSessionContext {
255263
private UserContext iUser;
256264

JavaSource/org/unitime/timetable/gwt/client/admin/ScriptPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ public void onFailure(Throwable caught) {
742742
}
743743
@Override
744744
public void onSuccess(EncodeQueryRpcResponse result) {
745-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
745+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
746746
}
747747
});
748748
}

JavaSource/org/unitime/timetable/gwt/client/admin/SimpleEditPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2090,7 +2090,7 @@ public void onFailure(Throwable caught) {
20902090
}
20912091
@Override
20922092
public void onSuccess(EncodeQueryRpcResponse result) {
2093-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
2093+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
20942094
}
20952095
});
20962096
}

JavaSource/org/unitime/timetable/gwt/client/events/EventDetail.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ public void onClick(ClickEvent event) {
315315
public void onFailure(Throwable caught) {}
316316
@Override
317317
public void onSuccess(EncodeQueryRpcResponse result) {
318-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
318+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
319319
}
320320
});
321321
}
@@ -331,7 +331,7 @@ public void onClick(ClickEvent event) {
331331
public void onFailure(Throwable caught) {}
332332
@Override
333333
public void onSuccess(EncodeQueryRpcResponse result) {
334-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
334+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
335335
}
336336
});
337337
}

JavaSource/org/unitime/timetable/gwt/client/events/EventResourceTimetable.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ public void onFailure(Throwable caught) {
14601460
}
14611461
@Override
14621462
public void onSuccess(EncodeQueryRpcResponse result) {
1463-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
1463+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
14641464
}
14651465
});
14661466
}
@@ -1487,7 +1487,7 @@ public void onSuccess(final EncodeQueryRpcResponse result) {
14871487
ta.setStyleName("unitime-TextArea");
14881488
ta.setVisibleLines(5);
14891489
ta.setCharacterWidth(80);
1490-
ta.setText(GWT.getHostPageBaseURL() + (result.hasHash() ? "export?x=" + result.getHash() : "export?q=" + result.getQuery()));
1490+
ta.setText(GWT.getHostPageBaseURL() + result.getExportUrl());
14911491
UniTimeWidget<TextArea> w = new UniTimeWidget<TextArea>(ta);
14921492
Roles.getTextboxRole().setAriaLabelProperty(ta.getElement(), MESSAGES.opExportICalendar());
14931493
w.setHint(MESSAGES.hintCtrlCToCopy());
@@ -1502,7 +1502,7 @@ public void onSuccess(final EncodeQueryRpcResponse result) {
15021502
h.addButton("download", MESSAGES.buttonDownload(), new ClickHandler() {
15031503
@Override
15041504
public void onClick(ClickEvent event) {
1505-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
1505+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
15061506
dialog.hide();
15071507
}
15081508
});

JavaSource/org/unitime/timetable/gwt/client/hql/SavedHQLPage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ public void onFailure(Throwable caught) {
398398
}
399399
@Override
400400
public void onSuccess(EncodeQueryRpcResponse result) {
401-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
401+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
402402
}
403403
});
404404
}
@@ -456,7 +456,7 @@ public void onFailure(Throwable caught) {
456456
}
457457
@Override
458458
public void onSuccess(EncodeQueryRpcResponse result) {
459-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
459+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
460460
}
461461
});
462462
}
@@ -904,7 +904,7 @@ public void onFailure(Throwable caught) {
904904
}
905905
@Override
906906
public void onSuccess(EncodeQueryRpcResponse result) {
907-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
907+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
908908
}
909909
});
910910
}

JavaSource/org/unitime/timetable/gwt/client/instructor/InstructorAttributesPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ public void onFailure(Throwable caught) {
331331
}
332332
@Override
333333
public void onSuccess(EncodeQueryRpcResponse result) {
334-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
334+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
335335
}
336336
});
337337
}

JavaSource/org/unitime/timetable/gwt/client/instructor/TeachingAssignmentsPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ public void onFailure(Throwable caught) {
245245
}
246246
@Override
247247
public void onSuccess(EncodeQueryRpcResponse result) {
248-
ToolBox.open(GWT.getHostPageBaseURL() + "export?q=" + result.getQuery());
248+
ToolBox.open(GWT.getHostPageBaseURL() + result.getExportUrl());
249249
}
250250
});
251251
}

0 commit comments

Comments
 (0)