or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication-components.mdevent-resolution.mdindex.mdprovider-selection.mdwebflow-actions.mdwebflow-configuration.mdwebflow-utilities.md

webflow-utilities.mddocs/

0

# Webflow Utilities

1

2

Static utility methods for managing MFA-related data in webflow scopes, device registration, provider selection, and token management. The `MultifactorAuthenticationWebflowUtils` class provides a comprehensive set of utilities for storing and retrieving MFA-related information across webflow transitions.

3

4

## Capabilities

5

6

### MultifactorAuthenticationWebflowUtils

7

8

Utility class providing static methods for managing MFA-related data in webflow scopes.

9

10

```java { .api }

11

/**

12

* Utility class for managing MFA-related data in webflow scopes

13

*/

14

@UtilityClass

15

public class MultifactorAuthenticationWebflowUtils {

16

17

// Webflow Customizer Management

18

19

/**

20

* Get multifactor authentication webflow customizers from application context

21

* @param applicationContext Spring application context

22

* @return List of sorted webflow customizers

23

*/

24

public static List<CasMultifactorWebflowCustomizer> getMultifactorAuthenticationWebflowCustomizers(

25

ConfigurableApplicationContext applicationContext);

26

27

// Device Registration Management

28

29

/**

30

* Check if multifactor device registration is enabled

31

* @param requestContext The webflow request context

32

* @return true if device registration is enabled

33

*/

34

public static boolean isMultifactorDeviceRegistrationEnabled(RequestContext requestContext);

35

36

/**

37

* Set multifactor device registration enabled flag

38

* @param requestContext The webflow request context

39

* @param enabled Whether device registration is enabled

40

*/

41

public static void putMultifactorDeviceRegistrationEnabled(RequestContext requestContext, boolean enabled);

42

43

// Provider Management

44

45

/**

46

* Store resolved multifactor authentication providers in conversation scope

47

* @param context The webflow request context

48

* @param value Collection of resolved MFA providers

49

*/

50

public static void putResolvedMultifactorAuthenticationProviders(

51

RequestContext context,

52

Collection<MultifactorAuthenticationProvider> value);

53

54

/**

55

* Get resolved multifactor authentication providers from conversation scope

56

* @param context The webflow request context

57

* @return Collection of resolved provider IDs

58

*/

59

public static Collection<String> getResolvedMultifactorAuthenticationProviders(RequestContext context);

60

61

/**

62

* Store MFA provider ID in flow scope

63

* @param context The webflow request context

64

* @param provider The MFA provider

65

*/

66

public static void putMultifactorAuthenticationProvider(RequestContext context, MultifactorAuthenticationProvider provider);

67

68

/**

69

* Get MFA provider ID from flow scope

70

* @param context The webflow request context

71

* @return Provider ID string

72

*/

73

public static String getMultifactorAuthenticationProvider(RequestContext context);

74

75

// Provider Selection Management

76

77

/**

78

* Store selectable multifactor authentication providers in view scope

79

* @param requestContext The webflow request context

80

* @param mfaProviders List of selectable provider IDs

81

*/

82

public static void putSelectableMultifactorAuthenticationProviders(RequestContext requestContext, List<String> mfaProviders);

83

84

/**

85

* Get selectable multifactor authentication providers from view scope

86

* @param requestContext The webflow request context

87

* @return List of selectable provider IDs

88

*/

89

public static List<String> getSelectableMultifactorAuthenticationProviders(RequestContext requestContext);

90

91

// Google Authenticator Specific

92

93

/**

94

* Set Google Authenticator multiple device registration enabled flag

95

* @param requestContext The webflow request context

96

* @param enabled Whether multiple device registration is enabled

97

*/

98

public static void putGoogleAuthenticatorMultipleDeviceRegistrationEnabled(RequestContext requestContext, boolean enabled);

99

100

/**

101

* Check if Google Authenticator multiple device registration is enabled

102

* @param requestContext The webflow request context

103

* @return Boolean indicating if multiple device registration is enabled

104

*/

105

public static Boolean isGoogleAuthenticatorMultipleDeviceRegistrationEnabled(RequestContext requestContext);

106

107

// YubiKey Specific

108

109

/**

110

* Set YubiKey multiple device registration enabled flag

111

* @param requestContext The webflow request context

112

* @param enabled Whether multiple device registration is enabled

113

*/

114

public static void putYubiKeyMultipleDeviceRegistrationEnabled(RequestContext requestContext, boolean enabled);

115

116

// Simple MFA Token Management

117

118

/**

119

* Store simple multifactor authentication token in flow scope

120

* @param requestContext The webflow request context

121

* @param token The ticket token

122

*/

123

public static void putSimpleMultifactorAuthenticationToken(RequestContext requestContext, Ticket token);

124

125

/**

126

* Remove simple multifactor authentication token from flow scope

127

* @param requestContext The webflow request context

128

*/

129

public static void removeSimpleMultifactorAuthenticationToken(RequestContext requestContext);

130

131

/**

132

* Get simple multifactor authentication token from flow scope

133

* @param <T> Type of ticket extending Ticket

134

* @param requestContext The webflow request context

135

* @param clazz Class type of the ticket

136

* @return Typed ticket instance or null

137

*/

138

public static <T extends Ticket> T getSimpleMultifactorAuthenticationToken(RequestContext requestContext, Class<T> clazz);

139

140

// Parent Credential Management

141

142

/**

143

* Get multifactor authentication parent credential from flow scope

144

* @param requestContext The webflow request context

145

* @return Parent credential or null

146

*/

147

public static Credential getMultifactorAuthenticationParentCredential(RequestContext requestContext);

148

149

// Registered Device Management

150

151

/**

152

* Store multifactor authentication registered devices in flow scope

153

* @param requestContext The webflow request context

154

* @param accounts Set of registered devices/accounts

155

*/

156

public static void putMultifactorAuthenticationRegisteredDevices(RequestContext requestContext, Set accounts);

157

158

/**

159

* Get multifactor authentication registered devices from flow scope

160

* Note: This method is NOT static in the source, which appears to be an inconsistency

161

* @param requestContext The webflow request context

162

* @return Set of registered devices

163

*/

164

public Set<MultifactorAuthenticationRegisteredDevice> getMultifactorAuthenticationRegisteredDevices(RequestContext requestContext);

165

166

// One-Time Token Account Management

167

168

/**

169

* Store one-time token account in flow scope

170

* @param requestContext The webflow request context

171

* @param account The one-time token account

172

*/

173

public static void putOneTimeTokenAccount(RequestContext requestContext, OneTimeTokenAccount account);

174

175

/**

176

* Store collection of one-time token accounts in flow scope

177

* @param requestContext The webflow request context

178

* @param accounts Collection of one-time token accounts

179

*/

180

public static void putOneTimeTokenAccounts(RequestContext requestContext, Collection accounts);

181

182

/**

183

* Get one-time token accounts from flow scope

184

* @param requestContext The webflow request context

185

* @return Collection of one-time token accounts

186

*/

187

public static Collection getOneTimeTokenAccounts(RequestContext requestContext);

188

189

/**

190

* Get typed one-time token account from flow scope

191

* @param <T> Type extending OneTimeTokenAccount

192

* @param requestContext The webflow request context

193

* @param clazz Class type of the account

194

* @return Typed account instance or null

195

*/

196

public static <T extends OneTimeTokenAccount> T getOneTimeTokenAccount(RequestContext requestContext, Class<T> clazz);

197

}

198

```

