blob: 11d466150d25ab285bb99355b81f51dd94af9591 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ike.eap;
import static com.android.ike.TestUtils.hexStringToByteArray;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_FAILURE_PACKET;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_SIM_RESPONSE_PACKET;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_SUCCESS_PACKET;
import static com.android.ike.eap.message.EapTestMessageDefinitions.REQUEST_UNSUPPORTED_TYPE_PACKET;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.os.Looper;
import android.os.test.TestLooper;
import com.android.ike.eap.EapResult.EapError;
import com.android.ike.eap.EapResult.EapFailure;
import com.android.ike.eap.EapResult.EapResponse;
import com.android.ike.eap.EapResult.EapSuccess;
import com.android.ike.eap.exceptions.EapInvalidRequestException;
import com.android.ike.eap.statemachine.EapStateMachine;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.TimeoutException;
public class EapAuthenticatorTest {
private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
private static final long TEST_TIMEOUT_MILLIS = 2 * AUTHENTICATOR_TIMEOUT_MILLIS;
private static final byte[] MSK = hexStringToByteArray(
"00112233445566778899AABBCCDDEEFF"
+ "00112233445566778899AABBCCDDEEFF"
+ "00112233445566778899AABBCCDDEEFF"
+ "00112233445566778899AABBCCDDEEFF");
private static final byte[] EMSK = hexStringToByteArray(
"FFEEDDCCBBAA99887766554433221100"
+ "FFEEDDCCBBAA99887766554433221100"
+ "FFEEDDCCBBAA99887766554433221100"
+ "FFEEDDCCBBAA99887766554433221100");
private EapStateMachine mMockEapStateMachine;
private TestLooper mTestLooper;
private boolean mCallbackFired;
@Before
public void setUp() {
if (Looper.myLooper() == null) Looper.prepare();
mMockEapStateMachine = mock(EapStateMachine.class);
mTestLooper = new TestLooper();
mCallbackFired = false;
}
@Test
public void testProcessEapMessageResponse() {
EapCallback eapCallback = new EapCallback() {
@Override
public void onResponse(byte[] eapMsg) {
assertArrayEquals(EAP_SIM_RESPONSE_PACKET, eapMsg);
assertFalse("Callback has already been fired", mCallbackFired);
mCallbackFired = true;
}
};
EapResponse eapResponse = new EapResponse(EAP_SIM_RESPONSE_PACKET);
when(mMockEapStateMachine.process(eq(EAP_REQUEST_SIM_START_PACKET)))
.thenReturn(eapResponse);
getEapAuthenticatorWithCallback(eapCallback)
.processEapMessage(EAP_REQUEST_SIM_START_PACKET);
mTestLooper.dispatchAll();
assertTrue("Callback didn't fire", mCallbackFired);
verify(mMockEapStateMachine).process(eq(EAP_REQUEST_SIM_START_PACKET));
verifyNoMoreInteractions(mMockEapStateMachine);
}
@Test
public void testProcessEapMessageError() {
EapCallback eapCallback = new EapCallback() {
@Override
public void onError(Throwable cause) {
assertTrue(cause instanceof EapInvalidRequestException);
assertFalse("Callback has already been fired", mCallbackFired);
mCallbackFired = true;
}
};
Exception cause = new EapInvalidRequestException("Error");
EapError eapError = new EapError(cause);
when(mMockEapStateMachine.process(eq(REQUEST_UNSUPPORTED_TYPE_PACKET)))
.thenReturn(eapError);
getEapAuthenticatorWithCallback(eapCallback)
.processEapMessage(REQUEST_UNSUPPORTED_TYPE_PACKET);
mTestLooper.dispatchAll();
assertTrue("Callback didn't fire", mCallbackFired);
verify(mMockEapStateMachine).process(eq(REQUEST_UNSUPPORTED_TYPE_PACKET));
verifyNoMoreInteractions(mMockEapStateMachine);
}
@Test
public void testProcessEapMessageSuccess() {
EapCallback eapCallback = new EapCallback() {
@Override
public void onSuccess(byte[] msk, byte[] emsk) {
assertArrayEquals(MSK, msk);
assertArrayEquals(EMSK, emsk);
assertFalse("Callback has already been fired", mCallbackFired);
mCallbackFired = true;
}
};
EapSuccess eapSuccess = new EapSuccess(MSK, EMSK);
when(mMockEapStateMachine.process(eq(EAP_SUCCESS_PACKET)))
.thenReturn(eapSuccess);
getEapAuthenticatorWithCallback(eapCallback)
.processEapMessage(EAP_SUCCESS_PACKET);
mTestLooper.dispatchAll();
assertTrue("Callback didn't fire", mCallbackFired);
verify(mMockEapStateMachine).process(eq(EAP_SUCCESS_PACKET));
verifyNoMoreInteractions(mMockEapStateMachine);
}
@Test
public void testProcessEapMessageFailure() {
EapCallback eapCallback = new EapCallback() {
@Override
public void onFail() {
// nothing to check here
assertFalse("Callback has already been fired", mCallbackFired);
mCallbackFired = true;
}
};
when(mMockEapStateMachine.process(eq(EAP_FAILURE_PACKET)))
.thenReturn(new EapFailure());
getEapAuthenticatorWithCallback(eapCallback)
.processEapMessage(EAP_FAILURE_PACKET);
mTestLooper.dispatchAll();
assertTrue("Callback didn't fire", mCallbackFired);
verify(mMockEapStateMachine).process(eq(EAP_FAILURE_PACKET));
verifyNoMoreInteractions(mMockEapStateMachine);
}
@Test
public void testProcessEapMessageExceptionThrown() {
EapCallback eapCallback = new EapCallback() {
@Override
public void onError(Throwable cause) {
assertTrue(cause instanceof NullPointerException);
assertFalse("Callback has already been fired", mCallbackFired);
mCallbackFired = true;
}
};
when(mMockEapStateMachine.process(EAP_REQUEST_SIM_START_PACKET))
.thenThrow(new NullPointerException());
getEapAuthenticatorWithCallback(eapCallback)
.processEapMessage(EAP_REQUEST_SIM_START_PACKET);
mTestLooper.dispatchAll();
assertTrue("Callback didn't fire", mCallbackFired);
verify(mMockEapStateMachine).process(eq(EAP_REQUEST_SIM_START_PACKET));
verifyNoMoreInteractions(mMockEapStateMachine);
}
@Test
public void testProcessEapMessageStateMachineTimeout() {
EapCallback eapCallback = new EapCallback() {
@Override
public void onError(Throwable cause) {
assertTrue(cause instanceof TimeoutException);
assertFalse("Callback has already been fired", mCallbackFired);
mCallbackFired = true;
}
};
EapResponse eapResponse = new EapResponse(EAP_SIM_RESPONSE_PACKET);
when(mMockEapStateMachine.process(eq(EAP_REQUEST_SIM_START_PACKET)))
.then((invocation) -> {
// move time forward to trigger the timeout
mTestLooper.moveTimeForward(TEST_TIMEOUT_MILLIS);
return eapResponse;
});
getEapAuthenticatorWithCallback(eapCallback)
.processEapMessage(EAP_REQUEST_SIM_START_PACKET);
mTestLooper.dispatchAll();
assertTrue("Callback didn't fire", mCallbackFired);
verify(mMockEapStateMachine).process(eq(EAP_REQUEST_SIM_START_PACKET));
verifyNoMoreInteractions(mMockEapStateMachine);
}
private EapAuthenticator getEapAuthenticatorWithCallback(EapCallback eapCallback) {
return new EapAuthenticator(
mTestLooper.getLooper(),
eapCallback,
mMockEapStateMachine,
(runnable) -> runnable.run(),
AUTHENTICATOR_TIMEOUT_MILLIS);
}
/**
* Default {@link IEapCallback} implementation that throws {@link UnsupportedOperationException}
* for all calls.
*/
private abstract static class EapCallback implements IEapCallback {
@Override
public void onSuccess(byte[] msk, byte[] emsk) {
throw new UnsupportedOperationException();
}
@Override
public void onFail() {
throw new UnsupportedOperationException();
}
@Override
public void onResponse(byte[] eapMsg) {
throw new UnsupportedOperationException();
}
@Override
public void onError(Throwable cause) {
throw new UnsupportedOperationException();
}
}
}