or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration.mdindex.mdjson-serialization.mdticket-caching.mduser-details.mdweb-integration.md

json-serialization.mddocs/

0

# JSON Serialization

1

2

Jackson module for serializing CAS authentication tokens and related objects in distributed session scenarios. This module enables proper JSON serialization and deserialization of CAS authentication objects for session management in clustered applications.

3

4

## Capabilities

5

6

### CAS Jackson2 Module

7

8

Jackson module that provides JSON serialization support for CAS authentication types, enabling distributed session management and caching scenarios.

9

10

```java { .api }

11

/**

12

* Jackson module for JSON serialization of CAS authentication objects.

13

* Registers mixins for proper serialization of CAS types in distributed environments.

14

*/

15

public class CasJackson2Module extends SimpleModule {

16

17

/**

18

* Creates CAS Jackson2 module with default configuration.

19

* Automatically registers mixins for CAS authentication types.

20

*/

21

public CasJackson2Module();

22

23

/**

24

* Sets up the module by registering mixins for CAS types.

25

* Called automatically by Jackson during module registration.

26

* @param context Jackson setup context for module configuration

27

*/

28

public void setupModule(SetupContext context);

29

}

30

```

31

32

**Usage Example:**

33

34

```java

35

@Configuration

36

public class JacksonConfig {

37

38

@Bean

39

@Primary

40

public ObjectMapper objectMapper() {

41

ObjectMapper mapper = new ObjectMapper();

42

mapper.registerModule(new CasJackson2Module());

43

return mapper;

44

}

45

}

46

```

47

48

## Jackson Mixin Classes

49

50

The module includes several Jackson mixin classes that handle the serialization complexity of CAS objects:

51

52

### CAS Authentication Token Mixin

53

54

Mixin for deserializing `CasAuthenticationToken` objects using Jackson.

55

56

```java { .api }

57

/**

58

* Mixin class for CasAuthenticationToken deserialization.

59

* Uses the private constructor designed for Jackson deserialization.

60

*/

61

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)

62

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,

63

isGetterVisibility = JsonAutoDetect.Visibility.NONE,

64

getterVisibility = JsonAutoDetect.Visibility.NONE,

65

creatorVisibility = JsonAutoDetect.Visibility.ANY)

66

@JsonIgnoreProperties(ignoreUnknown = true)

67

class CasAuthenticationTokenMixin {

68

69

/**

70

* Mixin constructor for deserializing CasAuthenticationToken.

71

* @param keyHash hashCode of the provider key for token validation

72

* @param principal the authenticated principal (usually username)

73

* @param credentials the service/proxy ticket ID from CAS

74

* @param authorities granted authorities for the user

75

* @param userDetails detailed user information

76

* @param assertion CAS assertion containing user attributes

77

*/

78

@JsonCreator

79

CasAuthenticationTokenMixin(

80

@JsonProperty("keyHash") Integer keyHash,

81

@JsonProperty("principal") Object principal,

82

@JsonProperty("credentials") Object credentials,

83

@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities,

84

@JsonProperty("userDetails") UserDetails userDetails,

85

@JsonProperty("assertion") Assertion assertion);

86

}

87

```

88

89

### Assertion Implementation Mixin

90

91

Mixin for deserializing CAS `AssertionImpl` objects from the Apereo CAS client.

92

93

```java { .api }

94

/**

95

* Mixin for deserializing AssertionImpl from org.apereo.cas.client.validation package.

96

* Handles CAS assertion objects containing authentication details and user attributes.

97

*/

98

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)

99

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,

100

getterVisibility = JsonAutoDetect.Visibility.NONE,

101

isGetterVisibility = JsonAutoDetect.Visibility.NONE)

102

@JsonIgnoreProperties(ignoreUnknown = true)

103

class AssertionImplMixin {

104

105

/**

106

* Mixin constructor for deserializing AssertionImpl.

107

* @param principal the Principal associated with the assertion

108

* @param validFromDate when the assertion becomes valid

109

* @param validUntilDate when the assertion expires

110

* @param authenticationDate when the user was authenticated

111

* @param attributes key/value pairs for assertion attributes

112

*/

113

@JsonCreator

114

AssertionImplMixin(

115

@JsonProperty("principal") AttributePrincipal principal,

116

@JsonProperty("validFromDate") Date validFromDate,

117

@JsonProperty("validUntilDate") Date validUntilDate,

118

@JsonProperty("authenticationDate") Date authenticationDate,

119

@JsonProperty("attributes") Map<String, Object> attributes);

120

}

121

```

122

123

### Attribute Principal Implementation Mixin

124

125

Mixin for deserializing CAS `AttributePrincipalImpl` objects from the Apereo CAS client.

126

127

