blob: 7635d86556f5b9706d69ce823827fb1f34367e3f [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;
Ari Saha89831742015-06-26 10:31:48 -070070
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000071 // Boolean flag indicating whether response is pending from AAA Server.
72 // Used for counting timeout happening for AAA Sessions due to no response.
73 private boolean waitingForRadiusResponse;
74
75 private static int cleanupTimerTimeOutInMins;
76
Ari Saha89831742015-06-26 10:31:48 -070077 private String sessionId = null;
78
79 private final Logger log = getLogger(getClass());
80
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000081 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -070082
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000083 // Cleanup Timer instance created for this session
84 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -070085
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000086 // TimeStamp of last EAPOL or RADIUS message received.
87 private long lastPacketReceivedTime = 0;
88
89 // State transition table
Ari Saha89831742015-06-26 10:31:48 -070090 /*
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +000091 *
92 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
93 * -----------------------------------------------------------------------------
94 * -----------------------
95 *
96 * START STARTED | _ | _ | STARTED | STARTED
97 *
98 * REQUEST_ACCESS _ | PENDING | _ | _ | _
99 *
100 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
101 *
102 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
103 *
104 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700105 */
106
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000107 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
108 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
109 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
110 STATE_PENDING };
111 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
112 STATE_IDLE };
113 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
114 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700115
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000116 // THE TRANSITION TABLE
117 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
118 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700119
120 private int currentState = STATE_IDLE;
121
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700122 // Maps of state machines. Each state machine is represented by an
123 // unique identifier on the switch: dpid + port number
124 private static Map<String, StateMachine> sessionIdMap;
125 private static Map<Integer, StateMachine> identifierMap;
Ari Saha89831742015-06-26 10:31:48 -0700126
Jonathan Hart5db44532018-07-12 18:13:54 -0700127 private static StateMachineDelegate delegate;
128
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700129 public static void initializeMaps() {
130 sessionIdMap = Maps.newConcurrentMap();
131 identifierMap = Maps.newConcurrentMap();
Shubham Sharma048cc262019-06-19 14:18:50 +0000132 identifier = 1;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700133 }
134
135 public static void destroyMaps() {
136 sessionIdMap = null;
137 identifierMap = null;
138 }
139
Matteo Scandolocf847b82019-04-26 15:00:00 -0700140 public static void setDelegate(StateMachineDelegate delegate) {
141 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700142 }
143
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000144 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
145 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
146 }
147
Jonathan Hart5db44532018-07-12 18:13:54 -0700148 public static void unsetDelegate(StateMachineDelegate delegate) {
149 if (StateMachine.delegate == delegate) {
150 StateMachine.delegate = null;
151 }
152 }
153
Qianqian Hu61a6a402016-02-16 15:18:05 +0800154 public static Map<String, StateMachine> sessionIdMap() {
155 return sessionIdMap;
156 }
157
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700158 public static StateMachine lookupStateMachineById(byte identifier) {
159 return identifierMap.get((int) identifier);
160 }
161
162 public static StateMachine lookupStateMachineBySessionId(String sessionId) {
163 return sessionIdMap.get(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100164 }
165
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000166 public static void deleteStateMachineId(String sessionId) {
167 sessionIdMap.remove(sessionId);
168 }
169
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100170 public static void deleteStateMachineMapping(StateMachine machine) {
171 identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000172 if (machine.cleanupTimer != null) {
173 machine.cleanupTimer.cancel(false);
174 machine.cleanupTimer = null;
175 }
176 }
177
178 public java.util.concurrent.ScheduledFuture<?> getCleanupTimer() {
179 return cleanupTimer;
180 }
181
182 public boolean isWaitingForRadiusResponse() {
183 return waitingForRadiusResponse;
184 }
185
186 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
187 this.waitingForRadiusResponse = waitingForRadiusResponse;
188 }
189
190 public void setCleanupTimer(java.util.concurrent.ScheduledFuture<?> cleanupTimer) {
191 this.cleanupTimer = cleanupTimer;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100192 }
193
194 /**
David K. Bainbridge62019492017-07-28 17:02:10 -0700195 * Deletes authentication state machine records for a given MAC address.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000196 *
David K. Bainbridge62019492017-07-28 17:02:10 -0700197 * @param mac mac address of the suppliant who's state machine should be removed
198 */
199 public static void deleteByMac(MacAddress mac) {
200
201 // Walk the map from session IDs to state machines looking for a MAC match
202 for (Map.Entry<String, StateMachine> e : sessionIdMap.entrySet()) {
203
204 // If a MAC match is found then delete the entry from the session ID
205 // and identifier map as well as call delete identifier to clean up
206 // the identifier bit set.
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000207 if (e.getValue() != null && e.getValue().supplicantAddress != null
208 && e.getValue().supplicantAddress.equals(mac)) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700209 sessionIdMap.remove(e.getValue().sessionId);
Shubham Sharma048cc262019-06-19 14:18:50 +0000210 if (e.getValue().identifier != 1) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700211 deleteStateMachineMapping(e.getValue());
212 }
213 break;
214 }
215 }
216 }
217
218 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700219 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700220 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000221 * @param sessionId session Id represented by the switch dpid + port number
Ari Saha89831742015-06-26 10:31:48 -0700222 */
Jonathan Hart932bedc2018-07-12 13:46:09 -0700223 public StateMachine(String sessionId) {
224 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700225 this.sessionId = sessionId;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700226 sessionIdMap.put(sessionId, this);
Ari Saha89831742015-06-26 10:31:48 -0700227 }
228
229 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700230 * Gets the connect point for the supplicant side.
231 *
232 * @return supplicant connect point
233 */
234 public ConnectPoint supplicantConnectpoint() {
235 return supplicantConnectpoint;
236 }
237
238 /**
239 * Sets the supplicant side connect point.
240 *
241 * @param supplicantConnectpoint supplicant select point.
242 */
243 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
244 this.supplicantConnectpoint = supplicantConnectpoint;
245 }
246
247 /**
248 * Gets the MAC address of the supplicant.
249 *
250 * @return supplicant MAC address
251 */
252 public MacAddress supplicantAddress() {
253 return supplicantAddress;
254 }
255
256 /**
257 * Sets the supplicant MAC address.
258 *
259 * @param supplicantAddress new supplicant MAC address
260 */
261 public void setSupplicantAddress(MacAddress supplicantAddress) {
262 this.supplicantAddress = supplicantAddress;
263 }
264
265 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000266 * Sets the lastPacketReceivedTime.
267 *
268 * @param lastPacketReceivedTime timelastPacket was received
269 */
270 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
271 this.lastPacketReceivedTime = lastPacketReceivedTime;
272 }
273
274 /**
275 * Gets the lastPacketReceivedTime.
276 *
277 * @return lastPacketReceivedTime
278 */
279 public long getLastPacketReceivedTime() {
280 return lastPacketReceivedTime;
281 }
282
283 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700284 * Gets the client's Vlan ID.
285 *
286 * @return client vlan ID
287 */
288 public short vlanId() {
289 return vlanId;
290 }
291
292 /**
293 * Sets the client's vlan ID.
294 *
295 * @param vlanId new client vlan ID
296 */
297 public void setVlanId(short vlanId) {
298 this.vlanId = vlanId;
299 }
300
301 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100302 * Gets the client's priority Code.
303 *
304 * @return client Priority code
305 */
306 public byte priorityCode() {
307 return priorityCode;
308 }
309
310 /**
311 * Sets the client's priority Code.
312 *
313 * @param priorityCode new client priority Code
314 */
315 public void setPriorityCode(byte priorityCode) {
316 this.priorityCode = priorityCode;
317 }
318
319 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700320 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700321 *
Ari Saha89831742015-06-26 10:31:48 -0700322 * @return The client id.
323 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700324 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700325 return this.sessionId;
326 }
327
328 /**
Ari Saha89831742015-06-26 10:31:48 -0700329 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700330 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000331 * @param challengeIdentifier The challenge identifier set into the EAP packet
332 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700333 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700334 */
335 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
336 this.challengeIdentifier = challengeIdentifier;
337 this.challengeState = challengeState;
338 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700339
Ari Saha89831742015-06-26 10:31:48 -0700340 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000341 * Set the challenge identifier issued by the RADIUS on the access challenge
342 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700343 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000344 * @param challengeIdentifier The challenge identifier set into the EAP packet
345 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700346 */
347 protected void setChallengeIdentifier(byte challengeIdentifier) {
348 log.info("Set Challenge Identifier to {}", challengeIdentifier);
349 this.challengeIdentifier = challengeIdentifier;
350 }
351
352 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700353 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700354 *
Ari Saha89831742015-06-26 10:31:48 -0700355 * @return The challenge EAP identifier.
356 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700357 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700358 return this.challengeIdentifier;
359 }
360
Ari Saha89831742015-06-26 10:31:48 -0700361 /**
362 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700363 *
Ari Saha89831742015-06-26 10:31:48 -0700364 * @param challengeState The challenge state from the RADIUS.
365 */
366 protected void setChallengeState(byte[] challengeState) {
367 log.info("Set Challenge State");
368 this.challengeState = challengeState;
369 }
370
371 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700372 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700373 *
Ari Saha89831742015-06-26 10:31:48 -0700374 * @return The challenge state.
375 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700376 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700377 return this.challengeState;
378 }
379
380 /**
381 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700382 *
Ari Saha89831742015-06-26 10:31:48 -0700383 * @param username The username sent to the RADIUS upon access request.
384 */
385 protected void setUsername(byte[] username) {
386 this.username = username;
387 }
388
Ari Saha89831742015-06-26 10:31:48 -0700389 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700390 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700391 *
Ari Saha89831742015-06-26 10:31:48 -0700392 * @return The requestAuthenticator.
393 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700394 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700395 return this.requestAuthenticator;
396 }
397
398 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700399 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700400 *
Ari Saha89831742015-06-26 10:31:48 -0700401 * @param authenticator The username sent to the RADIUS upon access request.
402 */
403 protected void setRequestAuthenticator(byte[] authenticator) {
404 this.requestAuthenticator = authenticator;
405 }
406
Ari Saha89831742015-06-26 10:31:48 -0700407 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700408 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700409 *
Ari Saha89831742015-06-26 10:31:48 -0700410 * @return The username.
411 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700412 protected byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700413 return this.username;
414 }
415
416 /**
417 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700418 *
Ari Saha89831742015-06-26 10:31:48 -0700419 * @return The state machine identifier.
420 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100421 public synchronized byte identifier() {
Shubham Sharma048cc262019-06-19 14:18:50 +0000422 //identifier 0 is for statusServerrequest
423 //identifier 1 is for fake accessRequest
424 identifier = (identifier + 1) % 253;
425 identifierMap.put((identifier + 2), this);
426 return (byte) (identifier + 2);
Ari Saha89831742015-06-26 10:31:48 -0700427 }
428
Ari Saha89831742015-06-26 10:31:48 -0700429 /**
430 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700431 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700432 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700433 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700434 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700435 currentState = transition[currentState][msg];
436 log.info("Current State " + currentState);
437 }
438
439 /**
440 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700441 *
442 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700443 */
444 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700445 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700446
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000447 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700448
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000449 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700450 next(TRANSITION_START);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100451 identifier = this.identifier();
Ari Saha89831742015-06-26 10:31:48 -0700452 }
453
454 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000455 * An Identification information has been sent by the supplicant. Move to the
456 * next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700457 *
458 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700459 */
460 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700461 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700462
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000463 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700464
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000465 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700466 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700467 }
468
469 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000470 * RADIUS has accepted the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700471 *
472 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700473 */
474 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700475 states[currentState].radiusAccepted();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000476 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700477 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700478
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000479 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700480
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100481 // Clear mapping
482 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700483 }
484
485 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000486 * RADIUS has denied the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700487 *
488 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700489 */
490 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700491 states[currentState].radiusDenied();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000492 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700493 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700494
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000495 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700496
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100497 // Clear mappings
498 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700499 }
500
501 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000502 * Logoff request has been requested. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700503 *
504 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700505 */
506 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700507 states[currentState].logoff();
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000508 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700509 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700510 }
511
512 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700513 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700514 *
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000515 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
516 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700517 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700518 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700519 return currentState;
520 }
521
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700522 @Override
Ari Saha89831742015-06-26 10:31:48 -0700523 public String toString() {
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000524 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t"
525 + ("state: " + this.currentState);
Ari Saha89831742015-06-26 10:31:48 -0700526 }
Ari Saha89831742015-06-26 10:31:48 -0700527
Ray Milkey78e95a42015-09-24 08:36:45 -0700528 abstract class State {
529 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700530
Ray Milkey78e95a42015-09-24 08:36:45 -0700531 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700532
Ray Milkey78e95a42015-09-24 08:36:45 -0700533 public void start() throws StateMachineInvalidTransitionException {
534 log.warn("START transition from this state is not allowed.");
535 }
Ari Saha89831742015-06-26 10:31:48 -0700536
Ray Milkey78e95a42015-09-24 08:36:45 -0700537 public void requestAccess() throws StateMachineInvalidTransitionException {
538 log.warn("REQUEST ACCESS transition from this state is not allowed.");
539 }
540
541 public void radiusAccepted() throws StateMachineInvalidTransitionException {
542 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
543 }
544
545 public void radiusDenied() throws StateMachineInvalidTransitionException {
546 log.warn("DENY ACCESS transition from this state is not allowed.");
547 }
548
549 public void logoff() throws StateMachineInvalidTransitionException {
550 log.warn("LOGOFF transition from this state is not allowed.");
551 }
Ari Saha89831742015-06-26 10:31:48 -0700552 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700553
Ray Milkey78e95a42015-09-24 08:36:45 -0700554 /**
555 * Idle state: supplicant is logged of from the network.
556 */
557 class Idle extends State {
558 private final Logger log = getLogger(getClass());
559 private String name = "IDLE_STATE";
560
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000561 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700562 public void start() {
563 log.info("Moving from IDLE state to STARTED state.");
564 }
Ari Saha89831742015-06-26 10:31:48 -0700565 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700566
Ray Milkey78e95a42015-09-24 08:36:45 -0700567 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000568 * Started state: supplicant has entered the network and informed the
569 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700570 */
571 class Started extends State {
572 private final Logger log = getLogger(getClass());
573 private String name = "STARTED_STATE";
574
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000575 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700576 public void requestAccess() {
577 log.info("Moving from STARTED state to PENDING state.");
578 }
Ari Saha89831742015-06-26 10:31:48 -0700579 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700580
Ray Milkey78e95a42015-09-24 08:36:45 -0700581 /**
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000582 * Pending state: supplicant has been identified by the authenticator but has
583 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700584 */
585 class Pending extends State {
586 private final Logger log = getLogger(getClass());
587 private String name = "PENDING_STATE";
588
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000589 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700590 public void radiusAccepted() {
591 log.info("Moving from PENDING state to AUTHORIZED state.");
592 }
593
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000594 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700595 public void radiusDenied() {
596 log.info("Moving from PENDING state to UNAUTHORIZED state.");
597 }
Ari Saha89831742015-06-26 10:31:48 -0700598 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700599
Ray Milkey78e95a42015-09-24 08:36:45 -0700600 /**
601 * Authorized state: supplicant port has been accepted, access is granted.
602 */
603 class Authorized extends State {
604 private final Logger log = getLogger(getClass());
605 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700606
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000607 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800608 public void start() {
609 log.info("Moving from AUTHORIZED state to STARTED state.");
610 }
611
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000612 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700613 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700614
Ray Milkey78e95a42015-09-24 08:36:45 -0700615 log.info("Moving from AUTHORIZED state to IDLE state.");
616 }
Ari Saha89831742015-06-26 10:31:48 -0700617 }
618
Ray Milkey78e95a42015-09-24 08:36:45 -0700619 /**
620 * Unauthorized state: supplicant port has been rejected, access is denied.
621 */
622 class Unauthorized extends State {
623 private final Logger log = getLogger(getClass());
624 private String name = "UNAUTHORIZED_STATE";
625
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000626 @Override
ke han04e47f32016-10-28 14:15:43 +0800627 public void start() {
628 log.info("Moving from UNAUTHORIZED state to STARTED state.");
629 }
630
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000631 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700632 public void logoff() {
633 log.info("Moving from UNAUTHORIZED state to IDLE state.");
634 }
Ari Saha89831742015-06-26 10:31:48 -0700635 }
Ari Saha89831742015-06-26 10:31:48 -0700636
Shubham Sharmaa3b1bd32019-06-19 14:18:12 +0000637 /**
638 * Class for cleaning the StateMachine for those session for which no response
639 * is coming--implementing timeout.
640 */
641 class CleanupTimerTask implements Runnable {
642 private final Logger log = getLogger(getClass());
643 private String sessionId;
644 private AaaManager aaaManager;
645
646 CleanupTimerTask(String sessionId, AaaManager aaaManager) {
647 this.sessionId = sessionId;
648 this.aaaManager = aaaManager;
649 }
650
651 @Override
652 public void run() {
653 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
654 if (null != stateMachine) {
655 // Asserting if last packet received for this stateMachine session was beyond half of timeout period.
656 // StateMachine is considered eligible for cleanup when no packets has been exchanged by it with AAA
657 // Server or RG during a long period (half of timeout period). For example, when cleanup timer has
658 // been configured as 10 minutes, StateMachine would be cleaned up at the end of 10 minutes if
659 // the authentication is still pending and no packet was exchanged for this session during last 5
660 // minutes.
661
662 boolean noTrafficWithinThreshold = (System.currentTimeMillis()
663 - stateMachine.getLastPacketReceivedTime()) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
664
665 if ((TIMEOUT_ELIGIBLE_STATES.contains(stateMachine.state())) && noTrafficWithinThreshold) {
666 log.info("Deleting StateMachineMapping for sessionId: {}", sessionId);
667 cleanupTimer = null;
668 if (stateMachine.state() == STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
669 aaaManager.aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
670 }
671 deleteStateMachineId(sessionId);
672 deleteStateMachineMapping(stateMachine);
673
674 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
675 } else {
676 aaaManager.scheduleStateMachineCleanupTimer(sessionId, stateMachine);
677 }
678 } else {
679 // This statement should not be logged; cleanupTimer should be cancelled for stateMachine
680 // instances which have been authenticated successfully.
681 log.warn("state-machine not found for sessionId: {}", sessionId);
682 }
683
684 }
685 }
Ari Saha89831742015-06-26 10:31:48 -0700686
Ari Saha89831742015-06-26 10:31:48 -0700687}