blob: 16543df5beb6cf40390d60280ab2bd43b84da63a [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"),
92 PORT_REMOVED("PORT_REMOVED");
93
94 private final String reason;
95
96 private SessionTerminationReasons(String value) {
97 this.reason = value;
98 }
99
100 public String getReason() {
101 return this.reason;
102 }
103 };
104
105 // Supplicant packet count
106 private int totalPacketsSent;
107 private int totalPacketsReceived;
108 private int totalOctetSent;
109 private int totalOctetReceived;
Ari Saha89831742015-06-26 10:31:48 -0700110
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000111 // Boolean flag indicating whether response is pending from AAA Server.
112 // Used for counting timeout happening for AAA Sessions due to no response.
113 private boolean waitingForRadiusResponse;
114
115 private static int cleanupTimerTimeOutInMins;
116
Ari Saha89831742015-06-26 10:31:48 -0700117 private String sessionId = null;
118
119 private final Logger log = getLogger(getClass());
120
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000121 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -0700122
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000123 // Cleanup Timer instance created for this session
124 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700125
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000126 // TimeStamp of last EAPOL or RADIUS message received.
127 private long lastPacketReceivedTime = 0;
128
129 // State transition table
Ari Saha89831742015-06-26 10:31:48 -0700130 /*
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000131 *
132 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
133 * -----------------------------------------------------------------------------
134 * -----------------------
135 *
136 * START STARTED | _ | _ | STARTED | STARTED
137 *
138 * REQUEST_ACCESS _ | PENDING | _ | _ | _
139 *
140 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
141 *
142 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
143 *
144 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700145 */
146
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000147 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
148 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
149 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
150 STATE_PENDING };
151 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
152 STATE_IDLE };
153 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
154 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700155
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000156 // THE TRANSITION TABLE
157 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
158 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700159
160 private int currentState = STATE_IDLE;
161
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700162 // Maps of state machines. Each state machine is represented by an
163 // unique identifier on the switch: dpid + port number
164 private static Map<String, StateMachine> sessionIdMap;
165 private static Map<Integer, StateMachine> identifierMap;
Ari Saha89831742015-06-26 10:31:48 -0700166
Jonathan Hart5db44532018-07-12 18:13:54 -0700167 private static StateMachineDelegate delegate;
168
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700169 public static void initializeMaps() {
170 sessionIdMap = Maps.newConcurrentMap();
171 identifierMap = Maps.newConcurrentMap();
Shubham Sharma048cc262019-06-19 14:18:50 +0000172 identifier = 1;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700173 }
174
175 public static void destroyMaps() {
176 sessionIdMap = null;
177 identifierMap = null;
178 }
179
Matteo Scandolocf847b82019-04-26 15:00:00 -0700180 public static void setDelegate(StateMachineDelegate delegate) {
181 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700182 }
183
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000184 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
185 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
186 }
187
Jonathan Hart5db44532018-07-12 18:13:54 -0700188 public static void unsetDelegate(StateMachineDelegate delegate) {
189 if (StateMachine.delegate == delegate) {
190 StateMachine.delegate = null;
191 }
192 }
193
Qianqian Hu61a6a402016-02-16 15:18:05 +0800194 public static Map<String, StateMachine> sessionIdMap() {
195 return sessionIdMap;
196 }
197
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700198 public static StateMachine lookupStateMachineById(byte identifier) {
199 return identifierMap.get((int) identifier);
200 }
201
202 public static StateMachine lookupStateMachineBySessionId(String sessionId) {
203 return sessionIdMap.get(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100204 }
205
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000206 public static void deleteStateMachineId(String sessionId) {
207 sessionIdMap.remove(sessionId);
208 }
209
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100210 public static void deleteStateMachineMapping(StateMachine machine) {
211 identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000212 if (machine.cleanupTimer != null) {
213 machine.cleanupTimer.cancel(false);
214 machine.cleanupTimer = null;
215 }
216 }
217
218 public java.util.concurrent.ScheduledFuture<?> getCleanupTimer() {
219 return cleanupTimer;
220 }
221
222 public boolean isWaitingForRadiusResponse() {
223 return waitingForRadiusResponse;
224 }
225
226 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
227 this.waitingForRadiusResponse = waitingForRadiusResponse;
228 }
229
230 public void setCleanupTimer(java.util.concurrent.ScheduledFuture<?> cleanupTimer) {
231 this.cleanupTimer = cleanupTimer;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100232 }
233
234 /**
David K. Bainbridge62019492017-07-28 17:02:10 -0700235 * Deletes authentication state machine records for a given MAC address.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000236 *
David K. Bainbridge62019492017-07-28 17:02:10 -0700237 * @param mac mac address of the suppliant who's state machine should be removed
238 */
239 public static void deleteByMac(MacAddress mac) {
240
241 // Walk the map from session IDs to state machines looking for a MAC match
242 for (Map.Entry<String, StateMachine> e : sessionIdMap.entrySet()) {
243
244 // If a MAC match is found then delete the entry from the session ID
245 // and identifier map as well as call delete identifier to clean up
246 // the identifier bit set.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000247 if (e.getValue() != null && e.getValue().supplicantAddress != null
248 && e.getValue().supplicantAddress.equals(mac)) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700249 sessionIdMap.remove(e.getValue().sessionId);
Shubham Sharma048cc262019-06-19 14:18:50 +0000250 if (e.getValue().identifier != 1) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700251 deleteStateMachineMapping(e.getValue());
252 }
253 break;
254 }
255 }
256 }
257
258 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700259 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700260 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000261 * @param sessionId session Id represented by the switch dpid + port number
Ari Saha89831742015-06-26 10:31:48 -0700262 */
Jonathan Hart932bedc2018-07-12 13:46:09 -0700263 public StateMachine(String sessionId) {
264 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700265 this.sessionId = sessionId;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700266 sessionIdMap.put(sessionId, this);
Ari Saha89831742015-06-26 10:31:48 -0700267 }
268
269 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700270 * Gets the connect point for the supplicant side.
271 *
272 * @return supplicant connect point
273 */
274 public ConnectPoint supplicantConnectpoint() {
275 return supplicantConnectpoint;
276 }
277
278 /**
279 * Sets the supplicant side connect point.
280 *
281 * @param supplicantConnectpoint supplicant select point.
282 */
283 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
284 this.supplicantConnectpoint = supplicantConnectpoint;
285 }
286
287 /**
288 * Gets the MAC address of the supplicant.
289 *
290 * @return supplicant MAC address
291 */
292 public MacAddress supplicantAddress() {
293 return supplicantAddress;
294 }
295
296 /**
297 * Sets the supplicant MAC address.
298 *
299 * @param supplicantAddress new supplicant MAC address
300 */
301 public void setSupplicantAddress(MacAddress supplicantAddress) {
302 this.supplicantAddress = supplicantAddress;
303 }
304
305 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000306 * Sets the lastPacketReceivedTime.
307 *
308 * @param lastPacketReceivedTime timelastPacket was received
309 */
310 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
311 this.lastPacketReceivedTime = lastPacketReceivedTime;
312 }
313
314 /**
315 * Gets the lastPacketReceivedTime.
316 *
317 * @return lastPacketReceivedTime
318 */
319 public long getLastPacketReceivedTime() {
320 return lastPacketReceivedTime;
321 }
322
323 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700324 * Gets the client's Vlan ID.
325 *
326 * @return client vlan ID
327 */
328 public short vlanId() {
329 return vlanId;
330 }
331
332 /**
333 * Sets the client's vlan ID.
334 *
335 * @param vlanId new client vlan ID
336 */
337 public void setVlanId(short vlanId) {
338 this.vlanId = vlanId;
339 }
340
341 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100342 * Gets the client's priority Code.
343 *
344 * @return client Priority code
345 */
346 public byte priorityCode() {
347 return priorityCode;
348 }
349
350 /**
351 * Sets the client's priority Code.
352 *
353 * @param priorityCode new client priority Code
354 */
355 public void setPriorityCode(byte priorityCode) {
356 this.priorityCode = priorityCode;
357 }
358
359 /**
Kartikey Dubeybe14f472019-10-01 12:18:35 +0000360 * Gets the session start time.
361 *
362 * @return session start time
363 */
364 public long sessionStartTime() {
365 return sessionStartTime;
366 }
367
368 /**
369 * Sets the session start time.
370 *
371 * @param sessionStartTime new session start time
372 */
373 public void setSessionStartTime(long sessionStartTime) {
374 this.sessionStartTime = sessionStartTime;
375 }
376
377 /**
378 * returns eapol Type.
379 *
380 * @return eapolTypeVal.
381 */
382 public String eapolType() {
383 return this.eapolTypeVal;
384 }
385
386 /**
387 * Sets eapol Type name from eapol value.
388 *
389 * @param value eapol type as byte.
390 */
391 public void setEapolTypeVal(byte value) {
392 switch (value) {
393 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
394 break;
395 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
396 break;
397 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
398 break;
399 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
400 break;
401 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
402 break;
403 default : this.eapolTypeVal = "INVALID TYPE";
404 }
405 }
406
407 public String getSessionTerminateReason() {
408 return sessionTerminateReason;
409 }
410
411 public void setSessionTerminateReason(String sessionTerminateReason) {
412 this.sessionTerminateReason = sessionTerminateReason;
413 }
414
415 public int totalPacketsReceived() {
416 return this.totalPacketsReceived;
417 }
418
419 public void incrementTotalPacketsReceived() {
420 this.totalPacketsReceived = this.totalPacketsReceived + 1;
421 }
422
423 public int totalPacketsSent() {
424 return this.totalPacketsSent;
425 }
426
427 public void incrementTotalPacketsSent() {
428 this.totalPacketsSent = this.totalPacketsSent + 1;
429 }
430
431 public void incrementTotalOctetReceived(short packetLen) {
432 this.totalOctetReceived = this.totalOctetReceived + packetLen;
433 }
434
435 public void incrementTotalOctetSent(short packetLen) {
436 this.totalOctetSent = this.totalOctetSent + packetLen;
437 }
438
439 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700440 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700441 *
Ari Saha89831742015-06-26 10:31:48 -0700442 * @return The client id.
443 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700444 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700445 return this.sessionId;
446 }
447
448 /**
Ari Saha89831742015-06-26 10:31:48 -0700449 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700450 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000451 * @param challengeIdentifier The challenge identifier set into the EAP packet
452 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700453 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700454 */
455 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
456 this.challengeIdentifier = challengeIdentifier;
457 this.challengeState = challengeState;
458 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700459
Ari Saha89831742015-06-26 10:31:48 -0700460 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000461 * Set the challenge identifier issued by the RADIUS on the access challenge
462 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700463 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000464 * @param challengeIdentifier The challenge identifier set into the EAP packet
465 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700466 */
467 protected void setChallengeIdentifier(byte challengeIdentifier) {
468 log.info("Set Challenge Identifier to {}", challengeIdentifier);
469 this.challengeIdentifier = challengeIdentifier;
470 }
471
472 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700473 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700474 *
Ari Saha89831742015-06-26 10:31:48 -0700475 * @return The challenge EAP identifier.
476 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700477 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700478 return this.challengeIdentifier;
479 }
480
Ari Saha89831742015-06-26 10:31:48 -0700481 /**
482 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700483 *
Ari Saha89831742015-06-26 10:31:48 -0700484 * @param challengeState The challenge state from the RADIUS.
485 */
486 protected void setChallengeState(byte[] challengeState) {
487 log.info("Set Challenge State");
488 this.challengeState = challengeState;
489 }
490
491 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700492 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700493 *
Ari Saha89831742015-06-26 10:31:48 -0700494 * @return The challenge state.
495 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700496 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700497 return this.challengeState;
498 }
499
500 /**
501 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700502 *
Ari Saha89831742015-06-26 10:31:48 -0700503 * @param username The username sent to the RADIUS upon access request.
504 */
505 protected void setUsername(byte[] username) {
506 this.username = username;
507 }
508
Ari Saha89831742015-06-26 10:31:48 -0700509 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700510 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700511 *
Ari Saha89831742015-06-26 10:31:48 -0700512 * @return The requestAuthenticator.
513 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700514 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700515 return this.requestAuthenticator;
516 }
517
518 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700519 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700520 *
Ari Saha89831742015-06-26 10:31:48 -0700521 * @param authenticator The username sent to the RADIUS upon access request.
522 */
523 protected void setRequestAuthenticator(byte[] authenticator) {
524 this.requestAuthenticator = authenticator;
525 }
526
Ari Saha89831742015-06-26 10:31:48 -0700527 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700528 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700529 *
Ari Saha89831742015-06-26 10:31:48 -0700530 * @return The username.
531 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700532 protected byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700533 return this.username;
534 }
535
536 /**
537 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700538 *
Ari Saha89831742015-06-26 10:31:48 -0700539 * @return The state machine identifier.
540 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100541 public synchronized byte identifier() {
Shubham Sharma048cc262019-06-19 14:18:50 +0000542 //identifier 0 is for statusServerrequest
543 //identifier 1 is for fake accessRequest
544 identifier = (identifier + 1) % 253;
545 identifierMap.put((identifier + 2), this);
546 return (byte) (identifier + 2);
Ari Saha89831742015-06-26 10:31:48 -0700547 }
548
Ari Saha89831742015-06-26 10:31:48 -0700549 /**
550 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700551 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700552 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700553 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700554 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700555 currentState = transition[currentState][msg];
556 log.info("Current State " + currentState);
557 }
558
559 /**
560 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700561 *
562 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700563 */
564 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700565 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700566
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000567 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700568
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000569 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700570 next(TRANSITION_START);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100571 identifier = this.identifier();
Ari Saha89831742015-06-26 10:31:48 -0700572 }
573
574 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000575 * An Identification information has been sent by the supplicant. Move to the
576 * next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700577 *
578 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700579 */
580 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700581 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700582
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000583 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700584
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000585 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700586 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700587 }
588
589 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000590 * RADIUS has accepted the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700591 *
592 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700593 */
594 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700595 states[currentState].radiusAccepted();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000596 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700597 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700598
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000599 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700600
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100601 // Clear mapping
602 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700603 }
604
605 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000606 * RADIUS has denied the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700607 *
608 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700609 */
610 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700611 states[currentState].radiusDenied();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000612 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700613 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700614
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000615 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700616
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100617 // Clear mappings
618 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700619 }
620
621 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000622 * Logoff request has been requested. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700623 *
624 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700625 */
626 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700627 states[currentState].logoff();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000628 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700629 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700630 }
631
632 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700633 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700634 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000635 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
636 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700637 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700638 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700639 return currentState;
640 }
641
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700642 @Override
Ari Saha89831742015-06-26 10:31:48 -0700643 public String toString() {
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000644 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t"
645 + ("state: " + this.currentState);
Ari Saha89831742015-06-26 10:31:48 -0700646 }
Ari Saha89831742015-06-26 10:31:48 -0700647
Ray Milkey78e95a42015-09-24 08:36:45 -0700648 abstract class State {
649 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700650
Ray Milkey78e95a42015-09-24 08:36:45 -0700651 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700652
Ray Milkey78e95a42015-09-24 08:36:45 -0700653 public void start() throws StateMachineInvalidTransitionException {
654 log.warn("START transition from this state is not allowed.");
655 }
Ari Saha89831742015-06-26 10:31:48 -0700656
Ray Milkey78e95a42015-09-24 08:36:45 -0700657 public void requestAccess() throws StateMachineInvalidTransitionException {
658 log.warn("REQUEST ACCESS transition from this state is not allowed.");
659 }
660
661 public void radiusAccepted() throws StateMachineInvalidTransitionException {
662 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
663 }
664
665 public void radiusDenied() throws StateMachineInvalidTransitionException {
666 log.warn("DENY ACCESS transition from this state is not allowed.");
667 }
668
669 public void logoff() throws StateMachineInvalidTransitionException {
670 log.warn("LOGOFF transition from this state is not allowed.");
671 }
Ari Saha89831742015-06-26 10:31:48 -0700672 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700673
Ray Milkey78e95a42015-09-24 08:36:45 -0700674 /**
675 * Idle state: supplicant is logged of from the network.
676 */
677 class Idle extends State {
678 private final Logger log = getLogger(getClass());
679 private String name = "IDLE_STATE";
680
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000681 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700682 public void start() {
683 log.info("Moving from IDLE state to STARTED state.");
684 }
Ari Saha89831742015-06-26 10:31:48 -0700685 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700686
Ray Milkey78e95a42015-09-24 08:36:45 -0700687 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000688 * Started state: supplicant has entered the network and informed the
689 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700690 */
691 class Started extends State {
692 private final Logger log = getLogger(getClass());
693 private String name = "STARTED_STATE";
694
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000695 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700696 public void requestAccess() {
697 log.info("Moving from STARTED state to PENDING state.");
698 }
Ari Saha89831742015-06-26 10:31:48 -0700699 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700700
Ray Milkey78e95a42015-09-24 08:36:45 -0700701 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000702 * Pending state: supplicant has been identified by the authenticator but has
703 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700704 */
705 class Pending extends State {
706 private final Logger log = getLogger(getClass());
707 private String name = "PENDING_STATE";
708
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000709 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700710 public void radiusAccepted() {
711 log.info("Moving from PENDING state to AUTHORIZED state.");
712 }
713
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000714 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700715 public void radiusDenied() {
716 log.info("Moving from PENDING state to UNAUTHORIZED state.");
717 }
Ari Saha89831742015-06-26 10:31:48 -0700718 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700719
Ray Milkey78e95a42015-09-24 08:36:45 -0700720 /**
721 * Authorized state: supplicant port has been accepted, access is granted.
722 */
723 class Authorized extends State {
724 private final Logger log = getLogger(getClass());
725 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700726
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000727 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800728 public void start() {
729 log.info("Moving from AUTHORIZED state to STARTED state.");
730 }
731
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000732 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700733 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700734
Ray Milkey78e95a42015-09-24 08:36:45 -0700735 log.info("Moving from AUTHORIZED state to IDLE state.");
736 }
Ari Saha89831742015-06-26 10:31:48 -0700737 }
738
Ray Milkey78e95a42015-09-24 08:36:45 -0700739 /**
740 * Unauthorized state: supplicant port has been rejected, access is denied.
741 */
742 class Unauthorized extends State {
743 private final Logger log = getLogger(getClass());
744 private String name = "UNAUTHORIZED_STATE";
745
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000746 @Override
ke han04e47f32016-10-28 14:15:43 +0800747 public void start() {
748 log.info("Moving from UNAUTHORIZED state to STARTED state.");
749 }
750
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000751 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700752 public void logoff() {
753 log.info("Moving from UNAUTHORIZED state to IDLE state.");
754 }
Ari Saha89831742015-06-26 10:31:48 -0700755 }
Ari Saha89831742015-06-26 10:31:48 -0700756
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000757 /**
758 * Class for cleaning the StateMachine for those session for which no response
759 * is coming--implementing timeout.
760 */
761 class CleanupTimerTask implements Runnable {
762 private final Logger log = getLogger(getClass());
763 private String sessionId;
764 private AaaManager aaaManager;
765
766 CleanupTimerTask(String sessionId, AaaManager aaaManager) {
767 this.sessionId = sessionId;
768 this.aaaManager = aaaManager;
769 }
770
771 @Override
772 public void run() {
773 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
774 if (null != stateMachine) {
775 // Asserting if last packet received for this stateMachine session was beyond half of timeout period.
776 // StateMachine is considered eligible for cleanup when no packets has been exchanged by it with AAA
777 // Server or RG during a long period (half of timeout period). For example, when cleanup timer has
778 // been configured as 10 minutes, StateMachine would be cleaned up at the end of 10 minutes if
779 // the authentication is still pending and no packet was exchanged for this session during last 5
780 // minutes.
781
782 boolean noTrafficWithinThreshold = (System.currentTimeMillis()
783 - stateMachine.getLastPacketReceivedTime()) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
784
785 if ((TIMEOUT_ELIGIBLE_STATES.contains(stateMachine.state())) && noTrafficWithinThreshold) {
786 log.info("Deleting StateMachineMapping for sessionId: {}", sessionId);
787 cleanupTimer = null;
788 if (stateMachine.state() == STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
789 aaaManager.aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
790 }
791 deleteStateMachineId(sessionId);
792 deleteStateMachineMapping(stateMachine);
793
794 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
795 } else {
796 aaaManager.scheduleStateMachineCleanupTimer(sessionId, stateMachine);
797 }
798 } else {
799 // This statement should not be logged; cleanupTimer should be cancelled for stateMachine
800 // instances which have been authenticated successfully.
801 log.warn("state-machine not found for sessionId: {}", sessionId);
802 }
803
804 }
805 }
Ari Saha89831742015-06-26 10:31:48 -0700806
Ari Saha89831742015-06-26 10:31:48 -0700807}