blob: 2c0d29f3738b576fa5eaf69f477047b7fcdcafe5 [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 *
16 */
17
Matteo Scandolocf847b82019-04-26 15:00:00 -070018package org.opencord.aaa.impl;
Ari Saha89831742015-06-26 10:31:48 -070019
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000020import static org.slf4j.LoggerFactory.getLogger;
21
22import java.util.HashSet;
23import java.util.Map;
24import java.util.Set;
25
Ari Saha89831742015-06-26 10:31:48 -070026import org.onlab.packet.MacAddress;
27import org.onosproject.net.ConnectPoint;
Matteo Scandolocf847b82019-04-26 15:00:00 -070028import org.opencord.aaa.AuthenticationEvent;
29import org.opencord.aaa.StateMachineDelegate;
Ari Saha89831742015-06-26 10:31:48 -070030import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070031
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000032import com.google.common.collect.Maps;
Ari Saha89831742015-06-26 10:31:48 -070033
34/**
35 * AAA Finite State Machine.
36 */
37
38class StateMachine {
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000039 // INDEX to identify the state in the transition table
Ari Saha89831742015-06-26 10:31:48 -070040 static final int STATE_IDLE = 0;
41 static final int STATE_STARTED = 1;
42 static final int STATE_PENDING = 2;
43 static final int STATE_AUTHORIZED = 3;
44 static final int STATE_UNAUTHORIZED = 4;
45
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000046 // Defining the states where timeout can happen
47 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet();
48 static {
49 TIMEOUT_ELIGIBLE_STATES.add(STATE_STARTED);
50 TIMEOUT_ELIGIBLE_STATES.add(STATE_PENDING);
51 }
52 // INDEX to identify the transition in the transition table
Ari Saha89831742015-06-26 10:31:48 -070053 static final int TRANSITION_START = 0; // --> started
54 static final int TRANSITION_REQUEST_ACCESS = 1;
55 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
56 static final int TRANSITION_DENY_ACCESS = 3;
57 static final int TRANSITION_LOGOFF = 4;
58
Shubham Sharma048cc262019-06-19 14:18:50 +000059 private static int identifier = 1;
Ari Saha89831742015-06-26 10:31:48 -070060 private byte challengeIdentifier;
61 private byte[] challengeState;
62 private byte[] username;
63 private byte[] requestAuthenticator;
64
65 // Supplicant connectivity info
Ray Milkeyf61a24e2015-09-24 16:34:02 -070066 private ConnectPoint supplicantConnectpoint;
67 private MacAddress supplicantAddress;
68 private short vlanId;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010069 private byte priorityCode;
Kartikey Dubeybe14f472019-10-01 12:18:35 +000070 private long sessionStartTime;
71 private String eapolTypeVal;
72
73 public enum EapolType {
74 EAPOL_PACKET("EAPOL_PACKET"),
75 EAPOL_START("EAPOL_START"),
76 EAPOL_LOGOFF("EAPOL_LOGOFF"),
77 EAPOL_KEY("EAPOL_KEY"),
78 EAPOL_ASF("EAPOL_ASF");
79
80 private final String eaptype;
81
82 private EapolType(String value) {
83 this.eaptype = value;
84 }
85 };
86
87 private String sessionTerminateReason;
88
89 public enum SessionTerminationReasons {
90 SUPPLICANT_LOGOFF("SUPPLICANT_LOGOFF"),
91 TIME_OUT("TIME_OUT"),
Girish Kumar8bc4eb32020-02-04 08:32:46 +000092 PORT_REMOVED("PORT_REMOVED"),
93 DEVICE_REMOVED("DEVICE_REMOVED");
Kartikey Dubeybe14f472019-10-01 12:18:35 +000094
95 private final String reason;
96
97 private SessionTerminationReasons(String value) {
98 this.reason = value;
99 }
100
101 public String getReason() {
102 return this.reason;
103 }
104 };
105
106 // Supplicant packet count
107 private int totalPacketsSent;
108 private int totalPacketsReceived;
109 private int totalOctetSent;
110 private int totalOctetReceived;
Ari Saha89831742015-06-26 10:31:48 -0700111
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000112 // Boolean flag indicating whether response is pending from AAA Server.
113 // Used for counting timeout happening for AAA Sessions due to no response.
114 private boolean waitingForRadiusResponse;
115
116 private static int cleanupTimerTimeOutInMins;
117
Ari Saha89831742015-06-26 10:31:48 -0700118 private String sessionId = null;
119
120 private final Logger log = getLogger(getClass());
121
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000122 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -0700123
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000124 // Cleanup Timer instance created for this session
125 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700126
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000127 // TimeStamp of last EAPOL or RADIUS message received.
128 private long lastPacketReceivedTime = 0;
129
130 // State transition table
Ari Saha89831742015-06-26 10:31:48 -0700131 /*
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000132 *
133 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
134 * -----------------------------------------------------------------------------
135 * -----------------------
136 *
137 * START STARTED | _ | _ | STARTED | STARTED
138 *
139 * REQUEST_ACCESS _ | PENDING | _ | _ | _
140 *
141 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
142 *
143 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
144 *
145 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700146 */
147
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000148 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
149 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
150 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
151 STATE_PENDING };
152 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
153 STATE_IDLE };
154 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
155 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700156
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000157 // THE TRANSITION TABLE
158 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
159 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700160
161 private int currentState = STATE_IDLE;
162
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700163 // Maps of state machines. Each state machine is represented by an
164 // unique identifier on the switch: dpid + port number
165 private static Map<String, StateMachine> sessionIdMap;
166 private static Map<Integer, StateMachine> identifierMap;
Ari Saha89831742015-06-26 10:31:48 -0700167
Jonathan Hart5db44532018-07-12 18:13:54 -0700168 private static StateMachineDelegate delegate;
169
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700170 public static void initializeMaps() {
171 sessionIdMap = Maps.newConcurrentMap();
172 identifierMap = Maps.newConcurrentMap();
Shubham Sharma048cc262019-06-19 14:18:50 +0000173 identifier = 1;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700174 }
175
176 public static void destroyMaps() {
177 sessionIdMap = null;
178 identifierMap = null;
179 }
180
Matteo Scandolocf847b82019-04-26 15:00:00 -0700181 public static void setDelegate(StateMachineDelegate delegate) {
182 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700183 }
184
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000185 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
186 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
187 }
188
Jonathan Hart5db44532018-07-12 18:13:54 -0700189 public static void unsetDelegate(StateMachineDelegate delegate) {
190 if (StateMachine.delegate == delegate) {
191 StateMachine.delegate = null;
192 }
193 }
194
Qianqian Hu61a6a402016-02-16 15:18:05 +0800195 public static Map<String, StateMachine> sessionIdMap() {
196 return sessionIdMap;
197 }
198
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700199 public static StateMachine lookupStateMachineById(byte identifier) {
200 return identifierMap.get((int) identifier);
201 }
202
203 public static StateMachine lookupStateMachineBySessionId(String sessionId) {
204 return sessionIdMap.get(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100205 }
206
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000207 public static void deleteStateMachineId(String sessionId) {
208 sessionIdMap.remove(sessionId);
209 }
210
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100211 public static void deleteStateMachineMapping(StateMachine machine) {
212 identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000213 if (machine.cleanupTimer != null) {
214 machine.cleanupTimer.cancel(false);
215 machine.cleanupTimer = null;
216 }
217 }
218
219 public java.util.concurrent.ScheduledFuture<?> getCleanupTimer() {
220 return cleanupTimer;
221 }
222
223 public boolean isWaitingForRadiusResponse() {
224 return waitingForRadiusResponse;
225 }
226
227 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
228 this.waitingForRadiusResponse = waitingForRadiusResponse;
229 }
230
231 public void setCleanupTimer(java.util.concurrent.ScheduledFuture<?> cleanupTimer) {
232 this.cleanupTimer = cleanupTimer;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100233 }
234
235 /**
David K. Bainbridge62019492017-07-28 17:02:10 -0700236 * Deletes authentication state machine records for a given MAC address.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000237 *
David K. Bainbridge62019492017-07-28 17:02:10 -0700238 * @param mac mac address of the suppliant who's state machine should be removed
239 */
240 public static void deleteByMac(MacAddress mac) {
241
242 // Walk the map from session IDs to state machines looking for a MAC match
243 for (Map.Entry<String, StateMachine> e : sessionIdMap.entrySet()) {
244
245 // If a MAC match is found then delete the entry from the session ID
246 // and identifier map as well as call delete identifier to clean up
247 // the identifier bit set.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000248 if (e.getValue() != null && e.getValue().supplicantAddress != null
249 && e.getValue().supplicantAddress.equals(mac)) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700250 sessionIdMap.remove(e.getValue().sessionId);
Shubham Sharma048cc262019-06-19 14:18:50 +0000251 if (e.getValue().identifier != 1) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700252 deleteStateMachineMapping(e.getValue());
253 }
254 break;
255 }
256 }
257 }
258
259 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700260 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700261 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000262 * @param sessionId session Id represented by the switch dpid + port number
Ari Saha89831742015-06-26 10:31:48 -0700263 */
Jonathan Hart932bedc2018-07-12 13:46:09 -0700264 public StateMachine(String sessionId) {
265 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700266 this.sessionId = sessionId;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700267 sessionIdMap.put(sessionId, this);
Ari Saha89831742015-06-26 10:31:48 -0700268 }
269
270 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700271 * Gets the connect point for the supplicant side.
272 *
273 * @return supplicant connect point
274 */
275 public ConnectPoint supplicantConnectpoint() {
276 return supplicantConnectpoint;
277 }
278
279 /**
280 * Sets the supplicant side connect point.
281 *
282 * @param supplicantConnectpoint supplicant select point.
283 */
284 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
285 this.supplicantConnectpoint = supplicantConnectpoint;
286 }
287
288 /**
289 * Gets the MAC address of the supplicant.
290 *
291 * @return supplicant MAC address
292 */
293 public MacAddress supplicantAddress() {
294 return supplicantAddress;
295 }
296
297 /**
298 * Sets the supplicant MAC address.
299 *
300 * @param supplicantAddress new supplicant MAC address
301 */
302 public void setSupplicantAddress(MacAddress supplicantAddress) {
303 this.supplicantAddress = supplicantAddress;
304 }
305
306 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000307 * Sets the lastPacketReceivedTime.
308 *
309 * @param lastPacketReceivedTime timelastPacket was received
310 */
311 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
312 this.lastPacketReceivedTime = lastPacketReceivedTime;
313 }
314
315 /**
316 * Gets the lastPacketReceivedTime.
317 *
318 * @return lastPacketReceivedTime
319 */
320 public long getLastPacketReceivedTime() {
321 return lastPacketReceivedTime;
322 }
323
324 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700325 * Gets the client's Vlan ID.
326 *
327 * @return client vlan ID
328 */
329 public short vlanId() {
330 return vlanId;
331 }
332
333 /**
334 * Sets the client's vlan ID.
335 *
336 * @param vlanId new client vlan ID
337 */
338 public void setVlanId(short vlanId) {
339 this.vlanId = vlanId;
340 }
341
342 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100343 * Gets the client's priority Code.
344 *
345 * @return client Priority code
346 */
347 public byte priorityCode() {
348 return priorityCode;
349 }
350
351 /**
352 * Sets the client's priority Code.
353 *
354 * @param priorityCode new client priority Code
355 */
356 public void setPriorityCode(byte priorityCode) {
357 this.priorityCode = priorityCode;
358 }
359
360 /**
Kartikey Dubeybe14f472019-10-01 12:18:35 +0000361 * Gets the session start time.
362 *
363 * @return session start time
364 */
365 public long sessionStartTime() {
366 return sessionStartTime;
367 }
368
369 /**
370 * Sets the session start time.
371 *
372 * @param sessionStartTime new session start time
373 */
374 public void setSessionStartTime(long sessionStartTime) {
375 this.sessionStartTime = sessionStartTime;
376 }
377
378 /**
379 * returns eapol Type.
380 *
381 * @return eapolTypeVal.
382 */
383 public String eapolType() {
384 return this.eapolTypeVal;
385 }
386
387 /**
388 * Sets eapol Type name from eapol value.
389 *
390 * @param value eapol type as byte.
391 */
392 public void setEapolTypeVal(byte value) {
393 switch (value) {
394 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
395 break;
396 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
397 break;
398 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
399 break;
400 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
401 break;
402 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
403 break;
404 default : this.eapolTypeVal = "INVALID TYPE";
405 }
406 }
407
408 public String getSessionTerminateReason() {
409 return sessionTerminateReason;
410 }
411
412 public void setSessionTerminateReason(String sessionTerminateReason) {
413 this.sessionTerminateReason = sessionTerminateReason;
414 }
415
416 public int totalPacketsReceived() {
417 return this.totalPacketsReceived;
418 }
419
420 public void incrementTotalPacketsReceived() {
421 this.totalPacketsReceived = this.totalPacketsReceived + 1;
422 }
423
424 public int totalPacketsSent() {
425 return this.totalPacketsSent;
426 }
427
428 public void incrementTotalPacketsSent() {
429 this.totalPacketsSent = this.totalPacketsSent + 1;
430 }
431
432 public void incrementTotalOctetReceived(short packetLen) {
433 this.totalOctetReceived = this.totalOctetReceived + packetLen;
434 }
435
436 public void incrementTotalOctetSent(short packetLen) {
437 this.totalOctetSent = this.totalOctetSent + packetLen;
438 }
439
440 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700441 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700442 *
Ari Saha89831742015-06-26 10:31:48 -0700443 * @return The client id.
444 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700445 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700446 return this.sessionId;
447 }
448
449 /**
Ari Saha89831742015-06-26 10:31:48 -0700450 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700451 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000452 * @param challengeIdentifier The challenge identifier set into the EAP packet
453 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700454 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700455 */
456 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
457 this.challengeIdentifier = challengeIdentifier;
458 this.challengeState = challengeState;
459 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700460
Ari Saha89831742015-06-26 10:31:48 -0700461 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000462 * Set the challenge identifier issued by the RADIUS on the access challenge
463 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700464 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000465 * @param challengeIdentifier The challenge identifier set into the EAP packet
466 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700467 */
468 protected void setChallengeIdentifier(byte challengeIdentifier) {
469 log.info("Set Challenge Identifier to {}", challengeIdentifier);
470 this.challengeIdentifier = challengeIdentifier;
471 }
472
473 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700474 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700475 *
Ari Saha89831742015-06-26 10:31:48 -0700476 * @return The challenge EAP identifier.
477 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700478 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700479 return this.challengeIdentifier;
480 }
481
Ari Saha89831742015-06-26 10:31:48 -0700482 /**
483 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700484 *
Ari Saha89831742015-06-26 10:31:48 -0700485 * @param challengeState The challenge state from the RADIUS.
486 */
487 protected void setChallengeState(byte[] challengeState) {
488 log.info("Set Challenge State");
489 this.challengeState = challengeState;
490 }
491
492 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700493 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700494 *
Ari Saha89831742015-06-26 10:31:48 -0700495 * @return The challenge state.
496 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700497 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700498 return this.challengeState;
499 }
500
501 /**
502 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700503 *
Ari Saha89831742015-06-26 10:31:48 -0700504 * @param username The username sent to the RADIUS upon access request.
505 */
506 protected void setUsername(byte[] username) {
507 this.username = username;
508 }
509
Ari Saha89831742015-06-26 10:31:48 -0700510 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700511 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700512 *
Ari Saha89831742015-06-26 10:31:48 -0700513 * @return The requestAuthenticator.
514 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700515 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700516 return this.requestAuthenticator;
517 }
518
519 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700520 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700521 *
Ari Saha89831742015-06-26 10:31:48 -0700522 * @param authenticator The username sent to the RADIUS upon access request.
523 */
524 protected void setRequestAuthenticator(byte[] authenticator) {
525 this.requestAuthenticator = authenticator;
526 }
527
Ari Saha89831742015-06-26 10:31:48 -0700528 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700529 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700530 *
Ari Saha89831742015-06-26 10:31:48 -0700531 * @return The username.
532 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700533 protected byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700534 return this.username;
535 }
536
537 /**
538 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700539 *
Ari Saha89831742015-06-26 10:31:48 -0700540 * @return The state machine identifier.
541 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100542 public synchronized byte identifier() {
Shubham Sharma048cc262019-06-19 14:18:50 +0000543 //identifier 0 is for statusServerrequest
544 //identifier 1 is for fake accessRequest
545 identifier = (identifier + 1) % 253;
546 identifierMap.put((identifier + 2), this);
547 return (byte) (identifier + 2);
Ari Saha89831742015-06-26 10:31:48 -0700548 }
549
Ari Saha89831742015-06-26 10:31:48 -0700550 /**
551 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700552 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700553 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700554 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700555 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700556 currentState = transition[currentState][msg];
557 log.info("Current State " + currentState);
558 }
559
560 /**
561 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700562 *
563 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700564 */
565 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700566 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700567
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000568 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700569
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000570 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700571 next(TRANSITION_START);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100572 identifier = this.identifier();
Ari Saha89831742015-06-26 10:31:48 -0700573 }
574
575 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000576 * An Identification information has been sent by the supplicant. Move to the
577 * next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700578 *
579 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700580 */
581 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700582 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700583
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000584 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700585
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000586 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700587 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700588 }
589
590 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000591 * RADIUS has accepted the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700592 *
593 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700594 */
595 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700596 states[currentState].radiusAccepted();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000597 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700598 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700599
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000600 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700601
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100602 // Clear mapping
603 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700604 }
605
606 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000607 * RADIUS has denied the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700608 *
609 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700610 */
611 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700612 states[currentState].radiusDenied();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000613 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700614 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700615
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000616 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700617
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100618 // Clear mappings
619 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700620 }
621
622 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000623 * Logoff request has been requested. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700624 *
625 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700626 */
627 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700628 states[currentState].logoff();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000629 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700630 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700631 }
632
633 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700634 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700635 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000636 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
637 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700638 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700639 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700640 return currentState;
641 }
642
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700643 @Override
Ari Saha89831742015-06-26 10:31:48 -0700644 public String toString() {
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000645 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t"
646 + ("state: " + this.currentState);
Ari Saha89831742015-06-26 10:31:48 -0700647 }
Ari Saha89831742015-06-26 10:31:48 -0700648
Ray Milkey78e95a42015-09-24 08:36:45 -0700649 abstract class State {
650 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700651
Ray Milkey78e95a42015-09-24 08:36:45 -0700652 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700653
Ray Milkey78e95a42015-09-24 08:36:45 -0700654 public void start() throws StateMachineInvalidTransitionException {
655 log.warn("START transition from this state is not allowed.");
656 }
Ari Saha89831742015-06-26 10:31:48 -0700657
Ray Milkey78e95a42015-09-24 08:36:45 -0700658 public void requestAccess() throws StateMachineInvalidTransitionException {
659 log.warn("REQUEST ACCESS transition from this state is not allowed.");
660 }
661
662 public void radiusAccepted() throws StateMachineInvalidTransitionException {
663 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
664 }
665
666 public void radiusDenied() throws StateMachineInvalidTransitionException {
667 log.warn("DENY ACCESS transition from this state is not allowed.");
668 }
669
670 public void logoff() throws StateMachineInvalidTransitionException {
671 log.warn("LOGOFF transition from this state is not allowed.");
672 }
Ari Saha89831742015-06-26 10:31:48 -0700673 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700674
Ray Milkey78e95a42015-09-24 08:36:45 -0700675 /**
676 * Idle state: supplicant is logged of from the network.
677 */
678 class Idle extends State {
679 private final Logger log = getLogger(getClass());
680 private String name = "IDLE_STATE";
681
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000682 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700683 public void start() {
684 log.info("Moving from IDLE state to STARTED state.");
685 }
Ari Saha89831742015-06-26 10:31:48 -0700686 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700687
Ray Milkey78e95a42015-09-24 08:36:45 -0700688 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000689 * Started state: supplicant has entered the network and informed the
690 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700691 */
692 class Started extends State {
693 private final Logger log = getLogger(getClass());
694 private String name = "STARTED_STATE";
695
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000696 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700697 public void requestAccess() {
698 log.info("Moving from STARTED state to PENDING state.");
699 }
Ari Saha89831742015-06-26 10:31:48 -0700700 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700701
Ray Milkey78e95a42015-09-24 08:36:45 -0700702 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000703 * Pending state: supplicant has been identified by the authenticator but has
704 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700705 */
706 class Pending extends State {
707 private final Logger log = getLogger(getClass());
708 private String name = "PENDING_STATE";
709
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000710 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700711 public void radiusAccepted() {
712 log.info("Moving from PENDING state to AUTHORIZED state.");
713 }
714
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000715 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700716 public void radiusDenied() {
717 log.info("Moving from PENDING state to UNAUTHORIZED state.");
718 }
Ari Saha89831742015-06-26 10:31:48 -0700719 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700720
Ray Milkey78e95a42015-09-24 08:36:45 -0700721 /**
722 * Authorized state: supplicant port has been accepted, access is granted.
723 */
724 class Authorized extends State {
725 private final Logger log = getLogger(getClass());
726 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700727
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000728 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800729 public void start() {
730 log.info("Moving from AUTHORIZED state to STARTED state.");
731 }
732
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000733 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700734 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700735
Ray Milkey78e95a42015-09-24 08:36:45 -0700736 log.info("Moving from AUTHORIZED state to IDLE state.");
737 }
Ari Saha89831742015-06-26 10:31:48 -0700738 }
739
Ray Milkey78e95a42015-09-24 08:36:45 -0700740 /**
741 * Unauthorized state: supplicant port has been rejected, access is denied.
742 */
743 class Unauthorized extends State {
744 private final Logger log = getLogger(getClass());
745 private String name = "UNAUTHORIZED_STATE";
746
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000747 @Override
ke han04e47f32016-10-28 14:15:43 +0800748 public void start() {
749 log.info("Moving from UNAUTHORIZED state to STARTED state.");
750 }
751
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000752 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700753 public void logoff() {
754 log.info("Moving from UNAUTHORIZED state to IDLE state.");
755 }
Ari Saha89831742015-06-26 10:31:48 -0700756 }
Ari Saha89831742015-06-26 10:31:48 -0700757
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000758 /**
759 * Class for cleaning the StateMachine for those session for which no response
760 * is coming--implementing timeout.
761 */
762 class CleanupTimerTask implements Runnable {
763 private final Logger log = getLogger(getClass());
764 private String sessionId;
765 private AaaManager aaaManager;
766
767 CleanupTimerTask(String sessionId, AaaManager aaaManager) {
768 this.sessionId = sessionId;
769 this.aaaManager = aaaManager;
770 }
771
772 @Override
773 public void run() {
774 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
775 if (null != stateMachine) {
776 // Asserting if last packet received for this stateMachine session was beyond half of timeout period.
777 // StateMachine is considered eligible for cleanup when no packets has been exchanged by it with AAA
778 // Server or RG during a long period (half of timeout period). For example, when cleanup timer has
779 // been configured as 10 minutes, StateMachine would be cleaned up at the end of 10 minutes if
780 // the authentication is still pending and no packet was exchanged for this session during last 5
781 // minutes.
782
783 boolean noTrafficWithinThreshold = (System.currentTimeMillis()
784 - stateMachine.getLastPacketReceivedTime()) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
785
786 if ((TIMEOUT_ELIGIBLE_STATES.contains(stateMachine.state())) && noTrafficWithinThreshold) {
787 log.info("Deleting StateMachineMapping for sessionId: {}", sessionId);
788 cleanupTimer = null;
789 if (stateMachine.state() == STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
790 aaaManager.aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
791 }
792 deleteStateMachineId(sessionId);
793 deleteStateMachineMapping(stateMachine);
794
795 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
796 } else {
797 aaaManager.scheduleStateMachineCleanupTimer(sessionId, stateMachine);
798 }
799 } else {
800 // This statement should not be logged; cleanupTimer should be cancelled for stateMachine
801 // instances which have been authenticated successfully.
802 log.warn("state-machine not found for sessionId: {}", sessionId);
803 }
804
805 }
806 }
Ari Saha89831742015-06-26 10:31:48 -0700807
Ari Saha89831742015-06-26 10:31:48 -0700808}