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

user-details.mddocs/

0

# User Details

1

2

Specialized user details services for extracting user information and authorities from CAS assertions. These services integrate CAS user attributes with Spring Security's user details framework to populate user authorities and profile information.

3

4

## Capabilities

5

6

### Abstract CAS Assertion User Details Service

7

8

Base class for implementing user details services that load user information from CAS assertions rather than traditional username lookup.

9

10

```java { .api }

11

/**

12

* Base class for user details services that construct UserDetails from CAS assertions.

13

* Provides framework for loading user information from CAS assertion attributes.

14

*/

15

public abstract class AbstractCasAssertionUserDetailsService

16

implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {

17

18

/**

19

* Loads user details from CAS assertion authentication token.

20

* This method is final and delegates to the abstract loadUserDetails(Assertion) method.

21

* @param token authentication token containing CAS assertion

22

* @return UserDetails populated from CAS assertion

23

*/

24

public final UserDetails loadUserDetails(CasAssertionAuthenticationToken token);

25

26

/**

27

* Loads user details from CAS assertion.

28

* Implementations should extract user information and authorities from the assertion.

29

* @param assertion CAS assertion containing user attributes

30

* @return UserDetails object populated from assertion

31

*/

32

protected abstract UserDetails loadUserDetails(Assertion assertion);

33

}

34

```

35

36

### Granted Authority from Assertion Attributes User Details Service

37

38

Concrete implementation that creates user authorities from specific CAS assertion attributes.

39

40

```java { .api }

41

/**

42

* User details service that extracts granted authorities from specified CAS assertion attributes.

43

* Creates GrantedAuthority objects from assertion attribute values.

44

*/

45

public final class GrantedAuthorityFromAssertionAttributesUserDetailsService

46

extends AbstractCasAssertionUserDetailsService {

47

48

/**

49

* Creates service that extracts authorities from specified assertion attributes.

50

* @param attributes array of assertion attribute names to use for authorities

51

* @throws IllegalArgumentException if attributes array is null or empty

52

*/

53

public GrantedAuthorityFromAssertionAttributesUserDetailsService(String[] attributes);

54

55

/**

56

* Sets whether to convert attribute values to uppercase before creating authorities.

57

* Useful for normalizing role names (e.g., "admin" becomes "ADMIN").

58

* @param convertToUpperCase true to convert authorities to uppercase

59

*/

60

public void setConvertToUpperCase(boolean convertToUpperCase);

61

62

/**

63

* Loads user details from CAS assertion by extracting authorities from configured attributes.

64

* @param assertion CAS assertion containing user attributes

65

* @return UserDetails with authorities populated from assertion attributes

66

*/

67

protected UserDetails loadUserDetails(Assertion assertion);

68

}

69

```

70

71

**Usage Example:**

72

73

```java

74

@Bean

75

public GrantedAuthorityFromAssertionAttributesUserDetailsService casUserDetailsService() {

76

String[] attributes = {"role", "group", "department"};

77

GrantedAuthorityFromAssertionAttributesUserDetailsService service =

78

new GrantedAuthorityFromAssertionAttributesUserDetailsService(attributes);

79

service.setConvertToUpperCase(true);

80

return service;

81

}

82

```

83

84

## Custom User Details Service Implementation

85

86

Example of creating a custom user details service that extends the abstract base:

87

88

```java

89

public class CustomCasUserDetailsService extends AbstractCasAssertionUserDetailsService {

90

91

private UserRepository userRepository;

92

93

public CustomCasUserDetailsService(UserRepository userRepository) {

94

this.userRepository = userRepository;

95

}

96

97

@Override

98

protected UserDetails loadUserDetails(Assertion assertion) {

99

String username = assertion.getPrincipal().getName();

100

Map<String, Object> attributes = assertion.getPrincipal().getAttributes();

101

102

// Load user from database

103

User user = userRepository.findByUsername(username);

104

if (user == null) {

105

// Handle user not found - could return a default user or throw a runtime exception

106

throw new IllegalStateException("User not found: " + username);

107

}

108

109

// Extract roles from CAS attributes

110

List<String> roles = (List<String>) attributes.get("roles");

111

List<GrantedAuthority> authorities = roles.stream()

112

.map(role -> new SimpleGrantedAuthority("ROLE_" + role.toUpperCase()))

113

.collect(Collectors.toList());

114

115

// Create UserDetails with additional attributes

116

return User.builder()

117

.username(username)

118

.password("") // Password not needed for CAS

119

.authorities(authorities)

120

.accountNonExpired(true)

121

.accountNonLocked(true)

122

.credentialsNonExpired(true)

123

.disabled(false)

124

.build();

125

}

126

}

127

```

128

129

## Configuration Examples

130

131

### Basic Attribute-Based Authorities

132

133

