VOL-149: Configure RADIUS Attributes as per subscriber information
VOL-148: RADIUS VLAN ID configurable
Change-Id: I2a51dbf316637e685b7e3c36595a27922c79b23c
diff --git a/src/main/java/org/opencord/aaa/AaaConfig.java b/src/main/java/org/opencord/aaa/AaaConfig.java
index 0dfa142..8ffdf00 100644
--- a/src/main/java/org/opencord/aaa/AaaConfig.java
+++ b/src/main/java/org/opencord/aaa/AaaConfig.java
@@ -15,13 +15,22 @@
*/
package org.opencord.aaa;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+import com.google.common.collect.ImmutableSet;
+
import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.basics.BasicElementConfig;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Network config for the AAA app.
*/
@@ -33,8 +42,16 @@
private static final String NAS_IP = "nasIp";
private static final String NAS_MAC = "nasMac";
private static final String RADIUS_SECRET = "radiusSecret";
- private static final String RADIUS_SWITCH = "radiusSwitch";
- private static final String RADIUS_PORT = "radiusPort";
+ private static final String RADIUS_VLAN_ID = "vlanId";
+ private static final String RADIUS_VLAN_PRIORITY_BIT = "radiusPBit";
+ private static final String RADIUS_CONNECTION_TYPE = "radiusConnectionType";
+ private static final String RADIUS_SERVER_CONNECTPOINTS = "radiusServerConnectPoints";
+ // Which packet customizer to use
+ // "packetCustomizer" : "sample" -- Means use SamplePAcketCustomizer
+ // "packetCustomizer" : "default" -- No customization of packets
+ // if param is missing it is treated as default
+ // This class should be a subclass of PacketCustomizer
+ private static final String PACKET_CUSTOMIZER = "packetCustomizer";
// RADIUS server IP address
protected static final String DEFAULT_RADIUS_IP = "10.128.10.4";
@@ -51,15 +68,22 @@
// RADIUS server shared secret
protected static final String DEFAULT_RADIUS_SECRET = "ONOSecret";
- // Radius Switch Id
- protected static final String DEFAULT_RADIUS_SWITCH = "of:90e2ba82f97791e9";
-
- // Radius Port Number
- protected static final String DEFAULT_RADIUS_PORT = "1811";
-
// Radius Server UDP Port Number
protected static final String DEFAULT_RADIUS_SERVER_PORT = "1812";
+ // Radius Server Vlan ID
+ protected static final String DEFAULT_RADIUS_VLAN_ID = "4093";
+
+ // Radius Sever P-Bit
+ protected static final String DEFAULT_RADIUS_VLAN_PRIORITY_BIT = "3";
+
+ // Whether to use socket or not to communicate with RADIUS Server
+ protected static final String DEFAULT_RADIUS_CONNECTION_TYPE = "socket";
+
+ // Packet Customizer Default value
+ protected static final String DEFAULT_PACKET_CUSTOMIZER = "default";
+
+
/**
* Gets the value of a string property, protecting for an empty
* JSON object.
@@ -179,44 +203,6 @@
}
/**
- * Returns the ID of the RADIUS switch.
- *
- * @return radius switch ID or null if not set
- */
- public String radiusSwitch() {
- return getStringProperty(RADIUS_SWITCH, DEFAULT_RADIUS_SWITCH);
- }
-
- /**
- * Sets the ID of the RADIUS switch.
- *
- * @param switchId new RADIUS switch ID; null to clear
- * @return self
- */
- public BasicElementConfig radiusSwitch(String switchId) {
- return (BasicElementConfig) setOrClear(RADIUS_SWITCH, switchId);
- }
-
- /**
- * Returns the RADIUS port.
- *
- * @return radius port or null if not set
- */
- public long radiusPort() {
- return Integer.parseInt(getStringProperty(RADIUS_PORT, DEFAULT_RADIUS_PORT));
- }
-
- /**
- * Sets the RADIUS port.
- *
- * @param port new RADIUS port; null to clear
- * @return self
- */
- public BasicElementConfig radiusPort(long port) {
- return (BasicElementConfig) setOrClear(RADIUS_PORT, port);
- }
-
- /**
* Returns the RADIUS server UDP port.
*
* @return radius server UDP port.
@@ -236,4 +222,69 @@
return (BasicElementConfig) setOrClear(RADIUS_SERVER_PORT, (long) port);
}
+ /**
+ * Returns the RADIUS server vlan ID.
+ *
+ * @return Radius Server VLan id or default if not set
+ */
+ public short radiusServerVlanId() {
+ return Short.parseShort(getStringProperty(RADIUS_VLAN_ID, DEFAULT_RADIUS_VLAN_ID));
+ }
+
+ /**
+ * Returns the type of connection to use to communicate with the RADIUS Server.
+ *
+ * @return "socket" or "packet_out"
+ */
+ public String radiusConnectionType() {
+ return getStringProperty(RADIUS_CONNECTION_TYPE, DEFAULT_RADIUS_CONNECTION_TYPE);
+ }
+
+ /**
+ * Returns the RADIUS server p-bit.
+ *
+ * @return Radius Server P-bit to use, default if not set
+ */
+ public byte radiusServerPBit() {
+ return Byte.parseByte(getStringProperty(RADIUS_VLAN_PRIORITY_BIT, DEFAULT_RADIUS_VLAN_PRIORITY_BIT));
+ }
+
+ /**
+ * Returns the PACKET CUSTOMIZER CLASS NAME.
+ *
+ * @return PACKET CUSTOMIZER, default if not set
+ */
+ public String radiusPktCustomizer() {
+ return getStringProperty(PACKET_CUSTOMIZER, DEFAULT_PACKET_CUSTOMIZER);
+ }
+
+ /**
+ * Returns the List of ConnectPoints to reach the Radius Server.
+ *
+ * @return List of ConnectPoints
+ */
+ public Set<ConnectPoint> radiusServerConnectPoints() {
+ if (object == null) {
+ return new HashSet<ConnectPoint>();
+ }
+
+ if (!object.has(RADIUS_SERVER_CONNECTPOINTS)) {
+ return ImmutableSet.of();
+ }
+
+ ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
+ ArrayNode arrayNode = (ArrayNode) object.path(RADIUS_SERVER_CONNECTPOINTS);
+ for (JsonNode jsonNode : arrayNode) {
+ String portName = jsonNode.asText(null);
+ if (portName == null) {
+ return null;
+ }
+ try {
+ builder.add(ConnectPoint.deviceConnectPoint(portName));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+ return builder.build();
+ }
}
diff --git a/src/main/java/org/opencord/aaa/AaaManager.java b/src/main/java/org/opencord/aaa/AaaManager.java
index f945ebc..2f885db 100755
--- a/src/main/java/org/opencord/aaa/AaaManager.java
+++ b/src/main/java/org/opencord/aaa/AaaManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 AT&T Foundry
+ * 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.
@@ -15,21 +15,12 @@
*/
package org.opencord.aaa;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
import org.apache.felix.scr.annotations.Activate;
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.onlab.packet.DeserializationException;
+
import org.onlab.packet.EAP;
import org.onlab.packet.EAPOL;
import org.onlab.packet.EthType;
@@ -37,8 +28,12 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
+import org.onlab.packet.VlanId;
+
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
@@ -46,9 +41,8 @@
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
@@ -56,14 +50,20 @@
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
+
+import org.opencord.olt.AccessDeviceService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.SubscriberAndDeviceInformationService;
+
import org.slf4j.Logger;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-
import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
-import static org.onosproject.net.packet.PacketPriority.CONTROL;
+
import static org.slf4j.LoggerFactory.getLogger;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
/**
* AAA application for ONOS.
*/
@@ -86,25 +86,38 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry netCfgService;
- // Parsed RADIUS server addresses
- protected InetAddress radiusIpAddress;
- protected String radiusMacAddress;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected SubscriberAndDeviceInformationService subsService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected AccessDeviceService accessDeviceService;
// NAS IP address
protected InetAddress nasIpAddress;
- protected String nasMacAddress;
+
+ // self MAC address
+ protected static 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;
- // ID of RADIUS switch
- protected String radiusSwitch;
+ // NAS Identifier
+ protected String nasId;
- // RADIUS port number
- protected long radiusPort;
-
- // RADIUS server TCP port number
- protected short radiusServerPort;
+ // bindings
+ protected CustomizationInfo customInfo;
// our application-specific event handler
private ReactivePacketProcessor processor = new ReactivePacketProcessor();
@@ -112,11 +125,22 @@
// our unique identifier
private ApplicationId appId;
- // Socket used for UDP communications with RADIUS server
- private DatagramSocket radiusSocket;
+ // Setup specific customization/attributes on the RADIUS packets
+ PacketCustomizer pktCustomizer;
- // Executor for RADIUS communication thread
- private ExecutorService executor;
+ // 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 spcific 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 =
@@ -143,7 +167,7 @@
* @return Ethernet frame
*/
private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
- short vlan, byte eapolType, EAP eap) {
+ short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ethernet eth = new Ethernet();
eth.setDestinationMACAddress(dstMac.toBytes());
@@ -151,6 +175,7 @@
eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
if (vlan != Ethernet.VLAN_UNTAGGED) {
eth.setVlanID(vlan);
+ eth.setPriorityCode(priorityCode);
}
//eapol header
EAPOL eapol = new EAPOL();
@@ -165,86 +190,143 @@
return eth;
}
- private void initializeLocalState() {
- try {
- radiusSocket = new DatagramSocket(null);
- radiusSocket.setReuseAddress(true);
- radiusSocket.bind(new InetSocketAddress((int) radiusPort));
- } catch (Exception ex) {
- log.error("Can't open RADIUS socket", ex);
- }
-
- executor = Executors.newSingleThreadExecutor(
- new ThreadFactoryBuilder()
- .setNameFormat("AAA-radius-%d").build());
- executor.execute(radiusListener);
- }
-
@Activate
public void activate() {
netCfgService.registerConfigFactory(factory);
- // "org.onosproject.aaa" is the FQDN of our app
appId = coreService.registerApplication(APP_NAME);
cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
// register our event handler
packetService.addProcessor(processor, PacketProcessor.director(2));
- requestIntercepts();
+
+ customInfo = new CustomizationInfo(subsService, deviceService);
+
+ switch (customizer.toLowerCase()) {
+ case "sample":
+ pktCustomizer = new SamplePacketCustomizer(customInfo);
+ log.info("Created SamplePacketCustomizer");
+ break;
+ default:
+ pktCustomizer = new PacketCustomizer(customInfo);
+ log.info("Created default PacketCustomizer");
+ break;
+ }
+
+ if (radiusConnectionType.toLowerCase().equals("socket")) {
+ impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
+ } else {
+ impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
+ deviceService, subsService, pktCustomizer, this);
+ }
StateMachine.initializeMaps();
+ StateMachine.setAccessDeviceService(accessDeviceService);
- initializeLocalState();
+ impl.initializeLocalState(newCfg);
netCfgService.addListener(cfgListener);
+ impl.requestIntercepts();
+
log.info("Started");
}
@Deactivate
public void deactivate() {
- withdrawIntercepts();
+ impl.withdrawIntercepts();
// de-register and null our handler
packetService.removeProcessor(processor);
processor = null;
StateMachine.destroyMaps();
- radiusSocket.close();
- executor.shutdownNow();
+
+ impl.deactivate();
+
log.info("Stopped");
}
- protected void sendRadiusPacket(RADIUS radiusPacket) {
+ /**
+ * 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);
+ }
- try {
- final byte[] data = radiusPacket.serialize();
- final DatagramSocket socket = radiusSocket;
-
- DatagramPacket packet =
- new DatagramPacket(data, data.length,
- radiusIpAddress, radiusServerPort);
-
- socket.send(packet);
- } catch (IOException e) {
- log.info("Cannot send packet to RADIUS server", e);
+ /**
+ * Handles RADIUS packets.
+ *
+ * @param radiusPacket RADIUS packet coming from the RADIUS server.
+ * @throws StateMachineException if an illegal state transition is triggered
+ */
+ public void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
+ StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
+ if (stateMachine == null) {
+ log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
+ return;
}
- }
- /**
- * Request packet in via PacketService.
- */
- private void requestIntercepts() {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
- packetService.requestPackets(selector.build(),
- CONTROL, appId);
- }
+ EAP eapPayload;
+ Ethernet eth;
- /**
- * Cancel request for packet in via PacketService.
- */
- private void withdrawIntercepts() {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
- packetService.cancelPackets(selector.build(), CONTROL, appId);
+ switch (radiusPacket.getCode()) {
+ case RADIUS.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());
+ sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+ break;
+ case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
+ //send an EAPOL - Success to the supplicant.
+ byte[] eapMessageSuccess =
+ radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
+ eapPayload = new EAP();
+ eapPayload = (EAP) eapPayload.deserialize(eapMessageSuccess, 0, eapMessageSuccess.length);
+ eth = buildEapolResponse(stateMachine.supplicantAddress(),
+ MacAddress.valueOf(nasMacAddress),
+ stateMachine.vlanId(),
+ EAPOL.EAPOL_PACKET,
+ eapPayload, stateMachine.priorityCode());
+ sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+
+ stateMachine.authorizeAccess();
+
+ break;
+ case RADIUS.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) eapPayload.deserialize(eapMessageFailure, 0, eapMessageFailure.length);
+ }
+ eth = buildEapolResponse(stateMachine.supplicantAddress(),
+ MacAddress.valueOf(nasMacAddress),
+ stateMachine.vlanId(),
+ EAPOL.EAPOL_PACKET,
+ eapPayload, stateMachine.priorityCode());
+ sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+ stateMachine.denyAccess();
+
+ break;
+ default:
+ log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
+ }
}
/**
@@ -275,6 +357,7 @@
if (ethPkt == null) {
return;
}
+
try {
// identify if incoming packet comes from supplicant (EAP) or RADIUS
switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
@@ -282,11 +365,11 @@
handleSupplicantPacket(context.inPacket());
break;
default:
- log.trace("Skipping Ethernet packet type {}",
- EthType.EtherType.lookup(ethPkt.getEtherType()));
+ // any other packets let the specific implementation handle
+ impl.handlePacketFromServer(context);
}
} catch (StateMachineException e) {
- log.warn("Unable to process RADIUS packet:", e);
+ log.warn("Unable to process packet:", e);
}
}
@@ -332,9 +415,19 @@
String sessionId = deviceId.toString() + portNumber.toString();
StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
if (stateMachine == null) {
- stateMachine = new StateMachine(sessionId);
- }
+ if (deviceService != null) {
+ String nasPortId = deviceService.getPort(inPacket.receivedFrom()).
+ annotations().value(AnnotationKeys.PORT_NAME);
+ SubscriberAndDeviceInformation subscriber =
+ subsService.get(nasPortId);
+ if (subscriber != null) {
+ stateMachine = new StateMachine(sessionId, subscriber.cTag());
+ }
+ } else {
+ stateMachine = new StateMachine(sessionId, VlanId.vlanId((short) 0));
+ }
+ }
EAPOL eapol = (EAPOL) ethPkt.getPayload();
@@ -345,9 +438,12 @@
//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);
+ eapPayload, stateMachine.priorityCode());
stateMachine.setSupplicantAddress(srcMac);
stateMachine.setVlanId(ethPkt.getVlanID());
@@ -373,9 +469,10 @@
stateMachine.setUsername(eapPacket.getData());
radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
+ radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
- sendRadiusPacket(radiusPayload);
+ sendRadiusPacket(radiusPayload, inPacket);
// change the state to "PENDING"
stateMachine.requestAccess();
@@ -390,18 +487,20 @@
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);
+ sendRadiusPacket(radiusPayload, inPacket);
}
break;
case EAP.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,
@@ -410,7 +509,7 @@
stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
- sendRadiusPacket(radiusPayload);
+ sendRadiusPacket(radiusPayload, inPacket);
if (stateMachine.state() != StateMachine.STATE_PENDING) {
stateMachine.requestAccess();
@@ -424,123 +523,12 @@
default:
log.trace("Skipping EAPOL message {}", eapol.getEapolType());
}
-
}
}
- class RadiusListener implements Runnable {
-
- /**
- * Handles RADIUS packets.
- *
- * @param radiusPacket RADIUS packet coming from the RADIUS server.
- * @throws StateMachineException if an illegal state transition is triggered
- */
- protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
- StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
- if (stateMachine == null) {
- log.error("Invalid session identifier, exiting...");
- return;
- }
-
- EAP eapPayload;
- Ethernet eth;
- switch (radiusPacket.getCode()) {
- case RADIUS.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);
- sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
- break;
- case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
- //send an EAPOL - Success to the supplicant.
- byte[] eapMessageSuccess =
- radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
- eapPayload = new EAP();
- eapPayload = (EAP) eapPayload.deserialize(eapMessageSuccess, 0, eapMessageSuccess.length);
- eth = buildEapolResponse(stateMachine.supplicantAddress(),
- MacAddress.valueOf(nasMacAddress),
- stateMachine.vlanId(),
- EAPOL.EAPOL_PACKET,
- eapPayload);
- sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
-
- stateMachine.authorizeAccess();
- break;
- case RADIUS.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) eapPayload.deserialize(eapMessageFailure, 0, eapMessageFailure.length);
- }
- eth = buildEapolResponse(stateMachine.supplicantAddress(),
- MacAddress.valueOf(nasMacAddress),
- stateMachine.vlanId(),
- EAPOL.EAPOL_PACKET,
- eapPayload);
- sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
- stateMachine.denyAccess();
- break;
- default:
- log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
- }
- }
-
-
- @Override
- public void run() {
- boolean done = false;
- int packetNumber = 1;
-
- log.info("UDP listener thread starting up");
- RADIUS inboundRadiusPacket;
- while (!done) {
- try {
- byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
- DatagramPacket inboundBasePacket =
- new DatagramPacket(packetBuffer, packetBuffer.length);
- DatagramSocket socket = radiusSocket;
- socket.receive(inboundBasePacket);
- log.info("Packet #{} received", packetNumber++);
- try {
- inboundRadiusPacket =
- RADIUS.deserializer()
- .deserialize(inboundBasePacket.getData(),
- 0,
- inboundBasePacket.getLength());
- handleRadiusPacket(inboundRadiusPacket);
- } catch (DeserializationException dex) {
- log.error("Cannot deserialize packet", dex);
- } catch (StateMachineException sme) {
- log.error("Illegal state machine operation", sme);
- }
-
- } catch (IOException e) {
- log.info("Socket was closed, exiting listener thread");
- done = true;
- }
- }
- }
- }
-
- RadiusListener radiusListener = new RadiusListener();
-
+ /**
+ * Configuration Listener, handles change in configuration.
+ */
private class InternalConfigListener implements NetworkConfigListener {
/**
@@ -550,7 +538,7 @@
* @param cfg configuration object
*/
private void reconfigureNetwork(AaaConfig cfg) {
- AaaConfig newCfg;
+
if (cfg == null) {
newCfg = new AaaConfig();
} else {
@@ -571,14 +559,13 @@
if (newCfg.radiusSecret() != null) {
radiusSecret = newCfg.radiusSecret();
}
- if (newCfg.radiusSwitch() != null) {
- radiusSwitch = newCfg.radiusSwitch();
- }
- if (newCfg.radiusPort() != -1) {
- radiusPort = newCfg.radiusPort();
- }
- if (newCfg.radiusServerUdpPort() != -1) {
- radiusServerPort = newCfg.radiusServerUdpPort();
+
+ radiusConnectionType = newCfg.radiusConnectionType();
+ customizer = newCfg.radiusPktCustomizer();
+
+ if (impl != null) {
+ impl.clearLocalState();
+ impl.initializeLocalState(newCfg);
}
}
@@ -591,13 +578,9 @@
AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
reconfigureNetwork(cfg);
- radiusSocket.close();
- executor.shutdownNow();
- initializeLocalState();
+
log.info("Reconfigured");
}
}
}
-
-
}
diff --git a/src/main/java/org/opencord/aaa/CustomizationInfo.java b/src/main/java/org/opencord/aaa/CustomizationInfo.java
new file mode 100755
index 0000000..d0709f2
--- /dev/null
+++ b/src/main/java/org/opencord/aaa/CustomizationInfo.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+import org.onosproject.net.device.DeviceService;
+import org.opencord.sadis.SubscriberAndDeviceInformationService;
+
+//import java.util.Map;
+
+/**
+ * Info required to do customization to packets.
+ */
+public class CustomizationInfo {
+
+ private DeviceService devService;
+
+ private SubscriberAndDeviceInformationService subscriberService;
+
+ public CustomizationInfo(SubscriberAndDeviceInformationService subsService, DeviceService devService) {
+ this.subscriberService = subsService;
+ this.devService = devService;
+ }
+
+ public DeviceService deviceService() {
+ return devService;
+ }
+
+ public SubscriberAndDeviceInformationService subscriberService() {
+ return subscriberService;
+ }
+}
diff --git a/src/main/java/org/opencord/aaa/PacketCustomizer.java b/src/main/java/org/opencord/aaa/PacketCustomizer.java
new file mode 100755
index 0000000..5f48ba4
--- /dev/null
+++ b/src/main/java/org/opencord/aaa/PacketCustomizer.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.RADIUS;
+
+import org.onosproject.net.packet.InboundPacket;
+
+/**
+ * Default RADIUS Packet Customization.
+ * Does not change the packet
+ *
+ * Subclasses should implement filling of attributes depending on specifics ofsetup/RADIUS server
+ */
+public class PacketCustomizer {
+
+ protected CustomizationInfo customInfo;
+
+ public PacketCustomizer(CustomizationInfo info) {
+ this.customInfo = info;
+ }
+
+ /**
+ * Customize the packet as per specific Setup or RADIUS server requirements.
+ *
+ * @param inPkt RADIUS packet to be customized
+ * @param eapPacket Incoming packet containing EAP for which this the RADIUS message is being created
+ * @return Customized RADIUS packet
+ */
+ public RADIUS customizePacket(RADIUS inPkt, InboundPacket eapPacket) {
+ return inPkt;
+ }
+
+ /**
+ * Customize the Ethernet header as per specific Setup or RADIUS server requirements.
+ *
+ * @param inPkt Ethernet packet to be changed
+ * @param eapPacket Incoming packet containing EAP for which this the
+ * RADIUS message is being created
+ * @return Changed Ethernet packet
+ */
+ public Ethernet customizeEthernetIPHeaders(Ethernet inPkt,
+ InboundPacket eapPacket) {
+ return inPkt;
+ }
+}
diff --git a/src/main/java/org/opencord/aaa/PortBasedRadiusCommunicator.java b/src/main/java/org/opencord/aaa/PortBasedRadiusCommunicator.java
new file mode 100755
index 0000000..6e256b7
--- /dev/null
+++ b/src/main/java/org/opencord/aaa/PortBasedRadiusCommunicator.java
@@ -0,0 +1,446 @@
+/*
+ * 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;
+
+import org.onlab.packet.ARP;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.RADIUS;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.UDP;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.mastership.MastershipEvent;
+import org.onosproject.mastership.MastershipListener;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+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.PacketService;
+
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.SubscriberAndDeviceInformationService;
+
+import org.slf4j.Logger;
+
+import com.google.common.collect.Maps;
+
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Handles communication with the RADIUS server through ports
+ * of the SDN switches.
+ */
+public class PortBasedRadiusCommunicator implements RadiusCommunicator {
+
+ // for verbose output
+ private final Logger log = getLogger(getClass());
+
+ // our unique identifier
+ private ApplicationId appId;
+
+ // to receive Packet-in events that we'll respond to
+ PacketService packetService;
+
+ DeviceService deviceService;
+
+ MastershipService mastershipService;
+
+ SubscriberAndDeviceInformationService subsService;
+
+ // to store local mapping of IP Address and Serial No of Device
+ private Map<Ip4Address, String> ipToSnMap;
+
+ // connect points to the RADIUS server
+ Set<ConnectPoint> radiusConnectPoints;
+
+ // Parsed RADIUS server addresses
+ protected InetAddress radiusIpAddress;
+
+ // RADIUS server TCP port number
+ protected short radiusServerPort;
+
+ protected String radiusMacAddress;
+
+ // NAS IP address
+ protected InetAddress nasIpAddress;
+
+ protected String nasMacAddress;
+
+ // RADIUS server Vlan ID
+ private short radiusVlanID;
+
+ // RADIUS p-bit
+ private byte radiusPBit;
+
+ PacketCustomizer pktCustomizer;
+ AaaManager aaaManager;
+
+ ConnectPoint radiusServerConnectPoint = null;
+
+ InnerMastershipListener changeListener = new InnerMastershipListener();
+ InnerDeviceListener deviceListener = new InnerDeviceListener();
+
+ PortBasedRadiusCommunicator(ApplicationId appId, PacketService pktService,
+ MastershipService masService, DeviceService devService,
+ SubscriberAndDeviceInformationService subsService,
+ PacketCustomizer pktCustomizer, AaaManager aaaManager) {
+ this.appId = appId;
+ this.packetService = pktService;
+ this.mastershipService = masService;
+ this.deviceService = devService;
+ this.subsService = subsService;
+ this.pktCustomizer = pktCustomizer;
+ this.aaaManager = aaaManager;
+
+ ipToSnMap = Maps.newConcurrentMap();
+ mastershipService.addListener(changeListener);
+ deviceService.addListener(deviceListener);
+
+ log.error("Created PortBased");
+ }
+
+ private void initializeLocalState() {
+ synchronized (this) {
+ radiusServerConnectPoint = null;
+ if (radiusConnectPoints != null) {
+ // find a connect point through a device for which we are master
+ for (ConnectPoint cp: radiusConnectPoints) {
+ if (mastershipService.isLocalMaster(cp.deviceId())) {
+ if (deviceService.isAvailable(cp.deviceId())) {
+ radiusServerConnectPoint = cp;
+ }
+ log.warn("RADIUS connectPoint selected is {}", cp);
+ break;
+ }
+ }
+ }
+
+ log.warn("RADIUS connectPoint in initializeLocalState is {}", radiusServerConnectPoint);
+
+ if (radiusServerConnectPoint == null) {
+ log.error("Master of none, can't send radius Message to server");
+ }
+ }
+ }
+
+ @Override
+ public void initializeLocalState(AaaConfig newCfg) {
+ 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();
+ }
+
+ radiusServerPort = newCfg.radiusServerUdpPort();
+ radiusVlanID = newCfg.radiusServerVlanId();
+ radiusPBit = newCfg.radiusServerPBit();
+
+ radiusConnectPoints = newCfg.radiusServerConnectPoints();
+
+ initializeLocalState();
+ }
+
+ @Override
+ public void clearLocalState() {}
+
+ @Override
+ public void deactivate() {
+ mastershipService.removeListener(changeListener);
+ deviceService.removeListener(deviceListener);
+ }
+
+ @Override
+ public void requestIntercepts() {
+ TrafficSelector.Builder selectorArpServer = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_ARP);
+ packetService.requestPackets(selectorArpServer.build(), CONTROL, appId);
+
+ TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpSrc(TpPort.tpPort(radiusServerPort));
+ packetService.requestPackets(selectorServer.build(), CONTROL, appId);
+ }
+
+ @Override
+ public void withdrawIntercepts() {
+ TrafficSelector.Builder selectorArpServer = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_ARP);
+ packetService.cancelPackets(selectorArpServer.build(), CONTROL, appId);
+
+ TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpSrc(TpPort.tpPort(radiusServerPort));
+ packetService.cancelPackets(selectorServer.build(), CONTROL, appId);
+ }
+
+ @Override
+ public void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
+ // create the packet
+ Ethernet ethReply = new Ethernet();
+ ethReply.setSourceMACAddress(nasMacAddress);
+ ethReply.setDestinationMACAddress(radiusMacAddress);
+ ethReply.setEtherType(Ethernet.TYPE_IPV4);
+ ethReply.setVlanID(radiusVlanID);
+ ethReply.setPriorityCode(radiusPBit);
+
+ IPv4 ipv4Packet = new IPv4();
+ ipv4Packet.setTtl((byte) 64);
+ ipv4Packet.setSourceAddress(Ip4Address.
+ valueOf(nasIpAddress).toInt());
+ ipv4Packet.setDestinationAddress(Ip4Address.
+ valueOf(radiusIpAddress).toInt());
+
+ UDP udpPacket = new UDP();
+ udpPacket.setSourcePort(radiusServerPort);
+ udpPacket.setDestinationPort(radiusServerPort);
+
+ udpPacket.setPayload(radiusPacket);
+ ipv4Packet.setPayload(udpPacket);
+ ethReply.setPayload(ipv4Packet);
+
+ // store the IP address and SN of the device, later to be used
+ // for ARP responses
+ String serialNo = deviceService.getDevice(inPkt.
+ receivedFrom().deviceId()).serialNumber();
+
+ SubscriberAndDeviceInformation deviceInfo = subsService.get(serialNo);
+
+ if (deviceInfo == null) {
+ log.error("No Device found with SN {}", serialNo);
+ return;
+ }
+ ipToSnMap.put(deviceInfo.ipAddress(), serialNo);
+
+ // send the message out
+ sendFromRadiusServerPort(pktCustomizer.
+ customizeEthernetIPHeaders(ethReply, inPkt));
+ }
+
+ /**
+ * Sends packet to the RADIUS server using one of the switch ports.
+ *
+ * @param packet Ethernet packet to be sent
+ */
+ private void sendFromRadiusServerPort(Ethernet packet) {
+ if (radiusServerConnectPoint != null) {
+ log.trace("AAA Manager sending Ethernet packet = {}", packet);
+ TrafficTreatment t = DefaultTrafficTreatment.builder()
+ .setOutput(radiusServerConnectPoint.port()).build();
+ OutboundPacket o = new DefaultOutboundPacket(
+ radiusServerConnectPoint.deviceId(), t, ByteBuffer.wrap(packet.serialize()));
+ packetService.emit(o);
+ } else {
+ log.error("Unable to send RADIUS packet, connectPoint is null");
+ }
+ }
+
+ @Override
+ public void handlePacketFromServer(PacketContext context) {
+ // Extract the original Ethernet frame from the packet information
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+ if (ethPkt == null) {
+ return;
+ }
+
+ // identify if incoming packet
+ switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
+ case ARP:
+ handleArpPacketFromServer(context);
+ break;
+ case IPV4:
+ handleIPv4PacketFromServer(context);
+ break;
+ default:
+ log.debug("Skipping Ethernet packet type {}",
+ EthType.EtherType.lookup(ethPkt.getEtherType()));
+ }
+ }
+
+ /**
+ * Handles ARP packets from RADIUS server.
+ *
+ * @param context Context for the packet
+ */
+ private void handleArpPacketFromServer(PacketContext context) {
+ // Extract the original Ethernet frame from the packet information
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+ if (ethPkt == null) {
+ return;
+ }
+
+ ARP arpPacket = (ARP) ethPkt.getPayload();
+
+ Ip4Address targetAddress = Ip4Address.valueOf(arpPacket.
+ getTargetProtocolAddress());
+
+ String serialNo = ipToSnMap.get(targetAddress);
+ if (serialNo == null) {
+ log.info("No mapping found for ARP reply, target address {}",
+ targetAddress);
+ return;
+ }
+ MacAddress senderMac = subsService.get(serialNo).hardwareIdentifier();
+ if (senderMac == null) {
+ log.error("ARP resolution, MAC address not found for SN {}", serialNo);
+ return;
+ }
+
+ ARP arpReply = (ARP) arpPacket.clone();
+ arpReply.setOpCode(ARP.OP_REPLY);
+ arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
+ arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
+ arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
+ arpReply.setSenderHardwareAddress(senderMac.toBytes());
+
+ log.debug("AAA Manager: Query for ARP of IP : {}", arpPacket.getTargetProtocolAddress());
+
+ // Ethernet Frame.
+ Ethernet ethReply = new Ethernet();
+ ethReply.setSourceMACAddress(senderMac);
+ ethReply.setDestinationMACAddress(ethPkt.getSourceMAC());
+ ethReply.setEtherType(Ethernet.TYPE_ARP);
+ ethReply.setVlanID(radiusVlanID);
+ ethReply.setPriorityCode(ethPkt.getPriorityCode());
+
+ ethReply.setPayload(arpReply);
+ sendFromRadiusServerPort(ethReply);
+ }
+
+ /**
+ * Handles IP packets from RADIUS server.
+ *
+ * @param context Context for the packet
+ */
+ private void handleIPv4PacketFromServer(PacketContext context) {
+ // Extract the original Ethernet frame from the packet information
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+ if (ethPkt == null) {
+ return;
+ }
+
+ IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
+
+ if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
+ UDP udpPacket = (UDP) ipv4Packet.getPayload();
+
+ if (udpPacket.getSourcePort() == radiusServerPort) {
+ //This packet is RADIUS packet from the server.
+ RADIUS radiusMsg;
+ try {
+ radiusMsg =
+ RADIUS.deserializer()
+ .deserialize(udpPacket.serialize(),
+ 8,
+ udpPacket.getLength() - 8);
+ try {
+ aaaManager.handleRadiusPacket(radiusMsg);
+ } catch (StateMachineException sme) {
+ log.error("Illegal state machine operation", sme);
+ }
+ } catch (DeserializationException dex) {
+ log.error("Cannot deserialize packet", dex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles Mastership changes for the devices which connect
+ * to the RADIUS server.
+ */
+ private class InnerMastershipListener implements MastershipListener {
+ @Override
+ public void event(MastershipEvent event) {
+ if (radiusServerConnectPoint != null &&
+ radiusServerConnectPoint.deviceId().
+ equals(event.subject())) {
+ log.trace("Mastership Event recevived for {}", event.subject());
+ // mastership of the device for our connect point has changed
+ // reselect
+ initializeLocalState();
+ }
+ }
+ }
+
+ /**
+ * Handles Device status change for the devices which connect
+ * to the RADIUS server.
+ */
+ private class InnerDeviceListener implements DeviceListener {
+ @Override
+ public void event(DeviceEvent event) {
+ log.trace("Device Event recevived for {} event {}", event.subject(), event.type());
+ if (radiusServerConnectPoint == null) {
+ switch (event.type()) {
+ case DEVICE_ADDED:
+ case DEVICE_AVAILABILITY_CHANGED:
+ // some device is available check if we can get one
+ initializeLocalState();
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ if (radiusServerConnectPoint.deviceId().
+ equals(event.subject().id())) {
+ switch (event.type()) {
+ case DEVICE_AVAILABILITY_CHANGED:
+ case DEVICE_REMOVED:
+ case DEVICE_SUSPENDED:
+ // state of our device has changed, check if we need
+ // to re-select
+ initializeLocalState();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/opencord/aaa/RadiusCommunicator.java b/src/main/java/org/opencord/aaa/RadiusCommunicator.java
new file mode 100755
index 0000000..4809bca
--- /dev/null
+++ b/src/main/java/org/opencord/aaa/RadiusCommunicator.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import org.onlab.packet.RADIUS;
+
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+
+/**
+ * Interface to the implementations for RADIUS server side communication.
+ */
+public interface RadiusCommunicator {
+
+ /**
+ * Does initialization required for the implementation to work and applies the
+ * relevant part of the passed configuration.
+ *
+ * @param newCfg : New configuration to be applied
+ */
+ void initializeLocalState(AaaConfig newCfg);
+ /**
+ * Clears up all local state.
+ */
+ void clearLocalState();
+ /**
+ * Shutdown, called when AAA app is deactivated.
+ */
+ void deactivate();
+ /**
+ * Provision intercepts on the switches if needed.
+ */
+ void requestIntercepts();
+ /**
+ * Clear intercepts from the switches if needed.
+ */
+ void withdrawIntercepts();
+ /**
+ * Send RADIUS packet to the RADIUS server.
+ *
+ * @param radiusPacket RADIUS packet to be sent to server.
+ * @param inPkt Incoming EAPOL packet
+ */
+ void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt);
+ /**
+ * Handle packet from RADIUS server.
+ *
+ * @param context Incoming packet context.
+ */
+ void handlePacketFromServer(PacketContext context);
+}
diff --git a/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java b/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java
new file mode 100755
index 0000000..5e1bad5
--- /dev/null
+++ b/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java
@@ -0,0 +1,155 @@
+/*
+ * 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;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.RADIUS;
+import org.onlab.packet.RADIUSAttribute;
+
+
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.Port;
+import org.onosproject.net.packet.InboundPacket;
+
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * Sample RADIUS Packet Customization.
+ *
+ */
+public class SamplePacketCustomizer extends PacketCustomizer {
+
+ private final Logger log = getLogger(getClass());
+
+ public SamplePacketCustomizer(CustomizationInfo customInfo) {
+ super(customInfo);
+ }
+
+ /**
+ * Customize the packet as per specific Setup or RADIUS
+ * server requirements.
+ *
+ * @param inPkt RADIUS packet to be customized
+ * @param eapPacket Incoming packet containing EAP for which this the
+ * RADIUS message is being created
+ * @return Customized RADIUS packet
+ */
+ @Override
+ public RADIUS customizePacket(RADIUS inPkt, InboundPacket eapPacket) {
+ Port p = customInfo.deviceService().getPort(eapPacket.receivedFrom());
+
+ String id = p.annotations().value(AnnotationKeys.PORT_NAME);
+
+ log.info("Customizing packet Port received for {}", id);
+
+ SubscriberAndDeviceInformation subscriber = customInfo.
+ subscriberService().get(id);
+
+ if (subscriber == null) {
+ log.warn("No subscriber found with id {}", id);
+ return inPkt;
+ }
+
+ String nasPortId = subscriber.nasPortId();
+
+ Ethernet ethPkt = eapPacket.parsed();
+ MacAddress srcMac = ethPkt.getSourceMAC();
+
+ // Get the nasId from subscriber service using the Serial Number
+ String serialNo = customInfo.deviceService().getDevice(eapPacket.
+ receivedFrom().deviceId()).serialNumber();
+
+ log.info("SampleRadiusCustomizer serial = {}", serialNo);
+ SubscriberAndDeviceInformation deviceInfo = customInfo.
+ subscriberService().get(serialNo);
+
+ if (deviceInfo == null) {
+ log.warn("No Device found with SN {}", serialNo);
+ return inPkt;
+ }
+ String nodeName = deviceInfo.nasId();
+
+ log.info("Setting user={} nasId={} nasPort{}", srcMac, nodeName,
+ nasPortId);
+ inPkt.updateAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
+ srcMac.toString().getBytes());
+
+ inPkt.updateAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
+ deviceInfo.ipAddress().toOctets());
+
+ inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_CALLING_STATION_ID,
+ srcMac.toString().getBytes());
+
+ // Check value - 16 was used in PoC2, as per PoC3 TS value should be 15
+ inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_PORT_TYPE,
+ ByteBuffer.allocate(4).putInt(15).array());
+
+ // Check - This may not be needed but was used in PoC2
+ inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_PORT,
+ ByteBuffer.allocate(4).putInt(46178304).array());
+ // Check - If this is needed, worked with this value in PoC2
+ inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_ACCT_SESSION_ID,
+ "023:27:46:00000".getBytes());
+
+ inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_ID,
+ nodeName.getBytes());
+ inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_PORT_ID,
+ nasPortId.getBytes());
+
+ return inPkt;
+ }
+
+ /**
+ * Customize the Ethernet header as per specific Setup or RADIUS
+ * server requirements.
+ *
+ * @param inPkt Ethernet packet to be changed
+ * @param eapPacket Incoming packet containing EAP for which this the
+ * RADIUS message is being created
+ * @return Changed Ethernet packet
+ */
+ public Ethernet customizeEthernetIPHeaders(Ethernet inPkt,
+ InboundPacket eapPacket) {
+
+ String serialNo = customInfo.deviceService().getDevice(eapPacket.
+ receivedFrom().deviceId()).serialNumber();
+
+ log.info("SampleRadiusCustomzer customizer serial = {}", serialNo);
+ SubscriberAndDeviceInformation deviceInfo = customInfo.
+ subscriberService().get(serialNo);
+
+ if (deviceInfo == null) {
+ log.warn("No Device found with SN {}", serialNo);
+ return inPkt;
+ }
+
+ inPkt.setSourceMACAddress(deviceInfo.hardwareIdentifier());
+
+ IPv4 ipv4Packet = (IPv4) inPkt.getPayload();
+ ipv4Packet.setSourceAddress(deviceInfo.ipAddress().toString());
+ inPkt.setPayload(ipv4Packet);
+
+ return inPkt;
+ }
+}
diff --git a/src/main/java/org/opencord/aaa/SocketBasedRadiusCommunicator.java b/src/main/java/org/opencord/aaa/SocketBasedRadiusCommunicator.java
new file mode 100755
index 0000000..1f046e4
--- /dev/null
+++ b/src/main/java/org/opencord/aaa/SocketBasedRadiusCommunicator.java
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.RADIUS;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketService;
+
+import org.slf4j.Logger;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Handles Socket based communication with the RADIUS server.
+ */
+public class SocketBasedRadiusCommunicator implements RadiusCommunicator {
+
+ // for verbose output
+ private final Logger log = getLogger(getClass());
+
+ // our unique identifier
+ private ApplicationId appId;
+
+ // to receive Packet-in events that we'll respond to
+ PacketService packetService;
+
+ // Socket used for UDP communications with RADIUS server
+ private DatagramSocket radiusSocket;
+
+ // Parsed RADIUS server addresses
+ protected InetAddress radiusIpAddress;
+
+ // RADIUS server TCP port number
+ protected short radiusServerPort;
+
+ // Executor for RADIUS communication thread
+ private ExecutorService executor;
+
+ AaaManager aaaManager;
+
+ SocketBasedRadiusCommunicator(ApplicationId appId, PacketService pktService,
+ AaaManager aaaManager) {
+ this.appId = appId;
+ this.packetService = pktService;
+ this.aaaManager = aaaManager;
+ }
+
+ @Override
+ public void initializeLocalState(AaaConfig newCfg) {
+ if (newCfg.radiusIp() != null) {
+ radiusIpAddress = newCfg.radiusIp();
+ }
+ radiusServerPort = newCfg.radiusServerUdpPort();
+
+ try {
+ radiusSocket = new DatagramSocket(null);
+ radiusSocket.setReuseAddress(true);
+ radiusSocket.bind(new InetSocketAddress(radiusServerPort));
+ } catch (Exception ex) {
+ log.error("Can't open RADIUS socket", ex);
+ }
+
+ executor = Executors.newSingleThreadExecutor(
+ new ThreadFactoryBuilder()
+ .setNameFormat("AAA-radius-%d").build());
+ executor.execute(radiusListener);
+ }
+
+ @Override
+ public void clearLocalState() {
+ radiusSocket.close();
+ executor.shutdownNow();
+ }
+
+ @Override
+ public void deactivate() { }
+
+ @Override
+ public void requestIntercepts() {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
+ packetService.requestPackets(selector.build(), CONTROL, appId);
+ }
+
+ @Override
+ public void withdrawIntercepts() {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
+ packetService.cancelPackets(selector.build(), CONTROL, appId);
+ }
+
+ @Override
+ public void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
+ try {
+ final byte[] data = radiusPacket.serialize();
+ final DatagramSocket socket = radiusSocket;
+
+ DatagramPacket packet =
+ new DatagramPacket(data, data.length,
+ radiusIpAddress, radiusServerPort);
+
+ socket.send(packet);
+ log.warn("Packet sent to Radius Server using socket packet = {}", packet);
+ } catch (IOException e) {
+ log.info("Cannot send packet to RADIUS server", e);
+ }
+ }
+
+ @Override
+ public void handlePacketFromServer(PacketContext context) {
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+
+ log.trace("Skipping Ethernet packet type {}",
+ EthType.EtherType.lookup(ethPkt.getEtherType()));
+ }
+
+ class RadiusListener implements Runnable {
+
+ @Override
+ public void run() {
+ boolean done = false;
+ int packetNumber = 1;
+
+ log.info("UDP listener thread starting up");
+ RADIUS inboundRadiusPacket;
+ while (!done) {
+ try {
+ byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
+ DatagramPacket inboundBasePacket =
+ new DatagramPacket(packetBuffer, packetBuffer.length);
+ DatagramSocket socket = radiusSocket;
+ socket.receive(inboundBasePacket);
+ log.info("Packet #{} received", packetNumber++);
+ try {
+ inboundRadiusPacket =
+ RADIUS.deserializer()
+ .deserialize(inboundBasePacket.getData(),
+ 0,
+ inboundBasePacket.getLength());
+ aaaManager.handleRadiusPacket(inboundRadiusPacket);
+ } catch (DeserializationException dex) {
+ log.error("Cannot deserialize packet", dex);
+ } catch (StateMachineException sme) {
+ log.error("Illegal state machine operation", sme);
+ }
+
+ } catch (IOException e) {
+ log.info("Socket was closed, exiting listener thread");
+ done = true;
+ }
+ }
+ }
+ }
+
+ RadiusListener radiusListener = new RadiusListener();
+}
diff --git a/src/main/java/org/opencord/aaa/StateMachine.java b/src/main/java/org/opencord/aaa/StateMachine.java
index 323313f..4a00966 100644
--- a/src/main/java/org/opencord/aaa/StateMachine.java
+++ b/src/main/java/org/opencord/aaa/StateMachine.java
@@ -1,6 +1,5 @@
/*
- *
- * Copyright 2015 AT&T Foundry
+ * 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.
@@ -18,11 +17,14 @@
package org.opencord.aaa;
-import java.util.BitSet;
import java.util.Map;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
+
+import org.opencord.olt.AccessDeviceService;
+
import org.slf4j.Logger;
import com.google.common.collect.Maps;
@@ -48,10 +50,9 @@
static final int TRANSITION_DENY_ACCESS = 3;
static final int TRANSITION_LOGOFF = 4;
- //map of access identifiers (issued at EAPOL START)
- static BitSet bitSet = new BitSet();
+ private static AccessDeviceService accessDeviceService;
- private int identifier = -1;
+ private static int identifier = -1;
private byte challengeIdentifier;
private byte[] challengeState;
private byte[] username;
@@ -61,6 +62,8 @@
private ConnectPoint supplicantConnectpoint;
private MacAddress supplicantAddress;
private short vlanId;
+ private VlanId ctag;
+ private byte priorityCode;
private String sessionId = null;
@@ -117,6 +120,7 @@
public static void initializeMaps() {
sessionIdMap = Maps.newConcurrentMap();
identifierMap = Maps.newConcurrentMap();
+ identifier = -1;
}
public static void destroyMaps() {
@@ -124,6 +128,10 @@
identifierMap = null;
}
+ public static void setAccessDeviceService(AccessDeviceService service) {
+ accessDeviceService = service;
+ }
+
public static Map<String, StateMachine> sessionIdMap() {
return sessionIdMap;
}
@@ -134,15 +142,24 @@
public static StateMachine lookupStateMachineBySessionId(String sessionId) {
return sessionIdMap.get(sessionId);
- } /**
+ }
+
+ public static void deleteStateMachineMapping(StateMachine machine) {
+ identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
+ }
+
+ /**
* State Machine Constructor.
*
* @param sessionId session Id represented by the switch dpid + port number
+ * @param ctag C-TAG for this subscriber
*/
- public StateMachine(String sessionId) {
- log.info("Creating a new state machine for {}", sessionId);
+ public StateMachine(String sessionId, VlanId ctag) {
+ log.info("Creating a new state machine for {} C-TAG {}", sessionId,
+ ctag);
this.sessionId = sessionId;
sessionIdMap.put(sessionId, this);
+ this.ctag = ctag;
}
/**
@@ -200,6 +217,24 @@
}
/**
+ * Gets the client's priority Code.
+ *
+ * @return client Priority code
+ */
+ public byte priorityCode() {
+ return priorityCode;
+ }
+
+ /**
+ * Sets the client's priority Code.
+ *
+ * @param priorityCode new client priority Code
+ */
+ public void setPriorityCode(byte priorityCode) {
+ this.priorityCode = priorityCode;
+ }
+
+ /**
* Gets the client id that is requesting for access.
*
* @return The client id.
@@ -209,30 +244,6 @@
}
/**
- * Create the identifier for the state machine (happens when goes to STARTED state).
- */
- private void createIdentifier() throws StateMachineException {
- log.debug("Creating Identifier.");
- int index;
-
- try {
- //find the first available spot for identifier assignment
- index = StateMachine.bitSet.nextClearBit(0);
-
- //there is a limit of 256 identifiers
- if (index == 256) {
- throw new StateMachineException("Cannot handle any new identifier. Limit is 256.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new StateMachineException(e.getMessage());
- }
-
- log.info("Assigning identifier {}", index);
- StateMachine.bitSet.set(index);
- this.identifier = index;
- }
-
- /**
* Set the challenge identifier and the state issued by the RADIUS.
*
* @param challengeIdentifier The challenge identifier set into the EAP packet from the RADIUS message.
@@ -325,21 +336,12 @@
*
* @return The state machine identifier.
*/
- public byte identifier() {
- return (byte) this.identifier;
+ public synchronized byte identifier() {
+ identifier = (identifier + 1) % 255;
+ identifierMap.put(identifier, this);
+ return (byte) identifier;
}
-
- protected void deleteIdentifier() {
- if (this.identifier != -1) {
- log.info("Freeing up " + this.identifier);
- //this state machine should be deleted and free up the identifier
- StateMachine.bitSet.clear(this.identifier);
- this.identifier = -1;
- }
- }
-
-
/**
* Move to the next state.
*
@@ -359,8 +361,7 @@
states[currentState].start();
//move to the next state
next(TRANSITION_START);
- createIdentifier();
- identifierMap.put(identifier, this);
+ identifier = this.identifier();
}
/**
@@ -386,9 +387,15 @@
//move to the next state
next(TRANSITION_AUTHORIZE_ACCESS);
- // TODO: put in calls to launch vSG here
+ if (accessDeviceService != null) {
+ log.info("Provisioning subscriber at {} with C-TAG {}",
+ supplicantConnectpoint(), ctag);
+ accessDeviceService.provisionSubscriber(supplicantConnectpoint(),
+ ctag);
+ }
- deleteIdentifier();
+ // Clear mapping
+ deleteStateMachineMapping(this);
}
/**
@@ -401,7 +408,8 @@
states[currentState].radiusDenied();
//move to the next state
next(TRANSITION_DENY_ACCESS);
- deleteIdentifier();
+ // Clear mappings
+ deleteStateMachineMapping(this);
}
/**
diff --git a/src/main/java/org/opencord/aaa/StateMachineException.java b/src/main/java/org/opencord/aaa/StateMachineException.java
index d132c2a..7e2e3ca 100644
--- a/src/main/java/org/opencord/aaa/StateMachineException.java
+++ b/src/main/java/org/opencord/aaa/StateMachineException.java
@@ -1,6 +1,5 @@
/*
- *
- * Copyright 2015 AT&T Foundry
+ * 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.
diff --git a/src/main/java/org/opencord/aaa/StateMachineInvalidTransitionException.java b/src/main/java/org/opencord/aaa/StateMachineInvalidTransitionException.java
index a97b02f..cfd949a 100644
--- a/src/main/java/org/opencord/aaa/StateMachineInvalidTransitionException.java
+++ b/src/main/java/org/opencord/aaa/StateMachineInvalidTransitionException.java
@@ -1,6 +1,5 @@
/*
- *
- * Copyright 2015 AT&T Foundry
+ * 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.
diff --git a/src/test/java/org/opencord/aaa/AaaManagerTest.java b/src/test/java/org/opencord/aaa/AaaManagerTest.java
index 4c1f7b2..dadcc71 100644
--- a/src/test/java/org/opencord/aaa/AaaManagerTest.java
+++ b/src/test/java/org/opencord/aaa/AaaManagerTest.java
@@ -29,6 +29,7 @@
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.NetworkConfigRegistryAdapter;
+import org.onosproject.net.packet.InboundPacket;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -47,7 +48,7 @@
private AaaManager aaaManager;
class AaaManagerWithoutRadiusServer extends AaaManager {
- protected void sendRadiusPacket(RADIUS radiusPacket) {
+ protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
savePacket(radiusPacket);
}
}
@@ -204,7 +205,7 @@
RADIUS radiusCodeAccessChallengePacket =
constructRadiusCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5);
- aaaManager.radiusListener.handleRadiusPacket(radiusCodeAccessChallengePacket);
+ aaaManager.handleRadiusPacket(radiusCodeAccessChallengePacket);
Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2);
checkRadiusPacket(aaaManager, radiusChallengeMD5Packet, EAP.ATTR_MD5);
@@ -221,7 +222,7 @@
RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3);
checkRadiusPacketFromSupplicant(responseMd5RadiusPacket);
- assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 0));
+ assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 3));
assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
// State machine should be in pending state
@@ -233,7 +234,7 @@
RADIUS successPacket =
constructRadiusCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS);
- aaaManager.radiusListener.handleRadiusPacket((successPacket));
+ aaaManager.handleRadiusPacket((successPacket));
Ethernet supplicantSuccessPacket = (Ethernet) fetchPacket(4);
checkRadiusPacket(aaaManager, supplicantSuccessPacket, EAP.SUCCESS);
diff --git a/src/test/java/org/opencord/aaa/StateMachineTest.java b/src/test/java/org/opencord/aaa/StateMachineTest.java
index f87d72f..3f95134 100644
--- a/src/test/java/org/opencord/aaa/StateMachineTest.java
+++ b/src/test/java/org/opencord/aaa/StateMachineTest.java
@@ -1,6 +1,5 @@
/*
- *
- * Copyright 2015 AT&T Foundry
+ * 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.
@@ -18,13 +17,13 @@
package org.opencord.aaa;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import org.onlab.packet.VlanId;
public class StateMachineTest {
StateMachine stateMachine = null;
@@ -32,15 +31,13 @@
@Before
public void setUp() {
System.out.println("Set Up.");
- StateMachine.bitSet.clear();
StateMachine.initializeMaps();
- stateMachine = new StateMachine("session0");
+ stateMachine = new StateMachine("session0", VlanId.vlanId((short) 2));
}
@After
public void tearDown() {
System.out.println("Tear Down.");
- StateMachine.bitSet.clear();
StateMachine.destroyMaps();
stateMachine = null;
}
@@ -216,62 +213,6 @@
assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
}
-
- @Test
- public void testIdentifierAvailability() throws StateMachineException {
- System.out.println("======= IDENTIFIER TEST =======.");
- byte identifier = stateMachine.identifier();
- System.out.println("State: " + stateMachine.state());
- System.out.println("Identifier: " + Byte.toUnsignedInt(identifier));
- Assert.assertEquals(-1, identifier);
- stateMachine.start();
-
-
- StateMachine sm247 = null;
- StateMachine sm3 = null;
-
-
- //create 255 others state machines
- for (int i = 1; i <= 255; i++) {
- StateMachine sm = new StateMachine("session" + i);
- sm.start();
- byte id = sm.identifier();
- Assert.assertEquals(i, Byte.toUnsignedInt(id));
- if (i == 3) {
- sm3 = sm;
- System.out.println("SM3: " + sm3.toString());
- }
- if (i == 247) {
- sm247 = sm;
- System.out.println("SM247: " + sm247.toString());
- }
- }
-
- //simulate the state machine for a specific session and logoff so we can free up a spot for an identifier
- //let's choose identifier 247 then we free up 3
- Assert.assertNotNull(sm247);
- sm247.requestAccess();
- sm247.authorizeAccess();
- sm247.logoff();
-
- Assert.assertNotNull(sm3);
- sm3.requestAccess();
- sm3.authorizeAccess();
- sm3.logoff();
-
- StateMachine otherSM3 = new StateMachine("session3b");
- otherSM3.start();
- otherSM3.requestAccess();
- byte id3 = otherSM3.identifier();
- Assert.assertEquals(3, Byte.toUnsignedInt(id3));
-
- StateMachine otherSM247 = new StateMachine("session247b");
- otherSM247.start();
- otherSM247.requestAccess();
- byte id247 = otherSM247.identifier();
- Assert.assertEquals(247, Byte.toUnsignedInt(id247));
- }
-
@Test
public void testSessionIdLookups() {
String sessionId1 = "session1";
@@ -285,8 +226,8 @@
StateMachine.lookupStateMachineBySessionId(sessionId2);
assertNull(machine2ShouldBeNull);
- StateMachine stateMachine1 = new StateMachine(sessionId1);
- StateMachine stateMachine2 = new StateMachine(sessionId2);
+ StateMachine stateMachine1 = new StateMachine(sessionId1, VlanId.vlanId((short) 2));
+ StateMachine stateMachine2 = new StateMachine(sessionId2, VlanId.vlanId((short) 2));
assertEquals(stateMachine1,
StateMachine.lookupStateMachineBySessionId(sessionId1));
@@ -307,9 +248,9 @@
StateMachine.lookupStateMachineById((byte) 2);
assertNull(machine2ShouldBeNull);
- StateMachine stateMachine1 = new StateMachine(sessionId1);
+ StateMachine stateMachine1 = new StateMachine(sessionId1, VlanId.vlanId((short) 2));
stateMachine1.start();
- StateMachine stateMachine2 = new StateMachine(sessionId2);
+ StateMachine stateMachine2 = new StateMachine(sessionId2, VlanId.vlanId((short) 2));
stateMachine2.start();
assertEquals(stateMachine1,