199

200

## Usage Examples

201

202

### Basic Provider Management

203

204

```java

205

// In a webflow action

206

public class MyMfaAction extends BaseCasWebflowAction {

207

208

@Override

209

protected Event doExecuteInternal(RequestContext requestContext) throws Exception {

210

// Get current MFA provider

211

val providerId = MultifactorAuthenticationWebflowUtils

212

.getMultifactorAuthenticationProvider(requestContext);

213

214

if (providerId == null) {

215

// No provider set, determine and store one

216

val selectedProvider = determineAppropriateProvider(requestContext);

217

MultifactorAuthenticationWebflowUtils

218

.putMultifactorAuthenticationProvider(requestContext, selectedProvider);

219

}

220

221

return success();

222

}

223

}

224

```

225

226

### Device Registration Management

227

228

```java

229

// Enable/disable device registration based on policy

230

public class DeviceRegistrationPolicyAction extends BaseCasWebflowAction {

231

232

@Override

233

protected Event doExecuteInternal(RequestContext requestContext) throws Exception {

234

val authentication = WebUtils.getAuthentication(requestContext);

235

val service = WebUtils.getService(requestContext);

236

237

// Check policy for device registration

238

val deviceRegistrationEnabled = shouldAllowDeviceRegistration(authentication, service);

239

240

// Store the decision in webflow scope

241

MultifactorAuthenticationWebflowUtils

242

.putMultifactorDeviceRegistrationEnabled(requestContext, deviceRegistrationEnabled);

243

244

// Provider-specific settings

245

if (isGoogleAuthenticatorProvider()) {

246

MultifactorAuthenticationWebflowUtils

247

.putGoogleAuthenticatorMultipleDeviceRegistrationEnabled(requestContext,

248

shouldAllowMultipleDevices(authentication));

249

}

250

251

return success();

252

}

253

}

254

```

