or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdindex.mdjaas.mdlogin-services.mdsecurity-framework.mduser-identity.md

security-framework.mddocs/

0

# Security Framework

1

2

The core security framework provides the foundational interfaces and handlers for authentication and authorization in Jetty applications.

3

4

## Core Interfaces

5

6

### SecurityHandler

7

8

The `SecurityHandler` is the central component that orchestrates security for web applications.

9

10

```java { .api }

11

public abstract class SecurityHandler extends Handler.Abstract {

12

13

// Identity and authentication services

14

public IdentityService getIdentityService();

15

public void setIdentityService(IdentityService identityService);

16

17

public LoginService getLoginService();

18

public void setLoginService(LoginService loginService);

19

20

public Authenticator getAuthenticator();

21

public void setAuthenticator(Authenticator authenticator);

22

23

public Authenticator.Factory getAuthenticatorFactory();

24

public void setAuthenticatorFactory(Authenticator.Factory authenticatorFactory);

25

26

// Realm configuration

27

public String getRealmName();

28

public void setRealmName(String realmName);

29

30

public String getAuthenticationType();

31

public void setAuthenticationType(String authenticationType);

32

33

// Parameter management

34

public String getParameter(String key);

35

public String setParameter(String key, String value);

36

37

// Session configuration

38

public boolean isSessionRenewedOnAuthentication();

39

public void setSessionRenewedOnAuthentication(boolean renew);

40

41

public int getSessionMaxInactiveIntervalOnAuthentication();

42

public void setSessionMaxInactiveIntervalOnAuthentication(int seconds);

43

44

// Abstract method for constraint resolution

45

protected abstract Constraint getConstraint(String pathInContext, Request request);

46

47

// Static utility

48

public static SecurityHandler getCurrentSecurityHandler();

49

}

50

```

51

52

### PathMapped SecurityHandler

53

54

The concrete implementation using path mappings for constraints:

55

56

```java { .api }

57

public static class PathMapped extends SecurityHandler {

58

// Path-based constraint mapping

59

public void put(String pathSpec, Constraint constraint);

60

public Constraint get(String pathSpec);

61

public boolean remove(String pathSpec);

62

63

// Bulk operations

64

public void putAll(Map<String, Constraint> constraints);

65

public void clear();

66

67

@Override

68

protected Constraint getConstraint(String pathInContext, Request request) {

69

// Implementation resolves constraint based on path mapping

70

}

71

}

72

```

73

74

## Constraint System

75

76

### Constraint Interface

77

78

Defines security requirements for resources:

79

80

```java { .api }

81

public interface Constraint {

82

83

// Basic properties

84

String getName();

85

Transport getTransport();

86

Authorization getAuthorization();

87

Set<String> getRoles();

88

89

// Authorization levels

90

enum Authorization {

91

FORBIDDEN, // Access denied to all

92

ALLOWED, // Access allowed to all

93

ANY_USER, // Any authenticated user

94

KNOWN_ROLE, // User must have at least one role

95

SPECIFIC_ROLE, // User must have specific role(s)

96

INHERIT // Inherit from parent constraint

97

}

98

99

// Transport requirements

100

enum Transport {

101

SECURE, // HTTPS required

102

ANY, // HTTP or HTTPS

103

INHERIT // Inherit from parent constraint

104

}

105

106

// Factory methods

107

static Constraint from(String... roles);

108

static Constraint from(String name, Transport transport);

109

static Constraint from(String name, Authorization authorization, String... roles);

110

static Constraint combine(Constraint leastSpecific, Constraint mostSpecific);

111

}

112

```

113

114

### Predefined Constraints

115

116

