blob: 4fc0fab7cf95c68fc45450ff872215f7d0f81422 [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;
Jonathan Hart4731dd92018-05-02 17:30:05 -070022import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070023import org.onlab.packet.EAP;
24import org.onlab.packet.EAPOL;
25import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070026import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070027import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070028import org.onlab.packet.RADIUS;
29import org.onlab.packet.RADIUSAttribute;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010030import org.onlab.packet.VlanId;
Ari Saha89831742015-06-26 10:31:48 -070031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010033import org.onosproject.mastership.MastershipService;
34import org.onosproject.net.AnnotationKeys;
Ari Saha89831742015-06-26 10:31:48 -070035import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070037import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigListener;
41import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010042import org.onosproject.net.device.DeviceEvent;
43import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010044import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070046import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070047import org.onosproject.net.packet.DefaultOutboundPacket;
48import org.onosproject.net.packet.InboundPacket;
49import org.onosproject.net.packet.OutboundPacket;
50import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070051import org.onosproject.net.packet.PacketProcessor;
52import org.onosproject.net.packet.PacketService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010053import org.opencord.olt.AccessDeviceService;
54import org.opencord.sadis.SubscriberAndDeviceInformation;
55import org.opencord.sadis.SubscriberAndDeviceInformationService;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053056import org.osgi.service.component.annotations.Activate;
Ari Saha89831742015-06-26 10:31:48 -070057import org.slf4j.Logger;
58
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010059import java.net.InetAddress;
60import java.nio.ByteBuffer;
Amit Ghoshf739be52017-09-21 15:49:37 +010061import java.util.Map;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010062
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053063import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
64import static org.slf4j.LoggerFactory.getLogger;
65
Ari Saha89831742015-06-26 10:31:48 -070066/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070067 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070068 */
69@Component(immediate = true)
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053070public class
71AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080072 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070073
Ray Milkeyf61a24e2015-09-24 16:34:02 -070074 // for verbose output
75 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070076
Ray Milkeyf61a24e2015-09-24 16:34:02 -070077 // a list of our dependencies :
78 // to register with ONOS as an application - described next
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070081
Ray Milkeyf61a24e2015-09-24 16:34:02 -070082 // to receive Packet-in events that we'll respond to
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070085
Ray Milkeyf61a24e2015-09-24 16:34:02 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070087 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070088
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected DeviceService deviceService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected SubscriberAndDeviceInformationService subsService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected MastershipService mastershipService;
97
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,
150 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700151 "AAA") {
152 @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 *
164 * @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 * @return Ethernet frame
170 */
171 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100172 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700173
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700174 Ethernet eth = new Ethernet();
175 eth.setDestinationMACAddress(dstMac.toBytes());
176 eth.setSourceMACAddress(srcMac.toBytes());
177 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
178 if (vlan != Ethernet.VLAN_UNTAGGED) {
179 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100180 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700181 }
182 //eapol header
183 EAPOL eapol = new EAPOL();
184 eapol.setEapolType(eapolType);
185 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700186
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700187 //eap part
188 eapol.setPayload(eap);
189
190 eth.setPayload(eapol);
191 eth.setPad(true);
192 return eth;
193 }
Ari Saha89831742015-06-26 10:31:48 -0700194
Ari Saha89831742015-06-26 10:31:48 -0700195 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700196 public void activate() {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700197 netCfgService.registerConfigFactory(factory);
Charles Chandf7ff862017-01-20 11:22:05 -0800198 appId = coreService.registerApplication(APP_NAME);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530199 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800200 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530201 configureRadiusCommunication();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700202
Ari Saha89831742015-06-26 10:31:48 -0700203 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700204 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100205
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700206
207 StateMachine.initializeMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100208 StateMachine.setAccessDeviceService(accessDeviceService);
Ari Saha89831742015-06-26 10:31:48 -0700209
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100210 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800211 netCfgService.addListener(cfgListener);
212
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100213 impl.requestIntercepts();
214
Amit Ghoshf739be52017-09-21 15:49:37 +0100215 deviceService.addListener(deviceListener);
216
Jian Li13c67162015-12-09 13:20:34 -0800217 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700218 }
219
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530220
Ari Saha89831742015-06-26 10:31:48 -0700221 @Deactivate
222 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100223 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700224 // de-register and null our handler
225 packetService.removeProcessor(processor);
226 processor = null;
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530227 netCfgService.removeListener(cfgListener);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530228 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100229 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100230 deviceService.removeListener(deviceListener);
Jian Li13c67162015-12-09 13:20:34 -0800231 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700232 }
233
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530234 private void configureRadiusCommunication() {
235 if (radiusConnectionType.toLowerCase().equals("socket")) {
236 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
237 } else {
238 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
239 deviceService, subsService, pktCustomizer, this);
240 }
241 }
242
243 private void configurePacketCustomizer() {
244 switch (customizer.toLowerCase()) {
245 case "sample":
246 pktCustomizer = new SamplePacketCustomizer(customInfo);
247 log.info("Created SamplePacketCustomizer");
248 break;
249 default:
250 pktCustomizer = new PacketCustomizer(customInfo);
251 log.info("Created default PacketCustomizer");
252 break;
253 }
254 }
255
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100256 /**
257 * Send RADIUS packet to the RADIUS server.
258 *
259 * @param radiusPacket RADIUS packet to be sent to server.
260 * @param inPkt Incoming EAPOL packet
261 */
262 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
263 impl.sendRadiusPacket(radiusPacket, inPkt);
264 }
Ray Milkey967776a2015-10-07 14:37:17 -0700265
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100266 /**
267 * Handles RADIUS packets.
268 *
269 * @param radiusPacket RADIUS packet coming from the RADIUS server.
270 * @throws StateMachineException if an illegal state transition is triggered
Jonathan Hart4731dd92018-05-02 17:30:05 -0700271 * @throws DeserializationException if packet deserialization fails
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100272 */
Jonathan Hart4731dd92018-05-02 17:30:05 -0700273 public void handleRadiusPacket(RADIUS radiusPacket)
274 throws StateMachineException, DeserializationException {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100275 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
276 if (stateMachine == null) {
277 log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
278 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700279 }
Ari Saha89831742015-06-26 10:31:48 -0700280
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100281 EAP eapPayload;
282 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700283
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100284 switch (radiusPacket.getCode()) {
285 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
286 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
287 byte[] challengeState = null;
288 if (radiusAttrState != null) {
289 challengeState = radiusAttrState.getValue();
290 }
291 eapPayload = radiusPacket.decapsulateMessage();
292 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
293 eth = buildEapolResponse(stateMachine.supplicantAddress(),
294 MacAddress.valueOf(nasMacAddress),
295 stateMachine.vlanId(),
296 EAPOL.EAPOL_PACKET,
297 eapPayload, stateMachine.priorityCode());
298 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
299 break;
300 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
301 //send an EAPOL - Success to the supplicant.
302 byte[] eapMessageSuccess =
303 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700304 eapPayload = EAP.deserializer().deserialize(
305 eapMessageSuccess, 0, eapMessageSuccess.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100306 eth = buildEapolResponse(stateMachine.supplicantAddress(),
307 MacAddress.valueOf(nasMacAddress),
308 stateMachine.vlanId(),
309 EAPOL.EAPOL_PACKET,
310 eapPayload, stateMachine.priorityCode());
311 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
312
313 stateMachine.authorizeAccess();
314
315 break;
316 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
317 //send an EAPOL - Failure to the supplicant.
318 byte[] eapMessageFailure;
319 eapPayload = new EAP();
320 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
321 if (radiusAttrEap == null) {
322 eapPayload.setCode(EAP.FAILURE);
323 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
324 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
325 } else {
326 eapMessageFailure = radiusAttrEap.getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700327 eapPayload = EAP.deserializer().deserialize(
328 eapMessageFailure, 0, eapMessageFailure.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100329 }
330 eth = buildEapolResponse(stateMachine.supplicantAddress(),
331 MacAddress.valueOf(nasMacAddress),
332 stateMachine.vlanId(),
333 EAPOL.EAPOL_PACKET,
334 eapPayload, stateMachine.priorityCode());
335 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
336 stateMachine.denyAccess();
337
338 break;
339 default:
340 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
341 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700342 }
343
Ray Milkey967776a2015-10-07 14:37:17 -0700344 /**
345 * Send the ethernet packet to the supplicant.
346 *
347 * @param ethernetPkt the ethernet packet
348 * @param connectPoint the connect point to send out
349 */
350 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
351 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
352 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
353 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
354 packetService.emit(packet);
355 }
356
Ari Saha89831742015-06-26 10:31:48 -0700357 // our handler defined as a private inner class
358
359 /**
360 * Packet processor responsible for forwarding packets along their paths.
361 */
362 private class ReactivePacketProcessor implements PacketProcessor {
363 @Override
364 public void process(PacketContext context) {
365
366 // Extract the original Ethernet frame from the packet information
367 InboundPacket pkt = context.inPacket();
368 Ethernet ethPkt = pkt.parsed();
369 if (ethPkt == null) {
370 return;
371 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100372
Ray Milkeyf51eba22015-09-25 10:24:23 -0700373 try {
374 // identify if incoming packet comes from supplicant (EAP) or RADIUS
375 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
376 case EAPOL:
377 handleSupplicantPacket(context.inPacket());
378 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700379 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100380 // any other packets let the specific implementation handle
381 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700382 }
Ray Milkey967776a2015-10-07 14:37:17 -0700383 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100384 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700385 }
386 }
387
Ray Milkey9eb293f2015-09-30 15:09:17 -0700388 /**
389 * Creates and initializes common fields of a RADIUS packet.
390 *
Ray Milkey967776a2015-10-07 14:37:17 -0700391 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700392 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700393 * @return RADIUS packet
394 */
Ray Milkey967776a2015-10-07 14:37:17 -0700395 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700396 RADIUS radiusPayload =
397 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
398 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700399
400 // set Request Authenticator in StateMachine
401 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
402
Ray Milkey9eb293f2015-09-30 15:09:17 -0700403 radiusPayload.setIdentifier(identifier);
404 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700405 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700406
407 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800408 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700409
410 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700411
412 return radiusPayload;
413 }
Ari Saha89831742015-06-26 10:31:48 -0700414
415 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700416 * Handles PAE packets (supplicant).
417 *
418 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700419 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700420 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700421 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700422 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800423 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700424
Jonathan Harta46dddf2015-06-30 15:31:20 -0700425 DeviceId deviceId = inPacket.receivedFrom().deviceId();
426 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700427 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700428 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
429 if (stateMachine == null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100430 if (deviceService != null) {
431 String nasPortId = deviceService.getPort(inPacket.receivedFrom()).
432 annotations().value(AnnotationKeys.PORT_NAME);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700433
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100434 SubscriberAndDeviceInformation subscriber =
435 subsService.get(nasPortId);
436 if (subscriber != null) {
437 stateMachine = new StateMachine(sessionId, subscriber.cTag());
Amit Ghoshcf39d972017-08-16 08:15:20 +0100438 } else {
439 log.error("Could not create new state machine for {}", nasPortId);
440 return;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100441 }
442 } else {
443 stateMachine = new StateMachine(sessionId, VlanId.vlanId((short) 0));
444 }
445 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700446
447 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700448
449 switch (eapol.getEapolType()) {
450 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700451 stateMachine.start();
452 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700453
Ray Milkeyf51eba22015-09-25 10:24:23 -0700454 //send an EAP Request/Identify to the supplicant
455 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100456 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
457 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
458 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800459 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700460 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100461 eapPayload, stateMachine.priorityCode());
Jonathan Hart092dfb22015-11-16 23:05:21 -0800462 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700463 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700464
Ray Milkey967776a2015-10-07 14:37:17 -0700465 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700466
467 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800468 case EAPOL.EAPOL_LOGOFF:
Ray Milkeyb34b4962016-01-04 10:24:43 -0800469 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
470 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800471 }
472
473 break;
Ari Saha89831742015-06-26 10:31:48 -0700474 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700475 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700476 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700477 EAP eapPacket = (EAP) eapol.getPayload();
478
479 byte dataType = eapPacket.getDataType();
480 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700481
Ray Milkey9eb293f2015-09-30 15:09:17 -0700482 case EAP.ATTR_IDENTITY:
483 // request id access to RADIUS
484 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700485
Ray Milkey967776a2015-10-07 14:37:17 -0700486 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100487 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800488 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700489
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100490 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700491
Ray Milkey9eb293f2015-09-30 15:09:17 -0700492 // change the state to "PENDING"
493 stateMachine.requestAccess();
494 break;
Ari Saha89831742015-06-26 10:31:48 -0700495 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700496 // verify if the EAP identifier corresponds to the
497 // challenge identifier from the client state
498 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700499 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700500 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700501 radiusPayload =
502 getRadiusPayload(stateMachine,
503 stateMachine.identifier(),
504 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100505 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700506
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800507 if (stateMachine.challengeState() != null) {
508 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
509 stateMachine.challengeState());
510 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800511 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100512 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700513 }
514 break;
515 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700516 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700517 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100518 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700519
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800520 if (stateMachine.challengeState() != null) {
521 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
522 stateMachine.challengeState());
523 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700524 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700525
Jonathan Hart092dfb22015-11-16 23:05:21 -0800526 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100527 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkey5493b512015-10-21 12:13:49 -0700528
Ray Milkeyf3790b82015-10-21 16:28:08 -0700529 if (stateMachine.state() != StateMachine.STATE_PENDING) {
530 stateMachine.requestAccess();
531 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700532
Ari Saha89831742015-06-26 10:31:48 -0700533 break;
534 default:
535 return;
536 }
537 break;
538 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700539 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700540 }
541 }
Ray Milkey967776a2015-10-07 14:37:17 -0700542 }
543
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100544 /**
545 * Configuration Listener, handles change in configuration.
546 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700547 private class InternalConfigListener implements NetworkConfigListener {
548
549 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800550 * Reconfigures the AAA application according to the
551 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700552 *
553 * @param cfg configuration object
554 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800555 private void reconfigureNetwork(AaaConfig cfg) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100556
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700557 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800558 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700559 } else {
560 newCfg = cfg;
561 }
562 if (newCfg.nasIp() != null) {
563 nasIpAddress = newCfg.nasIp();
564 }
565 if (newCfg.radiusIp() != null) {
566 radiusIpAddress = newCfg.radiusIp();
567 }
568 if (newCfg.radiusMac() != null) {
569 radiusMacAddress = newCfg.radiusMac();
570 }
571 if (newCfg.nasMac() != null) {
572 nasMacAddress = newCfg.nasMac();
573 }
574 if (newCfg.radiusSecret() != null) {
575 radiusSecret = newCfg.radiusSecret();
576 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100577
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530578 boolean reconfigureCustomizer = false;
579 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
580 customizer = newCfg.radiusPktCustomizer();
581 configurePacketCustomizer();
582 reconfigureCustomizer = true;
583 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100584
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530585 if (radiusConnectionType == null
586 || reconfigureCustomizer
587 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
588 radiusConnectionType = newCfg.radiusConnectionType();
589 if (impl != null) {
590 impl.withdrawIntercepts();
591 impl.clearLocalState();
592 }
593 configureRadiusCommunication();
594 impl.initializeLocalState(newCfg);
595 impl.requestIntercepts();
596 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100597 impl.clearLocalState();
598 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700599 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700600 }
601
602 @Override
603 public void event(NetworkConfigEvent event) {
604
605 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
606 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800607 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700608
Jonathan Hart092dfb22015-11-16 23:05:21 -0800609 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700610 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100611
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700612 log.info("Reconfigured");
613 }
614 }
615 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100616
617 private class InternalDeviceListener implements DeviceListener {
618 @Override
619 public void event(DeviceEvent event) {
620
621 switch (event.type()) {
622 case PORT_REMOVED:
623 DeviceId devId = event.subject().id();
624 PortNumber portNumber = event.port().number();
625 String sessionId = devId.toString() + portNumber.toString();
626
627 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
628 StateMachine removed = sessionIdMap.remove(sessionId);
629 if (removed != null) {
630 StateMachine.deleteStateMachineMapping(removed);
631 }
632
633 break;
634 default:
635 return;
636 }
637 }
638 }
Ari Saha89831742015-06-26 10:31:48 -0700639}