blob: 898433b0a1e73976f968a6f025dddaa2272ee267 [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
20import org.onlab.packet.MacAddress;
21import org.onosproject.net.ConnectPoint;
Matteo Scandolocf847b82019-04-26 15:00:00 -070022import org.opencord.aaa.AuthenticationEvent;
Jonathan Hart9d1ce802020-01-28 10:45:08 -080023import org.opencord.aaa.AuthenticationRecord;
Matteo Scandolocf847b82019-04-26 15:00:00 -070024import org.opencord.aaa.StateMachineDelegate;
Ari Saha89831742015-06-26 10:31:48 -070025import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070026
Shubham Sharma4900ce62019-06-19 14:18:50 +000027import java.util.HashSet;
Shubham Sharma4900ce62019-06-19 14:18:50 +000028import java.util.Set;
Jonathan Hart612651f2019-11-25 09:21:43 -080029import java.util.concurrent.ScheduledExecutorService;
30import java.util.concurrent.TimeUnit;
Shubham Sharma4900ce62019-06-19 14:18:50 +000031
32import static org.slf4j.LoggerFactory.getLogger;
Ari Saha89831742015-06-26 10:31:48 -070033
34/**
35 * AAA Finite State Machine.
36 */
Carmelo Cascone58b53292019-09-30 12:35:31 -070037public class StateMachine {
Ari Saha89831742015-06-26 10:31:48 -070038 //INDEX to identify the state in the transition table
39 static final int STATE_IDLE = 0;
40 static final int STATE_STARTED = 1;
41 static final int STATE_PENDING = 2;
42 static final int STATE_AUTHORIZED = 3;
43 static final int STATE_UNAUTHORIZED = 4;
44
Shubham Sharma1e43c562019-06-19 14:18:12 +000045 // Defining the states where timeout can happen
Jonathan Hart612651f2019-11-25 09:21:43 -080046 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet<>();
Shubham Sharma1e43c562019-06-19 14:18:12 +000047 static {
48 TIMEOUT_ELIGIBLE_STATES.add(STATE_STARTED);
49 TIMEOUT_ELIGIBLE_STATES.add(STATE_PENDING);
50 }
51 // INDEX to identify the transition in the transition table
Ari Saha89831742015-06-26 10:31:48 -070052 static final int TRANSITION_START = 0; // --> started
53 static final int TRANSITION_REQUEST_ACCESS = 1;
54 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
55 static final int TRANSITION_DENY_ACCESS = 3;
56 static final int TRANSITION_LOGOFF = 4;
57
Jonathan Hart612651f2019-11-25 09:21:43 -080058 private static int identifier = -1;
Ari Saha89831742015-06-26 10:31:48 -070059 private byte challengeIdentifier;
60 private byte[] challengeState;
61 private byte[] username;
62 private byte[] requestAuthenticator;
63
64 // Supplicant connectivity info
Ray Milkeyf61a24e2015-09-24 16:34:02 -070065 private ConnectPoint supplicantConnectpoint;
66 private MacAddress supplicantAddress;
67 private short vlanId;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010068 private byte priorityCode;
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +000069 private long sessionStartTime;
70 private String eapolTypeVal;
71
72 public enum EapolType {
73 EAPOL_PACKET("EAPOL_PACKET"),
74 EAPOL_START("EAPOL_START"),
75 EAPOL_LOGOFF("EAPOL_LOGOFF"),
76 EAPOL_KEY("EAPOL_KEY"),
77 EAPOL_ASF("EAPOL_ASF");
78
79 private final String eaptype;
80
81 private EapolType(String value) {
82 this.eaptype = value;
83 }
84 };
85
86 private String sessionTerminateReason;
87
88 public enum SessionTerminationReasons {
89 SUPPLICANT_LOGOFF("SUPPLICANT_LOGOFF"),
90 TIME_OUT("TIME_OUT"),
91 PORT_REMOVED("PORT_REMOVED");
92
93 private final String reason;
94
95 private SessionTerminationReasons(String value) {
96 this.reason = value;
97 }
98
99 public String getReason() {
100 return this.reason;
101 }
102 };
103
104 // Supplicant packet count
105 private int totalPacketsSent;
106 private int totalPacketsReceived;
107 private int totalOctetSent;
108 private int totalOctetReceived;
Ari Saha89831742015-06-26 10:31:48 -0700109
Shubham Sharma1e43c562019-06-19 14:18:12 +0000110 // Boolean flag indicating whether response is pending from AAA Server.
111 // Used for counting timeout happening for AAA Sessions due to no response.
112 private boolean waitingForRadiusResponse;
113
114 private static int cleanupTimerTimeOutInMins;
115
Ari Saha89831742015-06-26 10:31:48 -0700116 private String sessionId = null;
117
118 private final Logger log = getLogger(getClass());
119
Shubham Sharma1e43c562019-06-19 14:18:12 +0000120 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -0700121
Shubham Sharma1e43c562019-06-19 14:18:12 +0000122 // Cleanup Timer instance created for this session
Jonathan Hart612651f2019-11-25 09:21:43 -0800123 private ScheduledExecutorService executor;
Shubham Sharma1e43c562019-06-19 14:18:12 +0000124 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700125
Shubham Sharma1e43c562019-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 Sharma1e43c562019-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 Sharma1e43c562019-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 Sharma1e43c562019-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
Jonathan Hart5db44532018-07-12 18:13:54 -0700162 private static StateMachineDelegate delegate;
163
Matteo Scandolocf847b82019-04-26 15:00:00 -0700164 public static void setDelegate(StateMachineDelegate delegate) {
165 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700166 }
167
Shubham Sharma1e43c562019-06-19 14:18:12 +0000168 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
169 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
170 }
171
Jonathan Hart612651f2019-11-25 09:21:43 -0800172 private void scheduleTimeout() {
173 cleanupTimer = executor.schedule(this::timeout, cleanupTimerTimeOutInMins, TimeUnit.MINUTES);
174 }
175
Jonathan Hart5db44532018-07-12 18:13:54 -0700176 public static void unsetDelegate(StateMachineDelegate delegate) {
177 if (StateMachine.delegate == delegate) {
178 StateMachine.delegate = null;
179 }
180 }
181
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100182 public static void deleteStateMachineMapping(StateMachine machine) {
Shubham Sharma1e43c562019-06-19 14:18:12 +0000183 if (machine.cleanupTimer != null) {
184 machine.cleanupTimer.cancel(false);
185 machine.cleanupTimer = null;
186 }
187 }
188
Jonathan Hart612651f2019-11-25 09:21:43 -0800189 public void stop() {
190 if (cleanupTimer != null) {
191 cleanupTimer.cancel(false);
192 }
Shubham Sharma1e43c562019-06-19 14:18:12 +0000193 }
194
195 public boolean isWaitingForRadiusResponse() {
196 return waitingForRadiusResponse;
197 }
198
199 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
200 this.waitingForRadiusResponse = waitingForRadiusResponse;
201 }
202
David K. Bainbridge62019492017-07-28 17:02:10 -0700203 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700204 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700205 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000206 * @param sessionId session Id represented by the switch dpid + port number
Jonathan Hart612651f2019-11-25 09:21:43 -0800207 * @param executor executor to run background tasks on
Ari Saha89831742015-06-26 10:31:48 -0700208 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800209 public StateMachine(String sessionId, ScheduledExecutorService executor) {
Jonathan Hart932bedc2018-07-12 13:46:09 -0700210 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700211 this.sessionId = sessionId;
Jonathan Hart612651f2019-11-25 09:21:43 -0800212 this.executor = executor;
Ari Saha89831742015-06-26 10:31:48 -0700213 }
214
215 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700216 * Gets the connect point for the supplicant side.
217 *
218 * @return supplicant connect point
219 */
220 public ConnectPoint supplicantConnectpoint() {
221 return supplicantConnectpoint;
222 }
223
224 /**
225 * Sets the supplicant side connect point.
226 *
227 * @param supplicantConnectpoint supplicant select point.
228 */
229 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
230 this.supplicantConnectpoint = supplicantConnectpoint;
231 }
232
233 /**
234 * Gets the MAC address of the supplicant.
235 *
236 * @return supplicant MAC address
237 */
238 public MacAddress supplicantAddress() {
239 return supplicantAddress;
240 }
241
242 /**
243 * Sets the supplicant MAC address.
244 *
245 * @param supplicantAddress new supplicant MAC address
246 */
247 public void setSupplicantAddress(MacAddress supplicantAddress) {
248 this.supplicantAddress = supplicantAddress;
249 }
250
251 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000252 * Sets the lastPacketReceivedTime.
253 *
254 * @param lastPacketReceivedTime timelastPacket was received
255 */
256 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
257 this.lastPacketReceivedTime = lastPacketReceivedTime;
258 }
259
260 /**
261 * Gets the lastPacketReceivedTime.
262 *
263 * @return lastPacketReceivedTime
264 */
265 public long getLastPacketReceivedTime() {
266 return lastPacketReceivedTime;
267 }
268
269 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700270 * Gets the client's Vlan ID.
271 *
272 * @return client vlan ID
273 */
274 public short vlanId() {
275 return vlanId;
276 }
277
278 /**
279 * Sets the client's vlan ID.
280 *
281 * @param vlanId new client vlan ID
282 */
283 public void setVlanId(short vlanId) {
284 this.vlanId = vlanId;
285 }
286
287 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100288 * Gets the client's priority Code.
289 *
290 * @return client Priority code
291 */
292 public byte priorityCode() {
293 return priorityCode;
294 }
295
296 /**
297 * Sets the client's priority Code.
298 *
299 * @param priorityCode new client priority Code
300 */
301 public void setPriorityCode(byte priorityCode) {
302 this.priorityCode = priorityCode;
303 }
304
305 /**
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000306 * Gets the session start time.
307 *
308 * @return session start time
309 */
310 public long sessionStartTime() {
311 return sessionStartTime;
312 }
313
314 /**
315 * Sets the session start time.
316 *
317 * @param sessionStartTime new session start time
318 */
319 public void setSessionStartTime(long sessionStartTime) {
320 this.sessionStartTime = sessionStartTime;
321 }
322
323 /**
324 * returns eapol Type.
325 *
326 * @return eapolTypeVal.
327 */
328 public String eapolType() {
329 return this.eapolTypeVal;
330 }
331
332 /**
333 * Sets eapol Type name from eapol value.
334 *
335 * @param value eapol type as byte.
336 */
337 public void setEapolTypeVal(byte value) {
338 switch (value) {
339 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
340 break;
341 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
342 break;
343 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
344 break;
345 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
346 break;
347 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
348 break;
349 default : this.eapolTypeVal = "INVALID TYPE";
350 }
351 }
352
353 public String getSessionTerminateReason() {
354 return sessionTerminateReason;
355 }
356
357 public void setSessionTerminateReason(String sessionTerminateReason) {
358 this.sessionTerminateReason = sessionTerminateReason;
359 }
360
361 public int totalPacketsReceived() {
362 return this.totalPacketsReceived;
363 }
364
365 public void incrementTotalPacketsReceived() {
366 this.totalPacketsReceived = this.totalPacketsReceived + 1;
367 }
368
369 public int totalPacketsSent() {
370 return this.totalPacketsSent;
371 }
372
373 public void incrementTotalPacketsSent() {
374 this.totalPacketsSent = this.totalPacketsSent + 1;
375 }
376
377 public void incrementTotalOctetReceived(short packetLen) {
378 this.totalOctetReceived = this.totalOctetReceived + packetLen;
379 }
380
381 public void incrementTotalOctetSent(short packetLen) {
382 this.totalOctetSent = this.totalOctetSent + packetLen;
383 }
384
385 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700386 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700387 *
Ari Saha89831742015-06-26 10:31:48 -0700388 * @return The client id.
389 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700390 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700391 return this.sessionId;
392 }
393
394 /**
Ari Saha89831742015-06-26 10:31:48 -0700395 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700396 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000397 * @param challengeIdentifier The challenge identifier set into the EAP packet
398 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700399 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700400 */
401 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
402 this.challengeIdentifier = challengeIdentifier;
403 this.challengeState = challengeState;
404 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700405
Ari Saha89831742015-06-26 10:31:48 -0700406 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000407 * Set the challenge identifier issued by the RADIUS on the access challenge
408 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700409 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000410 * @param challengeIdentifier The challenge identifier set into the EAP packet
411 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700412 */
413 protected void setChallengeIdentifier(byte challengeIdentifier) {
414 log.info("Set Challenge Identifier to {}", challengeIdentifier);
415 this.challengeIdentifier = challengeIdentifier;
416 }
417
418 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700419 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700420 *
Ari Saha89831742015-06-26 10:31:48 -0700421 * @return The challenge EAP identifier.
422 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700423 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700424 return this.challengeIdentifier;
425 }
426
Ari Saha89831742015-06-26 10:31:48 -0700427 /**
428 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700429 *
Ari Saha89831742015-06-26 10:31:48 -0700430 * @param challengeState The challenge state from the RADIUS.
431 */
432 protected void setChallengeState(byte[] challengeState) {
433 log.info("Set Challenge State");
434 this.challengeState = challengeState;
435 }
436
437 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700438 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700439 *
Ari Saha89831742015-06-26 10:31:48 -0700440 * @return The challenge state.
441 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700442 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700443 return this.challengeState;
444 }
445
446 /**
447 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700448 *
Ari Saha89831742015-06-26 10:31:48 -0700449 * @param username The username sent to the RADIUS upon access request.
450 */
451 protected void setUsername(byte[] username) {
452 this.username = username;
453 }
454
Ari Saha89831742015-06-26 10:31:48 -0700455 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700456 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700457 *
Ari Saha89831742015-06-26 10:31:48 -0700458 * @return The requestAuthenticator.
459 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700460 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700461 return this.requestAuthenticator;
462 }
463
464 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700465 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700466 *
Ari Saha89831742015-06-26 10:31:48 -0700467 * @param authenticator The username sent to the RADIUS upon access request.
468 */
469 protected void setRequestAuthenticator(byte[] authenticator) {
470 this.requestAuthenticator = authenticator;
471 }
472
Ari Saha89831742015-06-26 10:31:48 -0700473 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700474 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700475 *
Ari Saha89831742015-06-26 10:31:48 -0700476 * @return The username.
477 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700478 public byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700479 return this.username;
480 }
481
482 /**
483 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700484 *
Ari Saha89831742015-06-26 10:31:48 -0700485 * @return The state machine identifier.
486 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100487 public synchronized byte identifier() {
Jonathan Hart612651f2019-11-25 09:21:43 -0800488 identifier = (identifier + 1) % 255;
489 return (byte) identifier;
Ari Saha89831742015-06-26 10:31:48 -0700490 }
491
Ari Saha89831742015-06-26 10:31:48 -0700492 /**
493 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700494 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700495 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700496 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700497 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700498 currentState = transition[currentState][msg];
499 log.info("Current State " + currentState);
500 }
501
502 /**
503 * Client has requested the start action to allow network access.
504 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800505 public void start() {
506 this.scheduleTimeout();
507
Ray Milkey78e95a42015-09-24 08:36:45 -0700508 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700509
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800510 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED,
511 supplicantConnectpoint, toAuthRecord()));
Jonathan Hart5db44532018-07-12 18:13:54 -0700512
Shubham Sharma1e43c562019-06-19 14:18:12 +0000513 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700514 next(TRANSITION_START);
Ari Saha89831742015-06-26 10:31:48 -0700515 }
516
517 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000518 * An Identification information has been sent by the supplicant. Move to the
519 * next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700520 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800521 public void requestAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700522 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700523
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800524 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED,
525 supplicantConnectpoint, toAuthRecord()));
Jonathan Hart5db44532018-07-12 18:13:54 -0700526
Shubham Sharma1e43c562019-06-19 14:18:12 +0000527 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700528 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700529 }
530
531 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000532 * RADIUS has accepted the identification. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700533 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800534 public void authorizeAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700535 states[currentState].radiusAccepted();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000536 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700537 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700538
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800539 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED,
540 supplicantConnectpoint, toAuthRecord()));
Ari Saha89831742015-06-26 10:31:48 -0700541
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100542 // Clear mapping
543 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700544 }
545
546 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000547 * RADIUS has denied the identification. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700548 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800549 public void denyAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700550 states[currentState].radiusDenied();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000551 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700552 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700553
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800554 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED,
555 supplicantConnectpoint, toAuthRecord()));
Jonathan Hart5db44532018-07-12 18:13:54 -0700556
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100557 // Clear mappings
558 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700559 }
560
561 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000562 * Logoff request has been requested. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700563 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800564 public void logoff() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700565 states[currentState].logoff();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800566
567 // TODO event here?
568
Shubham Sharma1e43c562019-06-19 14:18:12 +0000569 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700570 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700571 }
572
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800573 private AuthenticationRecord toAuthRecord() {
574 return new AuthenticationRecord(this.supplicantConnectpoint(),
575 this.username(), this.supplicantAddress(), this.stateString(),
576 this.getLastPacketReceivedTime());
577 }
578
Ari Saha89831742015-06-26 10:31:48 -0700579 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700580 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700581 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000582 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
583 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700584 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700585 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700586 return currentState;
587 }
588
Jonathan Hart612651f2019-11-25 09:21:43 -0800589 public String stateString() {
590 return states[currentState].name();
Ari Saha89831742015-06-26 10:31:48 -0700591 }
Ari Saha89831742015-06-26 10:31:48 -0700592
Jonathan Hart612651f2019-11-25 09:21:43 -0800593 @Override
594 public String toString() {
595 return ("sessionId: " + this.sessionId) + "\t" + ("state: " + this.currentState);
596 }
597
598 abstract static class State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700599 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700600
Jonathan Hart612651f2019-11-25 09:21:43 -0800601 abstract String name();
Ari Saha89831742015-06-26 10:31:48 -0700602
Jonathan Hart612651f2019-11-25 09:21:43 -0800603 public void start() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700604 log.warn("START transition from this state is not allowed.");
605 }
Ari Saha89831742015-06-26 10:31:48 -0700606
Jonathan Hart612651f2019-11-25 09:21:43 -0800607 public void requestAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700608 log.warn("REQUEST ACCESS transition from this state is not allowed.");
609 }
610
Jonathan Hart612651f2019-11-25 09:21:43 -0800611 public void radiusAccepted() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700612 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
613 }
614
Jonathan Hart612651f2019-11-25 09:21:43 -0800615 public void radiusDenied() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700616 log.warn("DENY ACCESS transition from this state is not allowed.");
617 }
618
Jonathan Hart612651f2019-11-25 09:21:43 -0800619 public void logoff() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700620 log.warn("LOGOFF transition from this state is not allowed.");
621 }
Ari Saha89831742015-06-26 10:31:48 -0700622 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700623
Ray Milkey78e95a42015-09-24 08:36:45 -0700624 /**
Jonathan Hart612651f2019-11-25 09:21:43 -0800625 * Idle state: supplicant is logged off from the network.
Ray Milkey78e95a42015-09-24 08:36:45 -0700626 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800627 static class Idle extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700628 private final Logger log = getLogger(getClass());
629 private String name = "IDLE_STATE";
630
Shubham Sharma1e43c562019-06-19 14:18:12 +0000631 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800632 String name() {
633 return this.name;
634 }
635
636 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700637 public void start() {
638 log.info("Moving from IDLE state to STARTED state.");
639 }
Ari Saha89831742015-06-26 10:31:48 -0700640 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700641
Ray Milkey78e95a42015-09-24 08:36:45 -0700642 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000643 * Started state: supplicant has entered the network and informed the
644 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700645 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800646 static class Started extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700647 private final Logger log = getLogger(getClass());
648 private String name = "STARTED_STATE";
649
Shubham Sharma1e43c562019-06-19 14:18:12 +0000650 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800651 String name() {
652 return this.name;
653 }
654
655 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700656 public void requestAccess() {
657 log.info("Moving from STARTED state to PENDING state.");
658 }
Ari Saha89831742015-06-26 10:31:48 -0700659 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700660
Ray Milkey78e95a42015-09-24 08:36:45 -0700661 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000662 * Pending state: supplicant has been identified by the authenticator but has
663 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700664 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800665 static class Pending extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700666 private final Logger log = getLogger(getClass());
667 private String name = "PENDING_STATE";
668
Shubham Sharma1e43c562019-06-19 14:18:12 +0000669 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800670 String name() {
671 return this.name;
672 }
673
674 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700675 public void radiusAccepted() {
676 log.info("Moving from PENDING state to AUTHORIZED state.");
677 }
678
Shubham Sharma1e43c562019-06-19 14:18:12 +0000679 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700680 public void radiusDenied() {
681 log.info("Moving from PENDING state to UNAUTHORIZED state.");
682 }
Ari Saha89831742015-06-26 10:31:48 -0700683 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700684
Ray Milkey78e95a42015-09-24 08:36:45 -0700685 /**
686 * Authorized state: supplicant port has been accepted, access is granted.
687 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800688 static class Authorized extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700689 private final Logger log = getLogger(getClass());
690 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700691
Shubham Sharma1e43c562019-06-19 14:18:12 +0000692 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800693 String name() {
694 return this.name;
695 }
696
697 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800698 public void start() {
699 log.info("Moving from AUTHORIZED state to STARTED state.");
700 }
701
Shubham Sharma1e43c562019-06-19 14:18:12 +0000702 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700703 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700704
Ray Milkey78e95a42015-09-24 08:36:45 -0700705 log.info("Moving from AUTHORIZED state to IDLE state.");
706 }
Ari Saha89831742015-06-26 10:31:48 -0700707 }
708
Ray Milkey78e95a42015-09-24 08:36:45 -0700709 /**
710 * Unauthorized state: supplicant port has been rejected, access is denied.
711 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800712 static class Unauthorized extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700713 private final Logger log = getLogger(getClass());
714 private String name = "UNAUTHORIZED_STATE";
715
Shubham Sharma1e43c562019-06-19 14:18:12 +0000716 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800717 String name() {
718 return this.name;
719 }
720
721 @Override
ke han04e47f32016-10-28 14:15:43 +0800722 public void start() {
723 log.info("Moving from UNAUTHORIZED state to STARTED state.");
724 }
725
Shubham Sharma1e43c562019-06-19 14:18:12 +0000726 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700727 public void logoff() {
728 log.info("Moving from UNAUTHORIZED state to IDLE state.");
729 }
Ari Saha89831742015-06-26 10:31:48 -0700730 }
Ari Saha89831742015-06-26 10:31:48 -0700731
Jonathan Hart612651f2019-11-25 09:21:43 -0800732 private void timeout() {
733 boolean noTrafficWithinThreshold =
734 (System.currentTimeMillis() - lastPacketReceivedTime) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000735
Jonathan Hart612651f2019-11-25 09:21:43 -0800736 if (TIMEOUT_ELIGIBLE_STATES.contains(currentState) && noTrafficWithinThreshold) {
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800737 this.setSessionTerminateReason(SessionTerminationReasons.TIME_OUT.reason);
738
739 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.TIMEOUT,
740 this.supplicantConnectpoint));
Jonathan Hart612651f2019-11-25 09:21:43 -0800741 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
742 } else {
743 this.scheduleTimeout();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000744 }
745 }
Ari Saha89831742015-06-26 10:31:48 -0700746
Ari Saha89831742015-06-26 10:31:48 -0700747}