```java { .api }

117

public class ConstraintExamples {

118

119

public void demonstrateConstraints() {

120

// Allow all access

121

Constraint allowAll = Constraint.ALLOWED;

122

123

// Deny all access

124

Constraint denyAll = Constraint.FORBIDDEN;

125

126

// Require any authenticated user

127

Constraint anyUser = Constraint.ANY_USER;

128

129

// Require specific roles

130

Constraint adminOnly = Constraint.from("admin");

131

Constraint userOrMod = Constraint.from("user", "moderator");

132

133

// Require HTTPS transport

134

Constraint secureOnly = Constraint.SECURE_TRANSPORT;

135

136

// Combined constraints

137

Constraint secureAdmin = Constraint.from("SecureAdmin",

138

Constraint.Transport.SECURE, "admin");

139

}

140

}

141

```

142

143

## Authentication State

144

145

### AuthenticationState Interface

146

147

Represents the current authentication status of a request:

148

149

```java { .api }

150

public interface AuthenticationState {

151

152

// Static utility methods

153

static AuthenticationState getAuthenticationState(Request request);

154

static void setAuthenticationState(Request request, AuthenticationState authenticationState);

155

156

static Principal getUserPrincipal(Request request);

157

static Succeeded authenticate(Request request);

158

static Succeeded authenticate(Request request, Response response, Callback callback);

159

160

static Succeeded login(String username, String password, Request request, Response response);

161

static boolean logout(Request request, Response response);

162

163

// Nested state interfaces

164

interface Succeeded extends AuthenticationState {

165

UserIdentity getUserIdentity();

166

String getAuthenticationType();

167

}

168

169

interface ResponseSent extends AuthenticationState {

170

// Marker interface for responses that were sent

171

}

172

173

interface Deferred extends AuthenticationState {

174

AuthenticationState authenticate(Request request, Response response, Callback callback);

175

}

176

}

177

```

178

179

### Authentication State Constants

180

181

```java { .api }

182

public class AuthenticationStates {

183

184

public void handleAuthenticationStates(AuthenticationState state) {

185

186

// Challenge was sent to client

187

if (state == AuthenticationState.CHALLENGE) {

188

// Client needs to provide credentials

189

}

190

191

// Failure response was sent

192

else if (state == AuthenticationState.SEND_FAILURE) {

193

// Authentication failed, error sent

194

}

195

196

// Success response was sent

197

else if (state == AuthenticationState.SEND_SUCCESS) {

198

// Authentication succeeded, response sent

199

}

200

201

// Successful authentication

202

else if (state instanceof AuthenticationState.Succeeded) {

203

AuthenticationState.Succeeded success = (AuthenticationState.Succeeded) state;

204

UserIdentity user = success.getUserIdentity();

205

String authType = success.getAuthenticationType();

206

}

207

208

// Deferred authentication

209

else if (state instanceof AuthenticationState.Deferred) {

210

AuthenticationState.Deferred deferred = (AuthenticationState.Deferred) state;

211

// Authentication will be handled later

212

}

213

}

214

}

215

```

216

217

## Authenticator Interface

218

219

### Core Authenticator Methods

220

221

```java { .api }

222

public interface Authenticator {

223

224

// Authentication type constants

225

String BASIC_AUTH = "BASIC";

226

String FORM_AUTH = "FORM";

227

String DIGEST_AUTH = "DIGEST";

228

String CERT_AUTH = "CLIENT_CERT";

229

String CERT_AUTH2 = "CLIENT-CERT";

230

String SPNEGO_AUTH = "SPNEGO";

231

String NEGOTIATE_AUTH = "NEGOTIATE";

232

String OPENID_AUTH = "OPENID";

233

234

// Configuration and identification

235

void setConfiguration(Configuration configuration);

236

String getAuthenticationType();

237

238

// Request preparation and validation

239

default Request prepareRequest(Request request, AuthenticationState authenticationState) {

240

return request;

241

}

242

243

default Constraint.Authorization getConstraintAuthentication(String pathInContext,

244

Constraint.Authorization existing, Function<Boolean, Session> getSession) {

245

return existing == null ? Constraint.Authorization.ALLOWED : existing;

246

}

247

248

AuthenticationState validateRequest(Request request, Response response, Callback callback)

249

throws ServerAuthException;

250

251

// Nested configuration interface

252

interface Configuration {

253

String getRealmName();

254

String getParameter(String key);

255

LoginService getLoginService();

256

IdentityService getIdentityService();

257

}

258

259

// Factory interface

260

interface Factory {

261

Authenticator getAuthenticator(Server server, Context context, Configuration configuration);

262

}

263

}

264

```

