blob: e623a16b661ba98160729bb8b2d7841b7a17d91f [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* 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 org.opencord.aaa.impl;
import com.google.common.base.Charsets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.packet.BasePacket;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.EAP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.event.DefaultEventSinkRegistry;
import org.onosproject.event.Event;
import org.onosproject.event.EventDeliveryService;
import org.onosproject.event.EventSink;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.Annotations;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.Device;
import org.onosproject.net.Port;
import org.onosproject.net.SparseAnnotations;
import org.onosproject.net.Port.Type;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.NetworkConfigRegistryAdapter;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketService;
import org.opencord.aaa.AaaConfig;
import org.opencord.aaa.AaaSupplicantMachineStats;
import org.slf4j.Logger;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import static com.google.common.base.Preconditions.checkState;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.onosproject.net.NetTestTools.connectPoint;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Set of tests of the ONOS application component for AAA Statistics.
*/
public class AaaStatisticsTest extends AaaTestBase {
static final String BAD_IP_ADDRESS = "198.51.100.0";
static final Long ZERO = (long) 0;
private final Logger log = getLogger(getClass());
private AaaManager aaaManager;
private AaaStatisticsManager aaaStatisticsManager;
private AaaSupplicantMachineStatsManager aaaSupplicantStatsManager;
class AaaManagerWithoutRadiusServer extends AaaManager {
protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
super.sendRadiusPacket(radiusPacket, inPkt);
aaaManager.aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
savePacket(radiusPacket);
}
// changed the configuration of parent method to protected
protected void configureRadiusCommunication() {
PacketService pktService = new MockPacketService();
ApplicationId appId = new CoreServiceAdapter().registerApplication("org.opencord.aaa");
aaaManager.impl = new TestSocketBasedRadiusCommunicator(appId, pktService, aaaManager);
}
}
/**
* Mocks the AAAConfig class to force usage of an unroutable address for the
* RADIUS server.
*/
static class MockAaaConfig extends AaaConfig {
@Override
public InetAddress radiusIp() {
try {
return InetAddress.getByName(BAD_IP_ADDRESS);
} catch (UnknownHostException ex) {
throw new IllegalStateException(ex);
}
}
}
/**
* Mocks the network config registry.
*/
@SuppressWarnings("unchecked")
private static final class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
@Override
public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
AaaConfig aaaConfig = new MockAaaConfig();
return (C) aaaConfig;
}
}
public static class TestEventDispatcher extends DefaultEventSinkRegistry implements EventDeliveryService {
@Override
@SuppressWarnings("unchecked")
public synchronized void post(Event event) {
EventSink sink = getSink(event.getClass());
checkState(sink != null, "No sink for event %s", event);
sink.process(event);
}
@Override
public void setDispatchTimeLimit(long millis) {
}
@Override
public long getDispatchTimeLimit() {
return 0;
}
}
/**
* Constructs an Ethernet packet containing a RADIUS challenge packet.
*
* @param challengeCode
* code to use in challenge packet
* @param challengeType
* type to use in challenge packet
* @return Ethernet packet
*/
private RADIUS constructRadiusCodeAccessChallengePacket(byte challengeCode, byte challengeType) {
String challenge = "12345678901234567";
EAP eap = new EAP(challengeType, (byte) 4, challengeType,
challenge.getBytes(Charsets.US_ASCII));
eap.setIdentifier((byte) 4);
RADIUS radius = new RADIUS();
radius.setCode(challengeCode);
radius.setIdentifier((byte) 4);
radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
challenge.getBytes(Charsets.US_ASCII));
radius.setPayload(eap);
radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE,
eap.serialize());
radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH,
aaaManager.radiusSecret.getBytes());
return radius;
}
public static void injectEventDispatcher(Object manager, EventDeliveryService svc) {
Class mc = manager.getClass();
for (Field f : mc.getSuperclass().getDeclaredFields()) {
if (f.getType().equals(EventDeliveryService.class)) {
try {
TestUtils.setField(manager, f.getName(), svc);
} catch (TestUtils.TestUtilsException e) {
throw new IllegalArgumentException("Unable to inject reference", e);
}
break;
}
}
}
/**
* Set up the services required by the AAA application.
*/
@Before
public void setUp() {
aaaManager = new AaaManagerWithoutRadiusServer();
aaaManager.radiusOperationalStatusService = new RadiusOperationalStatusManager();
aaaManager.netCfgService = new TestNetworkConfigRegistry();
aaaManager.coreService = new CoreServiceAdapter();
aaaManager.packetService = new MockPacketService();
aaaManager.deviceService = new TestDeviceService();
aaaManager.sadisService = new MockSadisService();
aaaManager.cfgService = new MockCfgService();
aaaStatisticsManager = new AaaStatisticsManager();
aaaSupplicantStatsManager = new AaaSupplicantMachineStatsManager();
TestUtils.setField(aaaStatisticsManager, "eventDispatcher", new TestEventDispatcher());
aaaStatisticsManager.activate();
TestUtils.setField(aaaSupplicantStatsManager, "eventDispatcher", new TestEventDispatcher());
aaaSupplicantStatsManager.activate();
aaaManager.aaaStatisticsManager = this.aaaStatisticsManager;
aaaManager.aaaSupplicantStatsManager = this.aaaSupplicantStatsManager;
TestUtils.setField(aaaManager, "eventDispatcher", new TestEventDispatcher());
aaaManager.activate(new AaaTestBase.MockComponentContext());
}
/**
* Tear down the AAA application.
*/
@After
public void tearDown() {
aaaManager.deactivate(new AaaTestBase.MockComponentContext());
}
/**
* Extracts the RADIUS packet from a packet sent by the supplicant.
*
* @param radius
* RADIUS packet sent by the supplicant
* @throws DeserializationException
* if deserialization of the packet contents fails.
*/
private void checkRadiusPacketFromSupplicant(RADIUS radius) throws DeserializationException {
assertThat(radius, notNullValue());
EAP eap = radius.decapsulateMessage();
assertThat(eap, notNullValue());
}
/**
* Fetches the sent packet at the given index. The requested packet must be the
* last packet on the list.
*
* @param index
* index into sent packets array
* @return packet
*/
private BasePacket fetchPacket(int index) {
BasePacket packet = savedPackets.get(index);
assertThat(packet, notNullValue());
return packet;
}
/** Tests the authentication path through the AAA application.
* And counts the aaa Stats for successful transmission.
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testAaaStatisticsForAcceptedPackets() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
Ethernet responsePacket = (Ethernet) fetchPacket(0);
checkRadiusPacket(aaaManager, responsePacket, EAP.ATTR_IDENTITY);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
assertThat(radiusIdentifyPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
assertThat(new String(radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()),
is("testuser"));
IpAddress nasIp = IpAddress.valueOf(IpAddress.Version.INET,
radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP).getValue());
assertThat(nasIp.toString(), is(aaaManager.nasIpAddress.getHostAddress()));
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
// (3) RADIUS MD5 challenge
RADIUS radiusCodeAccessChallengePacket = constructRadiusCodeAccessChallengePacket(
RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5);
aaaManager.handleRadiusPacket(radiusCodeAccessChallengePacket);
Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2);
checkRadiusPacket(aaaManager, radiusChallengeMD5Packet, EAP.ATTR_MD5);
// (4) Supplicant MD5 response
Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(stateMachine, EAP.ATTR_MD5,
stateMachine.challengeIdentifier(), radiusChallengeMD5Packet);
sendPacket(md5RadiusPacket);
RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3);
checkRadiusPacketFromSupplicant(responseMd5RadiusPacket);
assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 9));
assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
// State machine should be in pending state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
// (5) RADIUS Success
RADIUS successPacket =
constructRadiusCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS);
aaaManager.handleRadiusPacket((successPacket));
Ethernet supplicantSuccessPacket = (Ethernet) fetchPacket(4);
checkRadiusPacket(aaaManager, supplicantSuccessPacket, EAP.SUCCESS);
// State machine should be in authorized state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED));
//Check for increase of Stats
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolAuthSuccessTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolStartReqTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolTransRespNotNak(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapPktTxauthChooseEap(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getValidEapolFramesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolFramesTx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getReqEapFramesTx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getRequestIdFramesTx(), ZERO);
assertEquals(aaaStatisticsManager.getAaaStats().getInvalidBodyLength(), ZERO);
assertEquals(aaaStatisticsManager.getAaaStats().getInvalidPktType(), ZERO);
assertEquals(aaaStatisticsManager.getAaaStats().getPendingResSupp(), ZERO);
// Counts the aaa Statistics count and displays in the log
countAaaStatistics();
}
/** Tests invalid packets reaching AAA.
* And counts the aaa Stats for successful transmission.
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testStatisticsForInvalidPackets() throws Exception {
//Test Authenticator State Machine Status. Should be Pending
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
Ethernet responsePacket = (Ethernet) fetchPacket(0);
checkRadiusPacket(aaaManager, responsePacket, EAP.ATTR_IDENTITY);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
assertThat(radiusIdentifyPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
assertThat(new String(radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()),
is("testuser"));
IpAddress nasIp = IpAddress.valueOf(IpAddress.Version.INET,
radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP).getValue());
assertThat(nasIp.toString(), is(aaaManager.nasIpAddress.getHostAddress()));
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
// (3) RADIUS NAK challenge
RADIUS radiusCodeAccessChallengePacket = constructRadiusCodeAccessChallengePacket(
RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_NAK);
aaaManager.handleRadiusPacket(radiusCodeAccessChallengePacket);
Ethernet radiusChallengeNakPacket = (Ethernet) fetchPacket(2);
checkRadiusPacket(aaaManager, radiusChallengeNakPacket, EAP.ATTR_NAK);
// (4) Supplicant NAK response
Ethernet nakRadiusPacket = constructSupplicantIdentifyPacket(stateMachine, EAP.ATTR_NAK,
stateMachine.challengeIdentifier(), radiusChallengeNakPacket);
sendPacket(nakRadiusPacket);
//Statistic Should be increased.
assertNotEquals(aaaStatisticsManager.getAaaStats().getPendingResSupp(), ZERO);
//Test if packet with invalid eapol type recieved.
// Supplicant ASF Packet
Ethernet invalidPacket = constructSupplicantAsfPacket();
sendPacket(invalidPacket);
//Statistic Should be increased.
assertNotEquals(aaaStatisticsManager.getAaaStats().getInvalidPktType(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getAccessRequestsTx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getChallengeResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getDroppedResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getInvalidValidatorsRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getPendingRequests(), ZERO);
// Counts the aaa Statistics count and displays in the log
countAaaStatistics();
}
/** Tests the count for defected packets.
*
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testAaaStatisticsForDefectivePackets() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
// Calling the mock test socket based to handle packet
aaaManager.impl.handlePacketFromServer(null);
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
// (3) RADIUS MD5 challenge
RADIUS radiusCodeAccessChallengePacket = constructRadiusCodeAccessChallengePacket(
RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5);
aaaManager.handleRadiusPacket(radiusCodeAccessChallengePacket);
Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2);
// (4) Supplicant MD5 response
Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(stateMachine, EAP.ATTR_MD5,
stateMachine.challengeIdentifier(), radiusChallengeMD5Packet);
sendPacket(md5RadiusPacket);
aaaManager.aaaStatisticsManager.calculatePacketRoundtripTime();
// (5) RADIUS Rejected
RADIUS rejectedPacket =
constructRadiusCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_REJECT, EAP.FAILURE);
aaaManager.handleRadiusPacket((rejectedPacket));
Ethernet supplicantRejectedPacket = (Ethernet) fetchPacket(4);
checkRadiusPacket(aaaManager, supplicantRejectedPacket, EAP.FAILURE);
// State machine should be in unauthorized state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_UNAUTHORIZED));
// Calculated the total round trip time
aaaManager.aaaStatisticsManager.calculatePacketRoundtripTime();
//Check for increase of Stats
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolAuthFailureTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolStartReqTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapPktTxauthChooseEap(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolTransRespNotNak(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getAccessRequestsTx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getChallengeResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getDroppedResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getInvalidValidatorsRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getPendingRequests(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getRejectResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getRequestRttMilis(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getUnknownTypeRx(), ZERO);
// Counts the aaa Statistics count
countAaaStatistics();
}
/*
* Tests the retransmitted packet and malformed packet count
*
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testRequestRetransmittedCount() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
// again creating pending state for same packet
constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
aaaManager.impl.handlePacketFromServer(null);
aaaManager.aaaStatisticsManager.calculatePacketRoundtripTime();
// creating malformed packet
final ByteBuffer byteBuffer = ByteBuffer.wrap(startPacket.serialize());
InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
startPacket, byteBuffer);
PacketContext context = new TestPacketContext(127L, inPacket, null, false);
aaaManager.impl.handlePacketFromServer(context);
// Check for increase of Stats
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolStartReqTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getAccessRequestsTx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getDroppedResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getPendingRequests(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getMalformedResponsesRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getRequestReTx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getRequestRttMilis(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getUnknownTypeRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getUnknownServerRx(), ZERO);
countAaaStatistics();
}
/** Tests the authentication path through the AAA application.
* And counts the aaa Stats for logoff transactionXZ.
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testAaaStatisticsForLogoffPackets() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
Ethernet responsePacket = (Ethernet) fetchPacket(0);
checkRadiusPacket(aaaManager, responsePacket, EAP.ATTR_IDENTITY);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
assertThat(radiusIdentifyPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
assertThat(new String(radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()),
is("testuser"));
IpAddress nasIp = IpAddress.valueOf(IpAddress.Version.INET,
radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP).getValue());
assertThat(nasIp.toString(), is(aaaManager.nasIpAddress.getHostAddress()));
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
// (3) RADIUS MD5 challenge
RADIUS radiusCodeAccessChallengePacket = constructRadiusCodeAccessChallengePacket(
RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5);
aaaManager.handleRadiusPacket(radiusCodeAccessChallengePacket);
Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2);
checkRadiusPacket(aaaManager, radiusChallengeMD5Packet, EAP.ATTR_MD5);
// (4) Supplicant MD5 response
Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(stateMachine, EAP.ATTR_MD5,
stateMachine.challengeIdentifier(), radiusChallengeMD5Packet);
sendPacket(md5RadiusPacket);
RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3);
checkRadiusPacketFromSupplicant(responseMd5RadiusPacket);
assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 9));
assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
// State machine should be in pending state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
// (5) RADIUS Success
RADIUS successPacket =
constructRadiusCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS);
aaaManager.handleRadiusPacket((successPacket));
Ethernet supplicantSuccessPacket = (Ethernet) fetchPacket(4);
checkRadiusPacket(aaaManager, supplicantSuccessPacket, EAP.SUCCESS);
// State machine should be in authorized state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED));
// Supplicant trigger EAP Logoff
Ethernet loggoffPacket = constructSupplicantLogoffPacket();
sendPacket(loggoffPacket);
// State machine should be in logoff state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_IDLE));
//Check for increase in stats
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolLogoffRx(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolAuthSuccessTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolStartReqTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolTransRespNotNak(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapPktTxauthChooseEap(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getAuthStateIdle(), ZERO);
// Counts the aaa Statistics count
countAaaStatistics();
}
/** Tests the authentication path through the AAA application.
* And counts the aaa Stats for timeout.
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testAaaStatisticsForTimeoutPackets() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
Ethernet responsePacket = (Ethernet) fetchPacket(0);
checkRadiusPacket(aaaManager, responsePacket, EAP.ATTR_IDENTITY);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
assertThat(radiusIdentifyPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
assertThat(new String(radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()),
is("testuser"));
IpAddress nasIp = IpAddress.valueOf(IpAddress.Version.INET,
radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP).getValue());
assertThat(nasIp.toString(), is(aaaManager.nasIpAddress.getHostAddress()));
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
Thread.sleep((aaaManager.cleanupTimerTimeOutInMins / 2) + 1);
// State machine should be in timeout state
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
//Check for increase in stats
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans(), ZERO);
assertNotEquals(aaaStatisticsManager.getAaaStats().getEapolStartReqTrans(), ZERO);
countAaaStatistics();
}
/** Tests the authentication path through the AAA application.
* And counts the aaa Stats for logoff transactionXZ.
* @throws DeserializationException
* if packed deserialization fails.
*/
@Test
public void testAaaSuplicantStatsForEapolLogOff() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
Ethernet responsePacket = (Ethernet) fetchPacket(0);
checkRadiusPacket(aaaManager, responsePacket, EAP.ATTR_IDENTITY);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
// (3) RADIUS MD5 challenge
RADIUS radiusCodeAccessChallengePacket = constructRadiusCodeAccessChallengePacket(
RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5);
aaaManager.handleRadiusPacket(radiusCodeAccessChallengePacket);
Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2);
checkRadiusPacket(aaaManager, radiusChallengeMD5Packet, EAP.ATTR_MD5);
// (4) Supplicant MD5 response
Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(stateMachine, EAP.ATTR_MD5,
stateMachine.challengeIdentifier(), radiusChallengeMD5Packet);
sendPacket(md5RadiusPacket);
RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3);
checkRadiusPacketFromSupplicant(responseMd5RadiusPacket);
// (5) RADIUS Success
RADIUS successPacket =
constructRadiusCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS);
aaaManager.handleRadiusPacket((successPacket));
Ethernet supplicantSuccessPacket = (Ethernet) fetchPacket(4);
checkRadiusPacket(aaaManager, supplicantSuccessPacket, EAP.SUCCESS);
// Supplicant trigger EAP Logoff
Ethernet loggoffPacket = constructSupplicantLogoffPacket();
sendPacket(loggoffPacket);
AaaSupplicantMachineStats aaaSupplicantObj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
// Check the aaa supplicant stats.
assertEquals(aaaSupplicantObj.getSessionTerminateReason(), "SUPPLICANT_LOGOFF");
assertEquals(aaaSupplicantObj.getEapolType(), "EAPOL_LOGOFF");
assertNotEquals(aaaSupplicantObj.getSessionDuration(), 0);
assertEquals(aaaSupplicantObj.getSessionName(), "testuser");
assertEquals(aaaSupplicantObj.getSessionId(), SESSION_ID);
assertEquals(aaaSupplicantObj.getSrcMacAddress(), serverMac.toString());
assertNotEquals(aaaSupplicantObj.getTotalFramesReceived(), 0);
assertNotEquals(aaaSupplicantObj.getTotalFramesSent(), 0);
assertNotEquals(aaaSupplicantObj.getTotalPacketsRecieved(), 0);
assertNotEquals(aaaSupplicantObj.getTotalPacketsSent(), 0);
}
/** Tests the aaa supplicant stats through the AAA application.
* For authenticated onu (Port removed)
* @throws Exception
*/
@Test
public void testAaaSuplicantStatsForPortRemoved() throws Exception {
// (1) Supplicant start up
Ethernet startPacket = constructSupplicantStartPacket();
sendPacket(startPacket);
Ethernet responsePacket = (Ethernet) fetchPacket(0);
checkRadiusPacket(aaaManager, responsePacket, EAP.ATTR_IDENTITY);
// (2) Supplicant identify
Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
checkRadiusPacketFromSupplicant(radiusIdentifyPacket);
// State machine should have been created by now
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder()
.set(AnnotationKeys.MANAGEMENT_ADDRESS, SOURCE_IP.toString());
SparseAnnotations annotations = annotationsBuilder.build();
Annotations[] deviceAnnotations = {annotations };
Device deviceA = new DefaultDevice(null, DEVICE_ID, Device.Type.OTHER, "", "", "", "", null, deviceAnnotations);
Port port =
new DefaultPort(null, PORT_A, true, Type.COPPER, DefaultPort.DEFAULT_SPEED, annotations);
DeviceEvent deviceEvent = new DeviceEvent(DeviceEvent.Type.PORT_REMOVED, deviceA, port);
aaaManager.deviceListener.event(deviceEvent);
AaaSupplicantMachineStats aaaSupplicantObj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
// Check the aaa supplicant stats.
assertEquals(aaaSupplicantObj.getSessionTerminateReason(), "PORT_REMOVED");
assertEquals(aaaSupplicantObj.getEapolType(), "EAPOL_PACKET");
assertNotEquals(aaaSupplicantObj.getSessionDuration(), 0);
assertEquals(aaaSupplicantObj.getSessionName(), "testuser");
assertEquals(aaaSupplicantObj.getSessionId(), SESSION_ID);
assertEquals(aaaSupplicantObj.getSrcMacAddress(), serverMac.toString());
assertEquals(aaaSupplicantObj.getTotalFramesReceived(), 0);
assertEquals(aaaSupplicantObj.getTotalFramesSent(), 0);
assertEquals(aaaSupplicantObj.getTotalPacketsRecieved(), 0);
assertEquals(aaaSupplicantObj.getTotalPacketsSent(), 0);
}
// Test AAA supplicant Stats for unauthenticated onu (Port removed)
@Test
public void testAaaSuplicantStatsForUnauthenticatedOnu() throws Exception {
DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder()
.set(AnnotationKeys.MANAGEMENT_ADDRESS, SOURCE_IP.toString());
SparseAnnotations annotations = annotationsBuilder.build();
Annotations[] deviceAnnotations = {annotations };
Device deviceA = new DefaultDevice(null, DEVICE_ID, Device.Type.OTHER, "", "", "", "", null, deviceAnnotations);
Port port =
new DefaultPort(null, PORT_A, true, Type.COPPER, DefaultPort.DEFAULT_SPEED, annotations);
DeviceEvent deviceEvent = new DeviceEvent(DeviceEvent.Type.PORT_REMOVED, deviceA, port);
aaaManager.deviceListener.event(deviceEvent);
// State machine will not be created.
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(SESSION_ID);
// Check the state machine is null. As state machine is null aaaSuplicantObj is null.
assertNull(stateMachine);
}
// Calculates the AAA statistics count.
public void countAaaStatistics() {
assertThat(aaaStatisticsManager.getAaaStats().getAcceptResponsesRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getAccessRequestsTx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getChallengeResponsesRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getDroppedResponsesRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getInvalidValidatorsRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getMalformedResponsesRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getPendingRequests(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getRejectResponsesRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getRequestReTx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getRequestRttMilis(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getUnknownServerRx(), notNullValue());
assertThat(aaaStatisticsManager.getAaaStats().getUnknownTypeRx(), notNullValue());
}
/*
* Mock implementation of SocketBasedRadiusCommunicator class.
*
*/
class TestSocketBasedRadiusCommunicator extends SocketBasedRadiusCommunicator {
TestSocketBasedRadiusCommunicator(ApplicationId appId, PacketService pktService, AaaManager aaaManager) {
super(appId, pktService, aaaManager);
}
/**
* Wait 10 millis to simulate a non 0 rtt.
*
* @throws InterruptedException
*/
private void waitPacket() throws InterruptedException {
synchronized (this) {
this.wait(10);
}
}
// Implementation of socketBasedRadiusCommunicator--> run() method
public void handlePacketFromServer(PacketContext context) {
RADIUS incomingPkt = (RADIUS) fetchPacket(savedPackets.size() - 1);
try {
// wait a couple of millis to avoid rtt being 0
waitPacket();
if (context == null) {
aaaStatisticsManager.handleRoundtripTime(incomingPkt.getIdentifier());
aaaManager.handleRadiusPacket(incomingPkt);
} else if (null != context) {
aaaManager.checkForPacketFromUnknownServer("100.100.100.0");
aaaStatisticsManager.handleRoundtripTime(incomingPkt.getIdentifier());
aaaManager.handleRadiusPacket(incomingPkt);
incomingPkt =
RADIUS.deserializer().deserialize(incomingPkt.generateAuthCode(), 0, 1);
}
} catch (DeserializationException dex) {
aaaManager.aaaStatisticsManager.getAaaStats().increaseMalformedResponsesRx();
aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
log.error("Cannot deserialize packet", dex);
} catch (StateMachineException sme) {
log.error("Illegal state machine operation", sme);
} catch (InterruptedException inte) {
Thread.currentThread().interrupt();
}
}
}
}