aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java')
-rw-r--r--framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java244
1 files changed, 128 insertions, 116 deletions
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
index 479ec7ed..72a5b122 100644
--- a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
+++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
@@ -15,10 +15,13 @@
*/
package org.onosproject.aaa;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;
-import java.util.Optional;
-import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -30,20 +33,13 @@ import org.onlab.packet.EAP;
import org.onlab.packet.EAPOL;
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
-import org.onlab.packet.TpPort;
-import org.onlab.packet.UDP;
-import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
import org.onosproject.net.PortNumber;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
@@ -53,7 +49,6 @@ 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.host.HostService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
@@ -63,6 +58,8 @@ import org.onosproject.net.packet.PacketService;
import org.onosproject.xosintegration.VoltTenantService;
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;
@@ -85,10 +82,6 @@ public class AAA {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
- // end host information
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VoltTenantService voltTenantService;
@@ -121,6 +114,12 @@ public class AAA {
// our unique identifier
private ApplicationId appId;
+ // Socket used for UDP communications with RADIUS server
+ private DatagramSocket radiusSocket;
+
+ // Executor for RADIUS communication thread
+ private ExecutorService executor;
+
// Configuration properties factory
private final ConfigFactory factory =
new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY,
@@ -184,7 +183,16 @@ public class AAA {
StateMachine.initializeMaps();
- hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress));
+ try {
+ radiusSocket = new DatagramSocket(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);
}
@Deactivate
@@ -195,6 +203,24 @@ public class AAA {
packetService.removeProcessor(processor);
processor = null;
StateMachine.destroyMaps();
+ radiusSocket.close();
+ executor.shutdownNow();
+ }
+
+ protected void sendRADIUSPacket(RADIUS radiusPacket) {
+
+ 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);
+ }
}
/**
@@ -205,14 +231,6 @@ public class AAA {
selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
packetService.requestPackets(selector.build(),
CONTROL, appId);
-
- TrafficSelector radSelector = DefaultTrafficSelector.builder()
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(radiusServerPort))
- .matchUdpSrc(TpPort.tpPort(radiusServerPort))
- .build();
- packetService.requestPackets(radSelector, CONTROL, appId);
}
/**
@@ -222,14 +240,19 @@ public class AAA {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
packetService.cancelPackets(selector.build(), CONTROL, appId);
+ }
- TrafficSelector radSelector = DefaultTrafficSelector.builder()
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(radiusServerPort))
- .matchUdpSrc(TpPort.tpPort(radiusServerPort))
- .build();
- packetService.cancelPackets(radSelector, CONTROL, appId);
+ /**
+ * 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()));
+ packetService.emit(packet);
}
// our handler defined as a private inner class
@@ -253,26 +276,11 @@ public class AAA {
case EAPOL:
handleSupplicantPacket(context.inPacket());
break;
- case IPV4:
- IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
- Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress());
- Ip4Address radiusIp4Address = Ip4Address.valueOf(radiusIpAddress);
- if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
- // TODO: check for port as well when it's configurable
- UDP udpPacket = (UDP) ipv4Packet.getPayload();
-
- byte[] datagram = udpPacket.getPayload().serialize();
- RADIUS radiusPacket;
- radiusPacket = RADIUS.deserializer().deserialize(datagram, 0, datagram.length);
- handleRadiusPacket(radiusPacket);
- }
-
- break;
default:
log.trace("Skipping Ethernet packet type {}",
EthType.EtherType.lookup(ethPkt.getEtherType()));
}
- } catch (DeserializationException | StateMachineException e) {
+ } catch (StateMachineException e) {
log.warn("Unable to process RADIUS packet:", e);
}
}
@@ -280,23 +288,26 @@ public class AAA {
/**
* Creates and initializes common fields of a RADIUS packet.
*
- * @param identifier RADIUS identifier
+ * @param stateMachine state machine for the request
* @param eapPacket EAP packet
* @return RADIUS packet
*/
- private RADIUS getRadiusPayload(byte identifier, EAP eapPacket) {
+ 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,
- eapPacket.getData());
+ stateMachine.username());
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
AAA.this.nasIpAddress.getAddress());
radiusPayload.encapsulateMessage(eapPacket);
- radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
return radiusPayload;
}
@@ -329,13 +340,13 @@ public class AAA {
//send an EAP Request/Identify to the supplicant
EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
- Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L),
+ Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(nasMacAddress),
ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
eapPayload);
stateMachine.setSupplicantAddress(srcMAC);
stateMachine.setVlanId(ethPkt.getVlanID());
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+ sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
break;
case EAPOL.EAPOL_PACKET:
@@ -350,11 +361,10 @@ public class AAA {
// request id access to RADIUS
stateMachine.setUsername(eapPacket.getData());
- radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket);
+ radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
+ radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
- // set Request Authenticator in StateMachine
- stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
- sendRadiusMessage(radiusPayload);
+ sendRADIUSPacket(radiusPayload);
// change the state to "PENDING"
stateMachine.requestAccess();
@@ -365,24 +375,31 @@ public class AAA {
// machine.
if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
//send the RADIUS challenge response
- radiusPayload = getRadiusPayload(stateMachine.challengeIdentifier(), eapPacket);
+ radiusPayload =
+ getRadiusPayload(stateMachine,
+ stateMachine.identifier(),
+ eapPacket);
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
stateMachine.challengeState());
- sendRadiusMessage(radiusPayload);
+ radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
+ sendRADIUSPacket(radiusPayload);
}
break;
case EAP.ATTR_TLS:
// request id access to RADIUS
- radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket);
+ radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
stateMachine.challengeState());
stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
- sendRadiusMessage(radiusPayload);
- // TODO: this gets called on every fragment, should only be called at TLS-Start
- stateMachine.requestAccess();
+ radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
+ sendRADIUSPacket(radiusPayload);
+
+ if (stateMachine.state() != StateMachine.STATE_PENDING) {
+ stateMachine.requestAccess();
+ }
break;
default:
@@ -392,14 +409,18 @@ public class AAA {
default:
log.trace("Skipping EAPOL message {}", eapol.getEapolType());
}
+
}
+ }
+
+ class RadiusListener implements Runnable {
/**
* Handles RADIUS packets.
*
* @param radiusPacket RADIUS packet coming from the RADIUS server.
*/
- private void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
+ protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
if (stateMachine == null) {
log.error("Invalid session identifier, exiting...");
@@ -410,13 +431,16 @@ public class AAA {
Ethernet eth;
switch (radiusPacket.getCode()) {
case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
- byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
+ byte[] challengeState =
+ radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
eapPayload = radiusPacket.decapsulateMessage();
stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
eth = buildEapolResponse(stateMachine.supplicantAddress(),
- MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
+ MacAddress.valueOf(nasMacAddress),
+ stateMachine.vlanId(),
+ EAPOL.EAPOL_PACKET,
eapPayload);
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+ sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
break;
case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
//send an EAPOL - Success to the supplicant.
@@ -425,9 +449,11 @@ public class AAA {
eapPayload = new EAP();
eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
eth = buildEapolResponse(stateMachine.supplicantAddress(),
- MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
+ MacAddress.valueOf(nasMacAddress),
+ stateMachine.vlanId(),
+ EAPOL.EAPOL_PACKET,
eapPayload);
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+ sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
stateMachine.authorizeAccess();
break;
@@ -439,59 +465,45 @@ public class AAA {
}
}
- private void sendRadiusMessage(RADIUS radiusMessage) {
- Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress));
- Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst();
-
- Host dst;
- if (!odst.isPresent()) {
- log.info("Radius server {} is not present", radiusIpAddress);
- return;
- } else {
- dst = odst.get();
- }
-
- UDP udp = new UDP();
- IPv4 ip4Packet = new IPv4();
- Ethernet ethPkt = new Ethernet();
- radiusMessage.setParent(udp);
- udp.setDestinationPort(radiusServerPort);
- udp.setSourcePort(radiusServerPort);
- udp.setPayload(radiusMessage);
- udp.setParent(ip4Packet);
- ip4Packet.setSourceAddress(AAA.this.nasIpAddress.getHostAddress());
- ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress.getHostAddress());
- ip4Packet.setProtocol(IPv4.PROTOCOL_UDP);
- ip4Packet.setPayload(udp);
- ip4Packet.setParent(ethPkt);
- ethPkt.setDestinationMACAddress(radiusMacAddress);
- ethPkt.setSourceMACAddress(nasMacAddress);
- ethPkt.setEtherType(Ethernet.TYPE_IPV4);
- ethPkt.setPayload(ip4Packet);
-
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(PortNumber.portNumber(radiusPort)).build();
- OutboundPacket packet = new DefaultOutboundPacket(DeviceId.deviceId(radiusSwitch),
- treatment, ByteBuffer.wrap(ethPkt.serialize()));
- packetService.emit(packet);
- }
+ @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);
+ }
- /**
- * 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()));
- packetService.emit(packet);
+ } catch (IOException e) {
+ log.info("Socket was closed, exiting listener thread");
+ done = true;
+ }
+ }
}
-
}
+ RadiusListener radiusListener = new RadiusListener();
+
private class InternalConfigListener implements NetworkConfigListener {
/**