265

266

### DefaultAuthenticatorFactory

267

268

Default implementation of the Authenticator.Factory interface that creates authenticators based on configuration:

269

270

```java { .api }

271

public class DefaultAuthenticatorFactory implements Authenticator.Factory {

272

273

@Override

274

public Authenticator getAuthenticator(Server server, Context context, Configuration configuration);

275

}

276

```

277

278

The DefaultAuthenticatorFactory creates authenticators based on the configured authentication type:

279

- `BASIC``BasicAuthenticator`

280

- `DIGEST``DigestAuthenticator`

281

- `FORM``FormAuthenticator`

282

- `CLIENT-CERT``SslClientCertAuthenticator` (requires single SslContextFactory)

283

- `SPNEGO`/`NEGOTIATE``SPNEGOAuthenticator`

284

285

LoginAuthenticator instances are wrapped with DeferredAuthenticationState for non-mandatory authentication scenarios.

286

287

### ServerAuthException

288

289

Exception class for server-side authentication and authorization failures:

290

291

```java { .api }

292

public class ServerAuthException extends GeneralSecurityException {

293

294

// Constructors

295

public ServerAuthException();

296

public ServerAuthException(String message);

297

public ServerAuthException(String message, Throwable cause);

298

public ServerAuthException(Throwable cause);

299

}

300

```

301

302

Thrown by authenticators during request validation when authentication or authorization fails.

303

304

## Practical Examples

305

306

### Basic Security Setup

307

308

```java { .api }

309

public class BasicSecuritySetup {

310

311

public SecurityHandler createBasicSecurity() {

312

SecurityHandler.PathMapped security = new SecurityHandler.PathMapped();

313

314

// Configure realm

315

security.setRealmName("MyApplication");

316

317

// Set up login service

318

HashLoginService loginService = new HashLoginService();

319

loginService.setName("MyApplication");

320

loginService.setConfig(Resource.newResource("users.properties"));

321

security.setLoginService(loginService);

322

323

// Configure authenticator

324

BasicAuthenticator authenticator = new BasicAuthenticator();

325

security.setAuthenticator(authenticator);

326

327

// Define constraints

328

security.put("/public/*", Constraint.ALLOWED);

329

security.put("/users/*", Constraint.ANY_USER);

330

security.put("/admin/*", Constraint.from("admin"));

331

security.put("/api/secure/*", Constraint.from("SecureAPI",

332

Constraint.Transport.SECURE, "api-user"));

333

334

return security;

335

}

336

}

337

```

338

339

### Advanced Security Configuration

340

341

```java { .api }

342

public class AdvancedSecurityConfig {

343

344

public void configureAdvancedSecurity(SecurityHandler security) {

345

346

// Identity service for thread association

347

DefaultIdentityService identityService = new DefaultIdentityService();

348

security.setIdentityService(identityService);

349

350

// Session security settings

351

security.setSessionRenewedOnAuthentication(true);

352

security.setSessionMaxInactiveIntervalOnAuthentication(1800); // 30 minutes

353

354

// Custom authenticator factory

355

security.setAuthenticatorFactory(new DefaultAuthenticatorFactory());

356

357

// Parameters for authenticators

358

security.setParameter("charset", "UTF-8");

359

security.setParameter("realmName", "SecureRealm");

360

361

// Complex constraint combinations

362

setupComplexConstraints((SecurityHandler.PathMapped) security);

363

}

364

365

private void setupComplexConstraints(SecurityHandler.PathMapped security) {

366

367

// Public resources - no authentication required

368

security.put("/css/*", Constraint.ALLOWED);

369

security.put("/js/*", Constraint.ALLOWED);

370

security.put("/images/*", Constraint.ALLOWED);

371

security.put("/favicon.ico", Constraint.ALLOWED);

372

373

// API endpoints with role-based access

374

security.put("/api/public/*", Constraint.ALLOWED);

375

security.put("/api/users/*", Constraint.ANY_USER);

376

security.put("/api/admin/*", Constraint.from("admin", "super-admin"));

377

378

// Secure administrative areas requiring HTTPS

379

security.put("/admin/*", Constraint.from("AdminArea",

380

Constraint.Transport.SECURE, "admin"));

381

security.put("/config/*", Constraint.from("ConfigArea",

382

Constraint.Transport.SECURE, "super-admin"));

383

384

// User-specific areas

385

security.put("/user/*", Constraint.from("user", "premium-user"));

386

security.put("/premium/*", Constraint.from("premium-user"));

387

}

388

}

389

```

