[SEBA-593] Splitting aaa app in implementation and api bundles

Change-Id: Ib81650be0695258bdd1f4cd6131f2206760e0da6
diff --git a/app/src/main/java/org/opencord/aaa/impl/AaaManager.java b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
new file mode 100755
index 0000000..3e75f17
--- /dev/null
+++ b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
@@ -0,0 +1,689 @@
+/*
+ * Copyright 2017-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 static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.EAP;
+import org.onlab.packet.EAPOL;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.RADIUS;
+import org.onlab.packet.RADIUSAttribute;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.opencord.aaa.AaaConfig;
+import org.opencord.aaa.AuthenticationEvent;
+import org.opencord.aaa.AuthenticationEventListener;
+import org.opencord.aaa.AuthenticationService;
+import org.opencord.aaa.RadiusCommunicator;
+import org.opencord.aaa.StateMachineDelegate;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SadisService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.osgi.service.component.annotations.Activate;
+import org.slf4j.Logger;
+
+/**
+ * AAA application for ONOS.
+ */
+@Service
+@Component(immediate = true)
+public class AaaManager
+        extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
+        implements AuthenticationService {
+
+    private static final String APP_NAME = "org.opencord.aaa";
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry netCfgService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected SadisService sadisService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
+
+    protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
+
+    private final DeviceListener deviceListener = new InternalDeviceListener();
+
+    // NAS IP address
+    protected InetAddress nasIpAddress;
+
+    // self MAC address
+    protected String nasMacAddress;
+
+    // Parsed RADIUS server addresses
+    protected InetAddress radiusIpAddress;
+
+    // MAC address of RADIUS server or net hop router
+    protected String radiusMacAddress;
+
+    // RADIUS server secret
+    protected String radiusSecret;
+
+    // bindings
+    protected CustomizationInfo customInfo;
+
+    // our application-specific event handler
+    private ReactivePacketProcessor processor = new ReactivePacketProcessor();
+
+    // our unique identifier
+    private ApplicationId appId;
+
+    // Setup specific customization/attributes on the RADIUS packets
+    PacketCustomizer pktCustomizer;
+
+    // packet customizer to use
+    private String customizer;
+
+    // Type of connection to use to communicate with Radius server, options are
+    // "socket" or "packet_out"
+    private String radiusConnectionType;
+
+    // Object for the specific type of communication with the RADIUS
+    // server, socket based or packet_out based
+    RadiusCommunicator impl = null;
+
+    // latest configuration
+    AaaConfig newCfg;
+
+    // Configuration properties factory
+    private final ConfigFactory factory =
+            new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
+                                                         AaaConfig.class,
+                                                         "AAA") {
+                @Override
+                public AaaConfig createConfig() {
+                    return new AaaConfig();
+                }
+            };
+
+    // Listener for config changes
+    private final InternalConfigListener cfgListener = new InternalConfigListener();
+
+    private StateMachineDelegate delegate = new InternalStateMachineDelegate();
+
+    /**
+     * Builds an EAPOL packet based on the given parameters.
+     *
+     * @param dstMac    destination MAC address
+     * @param srcMac    source MAC address
+     * @param vlan      vlan identifier
+     * @param eapolType EAPOL type
+     * @param eap       EAP payload
+     * @return Ethernet frame
+     */
+    private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
+                                               short vlan, byte eapolType, EAP eap, byte priorityCode) {
+
+        Ethernet eth = new Ethernet();
+        eth.setDestinationMACAddress(dstMac.toBytes());
+        eth.setSourceMACAddress(srcMac.toBytes());
+        eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
+        if (vlan != Ethernet.VLAN_UNTAGGED) {
+            eth.setVlanID(vlan);
+            eth.setPriorityCode(priorityCode);
+        }
+        //eapol header
+        EAPOL eapol = new EAPOL();
+        eapol.setEapolType(eapolType);
+        eapol.setPacketLength(eap.getLength());
+
+        //eap part
+        eapol.setPayload(eap);
+
+        eth.setPayload(eapol);
+        eth.setPad(true);
+        return eth;
+    }
+
+    @Activate
+    public void activate() {
+        appId = coreService.registerApplication(APP_NAME);
+        eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
+        netCfgService.addListener(cfgListener);
+        netCfgService.registerConfigFactory(factory);
+        subsService = sadisService.getSubscriberInfoService();
+        customInfo = new CustomizationInfo(subsService, deviceService);
+        cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
+        log.info("Starting with config {} {}", this, newCfg);
+
+        configureRadiusCommunication();
+
+        // register our event handler
+        packetService.addProcessor(processor, PacketProcessor.director(2));
+
+
+        StateMachine.initializeMaps();
+        StateMachine.setDelegate(delegate);
+
+        impl.initializeLocalState(newCfg);
+
+        impl.requestIntercepts();
+
+        deviceService.addListener(deviceListener);
+
+        log.info("Started");
+    }
+
+
+    @Deactivate
+    public void deactivate() {
+        impl.withdrawIntercepts();
+        packetService.removeProcessor(processor);
+        netCfgService.removeListener(cfgListener);
+        StateMachine.unsetDelegate(delegate);
+        StateMachine.destroyMaps();
+        impl.deactivate();
+        deviceService.removeListener(deviceListener);
+        eventDispatcher.removeSink(AuthenticationEvent.class);
+        log.info("Stopped");
+    }
+
+    private void configureRadiusCommunication() {
+        if (radiusConnectionType.toLowerCase().equals("socket")) {
+            impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
+        } else {
+            impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
+                    deviceService, subsService, pktCustomizer, this);
+        }
+    }
+
+    private void configurePacketCustomizer() {
+        switch (customizer.toLowerCase()) {
+            case "sample":
+                pktCustomizer = new SamplePacketCustomizer(customInfo);
+                log.info("Created SamplePacketCustomizer");
+                break;
+            case "att":
+                pktCustomizer = new AttPacketCustomizer(customInfo);
+                log.info("Created AttPacketCustomizer");
+                break;
+            default:
+                pktCustomizer = new PacketCustomizer(customInfo);
+                log.info("Created default PacketCustomizer");
+                break;
+        }
+    }
+
+    /**
+     * Send RADIUS packet to the RADIUS server.
+     *
+     * @param radiusPacket RADIUS packet to be sent to server.
+     * @param inPkt        Incoming EAPOL packet
+     */
+    protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
+        impl.sendRadiusPacket(radiusPacket, inPkt);
+    }
+
+    /**
+     * Handles RADIUS packets.
+     *
+     * @param radiusPacket RADIUS packet coming from the RADIUS server.
+     * @throws StateMachineException if an illegal state transition is triggered
+     * @throws DeserializationException if packet deserialization fails
+     */
+    public void handleRadiusPacket(RADIUS radiusPacket)
+            throws StateMachineException, DeserializationException {
+        if (log.isTraceEnabled()) {
+            log.trace("Received RADIUS packet {}", radiusPacket);
+        }
+        StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
+        if (stateMachine == null) {
+            log.error("Invalid packet identifier {}, could not find corresponding "
+                    + "state machine ... exiting", radiusPacket.getIdentifier());
+            return;
+        }
+
+        EAP eapPayload;
+        Ethernet eth;
+
+        switch (radiusPacket.getCode()) {
+            case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
+                log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
+                RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
+                byte[] challengeState = null;
+                if (radiusAttrState != null) {
+                    challengeState = radiusAttrState.getValue();
+                }
+                eapPayload = radiusPacket.decapsulateMessage();
+                stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
+                eth = buildEapolResponse(stateMachine.supplicantAddress(),
+                        MacAddress.valueOf(nasMacAddress),
+                        stateMachine.vlanId(),
+                        EAPOL.EAPOL_PACKET,
+                        eapPayload, stateMachine.priorityCode());
+                log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
+                sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+                break;
+            case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
+                log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
+                //send an EAPOL - Success to the supplicant.
+                byte[] eapMessageSuccess =
+                        radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
+                eapPayload = EAP.deserializer().deserialize(
+                        eapMessageSuccess, 0, eapMessageSuccess.length);
+                eth = buildEapolResponse(stateMachine.supplicantAddress(),
+                        MacAddress.valueOf(nasMacAddress),
+                        stateMachine.vlanId(),
+                        EAPOL.EAPOL_PACKET,
+                        eapPayload, stateMachine.priorityCode());
+                log.info("Send EAP success message to supplicant {}", stateMachine.supplicantAddress().toString());
+                sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+
+                stateMachine.authorizeAccess();
+
+                break;
+            case RADIUS.RADIUS_CODE_ACCESS_REJECT:
+                log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
+                //send an EAPOL - Failure to the supplicant.
+                byte[] eapMessageFailure;
+                eapPayload = new EAP();
+                RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
+                if (radiusAttrEap == null) {
+                    eapPayload.setCode(EAP.FAILURE);
+                    eapPayload.setIdentifier(stateMachine.challengeIdentifier());
+                    eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
+                } else {
+                    eapMessageFailure = radiusAttrEap.getValue();
+                    eapPayload = EAP.deserializer().deserialize(
+                            eapMessageFailure, 0, eapMessageFailure.length);
+                }
+                eth = buildEapolResponse(stateMachine.supplicantAddress(),
+                        MacAddress.valueOf(nasMacAddress),
+                        stateMachine.vlanId(),
+                        EAPOL.EAPOL_PACKET,
+                        eapPayload, stateMachine.priorityCode());
+                log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
+                sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+                stateMachine.denyAccess();
+
+                break;
+            default:
+                log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
+        }
+    }
+
+    /**
+     * Send the ethernet packet to the supplicant.
+     *
+     * @param ethernetPkt  the ethernet packet
+     * @param connectPoint the connect point to send out
+     */
+    private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
+        OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
+                                                          treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
+        if (log.isTraceEnabled()) {
+            EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
+            log.trace("Sending eapol payload {} enclosed in {} to supplicant at {}",
+                      eap, ethernetPkt, connectPoint);
+        }
+        packetService.emit(packet);
+    }
+
+    @Override
+    public String toString() {
+        return ToStringBuilder.reflectionToString(this);
+    }
+
+    // our handler defined as a private inner class
+
+    /**
+     * Packet processor responsible for forwarding packets along their paths.
+     */
+    private class ReactivePacketProcessor implements PacketProcessor {
+        @Override
+        public void process(PacketContext context) {
+
+            // Extract the original Ethernet frame from the packet information
+            InboundPacket pkt = context.inPacket();
+            Ethernet ethPkt = pkt.parsed();
+            if (ethPkt == null) {
+                return;
+            }
+
+            try {
+                // identify if incoming packet comes from supplicant (EAP) or RADIUS
+                switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
+                    case EAPOL:
+                        handleSupplicantPacket(context.inPacket());
+                        break;
+                    default:
+                        // any other packets let the specific implementation handle
+                        impl.handlePacketFromServer(context);
+                }
+            } catch (StateMachineException e) {
+                log.warn("Unable to process packet:", e);
+            }
+        }
+
+        /**
+         * Creates and initializes common fields of a RADIUS packet.
+         *
+         * @param stateMachine state machine for the request
+         * @param eapPacket  EAP packet
+         * @return RADIUS packet
+         */
+        private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
+            RADIUS radiusPayload =
+                    new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
+                               eapPacket.getIdentifier());
+
+            // set Request Authenticator in StateMachine
+            stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
+
+            radiusPayload.setIdentifier(identifier);
+            radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
+                                       stateMachine.username());
+
+            radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
+                    AaaManager.this.nasIpAddress.getAddress());
+
+            radiusPayload.encapsulateMessage(eapPacket);
+
+            return radiusPayload;
+        }
+
+        /**
+         * Handles PAE packets (supplicant).
+         *
+         * @param inPacket Ethernet packet coming from the supplicant
+         */
+        private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
+            Ethernet ethPkt = inPacket.parsed();
+            // Where does it come from?
+            MacAddress srcMac = ethPkt.getSourceMAC();
+
+            DeviceId deviceId = inPacket.receivedFrom().deviceId();
+            PortNumber portNumber = inPacket.receivedFrom().port();
+            String sessionId = deviceId.toString() + portNumber.toString();
+            EAPOL eapol = (EAPOL) ethPkt.getPayload();
+            if (log.isTraceEnabled()) {
+                log.trace("Received EAPOL packet {} in enclosing packet {} from "
+                        + "dev/port: {}/{}", eapol, ethPkt, deviceId,
+                          portNumber);
+            }
+
+            StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
+            if (stateMachine == null) {
+                log.debug("Creating new state machine for sessionId: {} for "
+                                + "dev/port: {}/{}", sessionId, deviceId, portNumber);
+                stateMachine = new StateMachine(sessionId);
+            } else {
+                log.debug("Using existing state-machine for sessionId: {}", sessionId);
+            }
+
+
+            switch (eapol.getEapolType()) {
+                case EAPOL.EAPOL_START:
+                    log.debug("EAP packet: EAPOL_START");
+                    stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
+                    stateMachine.start();
+
+                    //send an EAP Request/Identify to the supplicant
+                    EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
+                    if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
+                       stateMachine.setPriorityCode(ethPkt.getPriorityCode());
+                    }
+                    Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
+                                                      ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
+                                                      eapPayload, stateMachine.priorityCode());
+
+                    stateMachine.setSupplicantAddress(srcMac);
+                    stateMachine.setVlanId(ethPkt.getVlanID());
+
+                    log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
+                    sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+
+                    break;
+                case EAPOL.EAPOL_LOGOFF:
+                    log.debug("EAP packet: EAPOL_LOGOFF");
+                    if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
+                        stateMachine.logoff();
+                    }
+
+                    break;
+                case EAPOL.EAPOL_PACKET:
+                    RADIUS radiusPayload;
+                    // check if this is a Response/Identify or  a Response/TLS
+                    EAP eapPacket = (EAP) eapol.getPayload();
+
+                    byte dataType = eapPacket.getDataType();
+                    switch (dataType) {
+
+                        case EAP.ATTR_IDENTITY:
+                            log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY");
+                            // request id access to RADIUS
+                            stateMachine.setUsername(eapPacket.getData());
+
+                            radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
+                            radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
+                            radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
+
+                            sendRadiusPacket(radiusPayload, inPacket);
+
+                            // change the state to "PENDING"
+                            stateMachine.requestAccess();
+                            break;
+                        case EAP.ATTR_MD5:
+                            log.debug("EAP packet: EAPOL_PACKET ATTR_MD5");
+                            // verify if the EAP identifier corresponds to the
+                            // challenge identifier from the client state
+                            // machine.
+                            if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
+                                //send the RADIUS challenge response
+                                radiusPayload =
+                                        getRadiusPayload(stateMachine,
+                                                         stateMachine.identifier(),
+                                                         eapPacket);
+                                radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
+
+                                if (stateMachine.challengeState() != null) {
+                                    radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+                                            stateMachine.challengeState());
+                                }
+                                radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
+                                sendRadiusPacket(radiusPayload, inPacket);
+                            }
+                            break;
+                        case EAP.ATTR_TLS:
+                            log.debug("EAP packet: EAPOL_PACKET ATTR_TLS");
+                            // request id access to RADIUS
+                            radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
+                            radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
+
+                            if (stateMachine.challengeState() != null) {
+                                radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+                                        stateMachine.challengeState());
+                            }
+                            stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
+
+                            radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
+                            sendRadiusPacket(radiusPayload, inPacket);
+
+                            if (stateMachine.state() != StateMachine.STATE_PENDING) {
+                                stateMachine.requestAccess();
+                            }
+
+                            break;
+                        default:
+                            log.warn("Unknown EAP packet type");
+                            return;
+                    }
+                    break;
+                default:
+                    log.debug("Skipping EAPOL message {}", eapol.getEapolType());
+            }
+        }
+    }
+
+    /**
+     * Delegate allowing the StateMachine to notify us of events.
+     */
+    private class InternalStateMachineDelegate implements StateMachineDelegate {
+
+        @Override
+        public void notify(AuthenticationEvent authenticationEvent) {
+            log.info("Auth event {} for {}",
+                    authenticationEvent.type(), authenticationEvent.subject());
+            post(authenticationEvent);
+        }
+    }
+
+    /**
+     * Configuration Listener, handles change in configuration.
+     */
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        /**
+         * Reconfigures the AAA application according to the
+         * configuration parameters passed.
+         *
+         * @param cfg configuration object
+         */
+        private void reconfigureNetwork(AaaConfig cfg) {
+            log.info("Reconfiguring AaaConfig from config: {}", cfg);
+
+            if (cfg == null) {
+                newCfg = new AaaConfig();
+            } else {
+                newCfg = cfg;
+            }
+            if (newCfg.nasIp() != null) {
+                nasIpAddress = newCfg.nasIp();
+            }
+            if (newCfg.radiusIp() != null) {
+                radiusIpAddress = newCfg.radiusIp();
+            }
+            if (newCfg.radiusMac() != null) {
+                radiusMacAddress = newCfg.radiusMac();
+            }
+            if (newCfg.nasMac() != null) {
+                nasMacAddress = newCfg.nasMac();
+            }
+            if (newCfg.radiusSecret() != null) {
+                radiusSecret = newCfg.radiusSecret();
+            }
+
+            boolean reconfigureCustomizer = false;
+            if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
+                customizer = newCfg.radiusPktCustomizer();
+                configurePacketCustomizer();
+                reconfigureCustomizer = true;
+            }
+
+            if (radiusConnectionType == null
+                    || reconfigureCustomizer
+                    || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
+                radiusConnectionType = newCfg.radiusConnectionType();
+                if (impl != null) {
+                    impl.withdrawIntercepts();
+                    impl.clearLocalState();
+                }
+                configureRadiusCommunication();
+                impl.initializeLocalState(newCfg);
+                impl.requestIntercepts();
+            } else if (impl != null) {
+                impl.clearLocalState();
+                impl.initializeLocalState(newCfg);
+            }
+        }
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+
+            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+                    event.configClass().equals(AaaConfig.class)) {
+
+                AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
+                reconfigureNetwork(cfg);
+
+                log.info("Reconfigured: {}", cfg.toString());
+            }
+        }
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+        @Override
+        public void event(DeviceEvent event) {
+
+            switch (event.type()) {
+                case PORT_REMOVED:
+                    DeviceId devId = event.subject().id();
+                    PortNumber portNumber = event.port().number();
+                    String sessionId = devId.toString() + portNumber.toString();
+
+                    Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
+                    StateMachine removed = sessionIdMap.remove(sessionId);
+                    if (removed != null) {
+                        StateMachine.deleteStateMachineMapping(removed);
+                    }
+
+                    break;
+                default:
+                    return;
+            }
+        }
+    }
+}