blob: 9ac7ffb9b6ec9f7823eba32ab2bb1f91b081a514 [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01002 * Copyright 2017-present Open Networking Foundation
Ari Saha89831742015-06-26 10:31:48 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
alshabib6d527452016-06-01 18:00:47 -070016package org.opencord.aaa;
Ari Saha89831742015-06-26 10:31:48 -070017
Ari Saha89831742015-06-26 10:31:48 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070021import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Simon Huntf31d8ce2017-10-24 15:51:24 -070023import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070024import org.onlab.packet.EAP;
25import org.onlab.packet.EAPOL;
26import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070027import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070028import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070029import org.onlab.packet.RADIUS;
30import org.onlab.packet.RADIUSAttribute;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010031import org.onlab.packet.VlanId;
Ari Saha89831742015-06-26 10:31:48 -070032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010034import org.onosproject.mastership.MastershipService;
35import org.onosproject.net.AnnotationKeys;
Ari Saha89831742015-06-26 10:31:48 -070036import org.onosproject.net.ConnectPoint;
37import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070038import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070039import org.onosproject.net.config.ConfigFactory;
40import org.onosproject.net.config.NetworkConfigEvent;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010043import org.onosproject.net.device.DeviceEvent;
44import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010045import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070046import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070047import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070048import org.onosproject.net.packet.DefaultOutboundPacket;
49import org.onosproject.net.packet.InboundPacket;
50import org.onosproject.net.packet.OutboundPacket;
51import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070052import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010054import org.opencord.sadis.SubscriberAndDeviceInformation;
55import org.opencord.sadis.SubscriberAndDeviceInformationService;
Ari Saha89831742015-06-26 10:31:48 -070056import org.slf4j.Logger;
57
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010058import java.net.InetAddress;
59import java.nio.ByteBuffer;
Amit Ghoshf739be52017-09-21 15:49:37 +010060import java.util.Map;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010061
Simon Huntf31d8ce2017-10-24 15:51:24 -070062import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
63import static org.slf4j.LoggerFactory.getLogger;
64
Ari Saha89831742015-06-26 10:31:48 -070065/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070066 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070067 */
68@Component(immediate = true)
Jonathan Hart092dfb22015-11-16 23:05:21 -080069public class AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080070 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070071
Ray Milkeyf61a24e2015-09-24 16:34:02 -070072 // for verbose output
73 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070074
Ray Milkeyf61a24e2015-09-24 16:34:02 -070075 // a list of our dependencies :
76 // to register with ONOS as an application - described next
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070079
Ray Milkeyf61a24e2015-09-24 16:34:02 -070080 // to receive Packet-in events that we'll respond to
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070083
Ray Milkeyf61a24e2015-09-24 16:34:02 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070085 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070086
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected SubscriberAndDeviceInformationService subsService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected MastershipService mastershipService;
95
Simon Huntf31d8ce2017-10-24 15:51:24 -070096 // FIXME: can't depend on AccessDeviceService
97// @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98// protected AccessDeviceService accessDeviceService;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070099
Amit Ghoshf739be52017-09-21 15:49:37 +0100100 private final DeviceListener deviceListener = new InternalDeviceListener();
101
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700102 // NAS IP address
103 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100104
105 // self MAC address
106 protected static String nasMacAddress;
107
108 // Parsed RADIUS server addresses
109 protected InetAddress radiusIpAddress;
110
111 // MAC address of RADIUS server or net hop router
112 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700113
114 // RADIUS server secret
115 protected String radiusSecret;
116
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100117 // NAS Identifier
118 protected String nasId;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700119
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100120 // bindings
121 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700122
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700123 // our application-specific event handler
124 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700125
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700126 // our unique identifier
127 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700128
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100129 // Setup specific customization/attributes on the RADIUS packets
130 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700131
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100132 // packet customizer to use
133 private String customizer;
134
135 // Type of connection to use to communicate with Radius server, options are
136 // "socket" or "packet_out"
137 private String radiusConnectionType;
138
139 // Object for the spcific type of communication with the RADIUS
140 // server, socket based or packet_out based
141 RadiusCommunicator impl = null;
142
143 // latest configuration
144 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700145
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700146 // Configuration properties factory
147 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800148 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700149 AaaConfig.class,
150 "AAA") {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700151 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800152 public AaaConfig createConfig() {
153 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700154 }
155 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700156
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700157 // Listener for config changes
158 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700159
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700160 /**
161 * Builds an EAPOL packet based on the given parameters.
162 *
Simon Huntf31d8ce2017-10-24 15:51:24 -0700163 * @param dstMac destination MAC address
164 * @param srcMac source MAC address
165 * @param vlan VLAN identifier
166 * @param eapolType EAPOL type
167 * @param eap EAP payload
168 * @param priorityCode the priority code associated with the VLAN
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700169 * @return Ethernet frame
170 */
Simon Huntf31d8ce2017-10-24 15:51:24 -0700171 private static Ethernet buildEapolResponse(MacAddress dstMac,
172 MacAddress srcMac,
173 short vlan,
174 byte eapolType,
175 EAP eap,
176 byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700177
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700178 Ethernet eth = new Ethernet();
179 eth.setDestinationMACAddress(dstMac.toBytes());
180 eth.setSourceMACAddress(srcMac.toBytes());
181 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
182 if (vlan != Ethernet.VLAN_UNTAGGED) {
183 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100184 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700185 }
186 //eapol header
187 EAPOL eapol = new EAPOL();
188 eapol.setEapolType(eapolType);
189 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700190
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700191 //eap part
192 eapol.setPayload(eap);
193
194 eth.setPayload(eapol);
195 eth.setPad(true);
196 return eth;
197 }
Ari Saha89831742015-06-26 10:31:48 -0700198
Ari Saha89831742015-06-26 10:31:48 -0700199 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700200 public void activate() {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700201 netCfgService.registerConfigFactory(factory);
Charles Chandf7ff862017-01-20 11:22:05 -0800202 appId = coreService.registerApplication(APP_NAME);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700203
Jonathan Hart092dfb22015-11-16 23:05:21 -0800204 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700205
Ari Saha89831742015-06-26 10:31:48 -0700206 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700207 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100208
209 customInfo = new CustomizationInfo(subsService, deviceService);
210
211 switch (customizer.toLowerCase()) {
212 case "sample":
213 pktCustomizer = new SamplePacketCustomizer(customInfo);
214 log.info("Created SamplePacketCustomizer");
215 break;
216 default:
217 pktCustomizer = new PacketCustomizer(customInfo);
218 log.info("Created default PacketCustomizer");
219 break;
220 }
221
222 if (radiusConnectionType.toLowerCase().equals("socket")) {
223 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
224 } else {
Simon Huntf31d8ce2017-10-24 15:51:24 -0700225 impl = new PortBasedRadiusCommunicator(appId, packetService,
226 mastershipService,
227 deviceService, subsService,
228 pktCustomizer, this);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100229 }
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700230
231 StateMachine.initializeMaps();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700232 // FIXME: can't depend on AccessDeviceService
233// StateMachine.setAccessDeviceService(accessDeviceService);
Ari Saha89831742015-06-26 10:31:48 -0700234
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100235 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800236 netCfgService.addListener(cfgListener);
237
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100238 impl.requestIntercepts();
239
Amit Ghoshf739be52017-09-21 15:49:37 +0100240 deviceService.addListener(deviceListener);
241
Jian Li13c67162015-12-09 13:20:34 -0800242 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700243 }
244
245 @Deactivate
246 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100247 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700248 // de-register and null our handler
249 packetService.removeProcessor(processor);
250 processor = null;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700251 StateMachine.destroyMaps();
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530252 netCfgService.removeListener(cfgListener);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100253 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100254 deviceService.removeListener(deviceListener);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100255
Jian Li13c67162015-12-09 13:20:34 -0800256 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700257 }
258
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100259 /**
260 * Send RADIUS packet to the RADIUS server.
261 *
262 * @param radiusPacket RADIUS packet to be sent to server.
263 * @param inPkt Incoming EAPOL packet
264 */
265 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
266 impl.sendRadiusPacket(radiusPacket, inPkt);
267 }
Ray Milkey967776a2015-10-07 14:37:17 -0700268
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100269 /**
270 * Handles RADIUS packets.
271 *
272 * @param radiusPacket RADIUS packet coming from the RADIUS server.
273 * @throws StateMachineException if an illegal state transition is triggered
274 */
275 public void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Simon Huntf31d8ce2017-10-24 15:51:24 -0700276 StateMachine stateMachine =
277 StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100278 if (stateMachine == null) {
279 log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
280 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700281 }
Ari Saha89831742015-06-26 10:31:48 -0700282
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100283 EAP eapPayload;
284 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700285
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100286 switch (radiusPacket.getCode()) {
287 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Simon Huntf31d8ce2017-10-24 15:51:24 -0700288 RADIUSAttribute radiusAttrState =
289 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100290 byte[] challengeState = null;
291 if (radiusAttrState != null) {
292 challengeState = radiusAttrState.getValue();
293 }
294 eapPayload = radiusPacket.decapsulateMessage();
295 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
296 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Simon Huntf31d8ce2017-10-24 15:51:24 -0700297 MacAddress.valueOf(nasMacAddress),
298 stateMachine.vlanId(),
299 EAPOL.EAPOL_PACKET,
300 eapPayload, stateMachine.priorityCode());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100301 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
302 break;
Simon Huntf31d8ce2017-10-24 15:51:24 -0700303
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100304 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
305 //send an EAPOL - Success to the supplicant.
306 byte[] eapMessageSuccess =
307 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700308 eapPayload = deserializeEap(eapMessageSuccess);
309 if (eapPayload != null) {
310 eth = buildEapolResponse(stateMachine.supplicantAddress(),
311 MacAddress.valueOf(nasMacAddress),
312 stateMachine.vlanId(),
313 EAPOL.EAPOL_PACKET,
314 eapPayload, stateMachine.priorityCode());
315 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
316 stateMachine.authorizeAccess();
317 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100318 break;
Simon Huntf31d8ce2017-10-24 15:51:24 -0700319
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100320 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
321 //send an EAPOL - Failure to the supplicant.
322 byte[] eapMessageFailure;
323 eapPayload = new EAP();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700324 RADIUSAttribute radiusAttrEap =
325 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100326 if (radiusAttrEap == null) {
327 eapPayload.setCode(EAP.FAILURE);
328 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
329 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
330 } else {
331 eapMessageFailure = radiusAttrEap.getValue();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700332 eapPayload = deserializeEap(eapMessageFailure);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100333 }
Simon Huntf31d8ce2017-10-24 15:51:24 -0700334 if (eapPayload != null) {
335 eth = buildEapolResponse(stateMachine.supplicantAddress(),
336 MacAddress.valueOf(nasMacAddress),
337 stateMachine.vlanId(),
338 EAPOL.EAPOL_PACKET,
339 eapPayload, stateMachine.priorityCode());
340 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
341 stateMachine.denyAccess();
342 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100343 break;
Simon Huntf31d8ce2017-10-24 15:51:24 -0700344
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100345 default:
Simon Huntf31d8ce2017-10-24 15:51:24 -0700346 log.warn("Unknown RADIUS message received with code: {}",
347 radiusPacket.getCode());
348 break;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100349 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700350 }
351
Simon Huntf31d8ce2017-10-24 15:51:24 -0700352 // Isolate the method call to deserialize the EAP payload --
353 // Note: the deserialize() instance method was deprecated in
354 // ONOS Cardinal (1.2), and removed in ONOS Magpie (1.12).
355 // A packet-specific Deserializer should be used instead.
356 private EAP deserializeEap(byte[] eapBytes) {
357 try {
358 return EAP.deserializer().deserialize(eapBytes, 0, eapBytes.length);
359 } catch (DeserializationException e) {
360 log.error("Unable to deserialize EAP packet", e);
361 }
362 return null;
363 }
364
Ray Milkey967776a2015-10-07 14:37:17 -0700365 /**
366 * Send the ethernet packet to the supplicant.
367 *
368 * @param ethernetPkt the ethernet packet
369 * @param connectPoint the connect point to send out
370 */
371 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
372 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
373 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
374 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
375 packetService.emit(packet);
376 }
377
Ari Saha89831742015-06-26 10:31:48 -0700378 // our handler defined as a private inner class
379
380 /**
381 * Packet processor responsible for forwarding packets along their paths.
382 */
383 private class ReactivePacketProcessor implements PacketProcessor {
384 @Override
385 public void process(PacketContext context) {
386
387 // Extract the original Ethernet frame from the packet information
388 InboundPacket pkt = context.inPacket();
389 Ethernet ethPkt = pkt.parsed();
390 if (ethPkt == null) {
391 return;
392 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100393
Ray Milkeyf51eba22015-09-25 10:24:23 -0700394 try {
395 // identify if incoming packet comes from supplicant (EAP) or RADIUS
396 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
397 case EAPOL:
398 handleSupplicantPacket(context.inPacket());
399 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700400 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100401 // any other packets let the specific implementation handle
402 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700403 }
Ray Milkey967776a2015-10-07 14:37:17 -0700404 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100405 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700406 }
407 }
408
Ray Milkey9eb293f2015-09-30 15:09:17 -0700409 /**
410 * Creates and initializes common fields of a RADIUS packet.
411 *
Ray Milkey967776a2015-10-07 14:37:17 -0700412 * @param stateMachine state machine for the request
Simon Huntf31d8ce2017-10-24 15:51:24 -0700413 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700414 * @return RADIUS packet
415 */
Ray Milkey967776a2015-10-07 14:37:17 -0700416 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700417 RADIUS radiusPayload =
418 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
419 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700420
421 // set Request Authenticator in StateMachine
422 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
423
Ray Milkey9eb293f2015-09-30 15:09:17 -0700424 radiusPayload.setIdentifier(identifier);
425 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700426 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700427
428 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700429 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700430
431 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700432
433 return radiusPayload;
434 }
Ari Saha89831742015-06-26 10:31:48 -0700435
436 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700437 * Handles PAE packets (supplicant).
438 *
439 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700440 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700441 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700442 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700443 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800444 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700445
Jonathan Harta46dddf2015-06-30 15:31:20 -0700446 DeviceId deviceId = inPacket.receivedFrom().deviceId();
447 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700448 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700449 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
450 if (stateMachine == null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100451 if (deviceService != null) {
452 String nasPortId = deviceService.getPort(inPacket.receivedFrom()).
453 annotations().value(AnnotationKeys.PORT_NAME);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700454
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100455 SubscriberAndDeviceInformation subscriber =
456 subsService.get(nasPortId);
457 if (subscriber != null) {
458 stateMachine = new StateMachine(sessionId, subscriber.cTag());
Amit Ghoshcf39d972017-08-16 08:15:20 +0100459 } else {
460 log.error("Could not create new state machine for {}", nasPortId);
461 return;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100462 }
463 } else {
464 stateMachine = new StateMachine(sessionId, VlanId.vlanId((short) 0));
465 }
466 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700467
468 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700469
470 switch (eapol.getEapolType()) {
471 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700472 stateMachine.start();
473 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700474
Ray Milkeyf51eba22015-09-25 10:24:23 -0700475 //send an EAP Request/Identify to the supplicant
476 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100477 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
Simon Huntf31d8ce2017-10-24 15:51:24 -0700478 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100479 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800480 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700481 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100482 eapPayload, stateMachine.priorityCode());
Jonathan Hart092dfb22015-11-16 23:05:21 -0800483 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700484 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700485
Ray Milkey967776a2015-10-07 14:37:17 -0700486 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700487
488 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800489 case EAPOL.EAPOL_LOGOFF:
Ray Milkeyb34b4962016-01-04 10:24:43 -0800490 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
491 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800492 }
493
494 break;
Ari Saha89831742015-06-26 10:31:48 -0700495 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700496 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700497 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700498 EAP eapPacket = (EAP) eapol.getPayload();
499
500 byte dataType = eapPacket.getDataType();
501 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700502
Ray Milkey9eb293f2015-09-30 15:09:17 -0700503 case EAP.ATTR_IDENTITY:
504 // request id access to RADIUS
505 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700506
Ray Milkey967776a2015-10-07 14:37:17 -0700507 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100508 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800509 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700510
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100511 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700512
Ray Milkey9eb293f2015-09-30 15:09:17 -0700513 // change the state to "PENDING"
514 stateMachine.requestAccess();
515 break;
Ari Saha89831742015-06-26 10:31:48 -0700516 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700517 // verify if the EAP identifier corresponds to the
518 // challenge identifier from the client state
519 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700520 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700521 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700522 radiusPayload =
523 getRadiusPayload(stateMachine,
524 stateMachine.identifier(),
525 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100526 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700527
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800528 if (stateMachine.challengeState() != null) {
529 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700530 stateMachine.challengeState());
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800531 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800532 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100533 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700534 }
535 break;
536 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700537 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700538 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100539 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700540
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800541 if (stateMachine.challengeState() != null) {
542 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700543 stateMachine.challengeState());
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800544 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700545 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700546
Jonathan Hart092dfb22015-11-16 23:05:21 -0800547 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100548 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkey5493b512015-10-21 12:13:49 -0700549
Ray Milkeyf3790b82015-10-21 16:28:08 -0700550 if (stateMachine.state() != StateMachine.STATE_PENDING) {
551 stateMachine.requestAccess();
552 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700553
Ari Saha89831742015-06-26 10:31:48 -0700554 break;
555 default:
556 return;
557 }
558 break;
559 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700560 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700561 }
562 }
Ray Milkey967776a2015-10-07 14:37:17 -0700563 }
564
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100565 /**
566 * Configuration Listener, handles change in configuration.
567 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700568 private class InternalConfigListener implements NetworkConfigListener {
569
570 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800571 * Reconfigures the AAA application according to the
572 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700573 *
574 * @param cfg configuration object
575 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800576 private void reconfigureNetwork(AaaConfig cfg) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100577
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700578 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800579 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700580 } else {
581 newCfg = cfg;
582 }
583 if (newCfg.nasIp() != null) {
584 nasIpAddress = newCfg.nasIp();
585 }
586 if (newCfg.radiusIp() != null) {
587 radiusIpAddress = newCfg.radiusIp();
588 }
589 if (newCfg.radiusMac() != null) {
590 radiusMacAddress = newCfg.radiusMac();
591 }
592 if (newCfg.nasMac() != null) {
593 nasMacAddress = newCfg.nasMac();
594 }
595 if (newCfg.radiusSecret() != null) {
596 radiusSecret = newCfg.radiusSecret();
597 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100598
599 radiusConnectionType = newCfg.radiusConnectionType();
600 customizer = newCfg.radiusPktCustomizer();
601
602 if (impl != null) {
603 impl.clearLocalState();
604 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700605 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700606 }
607
608 @Override
609 public void event(NetworkConfigEvent event) {
610
611 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
612 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800613 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700614
Jonathan Hart092dfb22015-11-16 23:05:21 -0800615 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700616 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100617
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700618 log.info("Reconfigured");
619 }
620 }
621 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100622
623 private class InternalDeviceListener implements DeviceListener {
624 @Override
625 public void event(DeviceEvent event) {
626
627 switch (event.type()) {
628 case PORT_REMOVED:
629 DeviceId devId = event.subject().id();
630 PortNumber portNumber = event.port().number();
631 String sessionId = devId.toString() + portNumber.toString();
632
633 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
634 StateMachine removed = sessionIdMap.remove(sessionId);
635 if (removed != null) {
636 StateMachine.deleteStateMachineMapping(removed);
637 }
638
639 break;
640 default:
641 return;
642 }
643 }
644 }
Ari Saha89831742015-06-26 10:31:48 -0700645}