```java { .api }

128

/**

129

* Mixin for deserializing AttributePrincipalImpl from org.apereo.cas.client.authentication package.

130

* Handles CAS principal objects containing user identity and attributes.

131

*/

132

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)

133

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,

134

getterVisibility = JsonAutoDetect.Visibility.NONE,

135

isGetterVisibility = JsonAutoDetect.Visibility.NONE)

136

@JsonIgnoreProperties(ignoreUnknown = true)

137

class AttributePrincipalImplMixin {

138

139

/**

140

* Mixin constructor for deserializing AttributePrincipalImpl.

141

* @param name unique identifier for the principal (username)

142

* @param attributes key/value pairs for user attributes

143

* @param proxyGrantingTicket ticket for obtaining proxy tickets

144

* @param proxyRetriever callback implementation for CAS server communication

145

*/

146

@JsonCreator

147

AttributePrincipalImplMixin(

148

@JsonProperty("name") String name,

149

@JsonProperty("attributes") Map<String, Object> attributes,

150

@JsonProperty("proxyGrantingTicket") String proxyGrantingTicket,

151

@JsonProperty("proxyRetriever") ProxyRetriever proxyRetriever);

152

}

153

```

154

155

## Serialization Support

156

157

The module provides serialization support for the following CAS types:

158

159

- **CasAuthenticationToken**: Complete authentication token with user details and CAS assertion

160

- **AssertionImpl**: CAS server assertion containing authentication details and attributes

161

- **AttributePrincipalImpl**: User principal with attributes from CAS server

162

163

### Usage Example

164

165

```java

166

// Example: Serializing CasAuthenticationToken

167

CasAuthenticationToken token = new CasAuthenticationToken(

168

"cas-key",

169

"username",

170

"ST-123456-abcdef",

171

authorities,

172

userDetails,

173

assertion

174

);

175

176

ObjectMapper mapper = new ObjectMapper();

177

mapper.registerModule(new CasJackson2Module());

178

179

// Serialize to JSON

180

String json = mapper.writeValueAsString(token);

181

182

// Deserialize from JSON

183

CasAuthenticationToken deserializedToken = mapper.readValue(json, CasAuthenticationToken.class);

184

```

185

186

## Configuration Examples

187

188

### Spring Boot Auto-Configuration

189

190

```java

191

@SpringBootApplication

192

public class Application {

193

194

@Bean

195

public Module casJackson2Module() {

196

return new CasJackson2Module();

197

}

198

199

public static void main(String[] args) {

200

SpringApplication.run(Application.class, args);

201

}

202

}

203

```

204

205

### Redis Session Configuration

206

207

```java

208

@Configuration

209

@EnableRedisHttpSession

210

public class RedisSessionConfig {

211

212

@Bean

213

public RedisSerializer<Object> springSessionDefaultRedisSerializer() {

214

ObjectMapper mapper = new ObjectMapper();

215

mapper.registerModule(new CasJackson2Module());

216

mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

217

return new GenericJackson2JsonRedisSerializer(mapper);

218

}

219

}

220

```

221

222

### Hazelcast Session Configuration

223

224

```java

225

@Configuration

226

public class HazelcastSessionConfig {

227

228

@Bean

229

public HazelcastInstance hazelcastInstance() {

230

Config config = new Config();

231

232

// Configure serialization for CAS objects

233

SerializationConfig serializationConfig = config.getSerializationConfig();

234

serializationConfig.addSerializerConfig(

235

new SerializerConfig()

236

.setTypeClass(CasAuthenticationToken.class)

237

.setImplementation(new JsonSerializer())

238

);

239

240

return Hazelcast.newHazelcastInstance(config);

241

}

242

243

public static class JsonSerializer implements StreamSerializer<CasAuthenticationToken> {

244

private final ObjectMapper mapper;

245

246

public JsonSerializer() {

247

this.mapper = new ObjectMapper();

248

this.mapper.registerModule(new CasJackson2Module());

249

}

250

251

@Override

252

public void write(ObjectDataOutput out, CasAuthenticationToken token) throws IOException {

253

String json = mapper.writeValueAsString(token);

254

out.writeUTF(json);

255

}

256

257

@Override

258

public CasAuthenticationToken read(ObjectDataInput in) throws IOException {

259

String json = in.readUTF();

260

return mapper.readValue(json, CasAuthenticationToken.class);

261

}

262

263

@Override

264

public int getTypeId() {

265

return 1;

266

}

267

}

268

}

269

```

270

271

## Session Integration

272

273

### HTTP Session Serialization

274

275

```java

276

@Configuration

277

public class SessionConfig {

278

279

@Bean

280

public HttpSessionIdResolver httpSessionIdResolver() {

281

return HeaderHttpSessionIdResolver.xAuthToken();

282

}

283

284

@Bean

285

public SessionRepository<MapSession> sessionRepository() {

286

MapSessionRepository repository = new MapSessionRepository(new ConcurrentHashMap<>());

287

repository.setDefaultMaxInactiveInterval(Duration.ofMinutes(30));

288

return repository;

289

}

290

291

@Bean

292

public ObjectMapper sessionObjectMapper() {

293

ObjectMapper mapper = new ObjectMapper();

294

mapper.registerModule(new CasJackson2Module());

295

mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

296

return mapper;

297

}

298

}

299

```

300

301

