blob: c920864179d8259758e78195deb1e44b8dc7f44f [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.Component;
19import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070020import org.apache.felix.scr.annotations.Reference;
21import org.apache.felix.scr.annotations.ReferenceCardinality;
Matt Jeanneret2ff1a782018-06-13 15:24:25 -040022import org.apache.commons.lang3.builder.ToStringBuilder;
Jonathan Hart4731dd92018-05-02 17:30:05 -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.olt.AccessDeviceService;
55import org.opencord.sadis.SubscriberAndDeviceInformation;
56import org.opencord.sadis.SubscriberAndDeviceInformationService;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053057import org.osgi.service.component.annotations.Activate;
Ari Saha89831742015-06-26 10:31:48 -070058import org.slf4j.Logger;
59
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010060import java.net.InetAddress;
61import java.nio.ByteBuffer;
Amit Ghoshf739be52017-09-21 15:49:37 +010062import java.util.Map;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010063
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053064import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
65import static org.slf4j.LoggerFactory.getLogger;
66
Ari Saha89831742015-06-26 10:31:48 -070067/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070068 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070069 */
70@Component(immediate = true)
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053071public class
72AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080073 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070074
Ray Milkeyf61a24e2015-09-24 16:34:02 -070075 // for verbose output
76 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070077
Ray Milkeyf61a24e2015-09-24 16:34:02 -070078 // a list of our dependencies :
79 // to register with ONOS as an application - described next
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070082
Ray Milkeyf61a24e2015-09-24 16:34:02 -070083 // to receive Packet-in events that we'll respond to
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070086
Ray Milkeyf61a24e2015-09-24 16:34:02 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070088 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070089
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DeviceService deviceService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected SubscriberAndDeviceInformationService subsService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected MastershipService mastershipService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected AccessDeviceService accessDeviceService;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700101
Amit Ghoshf739be52017-09-21 15:49:37 +0100102 private final DeviceListener deviceListener = new InternalDeviceListener();
103
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700104 // NAS IP address
105 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100106
107 // self MAC address
108 protected static String nasMacAddress;
109
110 // Parsed RADIUS server addresses
111 protected InetAddress radiusIpAddress;
112
113 // MAC address of RADIUS server or net hop router
114 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700115
116 // RADIUS server secret
117 protected String radiusSecret;
118
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100119 // NAS Identifier
120 protected String nasId;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700121
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100122 // bindings
123 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700124
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700125 // our application-specific event handler
126 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700127
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700128 // our unique identifier
129 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700130
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100131 // Setup specific customization/attributes on the RADIUS packets
132 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700133
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100134 // packet customizer to use
135 private String customizer;
136
137 // Type of connection to use to communicate with Radius server, options are
138 // "socket" or "packet_out"
139 private String radiusConnectionType;
140
141 // Object for the spcific type of communication with the RADIUS
142 // server, socket based or packet_out based
143 RadiusCommunicator impl = null;
144
145 // latest configuration
146 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700147
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700148 // Configuration properties factory
149 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800150 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
151 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700152 "AAA") {
153 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800154 public AaaConfig createConfig() {
155 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700156 }
157 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700158
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700159 // Listener for config changes
160 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700161
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700162 /**
163 * Builds an EAPOL packet based on the given parameters.
164 *
165 * @param dstMac destination MAC address
166 * @param srcMac source MAC address
167 * @param vlan vlan identifier
168 * @param eapolType EAPOL type
169 * @param eap EAP payload
170 * @return Ethernet frame
171 */
172 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100173 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700174
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700175 Ethernet eth = new Ethernet();
176 eth.setDestinationMACAddress(dstMac.toBytes());
177 eth.setSourceMACAddress(srcMac.toBytes());
178 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
179 if (vlan != Ethernet.VLAN_UNTAGGED) {
180 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100181 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700182 }
183 //eapol header
184 EAPOL eapol = new EAPOL();
185 eapol.setEapolType(eapolType);
186 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700187
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700188 //eap part
189 eapol.setPayload(eap);
190
191 eth.setPayload(eapol);
192 eth.setPad(true);
193 return eth;
194 }
Ari Saha89831742015-06-26 10:31:48 -0700195
Ari Saha89831742015-06-26 10:31:48 -0700196 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700197 public void activate() {
Charles Chandf7ff862017-01-20 11:22:05 -0800198 appId = coreService.registerApplication(APP_NAME);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400199 netCfgService.addListener(cfgListener);
200 netCfgService.registerConfigFactory(factory);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530201 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800202 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400203 log.info("Starting with config {} {}", this, newCfg);
204
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530205 configureRadiusCommunication();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700206
Ari Saha89831742015-06-26 10:31:48 -0700207 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700208 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100209
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700210
211 StateMachine.initializeMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100212 StateMachine.setAccessDeviceService(accessDeviceService);
Ari Saha89831742015-06-26 10:31:48 -0700213
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100214 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800215
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100216 impl.requestIntercepts();
217
Amit Ghoshf739be52017-09-21 15:49:37 +0100218 deviceService.addListener(deviceListener);
219
Jian Li13c67162015-12-09 13:20:34 -0800220 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700221 }
222
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530223
Ari Saha89831742015-06-26 10:31:48 -0700224 @Deactivate
225 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100226 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700227 // de-register and null our handler
228 packetService.removeProcessor(processor);
229 processor = null;
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530230 netCfgService.removeListener(cfgListener);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530231 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100232 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100233 deviceService.removeListener(deviceListener);
Jian Li13c67162015-12-09 13:20:34 -0800234 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700235 }
236
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530237 private void configureRadiusCommunication() {
238 if (radiusConnectionType.toLowerCase().equals("socket")) {
239 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
240 } else {
241 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
242 deviceService, subsService, pktCustomizer, this);
243 }
244 }
245
246 private void configurePacketCustomizer() {
247 switch (customizer.toLowerCase()) {
248 case "sample":
249 pktCustomizer = new SamplePacketCustomizer(customInfo);
250 log.info("Created SamplePacketCustomizer");
251 break;
252 default:
253 pktCustomizer = new PacketCustomizer(customInfo);
254 log.info("Created default PacketCustomizer");
255 break;
256 }
257 }
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
Jonathan Hart4731dd92018-05-02 17:30:05 -0700274 * @throws DeserializationException if packet deserialization fails
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100275 */
Jonathan Hart4731dd92018-05-02 17:30:05 -0700276 public void handleRadiusPacket(RADIUS radiusPacket)
277 throws StateMachineException, DeserializationException {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100278 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
279 if (stateMachine == null) {
280 log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
281 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700282 }
Ari Saha89831742015-06-26 10:31:48 -0700283
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100284 EAP eapPayload;
285 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700286
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100287 switch (radiusPacket.getCode()) {
288 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400289 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100290 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
291 byte[] challengeState = null;
292 if (radiusAttrState != null) {
293 challengeState = radiusAttrState.getValue();
294 }
295 eapPayload = radiusPacket.decapsulateMessage();
296 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
297 eth = buildEapolResponse(stateMachine.supplicantAddress(),
298 MacAddress.valueOf(nasMacAddress),
299 stateMachine.vlanId(),
300 EAPOL.EAPOL_PACKET,
301 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400302 log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100303 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
304 break;
305 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400306 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100307 //send an EAPOL - Success to the supplicant.
308 byte[] eapMessageSuccess =
309 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700310 eapPayload = EAP.deserializer().deserialize(
311 eapMessageSuccess, 0, eapMessageSuccess.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100312 eth = buildEapolResponse(stateMachine.supplicantAddress(),
313 MacAddress.valueOf(nasMacAddress),
314 stateMachine.vlanId(),
315 EAPOL.EAPOL_PACKET,
316 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400317 log.info("Send EAP success message to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100318 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
319
320 stateMachine.authorizeAccess();
321
322 break;
323 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400324 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100325 //send an EAPOL - Failure to the supplicant.
326 byte[] eapMessageFailure;
327 eapPayload = new EAP();
328 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
329 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();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700335 eapPayload = EAP.deserializer().deserialize(
336 eapMessageFailure, 0, eapMessageFailure.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100337 }
338 eth = buildEapolResponse(stateMachine.supplicantAddress(),
339 MacAddress.valueOf(nasMacAddress),
340 stateMachine.vlanId(),
341 EAPOL.EAPOL_PACKET,
342 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400343 log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100344 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
345 stateMachine.denyAccess();
346
347 break;
348 default:
349 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
350 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700351 }
352
Ray Milkey967776a2015-10-07 14:37:17 -0700353 /**
354 * Send the ethernet packet to the supplicant.
355 *
356 * @param ethernetPkt the ethernet packet
357 * @param connectPoint the connect point to send out
358 */
359 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
360 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
361 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
362 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
363 packetService.emit(packet);
364 }
365
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400366 @Override
367 public String toString() {
368 return ToStringBuilder.reflectionToString(this);
369 }
370
Ari Saha89831742015-06-26 10:31:48 -0700371 // our handler defined as a private inner class
372
373 /**
374 * Packet processor responsible for forwarding packets along their paths.
375 */
376 private class ReactivePacketProcessor implements PacketProcessor {
377 @Override
378 public void process(PacketContext context) {
379
380 // Extract the original Ethernet frame from the packet information
381 InboundPacket pkt = context.inPacket();
382 Ethernet ethPkt = pkt.parsed();
383 if (ethPkt == null) {
384 return;
385 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100386
Ray Milkeyf51eba22015-09-25 10:24:23 -0700387 try {
388 // identify if incoming packet comes from supplicant (EAP) or RADIUS
389 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
390 case EAPOL:
391 handleSupplicantPacket(context.inPacket());
392 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700393 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100394 // any other packets let the specific implementation handle
395 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700396 }
Ray Milkey967776a2015-10-07 14:37:17 -0700397 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100398 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700399 }
400 }
401
Ray Milkey9eb293f2015-09-30 15:09:17 -0700402 /**
403 * Creates and initializes common fields of a RADIUS packet.
404 *
Ray Milkey967776a2015-10-07 14:37:17 -0700405 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700406 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700407 * @return RADIUS packet
408 */
Ray Milkey967776a2015-10-07 14:37:17 -0700409 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700410 RADIUS radiusPayload =
411 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
412 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700413
414 // set Request Authenticator in StateMachine
415 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
416
Ray Milkey9eb293f2015-09-30 15:09:17 -0700417 radiusPayload.setIdentifier(identifier);
418 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700419 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700420
421 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800422 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700423
424 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700425
426 return radiusPayload;
427 }
Ari Saha89831742015-06-26 10:31:48 -0700428
429 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700430 * Handles PAE packets (supplicant).
431 *
432 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700433 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700434 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700435 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700436 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800437 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700438
Jonathan Harta46dddf2015-06-30 15:31:20 -0700439 DeviceId deviceId = inPacket.receivedFrom().deviceId();
440 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700441 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700442 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
443 if (stateMachine == null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100444 if (deviceService != null) {
445 String nasPortId = deviceService.getPort(inPacket.receivedFrom()).
446 annotations().value(AnnotationKeys.PORT_NAME);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700447
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100448 SubscriberAndDeviceInformation subscriber =
449 subsService.get(nasPortId);
450 if (subscriber != null) {
451 stateMachine = new StateMachine(sessionId, subscriber.cTag());
Amit Ghoshcf39d972017-08-16 08:15:20 +0100452 } else {
453 log.error("Could not create new state machine for {}", nasPortId);
454 return;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100455 }
456 } else {
457 stateMachine = new StateMachine(sessionId, VlanId.vlanId((short) 0));
458 }
459 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700460
461 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700462
463 switch (eapol.getEapolType()) {
464 case EAPOL.EAPOL_START:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400465 log.debug("EAP packet: EAPOL_START");
Ray Milkeyf51eba22015-09-25 10:24:23 -0700466 stateMachine.start();
467 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700468
Ray Milkeyf51eba22015-09-25 10:24:23 -0700469 //send an EAP Request/Identify to the supplicant
470 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100471 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
472 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
473 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800474 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700475 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100476 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400477
Jonathan Hart092dfb22015-11-16 23:05:21 -0800478 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700479 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700480
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400481 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
Ray Milkey967776a2015-10-07 14:37:17 -0700482 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700483
484 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800485 case EAPOL.EAPOL_LOGOFF:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400486 log.debug("EAP packet: EAPOL_LOGOFF");
Ray Milkeyb34b4962016-01-04 10:24:43 -0800487 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
488 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800489 }
490
491 break;
Ari Saha89831742015-06-26 10:31:48 -0700492 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700493 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700494 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700495 EAP eapPacket = (EAP) eapol.getPayload();
496
497 byte dataType = eapPacket.getDataType();
498 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700499
Ray Milkey9eb293f2015-09-30 15:09:17 -0700500 case EAP.ATTR_IDENTITY:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400501 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700502 // request id access to RADIUS
503 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700504
Ray Milkey967776a2015-10-07 14:37:17 -0700505 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100506 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800507 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700508
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100509 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700510
Ray Milkey9eb293f2015-09-30 15:09:17 -0700511 // change the state to "PENDING"
512 stateMachine.requestAccess();
513 break;
Ari Saha89831742015-06-26 10:31:48 -0700514 case EAP.ATTR_MD5:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400515 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700516 // verify if the EAP identifier corresponds to the
517 // challenge identifier from the client state
518 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700519 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700520 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700521 radiusPayload =
522 getRadiusPayload(stateMachine,
523 stateMachine.identifier(),
524 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100525 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700526
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800527 if (stateMachine.challengeState() != null) {
528 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
529 stateMachine.challengeState());
530 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800531 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100532 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700533 }
534 break;
535 case EAP.ATTR_TLS:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400536 log.debug("EAP packet: EAPOL_PACKET 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,
543 stateMachine.challengeState());
544 }
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:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400556 log.warn("Unknown EAP packet type");
Ari Saha89831742015-06-26 10:31:48 -0700557 return;
558 }
559 break;
560 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400561 log.debug("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700562 }
563 }
Ray Milkey967776a2015-10-07 14:37:17 -0700564 }
565
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100566 /**
567 * Configuration Listener, handles change in configuration.
568 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700569 private class InternalConfigListener implements NetworkConfigListener {
570
571 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800572 * Reconfigures the AAA application according to the
573 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700574 *
575 * @param cfg configuration object
576 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800577 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400578 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100579
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700580 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800581 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700582 } else {
583 newCfg = cfg;
584 }
585 if (newCfg.nasIp() != null) {
586 nasIpAddress = newCfg.nasIp();
587 }
588 if (newCfg.radiusIp() != null) {
589 radiusIpAddress = newCfg.radiusIp();
590 }
591 if (newCfg.radiusMac() != null) {
592 radiusMacAddress = newCfg.radiusMac();
593 }
594 if (newCfg.nasMac() != null) {
595 nasMacAddress = newCfg.nasMac();
596 }
597 if (newCfg.radiusSecret() != null) {
598 radiusSecret = newCfg.radiusSecret();
599 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100600
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530601 boolean reconfigureCustomizer = false;
602 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
603 customizer = newCfg.radiusPktCustomizer();
604 configurePacketCustomizer();
605 reconfigureCustomizer = true;
606 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100607
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530608 if (radiusConnectionType == null
609 || reconfigureCustomizer
610 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
611 radiusConnectionType = newCfg.radiusConnectionType();
612 if (impl != null) {
613 impl.withdrawIntercepts();
614 impl.clearLocalState();
615 }
616 configureRadiusCommunication();
617 impl.initializeLocalState(newCfg);
618 impl.requestIntercepts();
619 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100620 impl.clearLocalState();
621 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700622 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700623 }
624
625 @Override
626 public void event(NetworkConfigEvent event) {
627
628 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
629 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800630 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700631
Jonathan Hart092dfb22015-11-16 23:05:21 -0800632 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700633 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100634
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400635 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700636 }
637 }
638 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100639
640 private class InternalDeviceListener implements DeviceListener {
641 @Override
642 public void event(DeviceEvent event) {
643
644 switch (event.type()) {
645 case PORT_REMOVED:
646 DeviceId devId = event.subject().id();
647 PortNumber portNumber = event.port().number();
648 String sessionId = devId.toString() + portNumber.toString();
649
650 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
651 StateMachine removed = sessionIdMap.remove(sessionId);
652 if (removed != null) {
653 StateMachine.deleteStateMachineMapping(removed);
654 }
655
656 break;
657 default:
658 return;
659 }
660 }
661 }
Ari Saha89831742015-06-26 10:31:48 -0700662}