diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/filters/SessionManager.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/filters/SessionManager.java index 07174e5611..7cfdb0253e 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/filters/SessionManager.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/filters/SessionManager.java @@ -101,12 +101,15 @@ public HttpRequest filter(HttpRequest request) throws HttpException { return builder.build(); } + private static final String IP_MISMATCH = "IP address does not match current session"; + @Override public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) { boolean retry = false; // default try { - if (response.getStatusCode() == 401) { - closeClientButKeepContentStream(response); + byte[] data = closeClientButKeepContentStream(response); + String message = data != null ? new String(data) : null; + if (response.getStatusCode() == 401 || (message != null && message.indexOf(IP_MISMATCH) != -1)) { logger.debug("invalidating session"); sessionCache.invalidateAll(); retry = super.shouldRetryRequest(command, response); diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/filters/SessionManagerTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/filters/SessionManagerTest.java index 66f25aea55..c80401e75b 100644 --- a/providers/dynect/src/test/java/org/jclouds/dynect/v3/filters/SessionManagerTest.java +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/filters/SessionManagerTest.java @@ -18,6 +18,8 @@ */ package org.jclouds.dynect.v3.filters; +import static com.google.common.io.Resources.getResource; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; import static org.easymock.EasyMock.createMock; @@ -30,6 +32,8 @@ import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; +import java.io.IOException; + import org.jclouds.domain.Credentials; import org.jclouds.dynect.v3.domain.Session; import org.jclouds.dynect.v3.domain.SessionCredentials; @@ -95,6 +99,34 @@ public void testUnauthorizedShouldInvalidateSessionAndRetry() { verify(creds, sessionCache, sessionApi, command); } + @SuppressWarnings("unchecked") + @Test + public void testIPMismatchShouldInvalidateSessionAndRetry() throws IOException { + HttpCommand command = createMock(HttpCommand.class); + Supplier creds = createMock(Supplier.class); + LoadingCache sessionCache = createMock(LoadingCache.class); + SessionApi sessionApi = createMock(SessionApi.class); + + sessionCache.invalidateAll(); + expectLastCall(); + expect(command.incrementFailureCount()).andReturn(1); + expect(command.isReplayable()).andReturn(true); + expect(command.getFailureCount()).andReturn(1).atLeastOnce(); + + replay(creds, sessionCache, sessionApi, command); + + HttpResponse response = HttpResponse.builder() + .statusCode(BAD_REQUEST.getStatusCode()) + .payload(getResource("ip_mismatch.json").openStream()) + .build(); + + SessionManager retry = new SessionManager(creds, sessionCache, sessionApi); + + assertTrue(retry.shouldRetryRequest(command, response)); + + verify(creds, sessionCache, sessionApi, command); + } + @SuppressWarnings("unchecked") @Test public void testForbiddenShouldNotInvalidateSessionOrRetry() { diff --git a/providers/dynect/src/test/resources/ip_mismatch.json b/providers/dynect/src/test/resources/ip_mismatch.json new file mode 100644 index 0000000000..1fdcb6b3f0 --- /dev/null +++ b/providers/dynect/src/test/resources/ip_mismatch.json @@ -0,0 +1,17 @@ +{ + "status": "failure", + "data": {}, + "job_id": 305900967, + "msgs": [{ + "INFO": "login: IP address does not match current session", + "SOURCE": "BLL", + "ERR_CD": "INVALID_DATA", + "LVL": "ERROR" + }, { + "INFO": "login: There was a problem with your credentials", + "SOURCE": "BLL", + "ERR_CD": null, + "LVL": "INFO" + } + ] +}