1 package org
.argeo
.cms
.auth
;
3 import java
.security
.AccessController
;
4 import java
.security
.Principal
;
5 import java
.security
.PrivilegedAction
;
6 import java
.security
.PrivilegedActionException
;
7 import java
.security
.PrivilegedExceptionAction
;
8 import java
.util
.HashSet
;
9 import java
.util
.Iterator
;
10 import java
.util
.Locale
;
12 import java
.util
.UUID
;
13 import java
.util
.concurrent
.Callable
;
14 import java
.util
.concurrent
.CompletionException
;
16 import javax
.security
.auth
.Subject
;
17 import javax
.security
.auth
.x500
.X500Principal
;
19 import org
.argeo
.api
.cms
.CmsConstants
;
20 import org
.argeo
.api
.cms
.CmsSession
;
21 import org
.argeo
.api
.cms
.CmsSessionId
;
22 import org
.argeo
.cms
.internal
.auth
.CmsSessionImpl
;
23 import org
.argeo
.cms
.internal
.auth
.ImpliedByPrincipal
;
24 import org
.argeo
.cms
.internal
.runtime
.CmsContextImpl
;
25 import org
.osgi
.service
.useradmin
.Authorization
;
28 * Programmatic access to the currently authenticated user, within a CMS
31 public final class CurrentUser
{
37 * Technical username of the currently authenticated user.
39 * @return the authenticated username or null if not authenticated / anonymous
41 public static String
getUsername() {
42 return getUsername(currentSubject());
46 * Human readable name of the currently authenticated user (typically first name
49 public static String
getDisplayName() {
50 return getDisplayName(currentSubject());
53 /** Whether a user is currently authenticated. */
54 public static boolean isAnonymous() {
55 return isAnonymous(currentSubject());
58 /** Locale of the current user */
59 public final static Locale
locale() {
60 return locale(currentSubject());
63 /** Roles of the currently logged-in user */
64 public final static Set
<String
> roles() {
65 return roles(currentSubject());
68 /** Returns true if the current user is in the specified role */
69 public static boolean isInRole(String role
) {
70 Set
<String
> roles
= roles();
71 return roles
.contains(role
);
74 /** Implies this {@link SystemRole} in this context. */
75 public final static boolean implies(SystemRole role
, String context
) {
76 return role
.implied(currentSubject(), context
);
79 /** Executes as the current user */
80 public final static <T
> T
doAs(PrivilegedAction
<T
> action
) {
81 return Subject
.doAs(currentSubject(), action
);
84 /** Executes as the current user */
85 public final static <T
> T
tryAs(PrivilegedExceptionAction
<T
> action
) throws PrivilegedActionException
{
86 return Subject
.doAs(currentSubject(), action
);
93 public final static String
getUsername(Subject subject
) {
95 throw new IllegalArgumentException("Subject cannot be null");
96 if (subject
.getPrincipals(X500Principal
.class).size() != 1)
97 return CmsConstants
.ROLE_ANONYMOUS
;
98 Principal principal
= subject
.getPrincipals(X500Principal
.class).iterator().next();
99 return principal
.getName();
102 public final static String
getDisplayName(Subject subject
) {
103 return getAuthorization(subject
).toString();
106 public final static Set
<String
> roles(Subject subject
) {
107 Set
<String
> roles
= new HashSet
<String
>();
108 roles
.add(getUsername(subject
));
109 for (Principal group
: subject
.getPrincipals(ImpliedByPrincipal
.class)) {
110 roles
.add(group
.getName());
115 public final static Locale
locale(Subject subject
) {
116 Set
<Locale
> locales
= subject
.getPublicCredentials(Locale
.class);
117 if (locales
.isEmpty()) {
118 Locale defaultLocale
= CmsContextImpl
.getCmsContext().getDefaultLocale();
119 return defaultLocale
;
121 return locales
.iterator().next();
124 /** Whether this user is currently authenticated. */
125 public static boolean isAnonymous(Subject subject
) {
128 String username
= getUsername(subject
);
129 return username
== null || username
.equalsIgnoreCase(CmsConstants
.ROLE_ANONYMOUS
);
132 public static CmsSession
getCmsSession() {
133 Subject subject
= currentSubject();
134 Iterator
<CmsSessionId
> it
= subject
.getPrivateCredentials(CmsSessionId
.class).iterator();
136 throw new IllegalStateException("No CMS session id available for " + subject
);
137 CmsSessionId cmsSessionId
= it
.next();
139 throw new IllegalStateException("More than one CMS session id available for " + subject
);
140 return CmsContextImpl
.getCmsContext().getCmsSessionByUuid(cmsSessionId
.getUuid());
146 private static Subject
currentSubject() {
147 Subject subject
= getAccessControllerSubject();
150 throw new IllegalStateException("Cannot find related subject");
153 private static Subject
getAccessControllerSubject() {
154 return Subject
.getSubject(AccessController
.getContext());
157 private static Authorization
getAuthorization(Subject subject
) {
158 return subject
.getPrivateCredentials(Authorization
.class).iterator().next();
161 public static boolean logoutCmsSession(Subject subject
) {
163 if (subject
.getPrivateCredentials(CmsSessionId
.class).size() == 1)
164 nodeSessionId
= subject
.getPrivateCredentials(CmsSessionId
.class).iterator().next().getUuid();
167 CmsSessionImpl cmsSession
= CmsContextImpl
.getCmsContext().getCmsSessionByUuid(nodeSessionId
);
169 // FIXME logout all views
170 // TODO check why it is sometimes null
171 if (cmsSession
!= null)
173 // if (log.isDebugEnabled())
174 // log.debug("Logged out CMS session " + cmsSession.getUuid());
179 * PREPARE EVOLUTION OF JAVA APIs INTRODUCED IN JDK 18 The following static
180 * methods will be added to Subject
182 public Subject
current() {
183 return currentSubject();
186 public static <T
> T
callAs(Subject subject
, Callable
<T
> action
) {
188 return Subject
.doAs(subject
, new PrivilegedExceptionAction
<T
>() {
191 public T
run() throws Exception
{
192 return action
.call();
196 } catch (PrivilegedActionException e
) {
197 throw new CompletionException("Failed to execute action for " + subject
, e
.getCause());
201 private CurrentUser() {