Massive package refactoring
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / auth / RemoteAuthUtils.java
index cf30d8a715ea72cca0d8916ce9d9925081e478e8..4a8f18fcd811a11b516597e827d173542a441c50 100644 (file)
@@ -1,16 +1,21 @@
 package org.argeo.cms.auth;
 
-import java.security.AccessControlContext;
-import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Base64;
 import java.util.function.Supplier;
 
 import javax.security.auth.Subject;
 import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
 
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsSession;
+import org.argeo.cms.http.HttpHeader;
+import org.argeo.cms.http.HttpStatus;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
+import org.argeo.cms.util.CurrentSubject;
 import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
@@ -19,6 +24,8 @@ import org.ietf.jgss.Oid;
 
 /** Remote authentication utilities. */
 public class RemoteAuthUtils {
+       private final static CmsLog log = CmsLog.getLog(RemoteAuthUtils.class);
+
        static final String REMOTE_USER = "org.osgi.service.http.authentication.remote.user";
        private final static Oid KERBEROS_OID;
 //     private final static Oid KERB_V5_OID, KRB5_PRINCIPAL_NAME_OID;
@@ -37,47 +44,49 @@ public class RemoteAuthUtils {
         * Useful to log in to JCR.
         */
        public final static <T> T doAs(Supplier<T> supplier, RemoteAuthRequest req) {
-               ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
-               Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
-               try {
-                       return Subject.doAs(
-                                       Subject.getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())),
-                                       new PrivilegedAction<T>() {
-
-                                               @Override
-                                               public T run() {
-                                                       return supplier.get();
-                                               }
-
-                                       });
-               } finally {
-                       Thread.currentThread().setContextClassLoader(currentContextCl);
-               }
+               CmsSession cmsSession = getCmsSession(req);
+               return CurrentSubject.callAs(cmsSession.getSubject(), () -> supplier.get());
+//             ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
+//             Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
+//             try {
+//                     return Subject.doAs(
+//                                     Subject.getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())),
+//                                     new PrivilegedAction<T>() {
+//
+//                                             @Override
+//                                             public T run() {
+//                                                     return supplier.get();
+//                                             }
+//
+//                                     });
+//             } finally {
+//                     Thread.currentThread().setContextClassLoader(currentContextCl);
+//             }
        }
 
-       public final static void configureRequestSecurity(RemoteAuthRequest req) {
-               if (req.getAttribute(AccessControlContext.class.getName()) != null)
-                       throw new IllegalStateException("Request already authenticated.");
-               AccessControlContext acc = AccessController.getContext();
-               req.setAttribute(REMOTE_USER, CurrentUser.getUsername());
-               req.setAttribute(AccessControlContext.class.getName(), acc);
-       }
-
-       public final static void clearRequestSecurity(RemoteAuthRequest req) {
-               if (req.getAttribute(AccessControlContext.class.getName()) == null)
-                       throw new IllegalStateException("Cannot clear non-authenticated request.");
-               req.setAttribute(REMOTE_USER, null);
-               req.setAttribute(AccessControlContext.class.getName(), null);
-       }
+//     public final static void configureRequestSecurity(RemoteAuthRequest req) {
+//             if (req.getAttribute(AccessControlContext.class.getName()) != null)
+//                     throw new IllegalStateException("Request already authenticated.");
+//             AccessControlContext acc = AccessController.getContext();
+//             req.setAttribute(REMOTE_USER, CurrentUser.getUsername());
+//             req.setAttribute(AccessControlContext.class.getName(), acc);
+//     }
+//
+//     public final static void clearRequestSecurity(RemoteAuthRequest req) {
+//             if (req.getAttribute(AccessControlContext.class.getName()) == null)
+//                     throw new IllegalStateException("Cannot clear non-authenticated request.");
+//             req.setAttribute(REMOTE_USER, null);
+//             req.setAttribute(AccessControlContext.class.getName(), null);
+//     }
 
        public static CmsSession getCmsSession(RemoteAuthRequest req) {
-               Subject subject = Subject
-                               .getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName()));
-               CmsSession cmsSession = CmsContextImpl.getCmsContext().getCmsSession(subject);
+               CmsSession cmsSession = (CmsSession) req.getAttribute(CmsSession.class.getName());
+               if (cmsSession == null)
+                       throw new IllegalStateException("Request must have a CMS session attribute");
                return cmsSession;
        }
 
-       public static String getGssToken(Subject subject, String service, String server) {
+       public static String createGssToken(Subject subject, String service, String server) {
                if (subject.getPrivateCredentials(KerberosTicket.class).isEmpty())
                        throw new IllegalArgumentException("Subject " + subject + " is not GSS authenticated.");
                return Subject.doAs(subject, (PrivilegedAction<String>) () -> {
@@ -117,4 +126,60 @@ public class RemoteAuthUtils {
                        }
                });
        }
+
+       public static LoginContext anonymousLogin(RemoteAuthRequest remoteAuthRequest,
+                       RemoteAuthResponse remoteAuthResponse) {
+               // anonymous
+               ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
+               try {
+                       Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
+                       LoginContext lc = CmsAuth.ANONYMOUS
+                                       .newLoginContext(new RemoteAuthCallbackHandler(remoteAuthRequest, remoteAuthResponse));
+                       lc.login();
+                       return lc;
+               } catch (LoginException e1) {
+                       if (log.isDebugEnabled())
+                               log.error("Cannot log in as anonymous", e1);
+                       return null;
+               } finally {
+                       Thread.currentThread().setContextClassLoader(currentContextClassLoader);
+               }
+       }
+
+       public static int askForWwwAuth(RemoteAuthRequest remoteAuthRequest, RemoteAuthResponse remoteAuthResponse,
+                       String realm, boolean forceBasic) {
+               boolean negotiateFailed = false;
+               if (remoteAuthRequest.getHeader(HttpHeader.AUTHORIZATION.getHeaderName()) != null) {
+                       // we already tried, so we give up in order not too loop endlessly
+                       if (remoteAuthRequest.getHeader(HttpHeader.AUTHORIZATION.getHeaderName())
+                                       .startsWith(HttpHeader.NEGOTIATE)) {
+                               negotiateFailed = true;
+                       } else {
+                               return HttpStatus.FORBIDDEN.getCode();
+                       }
+               }
+
+               // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
+               // realm=\"" + httpAuthRealm + "\"");
+               if (hasAcceptorCredentials() && !forceBasic && !negotiateFailed)// SPNEGO
+                       remoteAuthResponse.setHeader(HttpHeader.WWW_AUTHENTICATE.getHeaderName(), HttpHeader.NEGOTIATE);
+               else
+                       remoteAuthResponse.setHeader(HttpHeader.WWW_AUTHENTICATE.getHeaderName(),
+                                       HttpHeader.BASIC + " " + HttpHeader.REALM + "=\"" + realm + "\"");
+
+               // response.setDateHeader("Date", System.currentTimeMillis());
+               // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
+               // 60 * 60 * 1000));
+               // response.setHeader("Accept-Ranges", "bytes");
+               // response.setHeader("Connection", "Keep-Alive");
+               // response.setHeader("Keep-Alive", "timeout=5, max=97");
+               // response.setContentType("text/html; charset=UTF-8");
+
+               return HttpStatus.UNAUTHORIZED.getCode();
+       }
+
+       private static boolean hasAcceptorCredentials() {
+               return CmsContextImpl.getCmsContext().getAcceptorCredentials() != null;
+       }
+
 }