Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent overwriting trip/user internal fields #195

Merged
merged 8 commits into from
Nov 27, 2023
JymDyerIBI marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,14 @@ U preUpdateHook(U user, U preExistingUser, Request req) {
}

// Include select attributes from existingOtpUser marked @JsonIgnore and
// that are not set in otpUser.
// that are not set in otpUser, and other attributes that should not be modifiable
// using web requests.
otpUser.smsConsentDate = existingOtpUser.smsConsentDate;
otpUser.email = existingOtpUser.email;
otpUser.auth0UserId = existingOtpUser.auth0UserId;
otpUser.isDataToolsUser = existingOtpUser.isDataToolsUser;
otpUser.pushDevices = existingOtpUser.pushDevices;

}
return user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,22 @@ MonitoredTrip preUpdateHook(MonitoredTrip monitoredTrip, MonitoredTrip preExisti
MonitoredTripLocks.lockTripForUpdating(monitoredTrip, req);

try {
preCreateOrUpdateChecks(monitoredTrip, req);

// Forbid the editing of certain values that are analyzed and set during the CheckMonitoredTrip job.
// For now, accomplish this by setting whatever the previous itinerary and journey state were in the preExisting
// trip.
// These include the itinerary, journeyState, and fields initially computed via processTripQueryParams
// that we don't need to recalculate.
// Note: There is no need to re-check for monitorability because the itinerary field cannot be changed.
monitoredTrip.itinerary = preExisting.itinerary;
monitoredTrip.journeyState = preExisting.journeyState;

checkTripCanBeMonitored(monitoredTrip, req);
processTripQueryParams(monitoredTrip, req);

// TODO: Update itinerary existence record when updating a trip.
monitoredTrip.itineraryExistence = preExisting.itineraryExistence;
monitoredTrip.tripTime = preExisting.tripTime;
monitoredTrip.queryParams = preExisting.queryParams;
monitoredTrip.userId = preExisting.userId;
monitoredTrip.from = preExisting.from;
monitoredTrip.to = preExisting.to;
monitoredTrip.arriveBy = preExisting.arriveBy;

// TODO: Update itinerary existence record when updating a trip?
// (Currently, we let web requests change the monitored days regardless of existence.)

// perform the database update here before releasing the lock to be sure that the record is updated in the
// database before a CheckMonitoredTripJob analyzes the data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class MonitoredTrip extends Model {
* separately) to the date and time within the query parameters. The reasoning is so that it doesn't have to be
* extracted every time the trip requires checking.
*/
@JsonIgnore
public String tripTime;

/**
Expand All @@ -71,6 +72,7 @@ public class MonitoredTrip extends Model {
/**
* whether the trip is an arriveBy trip
*/
@JsonIgnore
public boolean arriveBy;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.auth0.exception.Auth0Exception;
import com.auth0.json.mgmt.users.User;
import com.mongodb.BasicDBObject;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.junit.jupiter.api.AfterAll;
Expand All @@ -21,9 +22,10 @@
import org.opentripplanner.middleware.utils.HttpResponseValues;
import org.opentripplanner.middleware.utils.JsonUtils;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.opentripplanner.middleware.auth.Auth0Connection.restoreDefaultAuthDisabled;
import static org.opentripplanner.middleware.auth.Auth0Connection.setAuthDisabled;
Expand Down Expand Up @@ -55,12 +57,14 @@ public class GetMonitoredTripsTest extends OtpMiddlewareTestEnvironment {
private static OtpUser multiOtpUser;
private static final String MONITORED_TRIP_PATH = "api/secure/monitoredtrip";

private static final String DUMMY_STRING = "ABCDxyz";

/**
* Create Otp and Admin user accounts. Create Auth0 account for just the Otp users. If
* an Auth0 account is created for the admin user it will fail because the email address already exists.
*/
@BeforeAll
public static void setUp() throws IOException {
public static void setUp() {
assumeTrue(IS_END_TO_END);
setAuthDisabled(false);

Expand Down Expand Up @@ -105,14 +109,20 @@ public static void tearDown() {
@AfterEach
public void tearDownAfterTest() {
OtpTestUtils.resetOtpMocks();
BasicDBObject soloFilter = new BasicDBObject();
soloFilter.put("userId", soloOtpUser.id);
Persistence.monitoredTrips.removeFiltered(soloFilter);
BasicDBObject multiFilter = new BasicDBObject();
multiFilter.put("userId", multiOtpUser.id);
Persistence.monitoredTrips.removeFiltered(multiFilter);
}

/**
* Create trips for two different Otp users and attempt to get both trips with Otp user that has 'enhanced' admin
* credentials.
*/
@Test
public void canGetOwnMonitoredTrips() throws Exception {
void canGetOwnMonitoredTrips() throws Exception {
// Create a trip for the solo and the multi OTP user.
createMonitoredTripAsUser(soloOtpUser);
createMonitoredTripAsUser(multiOtpUser);
Expand All @@ -122,6 +132,10 @@ public void canGetOwnMonitoredTrips() throws Exception {
// Expect only 1 trip for solo Otp user.
assertEquals(1, soloTrips.data.size());

// Certain fields such as tripTime should be null when obtained from parsing JSON responses
// because of the @JsonIgnore annotation.
assertNull(soloTrips.data.get(0).tripTime);

// Get trips for multi Otp user/admin user.
ResponseList<MonitoredTrip> multiTrips = getMonitoredTripsForUser(MONITORED_TRIP_PATH, multiOtpUser);

Expand All @@ -138,6 +152,48 @@ public void canGetOwnMonitoredTrips() throws Exception {
assertEquals(1, tripsFiltered.data.size());
}

@Test
void canPreserveTripFields() throws Exception {
// Create a trip for the solo OTP user.
createMonitoredTripAsUser(soloOtpUser);

BasicDBObject filter = new BasicDBObject();
filter.put("userId", soloOtpUser.id);

// Expect only 1 trip for solo Otp user.
assertEquals(1, Persistence.monitoredTrips.getCountFiltered(filter));

MonitoredTrip originalTrip = Persistence.monitoredTrips.getOneFiltered(filter);
assertNotNull(originalTrip.itinerary);
assertNotNull(originalTrip.itineraryExistence);
// Can't really assert journeyState because itinerary checks will not be run for these tests.
assertNotEquals(DUMMY_STRING, originalTrip.tripTime);
assertNotEquals(DUMMY_STRING, originalTrip.queryParams);
assertNotEquals(DUMMY_STRING, originalTrip.userId);
assertNotNull(originalTrip.from);
assertNotNull(originalTrip.to);

MonitoredTrip modifiedTrip = new MonitoredTrip();
modifiedTrip.id = originalTrip.id;
modifiedTrip.tripTime = DUMMY_STRING;
modifiedTrip.queryParams = DUMMY_STRING;
modifiedTrip.userId = DUMMY_STRING;

mockAuthenticatedRequest(MONITORED_TRIP_PATH,
JsonUtils.toJson(modifiedTrip),
soloOtpUser,
HttpMethod.PUT
);

MonitoredTrip updatedTrip = Persistence.monitoredTrips.getById(originalTrip.id);
assertEquals(updatedTrip.itinerary.startTime, originalTrip.itinerary.startTime);
assertEquals(updatedTrip.tripTime, originalTrip.tripTime);
assertEquals(updatedTrip.queryParams, originalTrip.queryParams);
assertEquals(updatedTrip.userId, originalTrip.userId);
assertEquals(updatedTrip.from.name, originalTrip.from.name);
assertEquals(updatedTrip.to.name, originalTrip.to.name);
}

/**
* Helper method to get trips for user.
*/
Expand Down
Loading