blob: 80d380f451fc8058ff269574e487d04aaf289d20 [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)
Simon Hunt2ce83042017-10-30 14:57:34 -070069public class
70AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080071 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070072
Ray Milkeyf61a24e2015-09-24 16:34:02 -070073 // for verbose output
74 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070075
Ray Milkeyf61a24e2015-09-24 16:34:02 -070076 // a list of our dependencies :
77 // to register with ONOS as an application - described next
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070080
Ray Milkeyf61a24e2015-09-24 16:34:02 -070081 // to receive Packet-in events that we'll respond to
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070084
Ray Milkeyf61a24e2015-09-24 16:34:02 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070086 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070087
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected DeviceService deviceService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected SubscriberAndDeviceInformationService subsService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected MastershipService mastershipService;
96
Simon Huntf31d8ce2017-10-24 15:51:24 -070097 // FIXME: can't depend on AccessDeviceService
98// @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99// protected AccessDeviceService accessDeviceService;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700100
Amit Ghoshf739be52017-09-21 15:49:37 +0100101 private final DeviceListener deviceListener = new InternalDeviceListener();
102
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700103 // NAS IP address
104 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100105
106 // self MAC address
107 protected static String nasMacAddress;
108
109 // Parsed RADIUS server addresses
110 protected InetAddress radiusIpAddress;
111
112 // MAC address of RADIUS server or net hop router
113 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700114
115 // RADIUS server secret
116 protected String radiusSecret;
117
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100118 // NAS Identifier
119 protected String nasId;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700120
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100121 // bindings
122 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700123
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700124 // our application-specific event handler
125 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700126
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700127 // our unique identifier
128 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700129
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100130 // Setup specific customization/attributes on the RADIUS packets
131 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700132
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100133 // packet customizer to use
134 private String customizer;
135
136 // Type of connection to use to communicate with Radius server, options are
137 // "socket" or "packet_out"
138 private String radiusConnectionType;
139
140 // Object for the spcific type of communication with the RADIUS
141 // server, socket based or packet_out based
142 RadiusCommunicator impl = null;
143
144 // latest configuration
145 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700146
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700147 // Configuration properties factory
148 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800149 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700150 AaaConfig.class,
151 "AAA") {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700152 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800153 public AaaConfig createConfig() {
154 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700155 }
156 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700157
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700158 // Listener for config changes
159 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700160
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700161 /**
162 * Builds an EAPOL packet based on the given parameters.
163 *
Simon Huntf31d8ce2017-10-24 15:51:24 -0700164 * @param dstMac destination MAC address
165 * @param srcMac source MAC address
166 * @param vlan VLAN identifier
167 * @param eapolType EAPOL type
168 * @param eap EAP payload
169 * @param priorityCode the priority code associated with the VLAN
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700170 * @return Ethernet frame
171 */
Simon Huntf31d8ce2017-10-24 15:51:24 -0700172 private static Ethernet buildEapolResponse(MacAddress dstMac,
173 MacAddress srcMac,
174 short vlan,
175 byte eapolType,
176 EAP eap,
177 byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700178
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700179 Ethernet eth = new Ethernet();
180 eth.setDestinationMACAddress(dstMac.toBytes());
181 eth.setSourceMACAddress(srcMac.toBytes());
182 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
183 if (vlan != Ethernet.VLAN_UNTAGGED) {
184 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100185 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700186 }
187 //eapol header
188 EAPOL eapol = new EAPOL();
189 eapol.setEapolType(eapolType);
190 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700191
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700192 //eap part
193 eapol.setPayload(eap);
194
195 eth.setPayload(eapol);
196 eth.setPad(true);
197 return eth;
198 }
Ari Saha89831742015-06-26 10:31:48 -0700199
Ari Saha89831742015-06-26 10:31:48 -0700200 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700201 public void activate() {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700202 netCfgService.registerConfigFactory(factory);
Charles Chandf7ff862017-01-20 11:22:05 -0800203 appId = coreService.registerApplication(APP_NAME);
Simon Hunt2ce83042017-10-30 14:57:34 -0700204 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800205 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Simon Hunt2ce83042017-10-30 14:57:34 -0700206 configureRadiusCommunication();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700207
Ari Saha89831742015-06-26 10:31:48 -0700208 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700209 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100210
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700211
212 StateMachine.initializeMaps();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700213 // FIXME: can't depend on AccessDeviceService
214// StateMachine.setAccessDeviceService(accessDeviceService);
Ari Saha89831742015-06-26 10:31:48 -0700215
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100216 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800217 netCfgService.addListener(cfgListener);
218
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100219 impl.requestIntercepts();
220
Amit Ghoshf739be52017-09-21 15:49:37 +0100221 deviceService.addListener(deviceListener);
222
Jian Li13c67162015-12-09 13:20:34 -0800223 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700224 }
225
Simon Hunt2ce83042017-10-30 14:57:34 -0700226
Ari Saha89831742015-06-26 10:31:48 -0700227 @Deactivate
228 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100229 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700230 // de-register and null our handler
231 packetService.removeProcessor(processor);
232 processor = null;
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530233 netCfgService.removeListener(cfgListener);
Simon Hunt2ce83042017-10-30 14:57:34 -0700234 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100235 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100236 deviceService.removeListener(deviceListener);
Jian Li13c67162015-12-09 13:20:34 -0800237 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700238 }
239
Simon Hunt2ce83042017-10-30 14:57:34 -0700240 private void configureRadiusCommunication() {
241 if (radiusConnectionType.toLowerCase().equals("socket")) {
242 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
243 } else {
244 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
245 deviceService, subsService, pktCustomizer, this);
246 }
247 }
248
249 private void configurePacketCustomizer() {
250 switch (customizer.toLowerCase()) {
251 case "sample":
252 pktCustomizer = new SamplePacketCustomizer(customInfo);
253 log.info("Created SamplePacketCustomizer");
254 break;
255 default:
256 pktCustomizer = new PacketCustomizer(customInfo);
257 log.info("Created default PacketCustomizer");
258 break;
259 }
260 }
261
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100262 /**
263 * Send RADIUS packet to the RADIUS server.
264 *
265 * @param radiusPacket RADIUS packet to be sent to server.
266 * @param inPkt Incoming EAPOL packet
267 */
268 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
269 impl.sendRadiusPacket(radiusPacket, inPkt);
270 }
Ray Milkey967776a2015-10-07 14:37:17 -0700271
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100272 /**
273 * Handles RADIUS packets.
274 *
275 * @param radiusPacket RADIUS packet coming from the RADIUS server.
276 * @throws StateMachineException if an illegal state transition is triggered
277 */
278 public void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Simon Huntf31d8ce2017-10-24 15:51:24 -0700279 StateMachine stateMachine =
280 StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100281 if (stateMachine == null) {
282 log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
283 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700284 }
Ari Saha89831742015-06-26 10:31:48 -0700285
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100286 EAP eapPayload;
287 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700288
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100289 switch (radiusPacket.getCode()) {
290 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Simon Huntf31d8ce2017-10-24 15:51:24 -0700291 RADIUSAttribute radiusAttrState =
292 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100293 byte[] challengeState = null;
294 if (radiusAttrState != null) {
295 challengeState = radiusAttrState.getValue();
296 }
297 eapPayload = radiusPacket.decapsulateMessage();
298 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
299 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Simon Huntf31d8ce2017-10-24 15:51:24 -0700300 MacAddress.valueOf(nasMacAddress),
301 stateMachine.vlanId(),
302 EAPOL.EAPOL_PACKET,
303 eapPayload, stateMachine.priorityCode());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100304 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
305 break;
Simon Huntf31d8ce2017-10-24 15:51:24 -0700306
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100307 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
308 //send an EAPOL - Success to the supplicant.
309 byte[] eapMessageSuccess =
310 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700311 eapPayload = deserializeEap(eapMessageSuccess);
312 if (eapPayload != null) {
313 eth = buildEapolResponse(stateMachine.supplicantAddress(),
314 MacAddress.valueOf(nasMacAddress),
315 stateMachine.vlanId(),
316 EAPOL.EAPOL_PACKET,
317 eapPayload, stateMachine.priorityCode());
318 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
319 stateMachine.authorizeAccess();
320 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100321 break;
Simon Huntf31d8ce2017-10-24 15:51:24 -0700322
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100323 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
324 //send an EAPOL - Failure to the supplicant.
325 byte[] eapMessageFailure;
326 eapPayload = new EAP();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700327 RADIUSAttribute radiusAttrEap =
328 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100329 if (radiusAttrEap == null) {
330 eapPayload.setCode(EAP.FAILURE);
331 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
332 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
333 } else {
334 eapMessageFailure = radiusAttrEap.getValue();
Simon Huntf31d8ce2017-10-24 15:51:24 -0700335 eapPayload = deserializeEap(eapMessageFailure);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100336 }
Simon Huntf31d8ce2017-10-24 15:51:24 -0700337 if (eapPayload != null) {
338 eth = buildEapolResponse(stateMachine.supplicantAddress(),
339 MacAddress.valueOf(nasMacAddress),
340 stateMachine.vlanId(),
341 EAPOL.EAPOL_PACKET,
342 eapPayload, stateMachine.priorityCode());
343 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
344 stateMachine.denyAccess();
345 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100346 break;
Simon Huntf31d8ce2017-10-24 15:51:24 -0700347
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100348 default:
Simon Huntf31d8ce2017-10-24 15:51:24 -0700349 log.warn("Unknown RADIUS message received with code: {}",
350 radiusPacket.getCode());
351 break;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100352 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700353 }
354
Simon Huntf31d8ce2017-10-24 15:51:24 -0700355 // Isolate the method call to deserialize the EAP payload --
356 // Note: the deserialize() instance method was deprecated in
357 // ONOS Cardinal (1.2), and removed in ONOS Magpie (1.12).
358 // A packet-specific Deserializer should be used instead.
359 private EAP deserializeEap(byte[] eapBytes) {
360 try {
361 return EAP.deserializer().deserialize(eapBytes, 0, eapBytes.length);
362 } catch (DeserializationException e) {
363 log.error("Unable to deserialize EAP packet", e);
364 }
365 return null;
366 }
367
Ray Milkey967776a2015-10-07 14:37:17 -0700368 /**
369 * Send the ethernet packet to the supplicant.
370 *
371 * @param ethernetPkt the ethernet packet
372 * @param connectPoint the connect point to send out
373 */
374 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
375 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
376 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
377 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
378 packetService.emit(packet);
379 }
380
Ari Saha89831742015-06-26 10:31:48 -0700381 // our handler defined as a private inner class
382
383 /**
384 * Packet processor responsible for forwarding packets along their paths.
385 */
386 private class ReactivePacketProcessor implements PacketProcessor {
387 @Override
388 public void process(PacketContext context) {
389
390 // Extract the original Ethernet frame from the packet information
391 InboundPacket pkt = context.inPacket();
392 Ethernet ethPkt = pkt.parsed();
393 if (ethPkt == null) {
394 return;
395 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100396
Ray Milkeyf51eba22015-09-25 10:24:23 -0700397 try {
398 // identify if incoming packet comes from supplicant (EAP) or RADIUS
399 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
400 case EAPOL:
401 handleSupplicantPacket(context.inPacket());
402 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700403 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100404 // any other packets let the specific implementation handle
405 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700406 }
Ray Milkey967776a2015-10-07 14:37:17 -0700407 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100408 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700409 }
410 }
411
Ray Milkey9eb293f2015-09-30 15:09:17 -0700412 /**
413 * Creates and initializes common fields of a RADIUS packet.
414 *
Ray Milkey967776a2015-10-07 14:37:17 -0700415 * @param stateMachine state machine for the request
Simon Huntf31d8ce2017-10-24 15:51:24 -0700416 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700417 * @return RADIUS packet
418 */
Ray Milkey967776a2015-10-07 14:37:17 -0700419 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700420 RADIUS radiusPayload =
421 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
422 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700423
424 // set Request Authenticator in StateMachine
425 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
426
Ray Milkey9eb293f2015-09-30 15:09:17 -0700427 radiusPayload.setIdentifier(identifier);
428 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700429 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700430
431 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700432 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700433
434 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700435
436 return radiusPayload;
437 }
Ari Saha89831742015-06-26 10:31:48 -0700438
439 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700440 * Handles PAE packets (supplicant).
441 *
442 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700443 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700444 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700445 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700446 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800447 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700448
Jonathan Harta46dddf2015-06-30 15:31:20 -0700449 DeviceId deviceId = inPacket.receivedFrom().deviceId();
450 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700451 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700452 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
453 if (stateMachine == null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100454 if (deviceService != null) {
455 String nasPortId = deviceService.getPort(inPacket.receivedFrom()).
456 annotations().value(AnnotationKeys.PORT_NAME);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700457
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100458 SubscriberAndDeviceInformation subscriber =
459 subsService.get(nasPortId);
460 if (subscriber != null) {
461 stateMachine = new StateMachine(sessionId, subscriber.cTag());
Amit Ghoshcf39d972017-08-16 08:15:20 +0100462 } else {
463 log.error("Could not create new state machine for {}", nasPortId);
464 return;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100465 }
466 } else {
467 stateMachine = new StateMachine(sessionId, VlanId.vlanId((short) 0));
468 }
469 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700470
471 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700472
473 switch (eapol.getEapolType()) {
474 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700475 stateMachine.start();
476 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700477
Ray Milkeyf51eba22015-09-25 10:24:23 -0700478 //send an EAP Request/Identify to the supplicant
479 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100480 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
Simon Huntf31d8ce2017-10-24 15:51:24 -0700481 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100482 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800483 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700484 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100485 eapPayload, stateMachine.priorityCode());
Jonathan Hart092dfb22015-11-16 23:05:21 -0800486 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700487 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700488
Ray Milkey967776a2015-10-07 14:37:17 -0700489 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700490
491 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800492 case EAPOL.EAPOL_LOGOFF:
Ray Milkeyb34b4962016-01-04 10:24:43 -0800493 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
494 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800495 }
496
497 break;
Ari Saha89831742015-06-26 10:31:48 -0700498 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700499 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700500 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700501 EAP eapPacket = (EAP) eapol.getPayload();
502
503 byte dataType = eapPacket.getDataType();
504 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700505
Ray Milkey9eb293f2015-09-30 15:09:17 -0700506 case EAP.ATTR_IDENTITY:
507 // request id access to RADIUS
508 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700509
Ray Milkey967776a2015-10-07 14:37:17 -0700510 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100511 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800512 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700513
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100514 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700515
Ray Milkey9eb293f2015-09-30 15:09:17 -0700516 // change the state to "PENDING"
517 stateMachine.requestAccess();
518 break;
Ari Saha89831742015-06-26 10:31:48 -0700519 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700520 // verify if the EAP identifier corresponds to the
521 // challenge identifier from the client state
522 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700523 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700524 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700525 radiusPayload =
526 getRadiusPayload(stateMachine,
527 stateMachine.identifier(),
528 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100529 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700530
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800531 if (stateMachine.challengeState() != null) {
532 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700533 stateMachine.challengeState());
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800534 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800535 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100536 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700537 }
538 break;
539 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700540 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700541 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100542 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700543
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800544 if (stateMachine.challengeState() != null) {
545 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Simon Huntf31d8ce2017-10-24 15:51:24 -0700546 stateMachine.challengeState());
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800547 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700548 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700549
Jonathan Hart092dfb22015-11-16 23:05:21 -0800550 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100551 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkey5493b512015-10-21 12:13:49 -0700552
Ray Milkeyf3790b82015-10-21 16:28:08 -0700553 if (stateMachine.state() != StateMachine.STATE_PENDING) {
554 stateMachine.requestAccess();
555 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700556
Ari Saha89831742015-06-26 10:31:48 -0700557 break;
558 default:
559 return;
560 }
561 break;
562 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700563 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700564 }
565 }
Ray Milkey967776a2015-10-07 14:37:17 -0700566 }
567
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100568 /**
569 * Configuration Listener, handles change in configuration.
570 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700571 private class InternalConfigListener implements NetworkConfigListener {
572
573 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800574 * Reconfigures the AAA application according to the
575 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700576 *
577 * @param cfg configuration object
578 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800579 private void reconfigureNetwork(AaaConfig cfg) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100580
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700581 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800582 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700583 } else {
584 newCfg = cfg;
585 }
586 if (newCfg.nasIp() != null) {
587 nasIpAddress = newCfg.nasIp();
588 }
589 if (newCfg.radiusIp() != null) {
590 radiusIpAddress = newCfg.radiusIp();
591 }
592 if (newCfg.radiusMac() != null) {
593 radiusMacAddress = newCfg.radiusMac();
594 }
595 if (newCfg.nasMac() != null) {
596 nasMacAddress = newCfg.nasMac();
597 }
598 if (newCfg.radiusSecret() != null) {
599 radiusSecret = newCfg.radiusSecret();
600 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100601
Simon Hunt2ce83042017-10-30 14:57:34 -0700602 boolean reconfigureCustomizer = false;
603 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
604 customizer = newCfg.radiusPktCustomizer();
605 configurePacketCustomizer();
606 reconfigureCustomizer = true;
607 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100608
Simon Hunt2ce83042017-10-30 14:57:34 -0700609 if (radiusConnectionType == null
610 || reconfigureCustomizer
611 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
612 radiusConnectionType = newCfg.radiusConnectionType();
613 if (impl != null) {
614 impl.withdrawIntercepts();
615 impl.clearLocalState();
616 }
617 configureRadiusCommunication();
618 impl.initializeLocalState(newCfg);
619 impl.requestIntercepts();
620 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100621 impl.clearLocalState();
622 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700623 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700624 }
625
626 @Override
627 public void event(NetworkConfigEvent event) {
628
629 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
630 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800631 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700632
Jonathan Hart092dfb22015-11-16 23:05:21 -0800633 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700634 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100635
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700636 log.info("Reconfigured");
637 }
638 }
639 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100640
641 private class InternalDeviceListener implements DeviceListener {
642 @Override
643 public void event(DeviceEvent event) {
644
645 switch (event.type()) {
646 case PORT_REMOVED:
647 DeviceId devId = event.subject().id();
648 PortNumber portNumber = event.port().number();
649 String sessionId = devId.toString() + portNumber.toString();
650
651 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
652 StateMachine removed = sessionIdMap.remove(sessionId);
653 if (removed != null) {
654 StateMachine.deleteStateMachineMapping(removed);
655 }
656
657 break;
658 default:
659 return;
660 }
661 }
662 }
Ari Saha89831742015-06-26 10:31:48 -0700663}