### Security Context Serialization

302

303

```java

304

@Configuration

305

public class SecurityContextConfig {

306

307

@Bean

308

public SecurityContextRepository securityContextRepository() {

309

HttpSessionSecurityContextRepository repository = new HttpSessionSecurityContextRepository();

310

repository.setAllowSessionCreation(true);

311

return repository;

312

}

313

314

@Bean

315

public ObjectMapper securityContextObjectMapper() {

316

ObjectMapper mapper = new ObjectMapper();

317

mapper.registerModule(new CasJackson2Module());

318

mapper.registerModule(new CoreJackson2Module());

319

return mapper;

320

}

321

}

322

```

323

324

## Cache Integration

325

326

### Spring Cache with JSON Serialization

327

328

```java

329

@Configuration

330

@EnableCaching

331

public class CacheConfig {

332

333

@Bean

334

public CacheManager cacheManager() {

335

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()

336

.serializeValuesWith(RedisSerializationContext.SerializationPair

337

.fromSerializer(casRedisSerializer()));

338

339

return RedisCacheManager.builder(redisConnectionFactory())

340

.cacheDefaults(config)

341

.build();

342

}

343

344

@Bean

345

public RedisSerializer<Object> casRedisSerializer() {

346

ObjectMapper mapper = new ObjectMapper();

347

mapper.registerModule(new CasJackson2Module());

348

mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

349

return new GenericJackson2JsonRedisSerializer(mapper);

350

}

351

}

352

```

353

354

## Custom Serialization Configuration

355

356

### Custom Mixin Registration

357

358

```java

359

@Configuration

360

public class CustomJacksonConfig {

361

362

@Bean

363

public ObjectMapper customObjectMapper() {

364

ObjectMapper mapper = new ObjectMapper();

365

366

// Register CAS module

367

mapper.registerModule(new CasJackson2Module());

368

369

// Add custom mixins for additional types

370

mapper.addMixIn(CustomUserDetails.class, CustomUserDetailsMixin.class);

371

372

// Configure additional settings

373

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

374

mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

375

376

return mapper;

377

}

378

379

@JsonIgnoreProperties(ignoreUnknown = true)

380

public static abstract class CustomUserDetailsMixin {

381

@JsonIgnore

382

abstract String getPassword();

383

}

384

}

385

```

386

387

## JSON Structure Examples

388

389

### Serialized CasAuthenticationToken

390

391

```json

392

{

393

"@class": "org.springframework.security.cas.authentication.CasAuthenticationToken",

394

"keyHash": 123456789,

395

"principal": "username",

396

"credentials": "ST-123456-abcdefghijklmnop",

397

"authorities": [

398

{

399

"@class": "org.springframework.security.core.authority.SimpleGrantedAuthority",

400

"authority": "ROLE_USER"

401

}

402

],

403

"userDetails": {

404

"@class": "org.springframework.security.core.userdetails.User",

405

"username": "username",

406

"authorities": [...],

407

"accountNonExpired": true,

408

"accountNonLocked": true,

409

"credentialsNonExpired": true,

410

"enabled": true

411

},

412

"assertion": {

413

"@class": "org.apereo.cas.client.validation.AssertionImpl",

414

"principal": {

415

"@class": "org.apereo.cas.client.authentication.AttributePrincipalImpl",

416

"name": "username",

417

"attributes": {

418

"email": "user@example.com",

419

"role": ["USER", "ADMIN"]

420

}

421

},

422

"validFromDate": "2023-10-01T10:00:00.000+00:00",

423

"validUntilDate": "2023-10-01T10:05:00.000+00:00",

424

"authenticationAttributes": {}

425

},

426

"authenticated": true

427

}

428

```

429

430

## Troubleshooting

431

432

### Common Serialization Issues

433

434

```java

435

// Issue: Circular reference during serialization

436

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

437

public class User implements UserDetails {

438

// ...

439

}

440

441

// Issue: Missing default constructor

442

public class CustomUserDetails implements UserDetails {

443

@JsonCreator

444

public CustomUserDetails(@JsonProperty("username") String username) {

445

this.username = username;

446

}

447

}

448

449

// Issue: Incompatible Jackson versions

450

@Configuration

451

public class JacksonVersionConfig {

452

@Bean

453

public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {

454

return new Jackson2ObjectMapperBuilder()

455

.modules(new CasJackson2Module())

456

.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

457

}

458

}

459

```

460

461

## Security Considerations

462

463

- **Sensitive Data**: Avoid serializing passwords or sensitive credentials

464

- **Type Safety**: Use `@JsonTypeInfo` for secure polymorphic deserialization

465

- **Validation**: Validate deserialized objects before use

466

- **Version Compatibility**: Ensure Jackson version compatibility across services

467

468

## Integration Notes

469

470

- Register module before any CAS authentication occurs

471

- Compatible with Spring Session and Spring Security Context persistence

472

- Supports Redis, Hazelcast, and other distributed cache providers

473

- Required for clustered applications using CAS authentication

474

- Test serialization/deserialization in development environment