Skip to content

Commit f3f335e

Browse files
committed
Added a readObject metod which reinitializes the clock to Clock.system upon deserialization.
1 parent 5900c61 commit f3f335e

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundary.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.google.common.base.MoreObjects;
5050
import com.google.common.base.Preconditions;
5151
import java.io.IOException;
52+
import java.io.ObjectInputStream;
5253
import java.io.Serializable;
5354
import java.util.Collections;
5455
import java.util.List;
@@ -76,7 +77,7 @@ public final class RegionalAccessBoundary implements Serializable {
7677
private final String encodedLocations;
7778
private final List<String> locations;
7879
private final long refreshTime;
79-
private final transient Clock clock;
80+
private transient Clock clock;
8081

8182
private static EnvironmentProvider environmentProvider = SystemEnvironmentProvider.getInstance();
8283

@@ -267,4 +268,13 @@ static RegionalAccessBoundary refresh(
267268
}
268269
return new RegionalAccessBoundary(encodedLocations, json.getLocations(), clock);
269270
}
271+
272+
/**
273+
* Initializes the transient clock to Clock.SYSTEM upon deserialization to prevent
274+
* NullPointerException when evaluating expiration on deserialized objects.
275+
*/
276+
private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
277+
input.defaultReadObject();
278+
clock = Clock.SYSTEM;
279+
}
270280
}

oauth2_http/javatests/com/google/auth/oauth2/RegionalAccessBoundaryTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
import com.google.api.client.testing.http.MockLowLevelHttpResponse;
4040
import com.google.api.client.util.Clock;
4141
import com.google.auth.http.HttpTransportFactory;
42+
import java.io.ByteArrayInputStream;
43+
import java.io.ByteArrayOutputStream;
44+
import java.io.ObjectInputStream;
45+
import java.io.ObjectOutputStream;
4246
import java.util.Collections;
4347
import java.util.concurrent.atomic.AtomicLong;
4448
import org.junit.After;
@@ -99,6 +103,30 @@ public void testShouldRefresh() {
99103
assertFalse(rab.isExpired());
100104
}
101105

106+
@Test
107+
public void testSerialization() throws Exception {
108+
long now = testClock.currentTimeMillis();
109+
RegionalAccessBoundary rab =
110+
new RegionalAccessBoundary("encoded", Collections.singletonList("loc"), now, testClock);
111+
112+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
113+
ObjectOutputStream oos = new ObjectOutputStream(baos);
114+
oos.writeObject(rab);
115+
oos.close();
116+
117+
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
118+
ObjectInputStream ois = new ObjectInputStream(bais);
119+
RegionalAccessBoundary deserializedRab = (RegionalAccessBoundary) ois.readObject();
120+
ois.close();
121+
122+
assertEquals("encoded", deserializedRab.getEncodedLocations());
123+
assertEquals(1, deserializedRab.getLocations().size());
124+
assertEquals("loc", deserializedRab.getLocations().get(0));
125+
// The transient clock field should be restored to Clock.SYSTEM upon deserialization,
126+
// thereby avoiding a NullPointerException when checking expiration.
127+
assertFalse(deserializedRab.isExpired());
128+
}
129+
102130
@Test
103131
public void testManagerTriggersRefreshInGracePeriod() throws InterruptedException {
104132
final String url =

0 commit comments

Comments
 (0)