255

256

### Provider Selection Workflow

257

258

```java

259

// Prepare providers for user selection

260

public class PrepareProviderSelectionAction extends BaseCasWebflowAction {

261

262

@Override

263

protected Event doExecuteInternal(RequestContext requestContext) throws Exception {

264

val authentication = WebUtils.getAuthentication(requestContext);

265

val availableProviders = getAvailableProvidersForUser(authentication);

266

267

// Filter providers based on availability and bypass rules

268

val selectableProviders = availableProviders.stream()

269

.filter(provider -> isProviderAvailable(provider, authentication))

270

.filter(provider -> !shouldBypassProvider(provider, authentication))

271

.map(MultifactorAuthenticationProvider::getId)

272

.collect(Collectors.toList());

273

274

// Store selectable providers for the view

275

MultifactorAuthenticationWebflowUtils

276

.putSelectableMultifactorAuthenticationProviders(requestContext, selectableProviders);

277

278

if (selectableProviders.isEmpty()) {

279

return error();

280

} else if (selectableProviders.size() == 1) {

281

// Only one provider available, set it directly

282

val singleProvider = getProviderById(selectableProviders.get(0));

283

MultifactorAuthenticationWebflowUtils

284

.putMultifactorAuthenticationProvider(requestContext, singleProvider);

285

return new EventFactorySupport().event(this, "single");

286

} else {

287

// Multiple providers available, proceed to selection

288

return success();

289

}

290

}

291

}

292

```

293

294

### Token and Credential Management

295

296

```java

297

// Handle simple MFA token lifecycle

298

public class SimpleMfaTokenAction extends BaseCasWebflowAction {

299

300

private final TicketRegistry ticketRegistry;

301

302

@Override

303

protected Event doExecuteInternal(RequestContext requestContext) throws Exception {

304

val authentication = WebUtils.getAuthentication(requestContext);

305

306

// Generate and store token

307

val token = createSimpleMfaToken(authentication);

308

ticketRegistry.addTicket(token);

309

310

MultifactorAuthenticationWebflowUtils

311

.putSimpleMultifactorAuthenticationToken(requestContext, token);

312

313

// Send token to user (SMS, email, etc.)

314

sendTokenToUser(token, authentication.getPrincipal());

315

316

return success();

317

}

318

319

// In verification action

320

protected Event verifyToken(RequestContext requestContext) throws Exception {

321

val submittedToken = requestContext.getRequestParameters().get("token");

322

val storedToken = MultifactorAuthenticationWebflowUtils

323

.getSimpleMultifactorAuthenticationToken(requestContext, SimpleMfaToken.class);

324

325

if (storedToken != null && storedToken.getId().equals(submittedToken)) {

326

// Token verified, clean up

327

MultifactorAuthenticationWebflowUtils

328

.removeSimpleMultifactorAuthenticationToken(requestContext);

329

ticketRegistry.deleteTicket(storedToken.getId());

330

return success();

331

}

332

333

return error();

334

}

335

}

336

```

