blob: c60605efec8020741d457cd4443c1d80f4054c74 [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;
Arjun E Kac463f62020-02-03 14:05:45 +000030import org.opencord.aaa.AaaSupplicantMachineStats;
31import org.opencord.aaa.AaaMachineStatisticsEvent;
Ari Saha89831742015-06-26 10:31:48 -070032import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070033
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000034import com.google.common.collect.Maps;
Ari Saha89831742015-06-26 10:31:48 -070035
36/**
37 * AAA Finite State Machine.
38 */
39
40class StateMachine {
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000041 // INDEX to identify the state in the transition table
Ari Saha89831742015-06-26 10:31:48 -070042 static final int STATE_IDLE = 0;
43 static final int STATE_STARTED = 1;
44 static final int STATE_PENDING = 2;
45 static final int STATE_AUTHORIZED = 3;
46 static final int STATE_UNAUTHORIZED = 4;
47
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000048 // Defining the states where timeout can happen
49 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet();
50 static {
51 TIMEOUT_ELIGIBLE_STATES.add(STATE_STARTED);
52 TIMEOUT_ELIGIBLE_STATES.add(STATE_PENDING);
53 }
54 // INDEX to identify the transition in the transition table
Ari Saha89831742015-06-26 10:31:48 -070055 static final int TRANSITION_START = 0; // --> started
56 static final int TRANSITION_REQUEST_ACCESS = 1;
57 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
58 static final int TRANSITION_DENY_ACCESS = 3;
59 static final int TRANSITION_LOGOFF = 4;
60
Shubham Sharma048cc262019-06-19 14:18:50 +000061 private static int identifier = 1;
Ari Saha89831742015-06-26 10:31:48 -070062 private byte challengeIdentifier;
63 private byte[] challengeState;
64 private byte[] username;
65 private byte[] requestAuthenticator;
66
67 // Supplicant connectivity info
Ray Milkeyf61a24e2015-09-24 16:34:02 -070068 private ConnectPoint supplicantConnectpoint;
69 private MacAddress supplicantAddress;
70 private short vlanId;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010071 private byte priorityCode;
Kartikey Dubeybe14f472019-10-01 12:18:35 +000072 private long sessionStartTime;
73 private String eapolTypeVal;
74
75 public enum EapolType {
76 EAPOL_PACKET("EAPOL_PACKET"),
77 EAPOL_START("EAPOL_START"),
78 EAPOL_LOGOFF("EAPOL_LOGOFF"),
79 EAPOL_KEY("EAPOL_KEY"),
80 EAPOL_ASF("EAPOL_ASF");
81
82 private final String eaptype;
83
84 private EapolType(String value) {
85 this.eaptype = value;
86 }
87 };
88
89 private String sessionTerminateReason;
90
91 public enum SessionTerminationReasons {
92 SUPPLICANT_LOGOFF("SUPPLICANT_LOGOFF"),
93 TIME_OUT("TIME_OUT"),
Girish Kumar8bc4eb32020-02-04 08:32:46 +000094 PORT_REMOVED("PORT_REMOVED"),
95 DEVICE_REMOVED("DEVICE_REMOVED");
Kartikey Dubeybe14f472019-10-01 12:18:35 +000096
97 private final String reason;
98
99 private SessionTerminationReasons(String value) {
100 this.reason = value;
101 }
102
103 public String getReason() {
104 return this.reason;
105 }
106 };
107
108 // Supplicant packet count
109 private int totalPacketsSent;
110 private int totalPacketsReceived;
111 private int totalOctetSent;
112 private int totalOctetReceived;
Ari Saha89831742015-06-26 10:31:48 -0700113
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000114 // Boolean flag indicating whether response is pending from AAA Server.
115 // Used for counting timeout happening for AAA Sessions due to no response.
116 private boolean waitingForRadiusResponse;
117
118 private static int cleanupTimerTimeOutInMins;
119
Ari Saha89831742015-06-26 10:31:48 -0700120 private String sessionId = null;
121
122 private final Logger log = getLogger(getClass());
123
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000124 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -0700125
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000126 // Cleanup Timer instance created for this session
127 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700128
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000129 // TimeStamp of last EAPOL or RADIUS message received.
130 private long lastPacketReceivedTime = 0;
131
132 // State transition table
Ari Saha89831742015-06-26 10:31:48 -0700133 /*
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000134 *
135 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
136 * -----------------------------------------------------------------------------
137 * -----------------------
138 *
139 * START STARTED | _ | _ | STARTED | STARTED
140 *
141 * REQUEST_ACCESS _ | PENDING | _ | _ | _
142 *
143 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
144 *
145 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
146 *
147 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700148 */
149
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000150 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
151 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
152 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
153 STATE_PENDING };
154 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
155 STATE_IDLE };
156 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
157 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700158
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000159 // THE TRANSITION TABLE
160 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
161 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700162
163 private int currentState = STATE_IDLE;
164
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700165 // Maps of state machines. Each state machine is represented by an
166 // unique identifier on the switch: dpid + port number
167 private static Map<String, StateMachine> sessionIdMap;
168 private static Map<Integer, StateMachine> identifierMap;
Ari Saha89831742015-06-26 10:31:48 -0700169
Jonathan Hart5db44532018-07-12 18:13:54 -0700170 private static StateMachineDelegate delegate;
171
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700172 public static void initializeMaps() {
173 sessionIdMap = Maps.newConcurrentMap();
174 identifierMap = Maps.newConcurrentMap();
Shubham Sharma048cc262019-06-19 14:18:50 +0000175 identifier = 1;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700176 }
177
178 public static void destroyMaps() {
179 sessionIdMap = null;
180 identifierMap = null;
181 }
182
Matteo Scandolocf847b82019-04-26 15:00:00 -0700183 public static void setDelegate(StateMachineDelegate delegate) {
184 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700185 }
186
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000187 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
188 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
189 }
190
Jonathan Hart5db44532018-07-12 18:13:54 -0700191 public static void unsetDelegate(StateMachineDelegate delegate) {
192 if (StateMachine.delegate == delegate) {
193 StateMachine.delegate = null;
194 }
195 }
196
Qianqian Hu61a6a402016-02-16 15:18:05 +0800197 public static Map<String, StateMachine> sessionIdMap() {
198 return sessionIdMap;
199 }
200
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700201 public static StateMachine lookupStateMachineById(byte identifier) {
202 return identifierMap.get((int) identifier);
203 }
204
205 public static StateMachine lookupStateMachineBySessionId(String sessionId) {
206 return sessionIdMap.get(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100207 }
208
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000209 public static void deleteStateMachineId(String sessionId) {
210 sessionIdMap.remove(sessionId);
211 }
212
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100213 public static void deleteStateMachineMapping(StateMachine machine) {
214 identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000215 if (machine.cleanupTimer != null) {
216 machine.cleanupTimer.cancel(false);
217 machine.cleanupTimer = null;
218 }
219 }
220
221 public java.util.concurrent.ScheduledFuture<?> getCleanupTimer() {
222 return cleanupTimer;
223 }
224
225 public boolean isWaitingForRadiusResponse() {
226 return waitingForRadiusResponse;
227 }
228
229 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
230 this.waitingForRadiusResponse = waitingForRadiusResponse;
231 }
232
233 public void setCleanupTimer(java.util.concurrent.ScheduledFuture<?> cleanupTimer) {
234 this.cleanupTimer = cleanupTimer;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100235 }
236
237 /**
David K. Bainbridge62019492017-07-28 17:02:10 -0700238 * Deletes authentication state machine records for a given MAC address.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000239 *
David K. Bainbridge62019492017-07-28 17:02:10 -0700240 * @param mac mac address of the suppliant who's state machine should be removed
241 */
242 public static void deleteByMac(MacAddress mac) {
243
244 // Walk the map from session IDs to state machines looking for a MAC match
245 for (Map.Entry<String, StateMachine> e : sessionIdMap.entrySet()) {
246
247 // If a MAC match is found then delete the entry from the session ID
248 // and identifier map as well as call delete identifier to clean up
249 // the identifier bit set.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000250 if (e.getValue() != null && e.getValue().supplicantAddress != null
251 && e.getValue().supplicantAddress.equals(mac)) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700252 sessionIdMap.remove(e.getValue().sessionId);
Shubham Sharma048cc262019-06-19 14:18:50 +0000253 if (e.getValue().identifier != 1) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700254 deleteStateMachineMapping(e.getValue());
255 }
256 break;
257 }
258 }
259 }
260
261 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700262 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700263 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000264 * @param sessionId session Id represented by the switch dpid + port number
Ari Saha89831742015-06-26 10:31:48 -0700265 */
Jonathan Hart932bedc2018-07-12 13:46:09 -0700266 public StateMachine(String sessionId) {
267 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700268 this.sessionId = sessionId;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700269 sessionIdMap.put(sessionId, this);
Ari Saha89831742015-06-26 10:31:48 -0700270 }
271
272 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700273 * Gets the connect point for the supplicant side.
274 *
275 * @return supplicant connect point
276 */
277 public ConnectPoint supplicantConnectpoint() {
278 return supplicantConnectpoint;
279 }
280
281 /**
282 * Sets the supplicant side connect point.
283 *
284 * @param supplicantConnectpoint supplicant select point.
285 */
286 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
287 this.supplicantConnectpoint = supplicantConnectpoint;
288 }
289
290 /**
291 * Gets the MAC address of the supplicant.
292 *
293 * @return supplicant MAC address
294 */
295 public MacAddress supplicantAddress() {
296 return supplicantAddress;
297 }
298
299 /**
300 * Sets the supplicant MAC address.
301 *
302 * @param supplicantAddress new supplicant MAC address
303 */
304 public void setSupplicantAddress(MacAddress supplicantAddress) {
305 this.supplicantAddress = supplicantAddress;
306 }
307
308 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000309 * Sets the lastPacketReceivedTime.
310 *
311 * @param lastPacketReceivedTime timelastPacket was received
312 */
313 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
314 this.lastPacketReceivedTime = lastPacketReceivedTime;
315 }
316
317 /**
318 * Gets the lastPacketReceivedTime.
319 *
320 * @return lastPacketReceivedTime
321 */
322 public long getLastPacketReceivedTime() {
323 return lastPacketReceivedTime;
324 }
325
326 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700327 * Gets the client's Vlan ID.
328 *
329 * @return client vlan ID
330 */
331 public short vlanId() {
332 return vlanId;
333 }
334
335 /**
336 * Sets the client's vlan ID.
337 *
338 * @param vlanId new client vlan ID
339 */
340 public void setVlanId(short vlanId) {
341 this.vlanId = vlanId;
342 }
343
344 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100345 * Gets the client's priority Code.
346 *
347 * @return client Priority code
348 */
349 public byte priorityCode() {
350 return priorityCode;
351 }
352
353 /**
354 * Sets the client's priority Code.
355 *
356 * @param priorityCode new client priority Code
357 */
358 public void setPriorityCode(byte priorityCode) {
359 this.priorityCode = priorityCode;
360 }
361
362 /**
Kartikey Dubeybe14f472019-10-01 12:18:35 +0000363 * Gets the session start time.
364 *
365 * @return session start time
366 */
367 public long sessionStartTime() {
368 return sessionStartTime;
369 }
370
371 /**
372 * Sets the session start time.
373 *
374 * @param sessionStartTime new session start time
375 */
376 public void setSessionStartTime(long sessionStartTime) {
377 this.sessionStartTime = sessionStartTime;
378 }
379
380 /**
381 * returns eapol Type.
382 *
383 * @return eapolTypeVal.
384 */
385 public String eapolType() {
386 return this.eapolTypeVal;
387 }
388
389 /**
390 * Sets eapol Type name from eapol value.
391 *
392 * @param value eapol type as byte.
393 */
394 public void setEapolTypeVal(byte value) {
395 switch (value) {
396 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
397 break;
398 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
399 break;
400 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
401 break;
402 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
403 break;
404 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
405 break;
406 default : this.eapolTypeVal = "INVALID TYPE";
407 }
408 }
409
410 public String getSessionTerminateReason() {
411 return sessionTerminateReason;
412 }
413
414 public void setSessionTerminateReason(String sessionTerminateReason) {
415 this.sessionTerminateReason = sessionTerminateReason;
416 }
417
418 public int totalPacketsReceived() {
419 return this.totalPacketsReceived;
420 }
421
422 public void incrementTotalPacketsReceived() {
423 this.totalPacketsReceived = this.totalPacketsReceived + 1;
424 }
425
426 public int totalPacketsSent() {
427 return this.totalPacketsSent;
428 }
429
430 public void incrementTotalPacketsSent() {
431 this.totalPacketsSent = this.totalPacketsSent + 1;
432 }
433
434 public void incrementTotalOctetReceived(short packetLen) {
435 this.totalOctetReceived = this.totalOctetReceived + packetLen;
436 }
437
438 public void incrementTotalOctetSent(short packetLen) {
439 this.totalOctetSent = this.totalOctetSent + packetLen;
440 }
441
442 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700443 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700444 *
Ari Saha89831742015-06-26 10:31:48 -0700445 * @return The client id.
446 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700447 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700448 return this.sessionId;
449 }
450
451 /**
Ari Saha89831742015-06-26 10:31:48 -0700452 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700453 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000454 * @param challengeIdentifier The challenge identifier set into the EAP packet
455 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700456 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700457 */
458 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
459 this.challengeIdentifier = challengeIdentifier;
460 this.challengeState = challengeState;
461 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700462
Ari Saha89831742015-06-26 10:31:48 -0700463 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000464 * Set the challenge identifier issued by the RADIUS on the access challenge
465 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700466 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000467 * @param challengeIdentifier The challenge identifier set into the EAP packet
468 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700469 */
470 protected void setChallengeIdentifier(byte challengeIdentifier) {
471 log.info("Set Challenge Identifier to {}", challengeIdentifier);
472 this.challengeIdentifier = challengeIdentifier;
473 }
474
475 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700476 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700477 *
Ari Saha89831742015-06-26 10:31:48 -0700478 * @return The challenge EAP identifier.
479 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700480 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700481 return this.challengeIdentifier;
482 }
483
Ari Saha89831742015-06-26 10:31:48 -0700484 /**
485 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700486 *
Ari Saha89831742015-06-26 10:31:48 -0700487 * @param challengeState The challenge state from the RADIUS.
488 */
489 protected void setChallengeState(byte[] challengeState) {
490 log.info("Set Challenge State");
491 this.challengeState = challengeState;
492 }
493
494 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700495 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700496 *
Ari Saha89831742015-06-26 10:31:48 -0700497 * @return The challenge state.
498 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700499 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700500 return this.challengeState;
501 }
502
503 /**
504 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700505 *
Ari Saha89831742015-06-26 10:31:48 -0700506 * @param username The username sent to the RADIUS upon access request.
507 */
508 protected void setUsername(byte[] username) {
509 this.username = username;
510 }
511
Ari Saha89831742015-06-26 10:31:48 -0700512 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700513 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700514 *
Ari Saha89831742015-06-26 10:31:48 -0700515 * @return The requestAuthenticator.
516 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700517 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700518 return this.requestAuthenticator;
519 }
520
521 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700522 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700523 *
Ari Saha89831742015-06-26 10:31:48 -0700524 * @param authenticator The username sent to the RADIUS upon access request.
525 */
526 protected void setRequestAuthenticator(byte[] authenticator) {
527 this.requestAuthenticator = authenticator;
528 }
529
Ari Saha89831742015-06-26 10:31:48 -0700530 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700531 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700532 *
Ari Saha89831742015-06-26 10:31:48 -0700533 * @return The username.
534 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700535 protected byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700536 return this.username;
537 }
538
539 /**
540 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700541 *
Ari Saha89831742015-06-26 10:31:48 -0700542 * @return The state machine identifier.
543 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100544 public synchronized byte identifier() {
Shubham Sharma048cc262019-06-19 14:18:50 +0000545 //identifier 0 is for statusServerrequest
546 //identifier 1 is for fake accessRequest
547 identifier = (identifier + 1) % 253;
548 identifierMap.put((identifier + 2), this);
549 return (byte) (identifier + 2);
Ari Saha89831742015-06-26 10:31:48 -0700550 }
551
Ari Saha89831742015-06-26 10:31:48 -0700552 /**
553 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700554 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700555 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700556 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700557 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700558 currentState = transition[currentState][msg];
559 log.info("Current State " + currentState);
560 }
561
562 /**
563 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700564 *
565 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700566 */
567 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700568 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700569
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000570 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700571
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000572 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700573 next(TRANSITION_START);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100574 identifier = this.identifier();
Ari Saha89831742015-06-26 10:31:48 -0700575 }
576
577 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000578 * An Identification information has been sent by the supplicant. Move to the
579 * next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700580 *
581 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700582 */
583 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700584 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700585
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000586 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700587
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000588 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700589 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700590 }
591
592 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000593 * RADIUS has accepted the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700594 *
595 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700596 */
597 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700598 states[currentState].radiusAccepted();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000599 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700600 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700601
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000602 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700603
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100604 // Clear mapping
605 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700606 }
607
608 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000609 * RADIUS has denied the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700610 *
611 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700612 */
613 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700614 states[currentState].radiusDenied();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000615 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700616 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700617
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000618 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700619
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100620 // Clear mappings
621 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700622 }
623
624 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000625 * Logoff request has been requested. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700626 *
627 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700628 */
629 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700630 states[currentState].logoff();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000631 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700632 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700633 }
634
635 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700636 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700637 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000638 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
639 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700640 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700641 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700642 return currentState;
643 }
644
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700645 @Override
Ari Saha89831742015-06-26 10:31:48 -0700646 public String toString() {
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000647 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t"
648 + ("state: " + this.currentState);
Ari Saha89831742015-06-26 10:31:48 -0700649 }
Ari Saha89831742015-06-26 10:31:48 -0700650
Ray Milkey78e95a42015-09-24 08:36:45 -0700651 abstract class State {
652 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700653
Ray Milkey78e95a42015-09-24 08:36:45 -0700654 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700655
Ray Milkey78e95a42015-09-24 08:36:45 -0700656 public void start() throws StateMachineInvalidTransitionException {
657 log.warn("START transition from this state is not allowed.");
658 }
Ari Saha89831742015-06-26 10:31:48 -0700659
Ray Milkey78e95a42015-09-24 08:36:45 -0700660 public void requestAccess() throws StateMachineInvalidTransitionException {
661 log.warn("REQUEST ACCESS transition from this state is not allowed.");
662 }
663
664 public void radiusAccepted() throws StateMachineInvalidTransitionException {
665 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
666 }
667
668 public void radiusDenied() throws StateMachineInvalidTransitionException {
669 log.warn("DENY ACCESS transition from this state is not allowed.");
670 }
671
672 public void logoff() throws StateMachineInvalidTransitionException {
673 log.warn("LOGOFF transition from this state is not allowed.");
674 }
Ari Saha89831742015-06-26 10:31:48 -0700675 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700676
Ray Milkey78e95a42015-09-24 08:36:45 -0700677 /**
678 * Idle state: supplicant is logged of from the network.
679 */
680 class Idle extends State {
681 private final Logger log = getLogger(getClass());
682 private String name = "IDLE_STATE";
683
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000684 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700685 public void start() {
686 log.info("Moving from IDLE state to STARTED state.");
687 }
Ari Saha89831742015-06-26 10:31:48 -0700688 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700689
Ray Milkey78e95a42015-09-24 08:36:45 -0700690 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000691 * Started state: supplicant has entered the network and informed the
692 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700693 */
694 class Started extends State {
695 private final Logger log = getLogger(getClass());
696 private String name = "STARTED_STATE";
697
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000698 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700699 public void requestAccess() {
700 log.info("Moving from STARTED state to PENDING state.");
701 }
Ari Saha89831742015-06-26 10:31:48 -0700702 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700703
Ray Milkey78e95a42015-09-24 08:36:45 -0700704 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000705 * Pending state: supplicant has been identified by the authenticator but has
706 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700707 */
708 class Pending extends State {
709 private final Logger log = getLogger(getClass());
710 private String name = "PENDING_STATE";
711
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000712 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700713 public void radiusAccepted() {
714 log.info("Moving from PENDING state to AUTHORIZED state.");
715 }
716
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000717 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700718 public void radiusDenied() {
719 log.info("Moving from PENDING state to UNAUTHORIZED state.");
720 }
Ari Saha89831742015-06-26 10:31:48 -0700721 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700722
Ray Milkey78e95a42015-09-24 08:36:45 -0700723 /**
724 * Authorized state: supplicant port has been accepted, access is granted.
725 */
726 class Authorized extends State {
727 private final Logger log = getLogger(getClass());
728 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700729
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000730 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800731 public void start() {
732 log.info("Moving from AUTHORIZED state to STARTED state.");
733 }
734
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000735 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700736 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700737
Ray Milkey78e95a42015-09-24 08:36:45 -0700738 log.info("Moving from AUTHORIZED state to IDLE state.");
739 }
Ari Saha89831742015-06-26 10:31:48 -0700740 }
741
Ray Milkey78e95a42015-09-24 08:36:45 -0700742 /**
743 * Unauthorized state: supplicant port has been rejected, access is denied.
744 */
745 class Unauthorized extends State {
746 private final Logger log = getLogger(getClass());
747 private String name = "UNAUTHORIZED_STATE";
748
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000749 @Override
ke han04e47f32016-10-28 14:15:43 +0800750 public void start() {
751 log.info("Moving from UNAUTHORIZED state to STARTED state.");
752 }
753
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000754 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700755 public void logoff() {
756 log.info("Moving from UNAUTHORIZED state to IDLE state.");
757 }
Ari Saha89831742015-06-26 10:31:48 -0700758 }
Ari Saha89831742015-06-26 10:31:48 -0700759
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000760 /**
761 * Class for cleaning the StateMachine for those session for which no response
762 * is coming--implementing timeout.
763 */
764 class CleanupTimerTask implements Runnable {
765 private final Logger log = getLogger(getClass());
766 private String sessionId;
767 private AaaManager aaaManager;
768
769 CleanupTimerTask(String sessionId, AaaManager aaaManager) {
770 this.sessionId = sessionId;
771 this.aaaManager = aaaManager;
772 }
773
774 @Override
775 public void run() {
776 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
777 if (null != stateMachine) {
778 // Asserting if last packet received for this stateMachine session was beyond half of timeout period.
779 // StateMachine is considered eligible for cleanup when no packets has been exchanged by it with AAA
780 // Server or RG during a long period (half of timeout period). For example, when cleanup timer has
781 // been configured as 10 minutes, StateMachine would be cleaned up at the end of 10 minutes if
782 // the authentication is still pending and no packet was exchanged for this session during last 5
783 // minutes.
784
785 boolean noTrafficWithinThreshold = (System.currentTimeMillis()
786 - stateMachine.getLastPacketReceivedTime()) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
787
788 if ((TIMEOUT_ELIGIBLE_STATES.contains(stateMachine.state())) && noTrafficWithinThreshold) {
789 log.info("Deleting StateMachineMapping for sessionId: {}", sessionId);
790 cleanupTimer = null;
791 if (stateMachine.state() == STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
792 aaaManager.aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
793 }
Arjun E Kac463f62020-02-03 14:05:45 +0000794 //pushing captured machine stats to kafka
795 stateMachine.setSessionTerminateReason("Time out");
796 AaaSupplicantMachineStats obj = aaaManager.aaaSupplicantStatsManager
797 .getSupplicantStats(stateMachine);
798 aaaManager.aaaSupplicantStatsManager.getMachineStatsDelegate()
799 .notify(new AaaMachineStatisticsEvent(
800 AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
801
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000802 deleteStateMachineId(sessionId);
803 deleteStateMachineMapping(stateMachine);
804
805 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
806 } else {
807 aaaManager.scheduleStateMachineCleanupTimer(sessionId, stateMachine);
808 }
809 } else {
810 // This statement should not be logged; cleanupTimer should be cancelled for stateMachine
811 // instances which have been authenticated successfully.
812 log.warn("state-machine not found for sessionId: {}", sessionId);
813 }
814
815 }
816 }
Ari Saha89831742015-06-26 10:31:48 -0700817
Ari Saha89831742015-06-26 10:31:48 -0700818}