390

391

### Custom Constraint Implementation

392

393

```java { .api }

394

public class CustomConstraintExample {

395

396

public static class TimeBasedConstraint implements Constraint {

397

private final Constraint base;

398

private final int startHour;

399

private final int endHour;

400

401

public TimeBasedConstraint(Constraint base, int startHour, int endHour) {

402

this.base = base;

403

this.startHour = startHour;

404

this.endHour = endHour;

405

}

406

407

@Override

408

public String getName() {

409

return "TimeBased-" + base.getName();

410

}

411

412

@Override

413

public Transport getTransport() {

414

return base.getTransport();

415

}

416

417

@Override

418

public Authorization getAuthorization() {

419

int hour = LocalTime.now().getHour();

420

if (hour >= startHour && hour < endHour) {

421

return base.getAuthorization();

422

}

423

return Authorization.FORBIDDEN;

424

}

425

426

@Override

427

public Set<String> getRoles() {

428

return base.getRoles();

429

}

430

}

431

432

public void useTimeBasedConstraints(SecurityHandler.PathMapped security) {

433

// Business hours only access (9 AM to 6 PM)

434

Constraint businessHours = new TimeBasedConstraint(

435

Constraint.from("business-user"), 9, 18);

436

security.put("/business/*", businessHours);

437

438

// After-hours admin access

439

Constraint afterHours = new TimeBasedConstraint(

440

Constraint.from("admin"), 18, 9);

441

security.put("/maintenance/*", afterHours);

442

}

443

}

444

```

445

446

### SecurityHandler Extension

447

448

```java { .api }

449

public class CustomSecurityHandler extends SecurityHandler {

450

private final Map<String, Constraint> dynamicConstraints = new ConcurrentHashMap<>();

451

452

@Override

453

protected Constraint getConstraint(String pathInContext, Request request) {

454

455

// Check dynamic constraints first

456

Constraint dynamic = dynamicConstraints.get(pathInContext);

457

if (dynamic != null) {

458

return dynamic;

459

}

460

461

// Check user-specific constraints

462

UserIdentity user = getCurrentUser(request);

463

if (user != null && user.isUserInRole("super-admin")) {

464

return Constraint.ALLOWED; // Super admins bypass all constraints

465

}

466

467

// Default to forbidden for unknown paths

468

return Constraint.FORBIDDEN;

469

}

470

471

public void addDynamicConstraint(String path, Constraint constraint) {

472

dynamicConstraints.put(path, constraint);

473

}

474

475

public void removeDynamicConstraint(String path) {

476

dynamicConstraints.remove(path);

477

}

478

479

private UserIdentity getCurrentUser(Request request) {

480

AuthenticationState auth = AuthenticationState.getAuthenticationState(request);

481

if (auth instanceof AuthenticationState.Succeeded) {

482

return ((AuthenticationState.Succeeded) auth).getUserIdentity();

483

}

484

return null;

485

}

486

}

487

```

488

489

## Error Handling

490

491

### Security Exceptions

492

493