```java

134

@Configuration

135

public class CasUserDetailsConfig {

136

137

@Bean

138

public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUserDetailsService() {

139

// Extract authorities from 'role' attribute

140

String[] attributes = {"role"};

141

GrantedAuthorityFromAssertionAttributesUserDetailsService service =

142

new GrantedAuthorityFromAssertionAttributesUserDetailsService(attributes);

143

service.setConvertToUpperCase(true);

144

return service;

145

}

146

147

@Bean

148

public CasAuthenticationProvider casAuthenticationProvider() {

149

CasAuthenticationProvider provider = new CasAuthenticationProvider();

150

provider.setServiceProperties(serviceProperties());

151

provider.setTicketValidator(ticketValidator());

152

provider.setAuthenticationUserDetailsService(casUserDetailsService());

153

provider.setKey("cas-authentication-provider");

154

return provider;

155

}

156

}

157

```

158

159

### Multiple Attribute Sources

160

161

```java

162

@Bean

163

public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> multiAttributeUserDetailsService() {

164

// Extract authorities from multiple attributes

165

String[] attributes = {"role", "group", "department", "permission"};

166

GrantedAuthorityFromAssertionAttributesUserDetailsService service =

167

new GrantedAuthorityFromAssertionAttributesUserDetailsService(attributes);

168

service.setConvertToUpperCase(true);

169

return service;

170

}

171

```

172

173

### Hybrid Approach with UserDetailsService

174

175

```java

176

@Configuration

177

public class HybridUserDetailsConfig {

178

179

@Bean

180

public CasAuthenticationProvider casAuthenticationProvider() {

181

CasAuthenticationProvider provider = new CasAuthenticationProvider();

182

provider.setServiceProperties(serviceProperties());

183

provider.setTicketValidator(ticketValidator());

184

185

// Use traditional UserDetailsService for basic user loading

186

provider.setUserDetailsService(userDetailsService());

187

188

// Also set assertion-based service for additional attributes

189

provider.setAuthenticationUserDetailsService(casAssertionUserDetailsService());

190

191

provider.setKey("cas-authentication-provider");

192

return provider;

193

}

194

195

@Bean

196

public UserDetailsService userDetailsService() {

197

return new CustomUserDetailsService(); // Your existing implementation

198

}

199

200

@Bean

201

public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casAssertionUserDetailsService() {

202

String[] attributes = {"additionalRole"};

203

return new GrantedAuthorityFromAssertionAttributesUserDetailsService(attributes);

204

}

205

}

206

```

207

208

## CAS Assertion Structure

209

210

CAS assertions typically contain:

211

212

```java

213

// Example CAS assertion structure

214

Assertion assertion = ...;

215

216

// Principal information

217

AttributePrincipal principal = assertion.getPrincipal();

218

String username = principal.getName(); // Primary identifier

219

220

// User attributes from CAS server

221

Map<String, Object> attributes = principal.getAttributes();

222

List<String> roles = (List<String>) attributes.get("role");

223

String email = (String) attributes.get("email");

224

String fullName = (String) attributes.get("displayName");

225

String department = (String) attributes.get("department");

226

227

// Authentication metadata

228

Date validFromDate = assertion.getValidFromDate();

229

Date validUntilDate = assertion.getValidUntilDate();

230

Map<String, Object> authenticationAttributes = assertion.getAuthenticationAttributes();

231

```

232

233

## Authority Mapping Strategies

234

235

### Simple Role Mapping

236

237

```java

238

// CAS attribute: role = ["admin", "user"]

239

// Result: [ROLE_ADMIN, ROLE_USER] (if convertToUpperCase = true)

240

```

241

242

### Prefix-Based Mapping

243

244

```java

245

public class PrefixedAuthorityUserDetailsService extends AbstractCasAssertionUserDetailsService {

246

247

@Override

248

protected UserDetails loadUserDetails(Assertion assertion) {

249

String username = assertion.getPrincipal().getName();

250

Map<String, Object> attributes = assertion.getPrincipal().getAttributes();

251

252

List<GrantedAuthority> authorities = new ArrayList<>();

253

254

// Add role-based authorities

255

List<String> roles = (List<String>) attributes.get("role");

256

if (roles != null) {

257

roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase())));

258

}

259

260

// Add permission-based authorities

261

List<String> permissions = (List<String>) attributes.get("permission");

262

if (permissions != null) {

263

permissions.forEach(perm -> authorities.add(new SimpleGrantedAuthority("PERM_" + perm.toUpperCase())));

264

}

265

266

return new User(username, "", authorities);

267

}

268

}

269

```

270

271

## Integration Notes

272

273

- **Attribute Configuration**: CAS server must be configured to release required attributes

274

- **Authority Mapping**: Plan authority structure to align with Spring Security's role-based access control

275

- **Performance**: Consider caching user details if assertion processing is expensive

276

- **Fallback Strategy**: Implement fallback when required attributes are missing

277

- **Testing**: Test with various assertion structures and attribute combinations