blob: 9bd65a098efb7421fc5a70dc081196ff53f58c90 [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
2 * Copyright 2015 AT&T Foundry
3 *
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 */
16package org.onosproject.aaa;
17
Ray Milkey508cec52016-02-16 14:23:26 -080018import java.io.IOException;
19import java.net.DatagramPacket;
20import java.net.DatagramSocket;
21import java.net.InetAddress;
22import java.nio.ByteBuffer;
23import java.util.concurrent.ExecutorService;
24import java.util.concurrent.Executors;
25
Ari Saha89831742015-06-26 10:31:48 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harta46dddf2015-06-30 15:31:20 -070031import org.onlab.packet.DeserializationException;
32import org.onlab.packet.EAP;
33import org.onlab.packet.EAPOL;
34import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070035import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070036import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070037import org.onlab.packet.RADIUS;
38import org.onlab.packet.RADIUSAttribute;
Ari Saha89831742015-06-26 10:31:48 -070039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
41import org.onosproject.net.ConnectPoint;
42import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070043import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070044import org.onosproject.net.config.ConfigFactory;
45import org.onosproject.net.config.NetworkConfigEvent;
46import org.onosproject.net.config.NetworkConfigListener;
47import org.onosproject.net.config.NetworkConfigRegistry;
Ari Saha89831742015-06-26 10:31:48 -070048import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070050import org.onosproject.net.flow.TrafficSelector;
51import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070052import org.onosproject.net.packet.DefaultOutboundPacket;
53import org.onosproject.net.packet.InboundPacket;
54import org.onosproject.net.packet.OutboundPacket;
55import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070056import org.onosproject.net.packet.PacketProcessor;
57import org.onosproject.net.packet.PacketService;
Ari Saha89831742015-06-26 10:31:48 -070058import org.slf4j.Logger;
59
Ray Milkey508cec52016-02-16 14:23:26 -080060import com.google.common.util.concurrent.ThreadFactoryBuilder;
Ray Milkey967776a2015-10-07 14:37:17 -070061
Ray Milkeyfcb623d2015-10-01 16:48:18 -070062import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -070063import static org.onosproject.net.packet.PacketPriority.CONTROL;
Ari Saha89831742015-06-26 10:31:48 -070064import 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)
Jonathan Hart092dfb22015-11-16 23:05:21 -080070public class AaaManager {
Ray Milkeyf51eba22015-09-25 10:24:23 -070071
Ray Milkeyf61a24e2015-09-24 16:34:02 -070072 // for verbose output
73 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070074
Ray Milkeyf61a24e2015-09-24 16:34:02 -070075 // a list of our dependencies :
76 // to register with ONOS as an application - described next
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070079
Ray Milkeyf61a24e2015-09-24 16:34:02 -070080 // to receive Packet-in events that we'll respond to
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070083
Ray Milkeyf61a24e2015-09-24 16:34:02 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070085 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070086
Ray Milkeyfcb623d2015-10-01 16:48:18 -070087 // Parsed RADIUS server addresses
88 protected InetAddress radiusIpAddress;
89 protected String radiusMacAddress;
90
91 // NAS IP address
92 protected InetAddress nasIpAddress;
93 protected String nasMacAddress;
94
95 // RADIUS server secret
96 protected String radiusSecret;
97
98 // ID of RADIUS switch
99 protected String radiusSwitch;
100
101 // RADIUS port number
102 protected long radiusPort;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700103
Ray Milkey5d99bd12015-10-06 15:41:30 -0700104 // RADIUS server TCP port number
105 protected short radiusServerPort;
106
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700107 // our application-specific event handler
108 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700109
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700110 // our unique identifier
111 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700112
Ray Milkey967776a2015-10-07 14:37:17 -0700113 // Socket used for UDP communications with RADIUS server
114 private DatagramSocket radiusSocket;
115
116 // Executor for RADIUS communication thread
117 private ExecutorService executor;
118
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700119 // Configuration properties factory
120 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800121 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
122 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700123 "AAA") {
124 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800125 public AaaConfig createConfig() {
126 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700127 }
128 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700129
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700130 // Listener for config changes
131 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700132
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700133 /**
134 * Builds an EAPOL packet based on the given parameters.
135 *
136 * @param dstMac destination MAC address
137 * @param srcMac source MAC address
138 * @param vlan vlan identifier
139 * @param eapolType EAPOL type
140 * @param eap EAP payload
141 * @return Ethernet frame
142 */
143 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
144 short vlan, byte eapolType, EAP eap) {
Ari Saha89831742015-06-26 10:31:48 -0700145
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700146 Ethernet eth = new Ethernet();
147 eth.setDestinationMACAddress(dstMac.toBytes());
148 eth.setSourceMACAddress(srcMac.toBytes());
149 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
150 if (vlan != Ethernet.VLAN_UNTAGGED) {
151 eth.setVlanID(vlan);
152 }
153 //eapol header
154 EAPOL eapol = new EAPOL();
155 eapol.setEapolType(eapolType);
156 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700157
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700158 //eap part
159 eapol.setPayload(eap);
160
161 eth.setPayload(eapol);
162 eth.setPad(true);
163 return eth;
164 }
Ari Saha89831742015-06-26 10:31:48 -0700165
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800166 private void initializeLocalState() {
167 try {
168 radiusSocket = new DatagramSocket(radiusServerPort);
169 } catch (Exception ex) {
170 log.error("Can't open RADIUS socket", ex);
171 }
172
173 executor = Executors.newSingleThreadExecutor(
174 new ThreadFactoryBuilder()
175 .setNameFormat("AAA-radius-%d").build());
176 executor.execute(radiusListener);
177 }
178
Ari Saha89831742015-06-26 10:31:48 -0700179 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700180 public void activate() {
181 netCfgService.addListener(cfgListener);
182 netCfgService.registerConfigFactory(factory);
183
Ari Saha89831742015-06-26 10:31:48 -0700184 // "org.onosproject.aaa" is the FQDN of our app
185 appId = coreService.registerApplication("org.onosproject.aaa");
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700186
Jonathan Hart092dfb22015-11-16 23:05:21 -0800187 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700188
Ari Saha89831742015-06-26 10:31:48 -0700189 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700190 packetService.addProcessor(processor, PacketProcessor.director(2));
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700191 requestIntercepts();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700192
193 StateMachine.initializeMaps();
Ari Saha89831742015-06-26 10:31:48 -0700194
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800195 initializeLocalState();
Jian Li13c67162015-12-09 13:20:34 -0800196 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700197 }
198
199 @Deactivate
200 public void deactivate() {
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700201 withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700202 // de-register and null our handler
203 packetService.removeProcessor(processor);
204 processor = null;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700205 StateMachine.destroyMaps();
Ray Milkey967776a2015-10-07 14:37:17 -0700206 radiusSocket.close();
207 executor.shutdownNow();
Jian Li13c67162015-12-09 13:20:34 -0800208 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700209 }
210
Jonathan Hart092dfb22015-11-16 23:05:21 -0800211 protected void sendRadiusPacket(RADIUS radiusPacket) {
Ray Milkey967776a2015-10-07 14:37:17 -0700212
213 try {
214 final byte[] data = radiusPacket.serialize();
215 final DatagramSocket socket = radiusSocket;
216
217 DatagramPacket packet =
218 new DatagramPacket(data, data.length,
219 radiusIpAddress, radiusServerPort);
220
221 socket.send(packet);
222 } catch (IOException e) {
223 log.info("Cannot send packet to RADIUS server", e);
224 }
Ari Saha89831742015-06-26 10:31:48 -0700225 }
226
Jonathan Harta46dddf2015-06-30 15:31:20 -0700227 /**
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700228 * Request packet in via PacketService.
229 */
230 private void requestIntercepts() {
231 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
232 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
233 packetService.requestPackets(selector.build(),
234 CONTROL, appId);
235 }
236
237 /**
238 * Cancel request for packet in via PacketService.
239 */
240 private void withdrawIntercepts() {
241 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
242 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
243 packetService.cancelPackets(selector.build(), CONTROL, appId);
244 }
245
Ray Milkey967776a2015-10-07 14:37:17 -0700246 /**
247 * Send the ethernet packet to the supplicant.
248 *
249 * @param ethernetPkt the ethernet packet
250 * @param connectPoint the connect point to send out
251 */
252 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
253 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
254 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
255 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
256 packetService.emit(packet);
257 }
258
Ari Saha89831742015-06-26 10:31:48 -0700259 // our handler defined as a private inner class
260
261 /**
262 * Packet processor responsible for forwarding packets along their paths.
263 */
264 private class ReactivePacketProcessor implements PacketProcessor {
265 @Override
266 public void process(PacketContext context) {
267
268 // Extract the original Ethernet frame from the packet information
269 InboundPacket pkt = context.inPacket();
270 Ethernet ethPkt = pkt.parsed();
271 if (ethPkt == null) {
272 return;
273 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700274 try {
275 // identify if incoming packet comes from supplicant (EAP) or RADIUS
276 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
277 case EAPOL:
278 handleSupplicantPacket(context.inPacket());
279 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700280 default:
281 log.trace("Skipping Ethernet packet type {}",
282 EthType.EtherType.lookup(ethPkt.getEtherType()));
283 }
Ray Milkey967776a2015-10-07 14:37:17 -0700284 } catch (StateMachineException e) {
Ray Milkeyf51eba22015-09-25 10:24:23 -0700285 log.warn("Unable to process RADIUS packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700286 }
287 }
288
Ray Milkey9eb293f2015-09-30 15:09:17 -0700289 /**
290 * Creates and initializes common fields of a RADIUS packet.
291 *
Ray Milkey967776a2015-10-07 14:37:17 -0700292 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700293 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700294 * @return RADIUS packet
295 */
Ray Milkey967776a2015-10-07 14:37:17 -0700296 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700297 RADIUS radiusPayload =
298 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
299 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700300
301 // set Request Authenticator in StateMachine
302 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
303
Ray Milkey9eb293f2015-09-30 15:09:17 -0700304 radiusPayload.setIdentifier(identifier);
305 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700306 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700307
308 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800309 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700310
311 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700312
313 return radiusPayload;
314 }
Ari Saha89831742015-06-26 10:31:48 -0700315
316 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700317 * Handles PAE packets (supplicant).
318 *
319 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700320 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700321 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700322 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700323 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800324 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700325
Jonathan Harta46dddf2015-06-30 15:31:20 -0700326 DeviceId deviceId = inPacket.receivedFrom().deviceId();
327 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700328 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700329 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
330 if (stateMachine == null) {
Ray Milkey508cec52016-02-16 14:23:26 -0800331 stateMachine = new StateMachine(sessionId);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700332 }
333
Jonathan Harta46dddf2015-06-30 15:31:20 -0700334
335 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700336
337 switch (eapol.getEapolType()) {
338 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700339 stateMachine.start();
340 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700341
Ray Milkeyf51eba22015-09-25 10:24:23 -0700342 //send an EAP Request/Identify to the supplicant
343 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800344 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700345 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
346 eapPayload);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800347 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700348 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700349
Ray Milkey967776a2015-10-07 14:37:17 -0700350 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700351
352 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800353 case EAPOL.EAPOL_LOGOFF:
Ray Milkeyb34b4962016-01-04 10:24:43 -0800354 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
355 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800356 }
357
358 break;
Ari Saha89831742015-06-26 10:31:48 -0700359 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700360 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700361 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700362 EAP eapPacket = (EAP) eapol.getPayload();
363
364 byte dataType = eapPacket.getDataType();
365 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700366
Ray Milkey9eb293f2015-09-30 15:09:17 -0700367 case EAP.ATTR_IDENTITY:
368 // request id access to RADIUS
369 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700370
Ray Milkey967776a2015-10-07 14:37:17 -0700371 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800372 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700373
Jonathan Hart092dfb22015-11-16 23:05:21 -0800374 sendRadiusPacket(radiusPayload);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700375
Ray Milkey9eb293f2015-09-30 15:09:17 -0700376 // change the state to "PENDING"
377 stateMachine.requestAccess();
378 break;
Ari Saha89831742015-06-26 10:31:48 -0700379 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700380 // verify if the EAP identifier corresponds to the
381 // challenge identifier from the client state
382 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700383 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700384 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700385 radiusPayload =
386 getRadiusPayload(stateMachine,
387 stateMachine.identifier(),
388 eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700389
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800390 if (stateMachine.challengeState() != null) {
391 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
392 stateMachine.challengeState());
393 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800394 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
395 sendRadiusPacket(radiusPayload);
Ari Saha89831742015-06-26 10:31:48 -0700396 }
397 break;
398 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700399 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700400 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700401
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800402 if (stateMachine.challengeState() != null) {
403 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
404 stateMachine.challengeState());
405 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700406 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700407
Jonathan Hart092dfb22015-11-16 23:05:21 -0800408 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
409 sendRadiusPacket(radiusPayload);
Ray Milkey5493b512015-10-21 12:13:49 -0700410
Ray Milkeyf3790b82015-10-21 16:28:08 -0700411 if (stateMachine.state() != StateMachine.STATE_PENDING) {
412 stateMachine.requestAccess();
413 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700414
Ari Saha89831742015-06-26 10:31:48 -0700415 break;
416 default:
417 return;
418 }
419 break;
420 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700421 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700422 }
Ray Milkey967776a2015-10-07 14:37:17 -0700423
Ari Saha89831742015-06-26 10:31:48 -0700424 }
Ray Milkey967776a2015-10-07 14:37:17 -0700425 }
426
427 class RadiusListener implements Runnable {
Ari Saha89831742015-06-26 10:31:48 -0700428
429 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700430 * Handles RADIUS packets.
431 *
Ari Saha89831742015-06-26 10:31:48 -0700432 * @param radiusPacket RADIUS packet coming from the RADIUS server.
Ray Milkey17d6c492015-10-27 10:39:42 -0700433 * @throws StateMachineException if an illegal state transition is triggered
Ari Saha89831742015-06-26 10:31:48 -0700434 */
Ray Milkey967776a2015-10-07 14:37:17 -0700435 protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700436 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700437 if (stateMachine == null) {
438 log.error("Invalid session identifier, exiting...");
439 return;
440 }
441
Ray Milkeyf51eba22015-09-25 10:24:23 -0700442 EAP eapPayload;
443 Ethernet eth;
Ari Saha89831742015-06-26 10:31:48 -0700444 switch (radiusPacket.getCode()) {
445 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800446 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
447 byte[] challengeState = null;
448 if (radiusAttrState != null) {
449 challengeState = radiusAttrState.getValue();
450 }
Ari Saha89831742015-06-26 10:31:48 -0700451 eapPayload = radiusPacket.decapsulateMessage();
452 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700453 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700454 MacAddress.valueOf(nasMacAddress),
455 stateMachine.vlanId(),
456 EAPOL.EAPOL_PACKET,
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700457 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700458 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700459 break;
460 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700461 //send an EAPOL - Success to the supplicant.
462 byte[] eapMessage =
463 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
464 eapPayload = new EAP();
465 eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
466 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700467 MacAddress.valueOf(nasMacAddress),
468 stateMachine.vlanId(),
469 EAPOL.EAPOL_PACKET,
Ray Milkeyf51eba22015-09-25 10:24:23 -0700470 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700471 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700472
Ray Milkeyf51eba22015-09-25 10:24:23 -0700473 stateMachine.authorizeAccess();
Ari Saha89831742015-06-26 10:31:48 -0700474 break;
475 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700476 stateMachine.denyAccess();
Ari Saha89831742015-06-26 10:31:48 -0700477 break;
478 default:
479 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
480 }
481 }
482
Ari Saha89831742015-06-26 10:31:48 -0700483
Ray Milkey967776a2015-10-07 14:37:17 -0700484 @Override
485 public void run() {
486 boolean done = false;
487 int packetNumber = 1;
488
489 log.info("UDP listener thread starting up");
490 RADIUS inboundRadiusPacket;
491 while (!done) {
492 try {
Ray Milkey5493b512015-10-21 12:13:49 -0700493 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
494 DatagramPacket inboundBasePacket =
495 new DatagramPacket(packetBuffer, packetBuffer.length);
Ray Milkey967776a2015-10-07 14:37:17 -0700496 DatagramSocket socket = radiusSocket;
497 socket.receive(inboundBasePacket);
498 log.info("Packet #{} received", packetNumber++);
499 try {
500 inboundRadiusPacket =
501 RADIUS.deserializer()
502 .deserialize(inboundBasePacket.getData(),
503 0,
504 inboundBasePacket.getLength());
505 handleRadiusPacket(inboundRadiusPacket);
506 } catch (DeserializationException dex) {
507 log.error("Cannot deserialize packet", dex);
508 } catch (StateMachineException sme) {
509 log.error("Illegal state machine operation", sme);
510 }
511
512 } catch (IOException e) {
513 log.info("Socket was closed, exiting listener thread");
514 done = true;
515 }
Ari Saha89831742015-06-26 10:31:48 -0700516 }
Ari Saha89831742015-06-26 10:31:48 -0700517 }
Ari Saha89831742015-06-26 10:31:48 -0700518 }
519
Ray Milkey967776a2015-10-07 14:37:17 -0700520 RadiusListener radiusListener = new RadiusListener();
521
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700522 private class InternalConfigListener implements NetworkConfigListener {
523
524 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800525 * Reconfigures the AAA application according to the
526 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700527 *
528 * @param cfg configuration object
529 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800530 private void reconfigureNetwork(AaaConfig cfg) {
531 AaaConfig newCfg;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700532 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800533 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700534 } else {
535 newCfg = cfg;
536 }
537 if (newCfg.nasIp() != null) {
538 nasIpAddress = newCfg.nasIp();
539 }
540 if (newCfg.radiusIp() != null) {
541 radiusIpAddress = newCfg.radiusIp();
542 }
543 if (newCfg.radiusMac() != null) {
544 radiusMacAddress = newCfg.radiusMac();
545 }
546 if (newCfg.nasMac() != null) {
547 nasMacAddress = newCfg.nasMac();
548 }
549 if (newCfg.radiusSecret() != null) {
550 radiusSecret = newCfg.radiusSecret();
551 }
552 if (newCfg.radiusSwitch() != null) {
553 radiusSwitch = newCfg.radiusSwitch();
554 }
555 if (newCfg.radiusPort() != -1) {
556 radiusPort = newCfg.radiusPort();
557 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800558 if (newCfg.radiusServerUdpPort() != -1) {
559 radiusServerPort = newCfg.radiusServerUdpPort();
Ray Milkey5d99bd12015-10-06 15:41:30 -0700560 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700561 }
562
563 @Override
564 public void event(NetworkConfigEvent event) {
565
566 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
567 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800568 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700569
Jonathan Hart092dfb22015-11-16 23:05:21 -0800570 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700571 reconfigureNetwork(cfg);
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800572 radiusSocket.close();
573 executor.shutdownNow();
574 initializeLocalState();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700575 log.info("Reconfigured");
576 }
577 }
578 }
579
580
Ari Saha89831742015-06-26 10:31:48 -0700581}