```java { .api }

494

public class SecurityErrorHandling {

495

496

public void handleSecurityErrors(SecurityHandler security) {

497

498

try {

499

// Security operations that might fail

500

Constraint constraint = security.getConstraint("/protected", request);

501

502

} catch (ServerAuthException e) {

503

// Handle authentication/authorization errors

504

logger.error("Security error: " + e.getMessage(), e);

505

506

// Send appropriate error response

507

response.setStatus(HttpStatus.UNAUTHORIZED_401);

508

response.getHeaders().put(HttpHeader.WWW_AUTHENTICATE,

509

"Basic realm=\"" + security.getRealmName() + "\"");

510

}

511

}

512

513

public void customErrorHandling(Request request, Response response, Throwable error) {

514

515

if (error instanceof ServerAuthException) {

516

ServerAuthException authError = (ServerAuthException) error;

517

518

// Log security violations

519

logger.warn("Authentication failure for user: {} from IP: {}",

520

request.getHeaders().get("X-User"),

521

Request.getRemoteAddr(request));

522

523

// Custom error page

524

response.setStatus(HttpStatus.FORBIDDEN_403);

525

response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/html");

526

527

try {

528

response.getWriter().write("<html><body>" +

529

"<h1>Access Denied</h1>" +

530

"<p>You do not have permission to access this resource.</p>" +

531

"</body></html>");

532

} catch (IOException e) {

533

logger.error("Error writing security error page", e);

534

}

535

}

536

}

537

}

538

```

539

540

## Best Practices

541

542

### Security Configuration

543

544

```java { .api }

545

public class SecurityBestPractices {

546

547

public SecurityHandler createProductionSecurity() {

548

SecurityHandler.PathMapped security = new SecurityHandler.PathMapped();

549

550

// Always use strong realm names

551

security.setRealmName("ProductionApp-" + UUID.randomUUID().toString());

552

553

// Enable session renewal on authentication

554

security.setSessionRenewedOnAuthentication(true);

555

556

// Set reasonable session timeout

557

security.setSessionMaxInactiveIntervalOnAuthentication(1800); // 30 minutes

558

559

// Secure transport for sensitive operations

560

security.put("/login/*", Constraint.from("Login",

561

Constraint.Transport.SECURE));

562

security.put("/admin/*", Constraint.from("Admin",

563

Constraint.Transport.SECURE, "admin"));

564

security.put("/api/payment/*", Constraint.from("Payment",

565

Constraint.Transport.SECURE, "payment-user"));

566

567

return security;

568

}

569

570

public void secureDefaultsSetup(SecurityHandler security) {

571

572

// Deny by default - explicit allow only

573

security.put("/*", Constraint.FORBIDDEN);

574

575

// Explicitly allow public resources

576

security.put("/public/*", Constraint.ALLOWED);

577

security.put("/health", Constraint.ALLOWED);

578

security.put("/status", Constraint.ALLOWED);

579

580

// Authenticated areas

581

security.put("/app/*", Constraint.ANY_USER);

582

security.put("/user/*", Constraint.ANY_USER);

583

584

// Role-based areas

585

security.put("/admin/*", Constraint.from("admin"));

586

security.put("/reports/*", Constraint.from("admin", "manager"));

587

}

588

}

589

```

590

591

## Utility Classes

592

593

### Resource

594

595

Utility class for configuration resource management:

596

597

```java { .api }

598

public abstract class Resource {

599

600

// Factory methods for creating resources

601

public static Resource newResource(String resource);

602

public static Resource newClassPathResource(String name);

603

public static Resource newResource(URI uri);

604

public static Resource newResource(File file);

605

606

// Resource properties

607

public abstract boolean exists();

608

public abstract boolean isDirectory();

609

public abstract String getName();

610

public abstract URI getURI();

611

}

612

```

613

614

The Resource class provides abstracted access to configuration files, supporting filesystem paths, classpath resources, and URIs. Commonly used for specifying login service configuration files.

615

616

The Security Framework provides the foundation for all authentication and authorization in Jetty applications, offering flexible constraint definition, pluggable authenticators, and comprehensive security state management.