blob: 2fec41c6bd72a526a8cfb166b06525f3477db6c7 [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 */
alshabib6d527452016-06-01 18:00:47 -070016package org.opencord.aaa;
Ari Saha89831742015-06-26 10:31:48 -070017
Ray Milkey508cec52016-02-16 14:23:26 -080018import java.io.IOException;
19import java.net.DatagramPacket;
20import java.net.DatagramSocket;
21import java.net.InetAddress;
A.R Karthick6af9f432016-03-11 20:24:33 -080022import java.net.InetSocketAddress;
Ray Milkey508cec52016-02-16 14:23:26 -080023import java.nio.ByteBuffer;
24import java.util.concurrent.ExecutorService;
25import java.util.concurrent.Executors;
26
Ari Saha89831742015-06-26 10:31:48 -070027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070030import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harta46dddf2015-06-30 15:31:20 -070032import org.onlab.packet.DeserializationException;
33import org.onlab.packet.EAP;
34import org.onlab.packet.EAPOL;
35import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070036import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070037import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070038import org.onlab.packet.RADIUS;
39import org.onlab.packet.RADIUSAttribute;
Ari Saha89831742015-06-26 10:31:48 -070040import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
42import org.onosproject.net.ConnectPoint;
43import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070044import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070045import org.onosproject.net.config.ConfigFactory;
46import org.onosproject.net.config.NetworkConfigEvent;
47import org.onosproject.net.config.NetworkConfigListener;
48import org.onosproject.net.config.NetworkConfigRegistry;
Ari Saha89831742015-06-26 10:31:48 -070049import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070051import org.onosproject.net.flow.TrafficSelector;
52import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070053import org.onosproject.net.packet.DefaultOutboundPacket;
54import org.onosproject.net.packet.InboundPacket;
55import org.onosproject.net.packet.OutboundPacket;
56import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070057import org.onosproject.net.packet.PacketProcessor;
58import org.onosproject.net.packet.PacketService;
Ari Saha89831742015-06-26 10:31:48 -070059import org.slf4j.Logger;
60
Ray Milkey508cec52016-02-16 14:23:26 -080061import com.google.common.util.concurrent.ThreadFactoryBuilder;
Ray Milkey967776a2015-10-07 14:37:17 -070062
Ray Milkeyfcb623d2015-10-01 16:48:18 -070063import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -070064import static org.onosproject.net.packet.PacketPriority.CONTROL;
Ari Saha89831742015-06-26 10:31:48 -070065import static org.slf4j.LoggerFactory.getLogger;
66
Ari Saha89831742015-06-26 10:31:48 -070067/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070068 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070069 */
70@Component(immediate = true)
Jonathan Hart092dfb22015-11-16 23:05:21 -080071public class AaaManager {
Charles Chandf7ff862017-01-20 11:22:05 -080072 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070073
Ray Milkeyf61a24e2015-09-24 16:34:02 -070074 // for verbose output
75 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070076
Ray Milkeyf61a24e2015-09-24 16:34:02 -070077 // a list of our dependencies :
78 // to register with ONOS as an application - described next
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070081
Ray Milkeyf61a24e2015-09-24 16:34:02 -070082 // to receive Packet-in events that we'll respond to
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070085
Ray Milkeyf61a24e2015-09-24 16:34:02 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070087 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070088
Ray Milkeyfcb623d2015-10-01 16:48:18 -070089 // Parsed RADIUS server addresses
90 protected InetAddress radiusIpAddress;
91 protected String radiusMacAddress;
92
93 // NAS IP address
94 protected InetAddress nasIpAddress;
95 protected String nasMacAddress;
96
97 // RADIUS server secret
98 protected String radiusSecret;
99
100 // ID of RADIUS switch
101 protected String radiusSwitch;
102
103 // RADIUS port number
104 protected long radiusPort;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700105
Ray Milkey5d99bd12015-10-06 15:41:30 -0700106 // RADIUS server TCP port number
107 protected short radiusServerPort;
108
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700109 // our application-specific event handler
110 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700111
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700112 // our unique identifier
113 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700114
Ray Milkey967776a2015-10-07 14:37:17 -0700115 // Socket used for UDP communications with RADIUS server
116 private DatagramSocket radiusSocket;
117
118 // Executor for RADIUS communication thread
119 private ExecutorService executor;
120
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700121 // Configuration properties factory
122 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800123 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
124 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700125 "AAA") {
126 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800127 public AaaConfig createConfig() {
128 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700129 }
130 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700131
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700132 // Listener for config changes
133 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700134
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700135 /**
136 * Builds an EAPOL packet based on the given parameters.
137 *
138 * @param dstMac destination MAC address
139 * @param srcMac source MAC address
140 * @param vlan vlan identifier
141 * @param eapolType EAPOL type
142 * @param eap EAP payload
143 * @return Ethernet frame
144 */
145 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
146 short vlan, byte eapolType, EAP eap) {
Ari Saha89831742015-06-26 10:31:48 -0700147
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700148 Ethernet eth = new Ethernet();
149 eth.setDestinationMACAddress(dstMac.toBytes());
150 eth.setSourceMACAddress(srcMac.toBytes());
151 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
152 if (vlan != Ethernet.VLAN_UNTAGGED) {
153 eth.setVlanID(vlan);
154 }
155 //eapol header
156 EAPOL eapol = new EAPOL();
157 eapol.setEapolType(eapolType);
158 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700159
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700160 //eap part
161 eapol.setPayload(eap);
162
163 eth.setPayload(eapol);
164 eth.setPad(true);
165 return eth;
166 }
Ari Saha89831742015-06-26 10:31:48 -0700167
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800168 private void initializeLocalState() {
169 try {
A.R Karthick6af9f432016-03-11 20:24:33 -0800170 radiusSocket = new DatagramSocket(null);
171 radiusSocket.setReuseAddress(true);
172 radiusSocket.bind(new InetSocketAddress(radiusServerPort));
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800173 } catch (Exception ex) {
174 log.error("Can't open RADIUS socket", ex);
175 }
176
177 executor = Executors.newSingleThreadExecutor(
178 new ThreadFactoryBuilder()
179 .setNameFormat("AAA-radius-%d").build());
180 executor.execute(radiusListener);
181 }
182
Ari Saha89831742015-06-26 10:31:48 -0700183 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700184 public void activate() {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700185 netCfgService.registerConfigFactory(factory);
Ari Saha89831742015-06-26 10:31:48 -0700186 // "org.onosproject.aaa" is the FQDN of our app
Charles Chandf7ff862017-01-20 11:22:05 -0800187 appId = coreService.registerApplication(APP_NAME);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700188
Jonathan Hart092dfb22015-11-16 23:05:21 -0800189 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700190
Ari Saha89831742015-06-26 10:31:48 -0700191 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700192 packetService.addProcessor(processor, PacketProcessor.director(2));
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700193 requestIntercepts();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700194
195 StateMachine.initializeMaps();
Ari Saha89831742015-06-26 10:31:48 -0700196
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800197 initializeLocalState();
alshabib27afc1d2016-12-23 00:33:58 -0800198 netCfgService.addListener(cfgListener);
199
Jian Li13c67162015-12-09 13:20:34 -0800200 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700201 }
202
203 @Deactivate
204 public void deactivate() {
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700205 withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700206 // de-register and null our handler
207 packetService.removeProcessor(processor);
208 processor = null;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700209 StateMachine.destroyMaps();
Ray Milkey967776a2015-10-07 14:37:17 -0700210 radiusSocket.close();
211 executor.shutdownNow();
Jian Li13c67162015-12-09 13:20:34 -0800212 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700213 }
214
Jonathan Hart092dfb22015-11-16 23:05:21 -0800215 protected void sendRadiusPacket(RADIUS radiusPacket) {
Ray Milkey967776a2015-10-07 14:37:17 -0700216
217 try {
218 final byte[] data = radiusPacket.serialize();
219 final DatagramSocket socket = radiusSocket;
220
221 DatagramPacket packet =
222 new DatagramPacket(data, data.length,
223 radiusIpAddress, radiusServerPort);
224
225 socket.send(packet);
226 } catch (IOException e) {
227 log.info("Cannot send packet to RADIUS server", e);
228 }
Ari Saha89831742015-06-26 10:31:48 -0700229 }
230
Jonathan Harta46dddf2015-06-30 15:31:20 -0700231 /**
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700232 * Request packet in via PacketService.
233 */
234 private void requestIntercepts() {
235 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
236 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
237 packetService.requestPackets(selector.build(),
238 CONTROL, appId);
239 }
240
241 /**
242 * Cancel request for packet in via PacketService.
243 */
244 private void withdrawIntercepts() {
245 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
246 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
247 packetService.cancelPackets(selector.build(), CONTROL, appId);
248 }
249
Ray Milkey967776a2015-10-07 14:37:17 -0700250 /**
251 * Send the ethernet packet to the supplicant.
252 *
253 * @param ethernetPkt the ethernet packet
254 * @param connectPoint the connect point to send out
255 */
256 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
257 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
258 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
259 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
260 packetService.emit(packet);
261 }
262
Ari Saha89831742015-06-26 10:31:48 -0700263 // our handler defined as a private inner class
264
265 /**
266 * Packet processor responsible for forwarding packets along their paths.
267 */
268 private class ReactivePacketProcessor implements PacketProcessor {
269 @Override
270 public void process(PacketContext context) {
271
272 // Extract the original Ethernet frame from the packet information
273 InboundPacket pkt = context.inPacket();
274 Ethernet ethPkt = pkt.parsed();
275 if (ethPkt == null) {
276 return;
277 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700278 try {
279 // identify if incoming packet comes from supplicant (EAP) or RADIUS
280 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
281 case EAPOL:
282 handleSupplicantPacket(context.inPacket());
283 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700284 default:
285 log.trace("Skipping Ethernet packet type {}",
286 EthType.EtherType.lookup(ethPkt.getEtherType()));
287 }
Ray Milkey967776a2015-10-07 14:37:17 -0700288 } catch (StateMachineException e) {
Ray Milkeyf51eba22015-09-25 10:24:23 -0700289 log.warn("Unable to process RADIUS packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700290 }
291 }
292
Ray Milkey9eb293f2015-09-30 15:09:17 -0700293 /**
294 * Creates and initializes common fields of a RADIUS packet.
295 *
Ray Milkey967776a2015-10-07 14:37:17 -0700296 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700297 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700298 * @return RADIUS packet
299 */
Ray Milkey967776a2015-10-07 14:37:17 -0700300 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700301 RADIUS radiusPayload =
302 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
303 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700304
305 // set Request Authenticator in StateMachine
306 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
307
Ray Milkey9eb293f2015-09-30 15:09:17 -0700308 radiusPayload.setIdentifier(identifier);
309 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700310 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700311
312 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800313 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700314
315 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700316
317 return radiusPayload;
318 }
Ari Saha89831742015-06-26 10:31:48 -0700319
320 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700321 * Handles PAE packets (supplicant).
322 *
323 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700324 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700325 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700326 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700327 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800328 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700329
Jonathan Harta46dddf2015-06-30 15:31:20 -0700330 DeviceId deviceId = inPacket.receivedFrom().deviceId();
331 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700332 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700333 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
334 if (stateMachine == null) {
Ray Milkey508cec52016-02-16 14:23:26 -0800335 stateMachine = new StateMachine(sessionId);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700336 }
337
Jonathan Harta46dddf2015-06-30 15:31:20 -0700338
339 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700340
341 switch (eapol.getEapolType()) {
342 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700343 stateMachine.start();
344 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700345
Ray Milkeyf51eba22015-09-25 10:24:23 -0700346 //send an EAP Request/Identify to the supplicant
347 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800348 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700349 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
350 eapPayload);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800351 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700352 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700353
Ray Milkey967776a2015-10-07 14:37:17 -0700354 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700355
356 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800357 case EAPOL.EAPOL_LOGOFF:
Ray Milkeyb34b4962016-01-04 10:24:43 -0800358 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
359 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800360 }
361
362 break;
Ari Saha89831742015-06-26 10:31:48 -0700363 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700364 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700365 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700366 EAP eapPacket = (EAP) eapol.getPayload();
367
368 byte dataType = eapPacket.getDataType();
369 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700370
Ray Milkey9eb293f2015-09-30 15:09:17 -0700371 case EAP.ATTR_IDENTITY:
372 // request id access to RADIUS
373 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700374
Ray Milkey967776a2015-10-07 14:37:17 -0700375 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800376 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700377
Jonathan Hart092dfb22015-11-16 23:05:21 -0800378 sendRadiusPacket(radiusPayload);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700379
Ray Milkey9eb293f2015-09-30 15:09:17 -0700380 // change the state to "PENDING"
381 stateMachine.requestAccess();
382 break;
Ari Saha89831742015-06-26 10:31:48 -0700383 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700384 // verify if the EAP identifier corresponds to the
385 // challenge identifier from the client state
386 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700387 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700388 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700389 radiusPayload =
390 getRadiusPayload(stateMachine,
391 stateMachine.identifier(),
392 eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700393
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800394 if (stateMachine.challengeState() != null) {
395 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
396 stateMachine.challengeState());
397 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800398 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
399 sendRadiusPacket(radiusPayload);
Ari Saha89831742015-06-26 10:31:48 -0700400 }
401 break;
402 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700403 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700404 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700405
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800406 if (stateMachine.challengeState() != null) {
407 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
408 stateMachine.challengeState());
409 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700410 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700411
Jonathan Hart092dfb22015-11-16 23:05:21 -0800412 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
413 sendRadiusPacket(radiusPayload);
Ray Milkey5493b512015-10-21 12:13:49 -0700414
Ray Milkeyf3790b82015-10-21 16:28:08 -0700415 if (stateMachine.state() != StateMachine.STATE_PENDING) {
416 stateMachine.requestAccess();
417 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700418
Ari Saha89831742015-06-26 10:31:48 -0700419 break;
420 default:
421 return;
422 }
423 break;
424 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700425 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700426 }
Ray Milkey967776a2015-10-07 14:37:17 -0700427
Ari Saha89831742015-06-26 10:31:48 -0700428 }
Ray Milkey967776a2015-10-07 14:37:17 -0700429 }
430
431 class RadiusListener implements Runnable {
Ari Saha89831742015-06-26 10:31:48 -0700432
433 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700434 * Handles RADIUS packets.
435 *
Ari Saha89831742015-06-26 10:31:48 -0700436 * @param radiusPacket RADIUS packet coming from the RADIUS server.
Ray Milkey17d6c492015-10-27 10:39:42 -0700437 * @throws StateMachineException if an illegal state transition is triggered
Ari Saha89831742015-06-26 10:31:48 -0700438 */
Ray Milkey967776a2015-10-07 14:37:17 -0700439 protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700440 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700441 if (stateMachine == null) {
442 log.error("Invalid session identifier, exiting...");
443 return;
444 }
445
Ray Milkeyf51eba22015-09-25 10:24:23 -0700446 EAP eapPayload;
447 Ethernet eth;
Ari Saha89831742015-06-26 10:31:48 -0700448 switch (radiusPacket.getCode()) {
449 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800450 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
451 byte[] challengeState = null;
452 if (radiusAttrState != null) {
453 challengeState = radiusAttrState.getValue();
454 }
Ari Saha89831742015-06-26 10:31:48 -0700455 eapPayload = radiusPacket.decapsulateMessage();
456 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700457 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700458 MacAddress.valueOf(nasMacAddress),
459 stateMachine.vlanId(),
460 EAPOL.EAPOL_PACKET,
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700461 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700462 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700463 break;
464 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700465 //send an EAPOL - Success to the supplicant.
ke han04e47f32016-10-28 14:15:43 +0800466 byte[] eapMessageSuccess =
Ray Milkeyf51eba22015-09-25 10:24:23 -0700467 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
468 eapPayload = new EAP();
ke han04e47f32016-10-28 14:15:43 +0800469 eapPayload = (EAP) eapPayload.deserialize(eapMessageSuccess, 0, eapMessageSuccess.length);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700470 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700471 MacAddress.valueOf(nasMacAddress),
472 stateMachine.vlanId(),
473 EAPOL.EAPOL_PACKET,
Ray Milkeyf51eba22015-09-25 10:24:23 -0700474 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700475 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700476
Ray Milkeyf51eba22015-09-25 10:24:23 -0700477 stateMachine.authorizeAccess();
Ari Saha89831742015-06-26 10:31:48 -0700478 break;
479 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
ke han04e47f32016-10-28 14:15:43 +0800480 //send an EAPOL - Failure to the supplicant.
ke han5dcfa522016-11-29 14:21:30 +0800481 byte[] eapMessageFailure;
ke han04e47f32016-10-28 14:15:43 +0800482 eapPayload = new EAP();
ke han5dcfa522016-11-29 14:21:30 +0800483 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
484 if (radiusAttrEap == null) {
485 eapPayload.setCode(EAP.FAILURE);
486 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
487 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
488 } else {
489 eapMessageFailure = radiusAttrEap.getValue();
490 eapPayload = (EAP) eapPayload.deserialize(eapMessageFailure, 0, eapMessageFailure.length);
491 }
ke han04e47f32016-10-28 14:15:43 +0800492 eth = buildEapolResponse(stateMachine.supplicantAddress(),
493 MacAddress.valueOf(nasMacAddress),
494 stateMachine.vlanId(),
495 EAPOL.EAPOL_PACKET,
496 eapPayload);
497 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
ke han5dcfa522016-11-29 14:21:30 +0800498 stateMachine.denyAccess();
Ari Saha89831742015-06-26 10:31:48 -0700499 break;
500 default:
501 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
502 }
503 }
504
Ari Saha89831742015-06-26 10:31:48 -0700505
Ray Milkey967776a2015-10-07 14:37:17 -0700506 @Override
507 public void run() {
508 boolean done = false;
509 int packetNumber = 1;
510
511 log.info("UDP listener thread starting up");
512 RADIUS inboundRadiusPacket;
513 while (!done) {
514 try {
Ray Milkey5493b512015-10-21 12:13:49 -0700515 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
516 DatagramPacket inboundBasePacket =
517 new DatagramPacket(packetBuffer, packetBuffer.length);
Ray Milkey967776a2015-10-07 14:37:17 -0700518 DatagramSocket socket = radiusSocket;
519 socket.receive(inboundBasePacket);
520 log.info("Packet #{} received", packetNumber++);
521 try {
522 inboundRadiusPacket =
523 RADIUS.deserializer()
524 .deserialize(inboundBasePacket.getData(),
525 0,
526 inboundBasePacket.getLength());
527 handleRadiusPacket(inboundRadiusPacket);
528 } catch (DeserializationException dex) {
529 log.error("Cannot deserialize packet", dex);
530 } catch (StateMachineException sme) {
531 log.error("Illegal state machine operation", sme);
532 }
533
534 } catch (IOException e) {
535 log.info("Socket was closed, exiting listener thread");
536 done = true;
537 }
Ari Saha89831742015-06-26 10:31:48 -0700538 }
Ari Saha89831742015-06-26 10:31:48 -0700539 }
Ari Saha89831742015-06-26 10:31:48 -0700540 }
541
Ray Milkey967776a2015-10-07 14:37:17 -0700542 RadiusListener radiusListener = new RadiusListener();
543
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700544 private class InternalConfigListener implements NetworkConfigListener {
545
546 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800547 * Reconfigures the AAA application according to the
548 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700549 *
550 * @param cfg configuration object
551 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800552 private void reconfigureNetwork(AaaConfig cfg) {
553 AaaConfig newCfg;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700554 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800555 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700556 } else {
557 newCfg = cfg;
558 }
559 if (newCfg.nasIp() != null) {
560 nasIpAddress = newCfg.nasIp();
561 }
562 if (newCfg.radiusIp() != null) {
563 radiusIpAddress = newCfg.radiusIp();
564 }
565 if (newCfg.radiusMac() != null) {
566 radiusMacAddress = newCfg.radiusMac();
567 }
568 if (newCfg.nasMac() != null) {
569 nasMacAddress = newCfg.nasMac();
570 }
571 if (newCfg.radiusSecret() != null) {
572 radiusSecret = newCfg.radiusSecret();
573 }
574 if (newCfg.radiusSwitch() != null) {
575 radiusSwitch = newCfg.radiusSwitch();
576 }
577 if (newCfg.radiusPort() != -1) {
578 radiusPort = newCfg.radiusPort();
579 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800580 if (newCfg.radiusServerUdpPort() != -1) {
581 radiusServerPort = newCfg.radiusServerUdpPort();
Ray Milkey5d99bd12015-10-06 15:41:30 -0700582 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700583 }
584
585 @Override
586 public void event(NetworkConfigEvent event) {
587
588 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
589 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800590 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700591
Jonathan Hart092dfb22015-11-16 23:05:21 -0800592 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700593 reconfigureNetwork(cfg);
Ray Milkeyfe4fe562016-01-05 13:14:43 -0800594 radiusSocket.close();
595 executor.shutdownNow();
596 initializeLocalState();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700597 log.info("Reconfigured");
598 }
599 }
600 }
601
602
Ari Saha89831742015-06-26 10:31:48 -0700603}