blob: 8d73e158026dd84986919d120736c0989551725d [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 Sharma4900ce62019-06-19 14:18:50 +000020import com.google.common.collect.Maps;
Ari Saha89831742015-06-26 10:31:48 -070021import org.onlab.packet.MacAddress;
22import org.onosproject.net.ConnectPoint;
Matteo Scandolocf847b82019-04-26 15:00:00 -070023import org.opencord.aaa.AuthenticationEvent;
24import 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;
28import java.util.Map;
29import java.util.Set;
30
31import static org.slf4j.LoggerFactory.getLogger;
Ari Saha89831742015-06-26 10:31:48 -070032
33/**
34 * AAA Finite State Machine.
35 */
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
46 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet();
47 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
Shubham Sharma4900ce62019-06-19 14:18:50 +000058 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
123 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700124
Shubham Sharma1e43c562019-06-19 14:18:12 +0000125 // TimeStamp of last EAPOL or RADIUS message received.
126 private long lastPacketReceivedTime = 0;
127
128 // State transition table
Ari Saha89831742015-06-26 10:31:48 -0700129 /*
Shubham Sharma1e43c562019-06-19 14:18:12 +0000130 *
131 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
132 * -----------------------------------------------------------------------------
133 * -----------------------
134 *
135 * START STARTED | _ | _ | STARTED | STARTED
136 *
137 * REQUEST_ACCESS _ | PENDING | _ | _ | _
138 *
139 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
140 *
141 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
142 *
143 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700144 */
145
Shubham Sharma1e43c562019-06-19 14:18:12 +0000146 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
147 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
148 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
149 STATE_PENDING };
150 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
151 STATE_IDLE };
152 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
153 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700154
Shubham Sharma1e43c562019-06-19 14:18:12 +0000155 // THE TRANSITION TABLE
156 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
157 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700158
159 private int currentState = STATE_IDLE;
160
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700161 // Maps of state machines. Each state machine is represented by an
162 // unique identifier on the switch: dpid + port number
163 private static Map<String, StateMachine> sessionIdMap;
164 private static Map<Integer, StateMachine> identifierMap;
Ari Saha89831742015-06-26 10:31:48 -0700165
Jonathan Hart5db44532018-07-12 18:13:54 -0700166 private static StateMachineDelegate delegate;
167
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700168 public static void initializeMaps() {
169 sessionIdMap = Maps.newConcurrentMap();
170 identifierMap = Maps.newConcurrentMap();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000171 identifier = 1;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700172 }
173
174 public static void destroyMaps() {
175 sessionIdMap = null;
176 identifierMap = null;
177 }
178
Matteo Scandolocf847b82019-04-26 15:00:00 -0700179 public static void setDelegate(StateMachineDelegate delegate) {
180 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700181 }
182
Shubham Sharma1e43c562019-06-19 14:18:12 +0000183 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
184 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
185 }
186
Jonathan Hart5db44532018-07-12 18:13:54 -0700187 public static void unsetDelegate(StateMachineDelegate delegate) {
188 if (StateMachine.delegate == delegate) {
189 StateMachine.delegate = null;
190 }
191 }
192
Qianqian Hu61a6a402016-02-16 15:18:05 +0800193 public static Map<String, StateMachine> sessionIdMap() {
194 return sessionIdMap;
195 }
196
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700197 public static StateMachine lookupStateMachineById(byte identifier) {
198 return identifierMap.get((int) identifier);
199 }
200
201 public static StateMachine lookupStateMachineBySessionId(String sessionId) {
202 return sessionIdMap.get(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100203 }
204
Shubham Sharma1e43c562019-06-19 14:18:12 +0000205 public static void deleteStateMachineId(String sessionId) {
206 sessionIdMap.remove(sessionId);
207 }
208
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100209 public static void deleteStateMachineMapping(StateMachine machine) {
210 identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
Shubham Sharma1e43c562019-06-19 14:18:12 +0000211 if (machine.cleanupTimer != null) {
212 machine.cleanupTimer.cancel(false);
213 machine.cleanupTimer = null;
214 }
215 }
216
217 public java.util.concurrent.ScheduledFuture<?> getCleanupTimer() {
218 return cleanupTimer;
219 }
220
221 public boolean isWaitingForRadiusResponse() {
222 return waitingForRadiusResponse;
223 }
224
225 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
226 this.waitingForRadiusResponse = waitingForRadiusResponse;
227 }
228
229 public void setCleanupTimer(java.util.concurrent.ScheduledFuture<?> cleanupTimer) {
230 this.cleanupTimer = cleanupTimer;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100231 }
232
233 /**
David K. Bainbridge62019492017-07-28 17:02:10 -0700234 * Deletes authentication state machine records for a given MAC address.
Shubham Sharma1e43c562019-06-19 14:18:12 +0000235 *
David K. Bainbridge62019492017-07-28 17:02:10 -0700236 * @param mac mac address of the suppliant who's state machine should be removed
237 */
238 public static void deleteByMac(MacAddress mac) {
239
240 // Walk the map from session IDs to state machines looking for a MAC match
241 for (Map.Entry<String, StateMachine> e : sessionIdMap.entrySet()) {
242
243 // If a MAC match is found then delete the entry from the session ID
244 // and identifier map as well as call delete identifier to clean up
245 // the identifier bit set.
Shubham Sharma1e43c562019-06-19 14:18:12 +0000246 if (e.getValue() != null && e.getValue().supplicantAddress != null
247 && e.getValue().supplicantAddress.equals(mac)) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700248 sessionIdMap.remove(e.getValue().sessionId);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000249 if (e.getValue().identifier != 1) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700250 deleteStateMachineMapping(e.getValue());
251 }
252 break;
253 }
254 }
255 }
256
257 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700258 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700259 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000260 * @param sessionId session Id represented by the switch dpid + port number
Ari Saha89831742015-06-26 10:31:48 -0700261 */
Jonathan Hart932bedc2018-07-12 13:46:09 -0700262 public StateMachine(String sessionId) {
263 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700264 this.sessionId = sessionId;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700265 sessionIdMap.put(sessionId, this);
Ari Saha89831742015-06-26 10:31:48 -0700266 }
267
268 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700269 * Gets the connect point for the supplicant side.
270 *
271 * @return supplicant connect point
272 */
273 public ConnectPoint supplicantConnectpoint() {
274 return supplicantConnectpoint;
275 }
276
277 /**
278 * Sets the supplicant side connect point.
279 *
280 * @param supplicantConnectpoint supplicant select point.
281 */
282 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
283 this.supplicantConnectpoint = supplicantConnectpoint;
284 }
285
286 /**
287 * Gets the MAC address of the supplicant.
288 *
289 * @return supplicant MAC address
290 */
291 public MacAddress supplicantAddress() {
292 return supplicantAddress;
293 }
294
295 /**
296 * Sets the supplicant MAC address.
297 *
298 * @param supplicantAddress new supplicant MAC address
299 */
300 public void setSupplicantAddress(MacAddress supplicantAddress) {
301 this.supplicantAddress = supplicantAddress;
302 }
303
304 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000305 * Sets the lastPacketReceivedTime.
306 *
307 * @param lastPacketReceivedTime timelastPacket was received
308 */
309 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
310 this.lastPacketReceivedTime = lastPacketReceivedTime;
311 }
312
313 /**
314 * Gets the lastPacketReceivedTime.
315 *
316 * @return lastPacketReceivedTime
317 */
318 public long getLastPacketReceivedTime() {
319 return lastPacketReceivedTime;
320 }
321
322 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700323 * Gets the client's Vlan ID.
324 *
325 * @return client vlan ID
326 */
327 public short vlanId() {
328 return vlanId;
329 }
330
331 /**
332 * Sets the client's vlan ID.
333 *
334 * @param vlanId new client vlan ID
335 */
336 public void setVlanId(short vlanId) {
337 this.vlanId = vlanId;
338 }
339
340 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100341 * Gets the client's priority Code.
342 *
343 * @return client Priority code
344 */
345 public byte priorityCode() {
346 return priorityCode;
347 }
348
349 /**
350 * Sets the client's priority Code.
351 *
352 * @param priorityCode new client priority Code
353 */
354 public void setPriorityCode(byte priorityCode) {
355 this.priorityCode = priorityCode;
356 }
357
358 /**
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000359 * Gets the session start time.
360 *
361 * @return session start time
362 */
363 public long sessionStartTime() {
364 return sessionStartTime;
365 }
366
367 /**
368 * Sets the session start time.
369 *
370 * @param sessionStartTime new session start time
371 */
372 public void setSessionStartTime(long sessionStartTime) {
373 this.sessionStartTime = sessionStartTime;
374 }
375
376 /**
377 * returns eapol Type.
378 *
379 * @return eapolTypeVal.
380 */
381 public String eapolType() {
382 return this.eapolTypeVal;
383 }
384
385 /**
386 * Sets eapol Type name from eapol value.
387 *
388 * @param value eapol type as byte.
389 */
390 public void setEapolTypeVal(byte value) {
391 switch (value) {
392 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
393 break;
394 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
395 break;
396 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
397 break;
398 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
399 break;
400 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
401 break;
402 default : this.eapolTypeVal = "INVALID TYPE";
403 }
404 }
405
406 public String getSessionTerminateReason() {
407 return sessionTerminateReason;
408 }
409
410 public void setSessionTerminateReason(String sessionTerminateReason) {
411 this.sessionTerminateReason = sessionTerminateReason;
412 }
413
414 public int totalPacketsReceived() {
415 return this.totalPacketsReceived;
416 }
417
418 public void incrementTotalPacketsReceived() {
419 this.totalPacketsReceived = this.totalPacketsReceived + 1;
420 }
421
422 public int totalPacketsSent() {
423 return this.totalPacketsSent;
424 }
425
426 public void incrementTotalPacketsSent() {
427 this.totalPacketsSent = this.totalPacketsSent + 1;
428 }
429
430 public void incrementTotalOctetReceived(short packetLen) {
431 this.totalOctetReceived = this.totalOctetReceived + packetLen;
432 }
433
434 public void incrementTotalOctetSent(short packetLen) {
435 this.totalOctetSent = this.totalOctetSent + packetLen;
436 }
437
438 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700439 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700440 *
Ari Saha89831742015-06-26 10:31:48 -0700441 * @return The client id.
442 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700443 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700444 return this.sessionId;
445 }
446
447 /**
Ari Saha89831742015-06-26 10:31:48 -0700448 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700449 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000450 * @param challengeIdentifier The challenge identifier set into the EAP packet
451 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700452 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700453 */
454 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
455 this.challengeIdentifier = challengeIdentifier;
456 this.challengeState = challengeState;
457 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700458
Ari Saha89831742015-06-26 10:31:48 -0700459 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000460 * Set the challenge identifier issued by the RADIUS on the access challenge
461 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700462 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000463 * @param challengeIdentifier The challenge identifier set into the EAP packet
464 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700465 */
466 protected void setChallengeIdentifier(byte challengeIdentifier) {
467 log.info("Set Challenge Identifier to {}", challengeIdentifier);
468 this.challengeIdentifier = challengeIdentifier;
469 }
470
471 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700472 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700473 *
Ari Saha89831742015-06-26 10:31:48 -0700474 * @return The challenge EAP identifier.
475 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700476 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700477 return this.challengeIdentifier;
478 }
479
Ari Saha89831742015-06-26 10:31:48 -0700480 /**
481 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700482 *
Ari Saha89831742015-06-26 10:31:48 -0700483 * @param challengeState The challenge state from the RADIUS.
484 */
485 protected void setChallengeState(byte[] challengeState) {
486 log.info("Set Challenge State");
487 this.challengeState = challengeState;
488 }
489
490 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700491 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700492 *
Ari Saha89831742015-06-26 10:31:48 -0700493 * @return The challenge state.
494 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700495 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700496 return this.challengeState;
497 }
498
499 /**
500 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700501 *
Ari Saha89831742015-06-26 10:31:48 -0700502 * @param username The username sent to the RADIUS upon access request.
503 */
504 protected void setUsername(byte[] username) {
505 this.username = username;
506 }
507
Ari Saha89831742015-06-26 10:31:48 -0700508 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700509 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700510 *
Ari Saha89831742015-06-26 10:31:48 -0700511 * @return The requestAuthenticator.
512 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700513 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700514 return this.requestAuthenticator;
515 }
516
517 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700518 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700519 *
Ari Saha89831742015-06-26 10:31:48 -0700520 * @param authenticator The username sent to the RADIUS upon access request.
521 */
522 protected void setRequestAuthenticator(byte[] authenticator) {
523 this.requestAuthenticator = authenticator;
524 }
525
Ari Saha89831742015-06-26 10:31:48 -0700526 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700527 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700528 *
Ari Saha89831742015-06-26 10:31:48 -0700529 * @return The username.
530 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700531 public byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700532 return this.username;
533 }
534
535 /**
536 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700537 *
Ari Saha89831742015-06-26 10:31:48 -0700538 * @return The state machine identifier.
539 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100540 public synchronized byte identifier() {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000541 //identifier 0 is for statusServerrequest
542 //identifier 1 is for fake accessRequest
543 identifier = (identifier + 1) % 253;
544 identifierMap.put((identifier + 2), this);
545 return (byte) (identifier + 2);
Ari Saha89831742015-06-26 10:31:48 -0700546 }
547
Ari Saha89831742015-06-26 10:31:48 -0700548 /**
549 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700550 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700551 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700552 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700553 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700554 currentState = transition[currentState][msg];
555 log.info("Current State " + currentState);
556 }
557
558 /**
559 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700560 *
561 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700562 */
563 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700564 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700565
Shubham Sharma1e43c562019-06-19 14:18:12 +0000566 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700567
Shubham Sharma1e43c562019-06-19 14:18:12 +0000568 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700569 next(TRANSITION_START);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100570 identifier = this.identifier();
Ari Saha89831742015-06-26 10:31:48 -0700571 }
572
573 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000574 * An Identification information has been sent by the supplicant. Move to the
575 * next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700576 *
577 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700578 */
579 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700580 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700581
Shubham Sharma1e43c562019-06-19 14:18:12 +0000582 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700583
Shubham Sharma1e43c562019-06-19 14:18:12 +0000584 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700585 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700586 }
587
588 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000589 * RADIUS has accepted the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700590 *
591 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700592 */
593 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700594 states[currentState].radiusAccepted();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000595 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700596 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700597
Shubham Sharma1e43c562019-06-19 14:18:12 +0000598 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700599
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100600 // Clear mapping
601 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700602 }
603
604 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000605 * RADIUS has denied the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700606 *
607 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700608 */
609 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700610 states[currentState].radiusDenied();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000611 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700612 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700613
Shubham Sharma1e43c562019-06-19 14:18:12 +0000614 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700615
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100616 // Clear mappings
617 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700618 }
619
620 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000621 * Logoff request has been requested. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700622 *
623 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700624 */
625 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700626 states[currentState].logoff();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000627 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700628 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700629 }
630
631 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700632 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700633 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000634 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
635 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700636 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700637 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700638 return currentState;
639 }
640
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700641 @Override
Ari Saha89831742015-06-26 10:31:48 -0700642 public String toString() {
Shubham Sharma1e43c562019-06-19 14:18:12 +0000643 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t"
644 + ("state: " + this.currentState);
Ari Saha89831742015-06-26 10:31:48 -0700645 }
Ari Saha89831742015-06-26 10:31:48 -0700646
Ray Milkey78e95a42015-09-24 08:36:45 -0700647 abstract class State {
648 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700649
Ray Milkey78e95a42015-09-24 08:36:45 -0700650 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700651
Ray Milkey78e95a42015-09-24 08:36:45 -0700652 public void start() throws StateMachineInvalidTransitionException {
653 log.warn("START transition from this state is not allowed.");
654 }
Ari Saha89831742015-06-26 10:31:48 -0700655
Ray Milkey78e95a42015-09-24 08:36:45 -0700656 public void requestAccess() throws StateMachineInvalidTransitionException {
657 log.warn("REQUEST ACCESS transition from this state is not allowed.");
658 }
659
660 public void radiusAccepted() throws StateMachineInvalidTransitionException {
661 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
662 }
663
664 public void radiusDenied() throws StateMachineInvalidTransitionException {
665 log.warn("DENY ACCESS transition from this state is not allowed.");
666 }
667
668 public void logoff() throws StateMachineInvalidTransitionException {
669 log.warn("LOGOFF transition from this state is not allowed.");
670 }
Ari Saha89831742015-06-26 10:31:48 -0700671 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700672
Ray Milkey78e95a42015-09-24 08:36:45 -0700673 /**
674 * Idle state: supplicant is logged of from the network.
675 */
676 class Idle extends State {
677 private final Logger log = getLogger(getClass());
678 private String name = "IDLE_STATE";
679
Shubham Sharma1e43c562019-06-19 14:18:12 +0000680 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700681 public void start() {
682 log.info("Moving from IDLE state to STARTED state.");
683 }
Ari Saha89831742015-06-26 10:31:48 -0700684 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700685
Ray Milkey78e95a42015-09-24 08:36:45 -0700686 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000687 * Started state: supplicant has entered the network and informed the
688 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700689 */
690 class Started extends State {
691 private final Logger log = getLogger(getClass());
692 private String name = "STARTED_STATE";
693
Shubham Sharma1e43c562019-06-19 14:18:12 +0000694 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700695 public void requestAccess() {
696 log.info("Moving from STARTED state to PENDING state.");
697 }
Ari Saha89831742015-06-26 10:31:48 -0700698 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700699
Ray Milkey78e95a42015-09-24 08:36:45 -0700700 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000701 * Pending state: supplicant has been identified by the authenticator but has
702 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700703 */
704 class Pending extends State {
705 private final Logger log = getLogger(getClass());
706 private String name = "PENDING_STATE";
707
Shubham Sharma1e43c562019-06-19 14:18:12 +0000708 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700709 public void radiusAccepted() {
710 log.info("Moving from PENDING state to AUTHORIZED state.");
711 }
712
Shubham Sharma1e43c562019-06-19 14:18:12 +0000713 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700714 public void radiusDenied() {
715 log.info("Moving from PENDING state to UNAUTHORIZED state.");
716 }
Ari Saha89831742015-06-26 10:31:48 -0700717 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700718
Ray Milkey78e95a42015-09-24 08:36:45 -0700719 /**
720 * Authorized state: supplicant port has been accepted, access is granted.
721 */
722 class Authorized extends State {
723 private final Logger log = getLogger(getClass());
724 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700725
Shubham Sharma1e43c562019-06-19 14:18:12 +0000726 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800727 public void start() {
728 log.info("Moving from AUTHORIZED state to STARTED state.");
729 }
730
Shubham Sharma1e43c562019-06-19 14:18:12 +0000731 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700732 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700733
Ray Milkey78e95a42015-09-24 08:36:45 -0700734 log.info("Moving from AUTHORIZED state to IDLE state.");
735 }
Ari Saha89831742015-06-26 10:31:48 -0700736 }
737
Ray Milkey78e95a42015-09-24 08:36:45 -0700738 /**
739 * Unauthorized state: supplicant port has been rejected, access is denied.
740 */
741 class Unauthorized extends State {
742 private final Logger log = getLogger(getClass());
743 private String name = "UNAUTHORIZED_STATE";
744
Shubham Sharma1e43c562019-06-19 14:18:12 +0000745 @Override
ke han04e47f32016-10-28 14:15:43 +0800746 public void start() {
747 log.info("Moving from UNAUTHORIZED state to STARTED state.");
748 }
749
Shubham Sharma1e43c562019-06-19 14:18:12 +0000750 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700751 public void logoff() {
752 log.info("Moving from UNAUTHORIZED state to IDLE state.");
753 }
Ari Saha89831742015-06-26 10:31:48 -0700754 }
Ari Saha89831742015-06-26 10:31:48 -0700755
Shubham Sharma1e43c562019-06-19 14:18:12 +0000756 /**
757 * Class for cleaning the StateMachine for those session for which no response
758 * is coming--implementing timeout.
759 */
760 class CleanupTimerTask implements Runnable {
761 private final Logger log = getLogger(getClass());
762 private String sessionId;
763 private AaaManager aaaManager;
764
765 CleanupTimerTask(String sessionId, AaaManager aaaManager) {
766 this.sessionId = sessionId;
767 this.aaaManager = aaaManager;
768 }
769
770 @Override
771 public void run() {
772 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
773 if (null != stateMachine) {
774 // Asserting if last packet received for this stateMachine session was beyond half of timeout period.
775 // StateMachine is considered eligible for cleanup when no packets has been exchanged by it with AAA
776 // Server or RG during a long period (half of timeout period). For example, when cleanup timer has
777 // been configured as 10 minutes, StateMachine would be cleaned up at the end of 10 minutes if
778 // the authentication is still pending and no packet was exchanged for this session during last 5
779 // minutes.
780
781 boolean noTrafficWithinThreshold = (System.currentTimeMillis()
782 - stateMachine.getLastPacketReceivedTime()) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
783
784 if ((TIMEOUT_ELIGIBLE_STATES.contains(stateMachine.state())) && noTrafficWithinThreshold) {
785 log.info("Deleting StateMachineMapping for sessionId: {}", sessionId);
786 cleanupTimer = null;
787 if (stateMachine.state() == STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
788 aaaManager.aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
789 }
790 deleteStateMachineId(sessionId);
791 deleteStateMachineMapping(stateMachine);
792
793 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
794 } else {
795 aaaManager.scheduleStateMachineCleanupTimer(sessionId, stateMachine);
796 }
797 } else {
798 // This statement should not be logged; cleanupTimer should be cancelled for stateMachine
799 // instances which have been authenticated successfully.
800 log.warn("state-machine not found for sessionId: {}", sessionId);
801 }
802
803 }
804 }
Ari Saha89831742015-06-26 10:31:48 -0700805
Ari Saha89831742015-06-26 10:31:48 -0700806}