morristech
3/16/2018 - 9:09 AM

Protecting session sensitive responses with Retrofit 2 and okhttp 3

Protecting session sensitive responses with Retrofit 2 and okhttp 3

import java.net.SocketTimeoutException;

/** This exception extends {@link SocketTimeoutException} so that okhttp3 will not retry if retry is enabled. */
public class SessionMismatchException extends SocketTimeoutException {
    public SessionMismatchException() {
        super("Session Mismatch");
    }
}
import java.io.IOException;

import android.util.Log;

import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Call;

/**
 * Throw an exception for HTTP responses for invalidated sessions. This will end up calling the Retrofit 2 callback method:
 * 
 * @see retrofit2.Callback#onFailure(Call, Throwable)
 */
public class SessionSensitiveInterceptor implements okhttp3.Interceptor {

    private static final String TAG = SessionMismatchException.class.getSimpleName();

    private final SessionManager sessionManager;

    public SessionSensitiveInterceptor(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    /**
     * Catches the response and before sending it back, makes sure the same Authorization Token is still active.
     */
    @Override
    public Response intercept(Chain chain) throws IOException {
        final Request request = chain.request();

        // Execute Request Synchronously and pass through all other interceptors
        Response response = chain.proceed(request);

        // Request is complete, grab current session token to compare and block if it's changed, but shouldn't have.
        final String originalRequestAuthHeader = request.header("Authorization");
        final String currentSessionAuthHeader = sessionManager.getAuthorizationHeaderValue();
        if (originalRequestAuthHeader == null || originalRequestAuthHeader.length() == 0) {
            // Unauthenticated API, this is fine.
            return response;
        } else if (currentSessionAuthHeader != null && originalRequestAuthHeader.equals(currentSessionAuthHeader)) {
            // Authenticated API, same session is active, this is fine.
            return response;
        } else {
            // Authenticated API, but authorization header has changed. Send a custom exception to the failure handler.
            SessionMismatchException sessionMismatchException = new SessionMismatchException();
            Log.w(TAG, "Session Mismatch", new Exception());
            throw sessionMismatchException;
        }
    }
}