blob: c9fddc07acd23214c520b9fd413282728ac65ead [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
Jonathan Hart932bedc2018-07-12 13:46:09 -070018import org.apache.commons.lang3.builder.ToStringBuilder;
Ari Saha89831742015-06-26 10:31:48 -070019import 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;
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;
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;
Ari Saha89831742015-06-26 10:31:48 -070034import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070036import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070037import org.onosproject.net.config.ConfigFactory;
38import org.onosproject.net.config.NetworkConfigEvent;
39import org.onosproject.net.config.NetworkConfigListener;
40import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010041import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010043import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070044import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070046import org.onosproject.net.packet.DefaultOutboundPacket;
47import org.onosproject.net.packet.InboundPacket;
48import org.onosproject.net.packet.OutboundPacket;
49import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070050import org.onosproject.net.packet.PacketProcessor;
51import org.onosproject.net.packet.PacketService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010052import org.opencord.sadis.SubscriberAndDeviceInformationService;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053053import org.osgi.service.component.annotations.Activate;
Ari Saha89831742015-06-26 10:31:48 -070054import org.slf4j.Logger;
55
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010056import java.net.InetAddress;
57import java.nio.ByteBuffer;
Amit Ghoshf739be52017-09-21 15:49:37 +010058import java.util.Map;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010059
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053060import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
61import static org.slf4j.LoggerFactory.getLogger;
62
Ari Saha89831742015-06-26 10:31:48 -070063/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070064 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070065 */
66@Component(immediate = true)
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053067public class
68AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080069 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070070
Ray Milkeyf61a24e2015-09-24 16:34:02 -070071 // for verbose output
72 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070073
Ray Milkeyf61a24e2015-09-24 16:34:02 -070074 // a list of our dependencies :
75 // to register with ONOS as an application - described next
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070078
Ray Milkeyf61a24e2015-09-24 16:34:02 -070079 // to receive Packet-in events that we'll respond to
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070082
Ray Milkeyf61a24e2015-09-24 16:34:02 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070084 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070085
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010086 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected DeviceService deviceService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected SubscriberAndDeviceInformationService subsService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected MastershipService mastershipService;
94
Amit Ghoshf739be52017-09-21 15:49:37 +010095 private final DeviceListener deviceListener = new InternalDeviceListener();
96
Ray Milkeyfcb623d2015-10-01 16:48:18 -070097 // NAS IP address
98 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010099
100 // self MAC address
101 protected static String nasMacAddress;
102
103 // Parsed RADIUS server addresses
104 protected InetAddress radiusIpAddress;
105
106 // MAC address of RADIUS server or net hop router
107 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700108
109 // RADIUS server secret
110 protected String radiusSecret;
111
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100112 // NAS Identifier
113 protected String nasId;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700114
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100115 // bindings
116 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700117
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700118 // our application-specific event handler
119 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700120
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700121 // our unique identifier
122 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700123
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100124 // Setup specific customization/attributes on the RADIUS packets
125 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700126
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100127 // packet customizer to use
128 private String customizer;
129
130 // Type of connection to use to communicate with Radius server, options are
131 // "socket" or "packet_out"
132 private String radiusConnectionType;
133
134 // Object for the spcific type of communication with the RADIUS
135 // server, socket based or packet_out based
136 RadiusCommunicator impl = null;
137
138 // latest configuration
139 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700140
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700141 // Configuration properties factory
142 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800143 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
144 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700145 "AAA") {
146 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800147 public AaaConfig createConfig() {
148 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700149 }
150 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700151
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700152 // Listener for config changes
153 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700154
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700155 /**
156 * Builds an EAPOL packet based on the given parameters.
157 *
158 * @param dstMac destination MAC address
159 * @param srcMac source MAC address
160 * @param vlan vlan identifier
161 * @param eapolType EAPOL type
162 * @param eap EAP payload
163 * @return Ethernet frame
164 */
165 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100166 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700167
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700168 Ethernet eth = new Ethernet();
169 eth.setDestinationMACAddress(dstMac.toBytes());
170 eth.setSourceMACAddress(srcMac.toBytes());
171 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
172 if (vlan != Ethernet.VLAN_UNTAGGED) {
173 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100174 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700175 }
176 //eapol header
177 EAPOL eapol = new EAPOL();
178 eapol.setEapolType(eapolType);
179 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700180
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700181 //eap part
182 eapol.setPayload(eap);
183
184 eth.setPayload(eapol);
185 eth.setPad(true);
186 return eth;
187 }
Ari Saha89831742015-06-26 10:31:48 -0700188
Ari Saha89831742015-06-26 10:31:48 -0700189 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700190 public void activate() {
Charles Chandf7ff862017-01-20 11:22:05 -0800191 appId = coreService.registerApplication(APP_NAME);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400192 netCfgService.addListener(cfgListener);
193 netCfgService.registerConfigFactory(factory);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530194 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800195 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400196 log.info("Starting with config {} {}", this, newCfg);
197
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530198 configureRadiusCommunication();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700199
Ari Saha89831742015-06-26 10:31:48 -0700200 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700201 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100202
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700203
204 StateMachine.initializeMaps();
Ari Saha89831742015-06-26 10:31:48 -0700205
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100206 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800207
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100208 impl.requestIntercepts();
209
Amit Ghoshf739be52017-09-21 15:49:37 +0100210 deviceService.addListener(deviceListener);
211
Jian Li13c67162015-12-09 13:20:34 -0800212 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700213 }
214
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530215
Ari Saha89831742015-06-26 10:31:48 -0700216 @Deactivate
217 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100218 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700219 // de-register and null our handler
220 packetService.removeProcessor(processor);
221 processor = null;
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530222 netCfgService.removeListener(cfgListener);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530223 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100224 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100225 deviceService.removeListener(deviceListener);
Jian Li13c67162015-12-09 13:20:34 -0800226 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700227 }
228
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530229 private void configureRadiusCommunication() {
230 if (radiusConnectionType.toLowerCase().equals("socket")) {
231 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
232 } else {
233 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
234 deviceService, subsService, pktCustomizer, this);
235 }
236 }
237
238 private void configurePacketCustomizer() {
239 switch (customizer.toLowerCase()) {
240 case "sample":
241 pktCustomizer = new SamplePacketCustomizer(customInfo);
242 log.info("Created SamplePacketCustomizer");
243 break;
244 default:
245 pktCustomizer = new PacketCustomizer(customInfo);
246 log.info("Created default PacketCustomizer");
247 break;
248 }
249 }
250
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100251 /**
252 * Send RADIUS packet to the RADIUS server.
253 *
254 * @param radiusPacket RADIUS packet to be sent to server.
255 * @param inPkt Incoming EAPOL packet
256 */
257 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
258 impl.sendRadiusPacket(radiusPacket, inPkt);
259 }
Ray Milkey967776a2015-10-07 14:37:17 -0700260
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100261 /**
262 * Handles RADIUS packets.
263 *
264 * @param radiusPacket RADIUS packet coming from the RADIUS server.
265 * @throws StateMachineException if an illegal state transition is triggered
Jonathan Hart4731dd92018-05-02 17:30:05 -0700266 * @throws DeserializationException if packet deserialization fails
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100267 */
Jonathan Hart4731dd92018-05-02 17:30:05 -0700268 public void handleRadiusPacket(RADIUS radiusPacket)
269 throws StateMachineException, DeserializationException {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100270 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
271 if (stateMachine == null) {
272 log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
273 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700274 }
Ari Saha89831742015-06-26 10:31:48 -0700275
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100276 EAP eapPayload;
277 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700278
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100279 switch (radiusPacket.getCode()) {
280 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400281 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100282 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
283 byte[] challengeState = null;
284 if (radiusAttrState != null) {
285 challengeState = radiusAttrState.getValue();
286 }
287 eapPayload = radiusPacket.decapsulateMessage();
288 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
289 eth = buildEapolResponse(stateMachine.supplicantAddress(),
290 MacAddress.valueOf(nasMacAddress),
291 stateMachine.vlanId(),
292 EAPOL.EAPOL_PACKET,
293 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400294 log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100295 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
296 break;
297 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400298 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100299 //send an EAPOL - Success to the supplicant.
300 byte[] eapMessageSuccess =
301 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700302 eapPayload = EAP.deserializer().deserialize(
303 eapMessageSuccess, 0, eapMessageSuccess.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100304 eth = buildEapolResponse(stateMachine.supplicantAddress(),
305 MacAddress.valueOf(nasMacAddress),
306 stateMachine.vlanId(),
307 EAPOL.EAPOL_PACKET,
308 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400309 log.info("Send EAP success message to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100310 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
311
312 stateMachine.authorizeAccess();
313
314 break;
315 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400316 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100317 //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());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400335 log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100336 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
337 stateMachine.denyAccess();
338
339 break;
340 default:
341 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
342 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700343 }
344
Ray Milkey967776a2015-10-07 14:37:17 -0700345 /**
346 * Send the ethernet packet to the supplicant.
347 *
348 * @param ethernetPkt the ethernet packet
349 * @param connectPoint the connect point to send out
350 */
351 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
352 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
353 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
354 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
355 packetService.emit(packet);
356 }
357
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400358 @Override
359 public String toString() {
360 return ToStringBuilder.reflectionToString(this);
361 }
362
Ari Saha89831742015-06-26 10:31:48 -0700363 // our handler defined as a private inner class
364
365 /**
366 * Packet processor responsible for forwarding packets along their paths.
367 */
368 private class ReactivePacketProcessor implements PacketProcessor {
369 @Override
370 public void process(PacketContext context) {
371
372 // Extract the original Ethernet frame from the packet information
373 InboundPacket pkt = context.inPacket();
374 Ethernet ethPkt = pkt.parsed();
375 if (ethPkt == null) {
376 return;
377 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100378
Ray Milkeyf51eba22015-09-25 10:24:23 -0700379 try {
380 // identify if incoming packet comes from supplicant (EAP) or RADIUS
381 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
382 case EAPOL:
383 handleSupplicantPacket(context.inPacket());
384 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700385 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100386 // any other packets let the specific implementation handle
387 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700388 }
Ray Milkey967776a2015-10-07 14:37:17 -0700389 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100390 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700391 }
392 }
393
Ray Milkey9eb293f2015-09-30 15:09:17 -0700394 /**
395 * Creates and initializes common fields of a RADIUS packet.
396 *
Ray Milkey967776a2015-10-07 14:37:17 -0700397 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700398 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700399 * @return RADIUS packet
400 */
Ray Milkey967776a2015-10-07 14:37:17 -0700401 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700402 RADIUS radiusPayload =
403 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
404 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700405
406 // set Request Authenticator in StateMachine
407 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
408
Ray Milkey9eb293f2015-09-30 15:09:17 -0700409 radiusPayload.setIdentifier(identifier);
410 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700411 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700412
413 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800414 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700415
416 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700417
418 return radiusPayload;
419 }
Ari Saha89831742015-06-26 10:31:48 -0700420
421 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700422 * Handles PAE packets (supplicant).
423 *
424 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700425 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700426 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700427 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700428 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800429 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700430
Jonathan Harta46dddf2015-06-30 15:31:20 -0700431 DeviceId deviceId = inPacket.receivedFrom().deviceId();
432 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700433 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700434 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
435 if (stateMachine == null) {
Jonathan Hart932bedc2018-07-12 13:46:09 -0700436 stateMachine = new StateMachine(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100437 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700438
439 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700440
441 switch (eapol.getEapolType()) {
442 case EAPOL.EAPOL_START:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400443 log.debug("EAP packet: EAPOL_START");
Ray Milkeyf51eba22015-09-25 10:24:23 -0700444 stateMachine.start();
445 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700446
Ray Milkeyf51eba22015-09-25 10:24:23 -0700447 //send an EAP Request/Identify to the supplicant
448 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100449 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
450 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
451 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800452 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700453 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100454 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400455
Jonathan Hart092dfb22015-11-16 23:05:21 -0800456 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700457 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700458
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400459 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
Ray Milkey967776a2015-10-07 14:37:17 -0700460 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700461
462 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800463 case EAPOL.EAPOL_LOGOFF:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400464 log.debug("EAP packet: EAPOL_LOGOFF");
Ray Milkeyb34b4962016-01-04 10:24:43 -0800465 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
466 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800467 }
468
469 break;
Ari Saha89831742015-06-26 10:31:48 -0700470 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700471 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700472 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700473 EAP eapPacket = (EAP) eapol.getPayload();
474
475 byte dataType = eapPacket.getDataType();
476 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700477
Ray Milkey9eb293f2015-09-30 15:09:17 -0700478 case EAP.ATTR_IDENTITY:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400479 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700480 // request id access to RADIUS
481 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700482
Ray Milkey967776a2015-10-07 14:37:17 -0700483 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100484 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800485 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700486
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100487 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700488
Ray Milkey9eb293f2015-09-30 15:09:17 -0700489 // change the state to "PENDING"
490 stateMachine.requestAccess();
491 break;
Ari Saha89831742015-06-26 10:31:48 -0700492 case EAP.ATTR_MD5:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400493 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700494 // verify if the EAP identifier corresponds to the
495 // challenge identifier from the client state
496 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700497 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700498 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700499 radiusPayload =
500 getRadiusPayload(stateMachine,
501 stateMachine.identifier(),
502 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100503 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700504
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800505 if (stateMachine.challengeState() != null) {
506 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
507 stateMachine.challengeState());
508 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800509 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100510 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700511 }
512 break;
513 case EAP.ATTR_TLS:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400514 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700515 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700516 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100517 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700518
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800519 if (stateMachine.challengeState() != null) {
520 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
521 stateMachine.challengeState());
522 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700523 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700524
Jonathan Hart092dfb22015-11-16 23:05:21 -0800525 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100526 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkey5493b512015-10-21 12:13:49 -0700527
Ray Milkeyf3790b82015-10-21 16:28:08 -0700528 if (stateMachine.state() != StateMachine.STATE_PENDING) {
529 stateMachine.requestAccess();
530 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700531
Ari Saha89831742015-06-26 10:31:48 -0700532 break;
533 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400534 log.warn("Unknown EAP packet type");
Ari Saha89831742015-06-26 10:31:48 -0700535 return;
536 }
537 break;
538 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400539 log.debug("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) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400556 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100557
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700558 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800559 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700560 } else {
561 newCfg = cfg;
562 }
563 if (newCfg.nasIp() != null) {
564 nasIpAddress = newCfg.nasIp();
565 }
566 if (newCfg.radiusIp() != null) {
567 radiusIpAddress = newCfg.radiusIp();
568 }
569 if (newCfg.radiusMac() != null) {
570 radiusMacAddress = newCfg.radiusMac();
571 }
572 if (newCfg.nasMac() != null) {
573 nasMacAddress = newCfg.nasMac();
574 }
575 if (newCfg.radiusSecret() != null) {
576 radiusSecret = newCfg.radiusSecret();
577 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100578
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530579 boolean reconfigureCustomizer = false;
580 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
581 customizer = newCfg.radiusPktCustomizer();
582 configurePacketCustomizer();
583 reconfigureCustomizer = true;
584 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100585
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530586 if (radiusConnectionType == null
587 || reconfigureCustomizer
588 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
589 radiusConnectionType = newCfg.radiusConnectionType();
590 if (impl != null) {
591 impl.withdrawIntercepts();
592 impl.clearLocalState();
593 }
594 configureRadiusCommunication();
595 impl.initializeLocalState(newCfg);
596 impl.requestIntercepts();
597 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100598 impl.clearLocalState();
599 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700600 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700601 }
602
603 @Override
604 public void event(NetworkConfigEvent event) {
605
606 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
607 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800608 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700609
Jonathan Hart092dfb22015-11-16 23:05:21 -0800610 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700611 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100612
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400613 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700614 }
615 }
616 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100617
618 private class InternalDeviceListener implements DeviceListener {
619 @Override
620 public void event(DeviceEvent event) {
621
622 switch (event.type()) {
623 case PORT_REMOVED:
624 DeviceId devId = event.subject().id();
625 PortNumber portNumber = event.port().number();
626 String sessionId = devId.toString() + portNumber.toString();
627
628 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
629 StateMachine removed = sessionIdMap.remove(sessionId);
630 if (removed != null) {
631 StateMachine.deleteStateMachineMapping(removed);
632 }
633
634 break;
635 default:
636 return;
637 }
638 }
639 }
Ari Saha89831742015-06-26 10:31:48 -0700640}