blob: 799064a667dbcf3a4dc1a381912d1836dffb924f [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 Harta46dddf2015-06-30 15:31:20 -070022import org.onlab.packet.EAP;
23import org.onlab.packet.EAPOL;
24import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070025import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070026import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070027import org.onlab.packet.RADIUS;
28import org.onlab.packet.RADIUSAttribute;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010029import org.onlab.packet.VlanId;
Ari Saha89831742015-06-26 10:31:48 -070030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010032import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.AnnotationKeys;
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.olt.AccessDeviceService;
53import org.opencord.sadis.SubscriberAndDeviceInformation;
54import org.opencord.sadis.SubscriberAndDeviceInformationService;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053055import org.osgi.service.component.annotations.Activate;
Ari Saha89831742015-06-26 10:31:48 -070056import org.slf4j.Logger;
57
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010058import java.net.InetAddress;
59import java.nio.ByteBuffer;
Amit Ghoshf739be52017-09-21 15:49:37 +010060import java.util.Map;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010061
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053062import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
63import static org.slf4j.LoggerFactory.getLogger;
64
Ari Saha89831742015-06-26 10:31:48 -070065/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070066 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070067 */
68@Component(immediate = true)
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053069public class
70AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080071 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070072
Ray Milkeyf61a24e2015-09-24 16:34:02 -070073 // for verbose output
74 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070075
Ray Milkeyf61a24e2015-09-24 16:34:02 -070076 // a list of our dependencies :
77 // to register with ONOS as an application - described next
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070080
Ray Milkeyf61a24e2015-09-24 16:34:02 -070081 // to receive Packet-in events that we'll respond to
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070084
Ray Milkeyf61a24e2015-09-24 16:34:02 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070086 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070087
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected DeviceService deviceService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected SubscriberAndDeviceInformationService subsService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected MastershipService mastershipService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected AccessDeviceService accessDeviceService;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070099
Amit Ghoshf739be52017-09-21 15:49:37 +0100100 private final DeviceListener deviceListener = new InternalDeviceListener();
101
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700102 // NAS IP address
103 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100104
105 // self MAC address
106 protected static String nasMacAddress;
107
108 // Parsed RADIUS server addresses
109 protected InetAddress radiusIpAddress;
110
111 // MAC address of RADIUS server or net hop router
112 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700113
114 // RADIUS server secret
115 protected String radiusSecret;
116
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100117 // NAS Identifier
118 protected String nasId;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700119
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100120 // bindings
121 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700122
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700123 // our application-specific event handler
124 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700125
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700126 // our unique identifier
127 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700128
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100129 // Setup specific customization/attributes on the RADIUS packets
130 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700131
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100132 // packet customizer to use
133 private String customizer;
134
135 // Type of connection to use to communicate with Radius server, options are
136 // "socket" or "packet_out"
137 private String radiusConnectionType;
138
139 // Object for the spcific type of communication with the RADIUS
140 // server, socket based or packet_out based
141 RadiusCommunicator impl = null;
142
143 // latest configuration
144 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700145
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700146 // Configuration properties factory
147 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800148 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
149 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700150 "AAA") {
151 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800152 public AaaConfig createConfig() {
153 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700154 }
155 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700156
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700157 // Listener for config changes
158 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700159
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700160 /**
161 * Builds an EAPOL packet based on the given parameters.
162 *
163 * @param dstMac destination MAC address
164 * @param srcMac source MAC address
165 * @param vlan vlan identifier
166 * @param eapolType EAPOL type
167 * @param eap EAP payload
168 * @return Ethernet frame
169 */
170 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100171 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700172
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700173 Ethernet eth = new Ethernet();
174 eth.setDestinationMACAddress(dstMac.toBytes());
175 eth.setSourceMACAddress(srcMac.toBytes());
176 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
177 if (vlan != Ethernet.VLAN_UNTAGGED) {
178 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100179 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700180 }
181 //eapol header
182 EAPOL eapol = new EAPOL();
183 eapol.setEapolType(eapolType);
184 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700185
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700186 //eap part
187 eapol.setPayload(eap);
188
189 eth.setPayload(eapol);
190 eth.setPad(true);
191 return eth;
192 }
Ari Saha89831742015-06-26 10:31:48 -0700193
Ari Saha89831742015-06-26 10:31:48 -0700194 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700195 public void activate() {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700196 netCfgService.registerConfigFactory(factory);
Charles Chandf7ff862017-01-20 11:22:05 -0800197 appId = coreService.registerApplication(APP_NAME);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530198 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800199 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530200 configureRadiusCommunication();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700201
Ari Saha89831742015-06-26 10:31:48 -0700202 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700203 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100204
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700205
206 StateMachine.initializeMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100207 StateMachine.setAccessDeviceService(accessDeviceService);
Ari Saha89831742015-06-26 10:31:48 -0700208
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100209 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800210 netCfgService.addListener(cfgListener);
211
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100212 impl.requestIntercepts();
213
Amit Ghoshf739be52017-09-21 15:49:37 +0100214 deviceService.addListener(deviceListener);
215
Jian Li13c67162015-12-09 13:20:34 -0800216 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700217 }
218
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530219
Ari Saha89831742015-06-26 10:31:48 -0700220 @Deactivate
221 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100222 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700223 // de-register and null our handler
224 packetService.removeProcessor(processor);
225 processor = null;
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530226 netCfgService.removeListener(cfgListener);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530227 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100228 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100229 deviceService.removeListener(deviceListener);
Jian Li13c67162015-12-09 13:20:34 -0800230 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700231 }
232
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530233 private void configureRadiusCommunication() {
234 if (radiusConnectionType.toLowerCase().equals("socket")) {
235 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
236 } else {
237 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
238 deviceService, subsService, pktCustomizer, this);
239 }
240 }
241
242 private void configurePacketCustomizer() {
243 switch (customizer.toLowerCase()) {
244 case "sample":
245 pktCustomizer = new SamplePacketCustomizer(customInfo);
246 log.info("Created SamplePacketCustomizer");
247 break;
248 default:
249 pktCustomizer = new PacketCustomizer(customInfo);
250 log.info("Created default PacketCustomizer");
251 break;
252 }
253 }
254
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100255 /**
256 * Send RADIUS packet to the RADIUS server.
257 *
258 * @param radiusPacket RADIUS packet to be sent to server.
259 * @param inPkt Incoming EAPOL packet
260 */
261 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
262 impl.sendRadiusPacket(radiusPacket, inPkt);
263 }
Ray Milkey967776a2015-10-07 14:37:17 -0700264
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100265 /**
266 * Handles RADIUS packets.
267 *
268 * @param radiusPacket RADIUS packet coming from the RADIUS server.
269 * @throws StateMachineException if an illegal state transition is triggered
270 */
271 public void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
272 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
273 if (stateMachine == null) {
274 log.error("Invalid session identifier {}, exiting...", radiusPacket.getIdentifier());
275 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700276 }
Ari Saha89831742015-06-26 10:31:48 -0700277
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100278 EAP eapPayload;
279 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700280
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100281 switch (radiusPacket.getCode()) {
282 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
283 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
284 byte[] challengeState = null;
285 if (radiusAttrState != null) {
286 challengeState = radiusAttrState.getValue();
287 }
288 eapPayload = radiusPacket.decapsulateMessage();
289 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
290 eth = buildEapolResponse(stateMachine.supplicantAddress(),
291 MacAddress.valueOf(nasMacAddress),
292 stateMachine.vlanId(),
293 EAPOL.EAPOL_PACKET,
294 eapPayload, stateMachine.priorityCode());
295 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
296 break;
297 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
298 //send an EAPOL - Success to the supplicant.
299 byte[] eapMessageSuccess =
300 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
301 eapPayload = new EAP();
302 eapPayload = (EAP) eapPayload.deserialize(eapMessageSuccess, 0, eapMessageSuccess.length);
303 eth = buildEapolResponse(stateMachine.supplicantAddress(),
304 MacAddress.valueOf(nasMacAddress),
305 stateMachine.vlanId(),
306 EAPOL.EAPOL_PACKET,
307 eapPayload, stateMachine.priorityCode());
308 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
309
310 stateMachine.authorizeAccess();
311
312 break;
313 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
314 //send an EAPOL - Failure to the supplicant.
315 byte[] eapMessageFailure;
316 eapPayload = new EAP();
317 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
318 if (radiusAttrEap == null) {
319 eapPayload.setCode(EAP.FAILURE);
320 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
321 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
322 } else {
323 eapMessageFailure = radiusAttrEap.getValue();
324 eapPayload = (EAP) eapPayload.deserialize(eapMessageFailure, 0, eapMessageFailure.length);
325 }
326 eth = buildEapolResponse(stateMachine.supplicantAddress(),
327 MacAddress.valueOf(nasMacAddress),
328 stateMachine.vlanId(),
329 EAPOL.EAPOL_PACKET,
330 eapPayload, stateMachine.priorityCode());
331 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
332 stateMachine.denyAccess();
333
334 break;
335 default:
336 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
337 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700338 }
339
Ray Milkey967776a2015-10-07 14:37:17 -0700340 /**
341 * Send the ethernet packet to the supplicant.
342 *
343 * @param ethernetPkt the ethernet packet
344 * @param connectPoint the connect point to send out
345 */
346 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
347 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
348 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
349 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
350 packetService.emit(packet);
351 }
352
Ari Saha89831742015-06-26 10:31:48 -0700353 // our handler defined as a private inner class
354
355 /**
356 * Packet processor responsible for forwarding packets along their paths.
357 */
358 private class ReactivePacketProcessor implements PacketProcessor {
359 @Override
360 public void process(PacketContext context) {
361
362 // Extract the original Ethernet frame from the packet information
363 InboundPacket pkt = context.inPacket();
364 Ethernet ethPkt = pkt.parsed();
365 if (ethPkt == null) {
366 return;
367 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100368
Ray Milkeyf51eba22015-09-25 10:24:23 -0700369 try {
370 // identify if incoming packet comes from supplicant (EAP) or RADIUS
371 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
372 case EAPOL:
373 handleSupplicantPacket(context.inPacket());
374 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700375 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100376 // any other packets let the specific implementation handle
377 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700378 }
Ray Milkey967776a2015-10-07 14:37:17 -0700379 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100380 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700381 }
382 }
383
Ray Milkey9eb293f2015-09-30 15:09:17 -0700384 /**
385 * Creates and initializes common fields of a RADIUS packet.
386 *
Ray Milkey967776a2015-10-07 14:37:17 -0700387 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700388 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700389 * @return RADIUS packet
390 */
Ray Milkey967776a2015-10-07 14:37:17 -0700391 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700392 RADIUS radiusPayload =
393 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
394 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700395
396 // set Request Authenticator in StateMachine
397 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
398
Ray Milkey9eb293f2015-09-30 15:09:17 -0700399 radiusPayload.setIdentifier(identifier);
400 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700401 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700402
403 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800404 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700405
406 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700407
408 return radiusPayload;
409 }
Ari Saha89831742015-06-26 10:31:48 -0700410
411 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700412 * Handles PAE packets (supplicant).
413 *
414 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700415 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700416 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700417 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700418 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800419 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700420
Jonathan Harta46dddf2015-06-30 15:31:20 -0700421 DeviceId deviceId = inPacket.receivedFrom().deviceId();
422 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700423 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700424 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
425 if (stateMachine == null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100426 if (deviceService != null) {
427 String nasPortId = deviceService.getPort(inPacket.receivedFrom()).
428 annotations().value(AnnotationKeys.PORT_NAME);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700429
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100430 SubscriberAndDeviceInformation subscriber =
431 subsService.get(nasPortId);
432 if (subscriber != null) {
433 stateMachine = new StateMachine(sessionId, subscriber.cTag());
Amit Ghoshcf39d972017-08-16 08:15:20 +0100434 } else {
435 log.error("Could not create new state machine for {}", nasPortId);
436 return;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100437 }
438 } else {
439 stateMachine = new StateMachine(sessionId, VlanId.vlanId((short) 0));
440 }
441 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700442
443 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700444
445 switch (eapol.getEapolType()) {
446 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700447 stateMachine.start();
448 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700449
Ray Milkeyf51eba22015-09-25 10:24:23 -0700450 //send an EAP Request/Identify to the supplicant
451 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100452 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
453 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
454 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800455 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700456 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100457 eapPayload, stateMachine.priorityCode());
Jonathan Hart092dfb22015-11-16 23:05:21 -0800458 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700459 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700460
Ray Milkey967776a2015-10-07 14:37:17 -0700461 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700462
463 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800464 case EAPOL.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:
479 // request id access to RADIUS
480 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700481
Ray Milkey967776a2015-10-07 14:37:17 -0700482 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100483 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800484 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700485
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100486 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700487
Ray Milkey9eb293f2015-09-30 15:09:17 -0700488 // change the state to "PENDING"
489 stateMachine.requestAccess();
490 break;
Ari Saha89831742015-06-26 10:31:48 -0700491 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700492 // verify if the EAP identifier corresponds to the
493 // challenge identifier from the client state
494 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700495 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700496 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700497 radiusPayload =
498 getRadiusPayload(stateMachine,
499 stateMachine.identifier(),
500 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100501 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700502
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800503 if (stateMachine.challengeState() != null) {
504 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
505 stateMachine.challengeState());
506 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800507 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100508 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700509 }
510 break;
511 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700512 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700513 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100514 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700515
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800516 if (stateMachine.challengeState() != null) {
517 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
518 stateMachine.challengeState());
519 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700520 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700521
Jonathan Hart092dfb22015-11-16 23:05:21 -0800522 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100523 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkey5493b512015-10-21 12:13:49 -0700524
Ray Milkeyf3790b82015-10-21 16:28:08 -0700525 if (stateMachine.state() != StateMachine.STATE_PENDING) {
526 stateMachine.requestAccess();
527 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700528
Ari Saha89831742015-06-26 10:31:48 -0700529 break;
530 default:
531 return;
532 }
533 break;
534 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700535 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700536 }
537 }
Ray Milkey967776a2015-10-07 14:37:17 -0700538 }
539
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100540 /**
541 * Configuration Listener, handles change in configuration.
542 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700543 private class InternalConfigListener implements NetworkConfigListener {
544
545 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800546 * Reconfigures the AAA application according to the
547 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700548 *
549 * @param cfg configuration object
550 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800551 private void reconfigureNetwork(AaaConfig cfg) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100552
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700553 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800554 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700555 } else {
556 newCfg = cfg;
557 }
558 if (newCfg.nasIp() != null) {
559 nasIpAddress = newCfg.nasIp();
560 }
561 if (newCfg.radiusIp() != null) {
562 radiusIpAddress = newCfg.radiusIp();
563 }
564 if (newCfg.radiusMac() != null) {
565 radiusMacAddress = newCfg.radiusMac();
566 }
567 if (newCfg.nasMac() != null) {
568 nasMacAddress = newCfg.nasMac();
569 }
570 if (newCfg.radiusSecret() != null) {
571 radiusSecret = newCfg.radiusSecret();
572 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100573
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530574 boolean reconfigureCustomizer = false;
575 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
576 customizer = newCfg.radiusPktCustomizer();
577 configurePacketCustomizer();
578 reconfigureCustomizer = true;
579 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100580
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530581 if (radiusConnectionType == null
582 || reconfigureCustomizer
583 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
584 radiusConnectionType = newCfg.radiusConnectionType();
585 if (impl != null) {
586 impl.withdrawIntercepts();
587 impl.clearLocalState();
588 }
589 configureRadiusCommunication();
590 impl.initializeLocalState(newCfg);
591 impl.requestIntercepts();
592 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100593 impl.clearLocalState();
594 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700595 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700596 }
597
598 @Override
599 public void event(NetworkConfigEvent event) {
600
601 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
602 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800603 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700604
Jonathan Hart092dfb22015-11-16 23:05:21 -0800605 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700606 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100607
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700608 log.info("Reconfigured");
609 }
610 }
611 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100612
613 private class InternalDeviceListener implements DeviceListener {
614 @Override
615 public void event(DeviceEvent event) {
616
617 switch (event.type()) {
618 case PORT_REMOVED:
619 DeviceId devId = event.subject().id();
620 PortNumber portNumber = event.port().number();
621 String sessionId = devId.toString() + portNumber.toString();
622
623 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
624 StateMachine removed = sessionIdMap.remove(sessionId);
625 if (removed != null) {
626 StateMachine.deleteStateMachineMapping(removed);
627 }
628
629 break;
630 default:
631 return;
632 }
633 }
634 }
Ari Saha89831742015-06-26 10:31:48 -0700635}