Make logout more robust.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / auth / CurrentUser.java
index 11126014f2aba49e9a85a6ddf16f9242da8792a1..eaaf41ab72a458ee7acacb0778315922c9c52ba5 100644 (file)
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 package org.argeo.cms.auth;
 
 import java.security.AccessController;
 import java.security.Principal;
-import java.security.acl.Group;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Set;
+import java.util.UUID;
 
 import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
 
-import org.argeo.cms.CmsException;
-import org.argeo.cms.CmsView;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.internal.auth.CmsSessionImpl;
+import org.argeo.cms.internal.auth.ImpliedByPrincipal;
+import org.argeo.cms.internal.kernel.Activator;
 import org.osgi.service.useradmin.Authorization;
 
-/** Static utilities */
+/**
+ * Programmatic access to the currently authenticated user, within a CMS
+ * context.
+ */
 public final class CurrentUser {
+       /*
+        * CURRENT USER API
+        */
+
        /**
-        * @return the authenticated username or null if not authenticated /
-        *         anonymous
+        * Technical username of the currently authenticated user.
+        * 
+        * @return the authenticated username or null if not authenticated / anonymous
         */
        public static String getUsername() {
                return getUsername(currentSubject());
        }
 
+       /**
+        * Human readable name of the currently authenticated user (typically first name
+        * and last name).
+        */
        public static String getDisplayName() {
                return getDisplayName(currentSubject());
        }
 
+       /** Whether a user is currently authenticated. */
        public static boolean isAnonymous() {
                return isAnonymous(currentSubject());
        }
 
-       public static boolean isAnonymous(Subject subject) {
-               return getUsername(subject).equalsIgnoreCase(
-                               AuthConstants.ROLE_ANONYMOUS);
+       /** Locale of the current user */
+       public final static Locale locale() {
+               return locale(currentSubject());
        }
 
-       private static Subject currentSubject() {
-               Subject subject = Subject.getSubject(AccessController.getContext());
-               if (subject != null)
-                       return subject;
-               if (subject == null) {
-                       CmsView cmsView = CmsUtils.getCmsView();
-                       if (cmsView != null)
-                               return cmsView.getSubject();
-               }
-               throw new CmsException("Cannot find related subject");
+       /** Roles of the currently logged-in user */
+       public final static Set<String> roles() {
+               return roles(currentSubject());
        }
 
-       public final static String getUsername(Subject subject) {
-               // Subject subject = Subject.getSubject(AccessController.getContext());
-               // if (subject == null)
-               // return null;
-               if (subject.getPrincipals(X500Principal.class).size() != 1)
-                       return null;
-               Principal principal = subject.getPrincipals(X500Principal.class)
-                               .iterator().next();
-               return principal.getName();
+       /** Returns true if the current user is in the specified role */
+       public static boolean isInRole(String role) {
+               Set<String> roles = roles();
+               return roles.contains(role);
+       }
 
+       /** Executes as the current user */
+       public final static <T> T doAs(PrivilegedAction<T> action) {
+               return Subject.doAs(currentSubject(), action);
        }
 
-       public final static String getDisplayName(Subject subject) {
-               return getAuthorization(subject).toString();
+       /** Executes as the current user */
+       public final static <T> T tryAs(PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
+               return Subject.doAs(currentSubject(), action);
        }
 
-       private static Authorization getAuthorization(Subject subject) {
-               return subject.getPrivateCredentials(Authorization.class).iterator()
-                               .next();
+       /*
+        * WRAPPERS
+        */
+
+       public final static String getUsername(Subject subject) {
+               if (subject == null)
+                       throw new IllegalArgumentException("Subject cannot be null");
+               if (subject.getPrincipals(X500Principal.class).size() != 1)
+                       return NodeConstants.ROLE_ANONYMOUS;
+               Principal principal = subject.getPrincipals(X500Principal.class).iterator().next();
+               return principal.getName();
        }
 
-       public final static Set<String> roles() {
-               return roles(currentSubject());
+       public final static String getDisplayName(Subject subject) {
+               return getAuthorization(subject).toString();
        }
 
        public final static Set<String> roles(Subject subject) {
                Set<String> roles = new HashSet<String>();
-               X500Principal userPrincipal = subject
-                               .getPrincipals(X500Principal.class).iterator().next();
-               roles.add(userPrincipal.getName());
-               for (Principal group : subject.getPrincipals(Group.class)) {
+               roles.add(getUsername(subject));
+               for (Principal group : subject.getPrincipals(ImpliedByPrincipal.class)) {
                        roles.add(group.getName());
                }
                return roles;
        }
 
+       public final static Locale locale(Subject subject) {
+               Set<Locale> locales = subject.getPublicCredentials(Locale.class);
+               if (locales.isEmpty()) {
+                       Locale defaultLocale = Activator.getNodeState().getDefaultLocale();
+                       return defaultLocale;
+               } else
+                       return locales.iterator().next();
+       }
+
+       /** Whether this user is currently authenticated. */
+       public static boolean isAnonymous(Subject subject) {
+               if (subject == null)
+                       return true;
+               String username = getUsername(subject);
+               return username == null || username.equalsIgnoreCase(NodeConstants.ROLE_ANONYMOUS);
+       }
+
+       public CmsSession getCmsSession() {
+               Subject subject = currentSubject();
+               CmsSessionId cmsSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next();
+               return CmsSessionImpl.getByUuid(cmsSessionId.getUuid());
+       }
+
+       /*
+        * HELPERS
+        */
+       private static Subject currentSubject() {
+               Subject subject = getAccessControllerSubject();
+               if (subject != null)
+                       return subject;
+               throw new IllegalStateException("Cannot find related subject");
+       }
+
+       private static Subject getAccessControllerSubject() {
+               return Subject.getSubject(AccessController.getContext());
+       }
+
+       private static Authorization getAuthorization(Subject subject) {
+               return subject.getPrivateCredentials(Authorization.class).iterator().next();
+       }
+
+       public static boolean logoutCmsSession(Subject subject) {
+               UUID nodeSessionId;
+               if (subject.getPrivateCredentials(CmsSessionId.class).size() == 1)
+                       nodeSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next().getUuid();
+               else
+                       return false;
+               CmsSessionImpl cmsSession = CmsSessionImpl.getByUuid(nodeSessionId.toString());
+               
+               // FIXME logout all views
+               // TODO check why it is sometimes null
+               if (cmsSession != null)
+                       cmsSession.close();
+               // if (log.isDebugEnabled())
+               // log.debug("Logged out CMS session " + cmsSession.getUuid());
+               return true;
+       }
+
        private CurrentUser() {
        }
 }