337

338

### Registered Device Management

339

340

```java

341

// Load and manage registered devices

342

public class LoadRegisteredDevicesAction extends BaseCasWebflowAction {

343

344

private final MultifactorAuthenticationDeviceManager deviceManager;

345

346

@Override

347

protected Event doExecuteInternal(RequestContext requestContext) throws Exception {

348

val authentication = WebUtils.getAuthentication(requestContext);

349

val principal = authentication.getPrincipal();

350

351

// Load registered devices for the user

352

val registeredDevices = deviceManager.findRegisteredDevices(principal);

353

354

// Store in webflow scope for view access

355

MultifactorAuthenticationWebflowUtils

356

.putMultifactorAuthenticationRegisteredDevices(requestContext, registeredDevices);

357

358

// Also store as one-time token accounts if applicable

359

val tokenAccounts = registeredDevices.stream()

360

.filter(device -> device instanceof OneTimeTokenAccount)

361

.map(device -> (OneTimeTokenAccount) device)

362

.collect(Collectors.toSet());

363

364

if (!tokenAccounts.isEmpty()) {

365

MultifactorAuthenticationWebflowUtils

366

.putOneTimeTokenAccounts(requestContext, tokenAccounts);

367

}

368

369

return success();

370

}

371

}

372

```

373

374

### Custom Webflow Scope Integration

375

376

```java

377

// Custom utility methods extending the base utilities

378

@UtilityClass

379

public class CustomMfaWebflowUtils {

380

381

/**

382

* Store custom MFA context data

383

*/

384

public static void putCustomMfaContext(RequestContext context, String key, Object value) {

385

context.getFlowScope().put("customMfa_" + key, value);

386

}

387

388

/**

389

* Get custom MFA context data

390

*/

391

public static <T> T getCustomMfaContext(RequestContext context, String key, Class<T> type) {

392

return context.getFlowScope().get("customMfa_" + key, type);

393

}

394

395

/**

396

* Check if user has completed MFA recently (using conversation scope for session-wide storage)

397

*/

398

public static boolean hasRecentMfaCompletion(RequestContext context, String providerId) {

399

val completions = context.getConversationScope()

400

.get("recentMfaCompletions", Map.class);

401

if (completions != null) {

402

val lastCompletion = (Long) completions.get(providerId);

403

return lastCompletion != null &&

404

(System.currentTimeMillis() - lastCompletion) < Duration.ofMinutes(5).toMillis();

405

}

406

return false;

407

}

408

409

/**

410

* Record MFA completion timestamp

411

*/

412

public static void recordMfaCompletion(RequestContext context, String providerId) {

413

val completions = context.getConversationScope()

414

.get("recentMfaCompletions", Map.class);

415

val completionMap = completions != null ? completions : new HashMap<String, Long>();

416

completionMap.put(providerId, System.currentTimeMillis());

417

context.getConversationScope().put("recentMfaCompletions", completionMap);

418

}

419

}

420

```

421

422

## Scope Usage Guidelines

423

424

- **Flow Scope**: Use for data that needs to persist across the entire webflow execution (e.g., selected provider, tokens)

425

- **Conversation Scope**: Use for data that should persist across multiple webflow executions in the same session (e.g., resolved providers)

426

- **View Scope**: Use for data that's only needed for rendering the current view (e.g., selectable providers list)

427

428

The utility class automatically manages the appropriate scopes for different types of MFA data, ensuring optimal performance and proper cleanup.