0
# User Identity Management
1
2
User identity management in Jetty Security encompasses user principals, roles, identity services, and the association of security contexts with execution threads.
3
4
## Core Identity Interfaces
5
6
### UserIdentity
7
8
Central interface representing an authenticated user:
9
10
```java { .api }
11
public interface UserIdentity {
12
13
// Core identity access
14
Subject getSubject();
15
Principal getUserPrincipal();
16
17
// Role checking
18
boolean isUserInRole(String role);
19
20
// Static factory methods
21
static UserIdentity from(Subject subject, Principal userPrincipal, String... roles);
22
}
23
```
24
25
### UserIdentity Implementation
26
27
```java { .api }
28
public class UserIdentityExample {
29
30
public void createUserIdentity() {
31
32
// Create subject for user
33
Subject subject = new Subject();
34
35
// Create user principal
36
UserPrincipal userPrincipal = new UserPrincipal("john",
37
Credential.getCredential("password123"));
38
39
// Create user identity with roles
40
UserIdentity identity = UserIdentity.from(subject, userPrincipal,
41
"user", "developer", "api-access");
42
43
// Role checking
44
boolean canAccess = identity.isUserInRole("developer");
45
boolean isAdmin = identity.isUserInRole("admin");
46
47
// Access underlying components
48
Subject userSubject = identity.getSubject();
49
Principal principal = identity.getUserPrincipal();
50
}
51
}
52
```
53
54
## Identity Service
55
56
### IdentityService Interface
57
58
Manages associations between user identities and execution threads:
59
60
```java { .api }
61
public interface IdentityService {
62
63
// Thread association
64
Association associate(UserIdentity user, RunAsToken runAsToken);
65
66
// User lifecycle
67
void onLogout(UserIdentity user);
68
69
// Factory methods
70
UserIdentity newUserIdentity(Subject subject, Principal userPrincipal, String[] roles);
71
RunAsToken newRunAsToken(String roleName);
72
73
// System user access
74
UserIdentity getSystemUserIdentity();
75
76
// Nested interfaces
77
interface Association extends AutoCloseable {
78
@Override
79
void close();
80
}
81
82
interface RunAsToken {
83
// Opaque token for run-as operations
84
}
85
}
86
```
87
88
### DefaultIdentityService
89
90
Default implementation of IdentityService:
91
92
```java { .api }
93
public class DefaultIdentityService implements IdentityService {
94
95
@Override
96
public Association associate(UserIdentity user, RunAsToken runAsToken) {
97
98
// Associate user identity with current thread
99
return new AssociationImpl(user, runAsToken);
100
}
101
102
@Override
103
public void onLogout(UserIdentity user) {
104
// Clear any thread associations for this user
105
clearThreadAssociations(user);
106
}
107
108
@Override
109
public UserIdentity newUserIdentity(Subject subject, Principal userPrincipal, String[] roles) {
110
111
// Create DefaultUserIdentity with provided components
112
return new DefaultUserIdentity(subject, userPrincipal, roles);
113
}
114
115
@Override
116
public RunAsToken newRunAsToken(String roleName) {
117
118
// Create run-as token for the specified role
119
return new RoleRunAsToken(roleName);
120
}
121
122
@Override
123
public UserIdentity getSystemUserIdentity() {
124
125
// Return null - no system user by default
126
return null;
127
}
128
129
// Static utility methods
130
public static boolean isRoleAssociated(String role);
131
132
// Private implementation classes
133
private static class AssociationImpl implements Association {
134
// Implementation details
135
}
136
}
137
```
138
139
## User Principals
140
141
### UserPrincipal
142
143
Represents a user with authentication capabilities:
144
145
```java { .api }
146
public class UserPrincipal implements Principal {
147
148
// Constructor
149
public UserPrincipal(String name, Credential credential);
150
151
@Override
152
public String getName();
153
154
// Authentication methods
155
public boolean authenticate(Object credentials);
156
public boolean authenticate(Credential c);
157
public boolean authenticate(UserPrincipal u);
158
159
// Subject integration
160
public void configureSubject(Subject subject);
161
public void deconfigureSubject(Subject subject);
162
163
// Utility methods
164
@Override
165
public boolean equals(Object other);
166
167
@Override
168
public int hashCode();
169
170
@Override
171
public String toString();
172
}
173
```
174
175
### UserPrincipal Usage
176
177
```java { .api }
178
public class UserPrincipalExample {
179
180
public void createAndUseUserPrincipal() {
181
182
// Create user principal with password
183
Credential password = Credential.getCredential("secretPassword");
184
UserPrincipal user = new UserPrincipal("alice", password);
185
186
// Test authentication
187
boolean validPassword = user.authenticate("secretPassword");
188
boolean invalidPassword = user.authenticate("wrongPassword");
189
190
// Test credential object authentication
191
Credential testCred = Credential.getCredential("secretPassword");
192
boolean credValid = user.authenticate(testCred);
193
194
// Test user-to-user authentication
195
UserPrincipal sameUser = new UserPrincipal("alice", password);
196
boolean sameUserAuth = user.authenticate(sameUser);
197
198
// Configure subject
199
Subject subject = new Subject();
200
user.configureSubject(subject);
201
202
// Subject now contains the user principal
203
Set<Principal> principals = subject.getPrincipals();
204
boolean containsUser = principals.contains(user);
205
}
206
207
public void createUserWithHashedPassword() {
208
209
// Create user with MD5 hashed password
210
Credential md5Cred = Credential.getCredential("MD5:5d41402abc4b2a76b9719d911017c592");
211
UserPrincipal user = new UserPrincipal("bob", md5Cred);
212
213
// Authenticate with plain text (will be hashed for comparison)
214
boolean authenticated = user.authenticate("hello");
215
216
// Create user with crypt password
217
Credential cryptCred = Credential.getCredential("CRYPT:$1$salt$hash");
218
UserPrincipal cryptUser = new UserPrincipal("charlie", cryptCred);
219
}
220
}
221
```
222
223
## Credential Management
224
225
### Credential
226
227
Utility class for secure credential handling and password storage:
228
229
```java { .api }
230
public abstract class Credential {
231
232
// Factory method for creating credentials
233
public static Credential getCredential(String credential);
234
235
// Credential verification
236
public abstract boolean check(Object credentials);
237
238
// Common credential types supported:
239
// - Plain text passwords: "password123"
240
// - MD5 hashed: "MD5:5d41402abc4b2a76b9719d911017c592"
241
// - Crypt hashed: "CRYPT:$1$salt$hash"
242
// - BCrypt hashed: "$2y$10$..."
243
}
244
```
245
246
The Credential class provides secure password storage and verification. It automatically detects the credential type and applies appropriate hashing and verification algorithms.
247
248
## Role Principals
249
250
### RolePrincipal
251
252
Represents a role that can be associated with subjects:
253
254
```java { .api }
255
public class RolePrincipal implements Principal {
256
257
// Constructor
258
public RolePrincipal(String name);
259
260
@Override
261
public String getName();
262
263
// Subject integration
264
public void configureSubject(Subject subject);
265
public void deconfigureSubject(Subject subject);
266
267
@Override
268
public boolean equals(Object other);
269
270
@Override
271
public int hashCode();
272
273
@Override
274
public String toString();
275
}
276
```
277
278
### Role Management
279
280
```java { .api }
281
public class RoleManagementExample {
282
283
public void manageUserRoles() {
284
285
// Create user
286
UserPrincipal user = new UserPrincipal("manager",
287
Credential.getCredential("password"));
288
289
// Create roles
290
RolePrincipal userRole = new RolePrincipal("user");
291
RolePrincipal managerRole = new RolePrincipal("manager");
292
RolePrincipal adminRole = new RolePrincipal("admin");
293
294
// Create subject and configure
295
Subject subject = new Subject();
296
user.configureSubject(subject);
297
userRole.configureSubject(subject);
298
managerRole.configureSubject(subject);
299
300
// Create user identity
301
IdentityService identityService = new DefaultIdentityService();
302
UserIdentity identity = identityService.newUserIdentity(subject, user,
303
new String[]{"user", "manager"});
304
305
// Check roles
306
boolean isUser = identity.isUserInRole("user"); // true
307
boolean isManager = identity.isUserInRole("manager"); // true
308
boolean isAdmin = identity.isUserInRole("admin"); // false
309
}
310
311
public void createHierarchicalRoles() {
312
313
// Create role hierarchy
314
Map<String, Set<String>> roleHierarchy = new HashMap<>();
315
roleHierarchy.put("admin", Set.of("admin", "manager", "user"));
316
roleHierarchy.put("manager", Set.of("manager", "user"));
317
roleHierarchy.put("user", Set.of("user"));
318
319
// Custom identity service with role hierarchy
320
IdentityService hierarchicalService = new HierarchicalIdentityService(roleHierarchy);
321
322
// User with only "manager" role
323
UserPrincipal user = new UserPrincipal("supervisor",
324
Credential.getCredential("password"));
325
Subject subject = new Subject();
326
user.configureSubject(subject);
327
328
UserIdentity identity = hierarchicalService.newUserIdentity(subject, user,
329
new String[]{"manager"});
330
331
// Manager can act as user due to hierarchy
332
boolean canActAsUser = identity.isUserInRole("user"); // true
333
boolean canActAsManager = identity.isUserInRole("manager"); // true
334
boolean canActAsAdmin = identity.isUserInRole("admin"); // false
335
}
336
337
// Custom identity service with role hierarchy
338
private static class HierarchicalIdentityService extends DefaultIdentityService {
339
private final Map<String, Set<String>> roleHierarchy;
340
341
public HierarchicalIdentityService(Map<String, Set<String>> roleHierarchy) {
342
this.roleHierarchy = roleHierarchy;
343
}
344
345
@Override
346
public UserIdentity newUserIdentity(Subject subject, Principal userPrincipal, String[] roles) {
347
348
// Expand roles based on hierarchy
349
Set<String> expandedRoles = new HashSet<>();
350
for (String role : roles) {
351
Set<String> impliedRoles = roleHierarchy.get(role);
352
if (impliedRoles != null) {
353
expandedRoles.addAll(impliedRoles);
354
} else {
355
expandedRoles.add(role);
356
}
357
}
358
359
return super.newUserIdentity(subject, userPrincipal,
360
expandedRoles.toArray(new String[0]));
361
}
362
}
363
}
364
```
365
366
## Identity Association and RunAs
367
368
### Thread Association
369
370
```java { .api }
371
public class ThreadAssociationExample {
372
373
public void demonstrateThreadAssociation() {
374
375
IdentityService identityService = new DefaultIdentityService();
376
377
// Create user identity
378
UserPrincipal user = new UserPrincipal("worker",
379
Credential.getCredential("password"));
380
Subject subject = new Subject();
381
UserIdentity identity = identityService.newUserIdentity(subject, user,
382
new String[]{"worker", "api-user"});
383
384
// Associate with current thread
385
try (IdentityService.Association association =
386
identityService.associate(identity, null)) {
387
388
// Code in this block runs with user identity
389
performSecureOperation();
390
391
// Association is automatically cleaned up when block exits
392
}
393
394
// User identity is no longer associated with thread
395
}
396
397
public void demonstrateRunAs() {
398
399
IdentityService identityService = new DefaultIdentityService();
400
401
// Create regular user
402
UserIdentity regularUser = createUserIdentity("john", "user");
403
404
// Create run-as token for admin role
405
IdentityService.RunAsToken adminToken = identityService.newRunAsToken("admin");
406
407
// Associate regular user but run as admin
408
try (IdentityService.Association association =
409
identityService.associate(regularUser, adminToken)) {
410
411
// Check if admin role is associated with thread
412
boolean isAdmin = DefaultIdentityService.isRoleAssociated("admin");
413
414
// Perform admin operations
415
performAdminOperation();
416
}
417
}
418
419
public void demonstrateNestedAssociations() {
420
421
IdentityService identityService = new DefaultIdentityService();
422
423
UserIdentity user1 = createUserIdentity("alice", "user");
424
UserIdentity user2 = createUserIdentity("bob", "manager");
425
426
try (IdentityService.Association outer = identityService.associate(user1, null)) {
427
428
// Outer context: alice as user
429
performUserOperation();
430
431
try (IdentityService.Association inner = identityService.associate(user2, null)) {
432
433
// Inner context: bob as manager
434
performManagerOperation();
435
436
} // bob's association ends
437
438
// Back to alice's context
439
performUserOperation();
440
441
} // alice's association ends
442
}
443
444
private UserIdentity createUserIdentity(String name, String role) {
445
IdentityService identityService = new DefaultIdentityService();
446
UserPrincipal user = new UserPrincipal(name, Credential.getCredential("password"));
447
Subject subject = new Subject();
448
return identityService.newUserIdentity(subject, user, new String[]{role});
449
}
450
451
private void performSecureOperation() {
452
// Implementation
453
}
454
455
private void performAdminOperation() {
456
// Implementation requiring admin privileges
457
}
458
459
private void performUserOperation() {
460
// Implementation for regular users
461
}
462
463
private void performManagerOperation() {
464
// Implementation for managers
465
}
466
}
467
```
468
469
## RoleDelegateUserIdentity
470
471
### Delegated Role Checking
472
473
```java { .api }
474
public class RoleDelegateUserIdentity implements UserIdentity {
475
476
private final UserIdentity delegate;
477
private final Subject subject;
478
private final Principal userPrincipal;
479
480
// Constructor
481
public RoleDelegateUserIdentity(UserIdentity delegate, Subject subject, Principal userPrincipal);
482
483
@Override
484
public Subject getSubject() {
485
return subject;
486
}
487
488
@Override
489
public Principal getUserPrincipal() {
490
return userPrincipal;
491
}
492
493
@Override
494
public boolean isUserInRole(String role) {
495
496
// Delegate role checking to another UserIdentity
497
return delegate.isUserInRole(role);
498
}
499
}
500
```
501
502
### Role Delegation Usage
503
504
```java { .api }
505
public class RoleDelegationExample {
506
507
public void demonstrateRoleDelegation() {
508
509
// Create primary user identity with roles
510
UserPrincipal primaryUser = new UserPrincipal("primary",
511
Credential.getCredential("password"));
512
Subject primarySubject = new Subject();
513
IdentityService identityService = new DefaultIdentityService();
514
UserIdentity primaryIdentity = identityService.newUserIdentity(primarySubject,
515
primaryUser, new String[]{"admin", "manager", "user"});
516
517
// Create secondary user with different principal but same role checking
518
UserPrincipal secondaryUser = new UserPrincipal("secondary",
519
Credential.getCredential("password"));
520
Subject secondarySubject = new Subject();
521
522
// Create role delegate identity
523
RoleDelegateUserIdentity delegateIdentity = new RoleDelegateUserIdentity(
524
primaryIdentity, // Delegate role checking to primary
525
secondarySubject, // But use secondary subject
526
secondaryUser // And secondary principal
527
);
528
529
// Identity has secondary user's principal
530
String name = delegateIdentity.getUserPrincipal().getName(); // "secondary"
531
532
// But role checking is delegated to primary user
533
boolean isAdmin = delegateIdentity.isUserInRole("admin"); // true (from primary)
534
boolean isManager = delegateIdentity.isUserInRole("manager"); // true (from primary)
535
}
536
537
public void createServiceAccountWithUserRoles() {
538
539
// Create service account identity
540
UserPrincipal serviceAccount = new UserPrincipal("api-service",
541
Credential.getCredential("service-key"));
542
Subject serviceSubject = new Subject();
543
544
// Get user identity to delegate roles from
545
UserIdentity userIdentity = getCurrentUserIdentity(); // Assume this returns current user
546
547
// Create service account that inherits user's roles
548
RoleDelegateUserIdentity serviceIdentity = new RoleDelegateUserIdentity(
549
userIdentity, // Delegate to current user's roles
550
serviceSubject, // Service account subject
551
serviceAccount // Service account principal
552
);
553
554
// Service account can perform operations with user's roles
555
try (IdentityService.Association association =
556
new DefaultIdentityService().associate(serviceIdentity, null)) {
557
558
performServiceOperation();
559
}
560
}
561
562
private UserIdentity getCurrentUserIdentity() {
563
// Implementation to get current user identity
564
return null;
565
}
566
567
private void performServiceOperation() {
568
// Service operation that requires user's roles
569
}
570
}
571
```
572
573
## User Store Integration
574
575
### UserStore Interface
576
577
```java { .api }
578
public interface UserStore {
579
580
// User retrieval
581
UserPrincipal getUserPrincipal(String username);
582
List<RolePrincipal> getRolePrincipals(String username);
583
584
// User management (optional)
585
default void addUser(String username, Credential credential, String[] roles) {
586
throw new UnsupportedOperationException();
587
}
588
589
default void removeUser(String username) {
590
throw new UnsupportedOperationException();
591
}
592
593
default void updateUser(String username, Credential credential, String[] roles) {
594
throw new UnsupportedOperationException();
595
}
596
}
597
```
598
599
### Custom Identity Management
600
601
```java { .api }
602
public class CustomIdentityManager {
603
604
private final IdentityService identityService;
605
private final UserStore userStore;
606
607
public CustomIdentityManager(IdentityService identityService, UserStore userStore) {
608
this.identityService = identityService;
609
this.userStore = userStore;
610
}
611
612
public UserIdentity authenticateUser(String username, String password) {
613
614
// Get user principal from store
615
UserPrincipal userPrincipal = userStore.getUserPrincipal(username);
616
if (userPrincipal == null) {
617
return null;
618
}
619
620
// Authenticate credentials
621
if (!userPrincipal.authenticate(password)) {
622
return null;
623
}
624
625
// Get user roles
626
List<RolePrincipal> rolePrincipals = userStore.getRolePrincipals(username);
627
String[] roles = rolePrincipals.stream()
628
.map(RolePrincipal::getName)
629
.toArray(String[]::new);
630
631
// Create subject and configure
632
Subject subject = new Subject();
633
userPrincipal.configureSubject(subject);
634
for (RolePrincipal role : rolePrincipals) {
635
role.configureSubject(subject);
636
}
637
638
// Create user identity
639
return identityService.newUserIdentity(subject, userPrincipal, roles);
640
}
641
642
public boolean addUser(String username, String password, String... roles) {
643
644
try {
645
// Create credential
646
Credential credential = Credential.getCredential(password);
647
648
// Add to user store
649
userStore.addUser(username, credential, roles);
650
651
return true;
652
653
} catch (Exception e) {
654
logger.error("Failed to add user: " + username, e);
655
return false;
656
}
657
}
658
659
public boolean updateUserRoles(String username, String... newRoles) {
660
661
try {
662
// Get existing user
663
UserPrincipal existing = userStore.getUserPrincipal(username);
664
if (existing == null) {
665
return false;
666
}
667
668
// Update with new roles (keeping same credential)
669
userStore.updateUser(username, existing.getCredential(), newRoles);
670
671
return true;
672
673
} catch (Exception e) {
674
logger.error("Failed to update user roles: " + username, e);
675
return false;
676
}
677
}
678
679
public void logoutUser(UserIdentity user) {
680
681
// Notify identity service of logout
682
identityService.onLogout(user);
683
684
// Additional cleanup if needed
685
performLogoutCleanup(user);
686
}
687
688
private void performLogoutCleanup(UserIdentity user) {
689
// Custom logout cleanup logic
690
}
691
}
692
```
693
694
## Advanced Identity Patterns
695
696
### Composite Identity Service
697
698
```java { .api }
699
public class CompositeIdentityService implements IdentityService {
700
701
private final List<IdentityService> delegates;
702
703
public CompositeIdentityService(IdentityService... delegates) {
704
this.delegates = Arrays.asList(delegates);
705
}
706
707
@Override
708
public Association associate(UserIdentity user, RunAsToken runAsToken) {
709
710
// Associate with all delegates
711
List<Association> associations = delegates.stream()
712
.map(service -> service.associate(user, runAsToken))
713
.collect(Collectors.toList());
714
715
return new CompositeAssociation(associations);
716
}
717
718
@Override
719
public UserIdentity newUserIdentity(Subject subject, Principal userPrincipal, String[] roles) {
720
721
// Use first delegate for identity creation
722
return delegates.get(0).newUserIdentity(subject, userPrincipal, roles);
723
}
724
725
@Override
726
public void onLogout(UserIdentity user) {
727
728
// Notify all delegates
729
delegates.forEach(service -> service.onLogout(user));
730
}
731
732
@Override
733
public RunAsToken newRunAsToken(String roleName) {
734
735
// Create composite run-as token
736
List<RunAsToken> tokens = delegates.stream()
737
.map(service -> service.newRunAsToken(roleName))
738
.collect(Collectors.toList());
739
740
return new CompositeRunAsToken(tokens);
741
}
742
743
@Override
744
public UserIdentity getSystemUserIdentity() {
745
746
// Return system user from first delegate that has one
747
return delegates.stream()
748
.map(IdentityService::getSystemUserIdentity)
749
.filter(Objects::nonNull)
750
.findFirst()
751
.orElse(null);
752
}
753
754
private static class CompositeAssociation implements Association {
755
private final List<Association> associations;
756
757
public CompositeAssociation(List<Association> associations) {
758
this.associations = associations;
759
}
760
761
@Override
762
public void close() {
763
associations.forEach(Association::close);
764
}
765
}
766
767
private static class CompositeRunAsToken implements RunAsToken {
768
private final List<RunAsToken> tokens;
769
770
public CompositeRunAsToken(List<RunAsToken> tokens) {
771
this.tokens = tokens;
772
}
773
}
774
}
775
```
776
777
### Caching Identity Service
778
779
```java { .api }
780
public class CachingIdentityService implements IdentityService {
781
782
private final IdentityService delegate;
783
private final Cache<String, UserIdentity> identityCache;
784
785
public CachingIdentityService(IdentityService delegate, Duration cacheTTL) {
786
this.delegate = delegate;
787
this.identityCache = Caffeine.newBuilder()
788
.maximumSize(1000)
789
.expireAfterWrite(cacheTTL)
790
.build();
791
}
792
793
@Override
794
public UserIdentity newUserIdentity(Subject subject, Principal userPrincipal, String[] roles) {
795
796
String cacheKey = buildCacheKey(userPrincipal, roles);
797
798
return identityCache.get(cacheKey, key ->
799
delegate.newUserIdentity(subject, userPrincipal, roles));
800
}
801
802
@Override
803
public Association associate(UserIdentity user, RunAsToken runAsToken) {
804
return delegate.associate(user, runAsToken);
805
}
806
807
@Override
808
public void onLogout(UserIdentity user) {
809
810
// Invalidate cache entries for this user
811
String username = user.getUserPrincipal().getName();
812
identityCache.asMap().entrySet().removeIf(entry ->
813
entry.getKey().startsWith(username + ":"));
814
815
delegate.onLogout(user);
816
}
817
818
@Override
819
public RunAsToken newRunAsToken(String roleName) {
820
return delegate.newRunAsToken(roleName);
821
}
822
823
@Override
824
public UserIdentity getSystemUserIdentity() {
825
return delegate.getSystemUserIdentity();
826
}
827
828
private String buildCacheKey(Principal userPrincipal, String[] roles) {
829
return userPrincipal.getName() + ":" + Arrays.toString(roles);
830
}
831
}
832
```
833
834
## Best Practices
835
836
### Identity Management Best Practices
837
838
```java { .api }
839
public class IdentityBestPractices {
840
841
public void configureProductionIdentityService() {
842
843
// Use caching for performance
844
IdentityService baseService = new DefaultIdentityService();
845
IdentityService cachingService = new CachingIdentityService(baseService, Duration.ofMinutes(15));
846
847
// Create secure user store
848
UserStore secureStore = createSecureUserStore();
849
850
// Configure identity manager
851
CustomIdentityManager identityManager = new CustomIdentityManager(cachingService, secureStore);
852
853
// Use with security handler
854
SecurityHandler security = new SecurityHandler.PathMapped();
855
security.setIdentityService(cachingService);
856
}
857
858
private UserStore createSecureUserStore() {
859
860
// Use property store with secure defaults
861
PropertyUserStore store = new PropertyUserStore();
862
store.setConfig(Resource.newResource("secure-users.properties"));
863
store.setReloadInterval(300); // 5 minutes
864
865
return store;
866
}
867
868
public void demonstrateSecureIdentityCreation() {
869
870
IdentityService identityService = new DefaultIdentityService();
871
872
// Create user with strong password
873
String strongPassword = generateStrongPassword();
874
UserPrincipal user = new UserPrincipal("alice",
875
Credential.getCredential(strongPassword));
876
877
// Create subject with proper configuration
878
Subject subject = new Subject();
879
user.configureSubject(subject);
880
881
// Add role principals to subject
882
RolePrincipal userRole = new RolePrincipal("user");
883
RolePrincipal appRole = new RolePrincipal("app-user");
884
userRole.configureSubject(subject);
885
appRole.configureSubject(subject);
886
887
// Create identity with minimal necessary roles
888
UserIdentity identity = identityService.newUserIdentity(subject, user,
889
new String[]{"user", "app-user"});
890
891
// Always use try-with-resources for associations
892
try (IdentityService.Association association =
893
identityService.associate(identity, null)) {
894
895
performUserOperation();
896
}
897
}
898
899
private String generateStrongPassword() {
900
// Implementation to generate cryptographically strong password
901
return "StrongPassword123!";
902
}
903
904
private void performUserOperation() {
905
// Implementation
906
}
907
}
908
```
909
910
User Identity Management provides comprehensive support for user principals, roles, thread associations, and secure identity contexts, enabling fine-grained access control and secure execution environments.