You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2014/03/13 20:36:44 UTC

svn commit: r1577295 - in /tomee/tomee/trunk/container/openejb-core/src: main/java/org/apache/openejb/core/security/jaas/CDILoginModule.java test/java/org/apache/openejb/core/security/CDILoginModuleTest.java test/resources/cdi-login.config

Author: rmannibucau
Date: Thu Mar 13 19:36:43 2014
New Revision: 1577295

URL: http://svn.apache.org/r1577295
Log:
TOMEE-1140 cdi login module integration

Added:
    tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/core/security/jaas/CDILoginModule.java
    tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/CDILoginModuleTest.java
      - copied, changed from r1576592, tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/PropertiesLoginModuleTest.java
    tomee/tomee/trunk/container/openejb-core/src/test/resources/cdi-login.config

Added: tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/core/security/jaas/CDILoginModule.java
URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/core/security/jaas/CDILoginModule.java?rev=1577295&view=auto
==============================================================================
--- tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/core/security/jaas/CDILoginModule.java (added)
+++ tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/core/security/jaas/CDILoginModule.java Thu Mar 13 19:36:43 2014
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.openejb.core.security.jaas;
+
+import org.apache.openejb.AppContext;
+import org.apache.openejb.OpenEJBRuntimeException;
+import org.apache.openejb.core.WebContext;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.ContainerSystem;
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.container.BeanManagerImpl;
+import org.apache.webbeans.context.creational.CreationalContextImpl;
+import org.apache.webbeans.inject.OWBInjector;
+
+import javax.enterprise.inject.spi.Bean;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Usage:
+ *
+ * CDI {
+ *  org.apache.openejb.core.security.jaas.CDILoginModule required
+ *      delegate="org.apache.openejb.core.security.CDILoginModuleTest$Delegate"
+ *      loginModuleAsCdiBean=false
+ *      cdiName="xxx";
+ *  };
+ *
+ * Note: you can use instead of delegate <appid> to define a delegate by app.
+ * Note 2: loginModuleAsCdiBean=true is recommanded only for @Dependent beans
+ * Note 3: delegate and cdiName can be used alone
+ */
+public class CDILoginModule implements LoginModule {
+    private CreationalContextImpl<?> cc = null;
+    private LoginModule loginModule = null;
+
+    @Override
+    public void initialize(final Subject subject, final CallbackHandler callbackHandler,
+                           final Map<String, ?> sharedState, final Map<String, ?> options) {
+        final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
+        final BeanManagerImpl bm = webBeansContext.getBeanManagerImpl();
+        if (!bm.isInUse()) {
+            throw new OpenEJBRuntimeException("CDI not activated");
+        }
+
+        String delegate = String.valueOf(options.get("delegate"));
+        if ("null".equals(delegate)) {
+            final String app = findAppName(webBeansContext);
+            delegate = String.valueOf(options.get(app));
+            if ("null".equals(delegate)) {
+                throw new OpenEJBRuntimeException("Please specify a delegate class");
+            }
+        }
+
+        final Class<?> clazz;
+        try {
+            clazz = Thread.currentThread().getContextClassLoader().loadClass(delegate);
+        } catch (final ClassNotFoundException e) {
+            throw new OpenEJBRuntimeException(e.getMessage(), e);
+        }
+
+        cc = bm.createCreationalContext(null);
+        final String cdiName = String.valueOf(options.get("cdiName"));
+        if ("true".equals(String.valueOf(options.get("loginModuleAsCdiBean")))) {
+            final Set<Bean<?>> beans;
+            if ("null".equals(cdiName)) {
+                beans = bm.getBeans(clazz);
+            } else {
+                beans = bm.getBeans(cdiName);
+            }
+            loginModule = LoginModule.class.cast(bm.getReference(bm.resolve(beans), clazz, cc));
+        } else {
+            try {
+                loginModule = LoginModule.class.cast(clazz.newInstance());
+                OWBInjector.inject(bm, loginModule, cc);
+            } catch (final Exception e) {
+                throw new OpenEJBRuntimeException("Can't inject into delegate class " + loginModule, e);
+            }
+        }
+
+        loginModule.initialize(subject, callbackHandler, sharedState, options);
+    }
+
+    private static String findAppName(final WebBeansContext webBeansContext) {
+        final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
+        for (final AppContext appContext : containerSystem.getAppContexts()) {
+            if (appContext.getWebBeansContext() == webBeansContext) {
+                return appContext.getId();
+            }
+            for (final WebContext web : appContext.getWebContexts()) {
+                if (web.getWebbeansContext() == webBeansContext) { // ear
+                    return web.getId();
+                }
+            }
+        }
+        return "defaultDelegate";
+    }
+
+    @Override
+    public boolean login() throws LoginException {
+        return loginModule != null && loginModule.login();
+    }
+
+    @Override
+    public boolean commit() throws LoginException {
+        return loginModule == null || loginModule.commit(); // cleanUp is called on logout
+    }
+
+    @Override
+    public boolean abort() throws LoginException {
+        try {
+            return loginModule == null || loginModule.abort();
+        } finally {
+            cleanUp();
+        }
+    }
+
+    @Override
+    public boolean logout() throws LoginException {
+        try {
+            return loginModule == null || loginModule.logout();
+        } finally {
+            cleanUp();
+        }
+    }
+
+    private void cleanUp() {
+        if (cc != null) {
+            cc.release();
+            cc = null;
+        }
+    }
+}

Copied: tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/CDILoginModuleTest.java (from r1576592, tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/PropertiesLoginModuleTest.java)
URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/CDILoginModuleTest.java?p2=tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/CDILoginModuleTest.java&p1=tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/PropertiesLoginModuleTest.java&r1=1576592&r2=1577295&rev=1577295&view=diff
==============================================================================
--- tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/PropertiesLoginModuleTest.java (original)
+++ tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/core/security/CDILoginModuleTest.java Thu Mar 13 19:36:43 2014
@@ -16,72 +16,122 @@
  */
 package org.apache.openejb.core.security;
 
-import junit.framework.TestCase;
 import org.apache.openejb.core.security.jaas.GroupPrincipal;
 import org.apache.openejb.core.security.jaas.UserPrincipal;
 import org.apache.openejb.core.security.jaas.UsernamePasswordCallbackHandler;
+import org.apache.openejb.jee.Beans;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.Module;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import javax.inject.Inject;
 import javax.security.auth.Subject;
-import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
 import java.net.URL;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
 
 import static org.apache.openejb.util.URLs.toFilePath;
+import static org.junit.Assert.assertEquals;
 
-/**
- * @version $Rev$ $Date$
- */
-public class PropertiesLoginModuleTest extends TestCase {
+@RunWith(ApplicationComposer.class)
+public class CDILoginModuleTest {
+    @BeforeClass
+    public static void loadJassLoginConfig() {
+        final URL resource = CDILoginModuleTest.class.getClassLoader().getResource("cdi-login.config");
+        System.setProperty("java.security.auth.login.config", toFilePath(resource));
+    }
 
-    protected void setUp() throws Exception {
-        loadJassLoginConfig();
+    @AfterClass
+    public static void reset() {
+        System.clearProperty("java.security.auth.login.config");
     }
 
-    private static void loadJassLoginConfig() {
-        String path = System.getProperty("java.security.auth.login.config");
-        if (path == null) {
-            URL resource = PropertiesLoginModuleTest.class.getClassLoader().getResource("login.config");
-            if (resource != null) {
-                path = toFilePath(resource);
-                System.setProperty("java.security.auth.login.config", path);
-            }
-        }
-        //System.out.println("Path to login config: " + path);
+    @Module
+    public Beans beans() {
+        final Beans beans = new Beans();
+        beans.addManagedClass(Delegate.class);
+        beans.addManagedClass(CDIBean.class);
+        return beans;
     }
 
+    @Test
     public void testLogin() throws LoginException {
-        LoginContext context = new LoginContext("PropertiesLogin", new UsernamePasswordCallbackHandler("jonathan", "secret"));
+        final LoginContext context = new LoginContext("CDI", new UsernamePasswordCallbackHandler("foo", ""));
         context.login();
 
-        Subject subject = context.getSubject();
+        final Subject subject = context.getSubject();
 
-        assertEquals("Should have three principals", 3, subject.getPrincipals().size());
-        assertEquals("Should have one user principal", 1, subject.getPrincipals(UserPrincipal.class).size());
-        assertEquals("Should have two group principals", 2, subject.getPrincipals(GroupPrincipal.class).size());
+        assertEquals(1, subject.getPrincipals().size());
+        assertEquals("foo", subject.getPrincipals(AbstractSecurityService.User.class).iterator().next().getName());
 
         context.logout();
 
-        assertEquals("Should have zero principals", 0, subject.getPrincipals().size());
+        assertEquals(0, subject.getPrincipals().size());
     }
 
+    @Test(expected = LoginException.class)
     public void testBadUseridLogin() throws Exception {
-        LoginContext context = new LoginContext("PropertiesLogin", new UsernamePasswordCallbackHandler("nobody", "secret"));
-        try {
-            context.login();
-            fail("Should have thrown a FailedLoginException");
-        } catch (FailedLoginException doNothing) {
-        }
+        new LoginContext("CDI", new UsernamePasswordCallbackHandler("bar", "secret")).login();
+    }
 
+    public static class CDIBean {
+        public boolean ok(final String name) {
+            return "foo".equals(name);
+        }
     }
 
-    public void testBadPWLogin() throws Exception {
-        LoginContext context = new LoginContext("PropertiesLogin", new UsernamePasswordCallbackHandler("jonathan", "badpass"));
-        try {
-            context.login();
-            fail("Should have thrown a FailedLoginException");
-        } catch (FailedLoginException doNothing) {
+    public static class Delegate implements LoginModule {
+        @Inject
+        private CDIBean bean;
+
+        private String name;
+        private Subject subject;
+
+        @Override
+        public void initialize(final Subject subject, final CallbackHandler callbackHandler,
+                               final Map<String, ?> sharedState, final Map<String, ?> options) {
+            final NameCallback nameCallback = new NameCallback("whatever");
+            try {
+                callbackHandler.handle(new Callback[] {nameCallback});
+            } catch (final Exception e) {
+                // no-op
+            }
+            name = nameCallback.getName();
+            this.subject = subject;
         }
 
+        @Override
+        public boolean login() throws LoginException {
+            return bean.ok(name);
+        }
+
+        @Override
+        public boolean commit() throws LoginException {
+            subject.getPrincipals().add(new AbstractSecurityService.User(name));
+            return true;
+        }
+
+        @Override
+        public boolean abort() throws LoginException {
+            return true;
+        }
+
+        @Override
+        public boolean logout() throws LoginException {
+            final Iterator<Principal> iterator = subject.getPrincipals().iterator();
+            iterator.next();
+            iterator.remove();
+            return true;
+        }
     }
 }

Added: tomee/tomee/trunk/container/openejb-core/src/test/resources/cdi-login.config
URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/test/resources/cdi-login.config?rev=1577295&view=auto
==============================================================================
--- tomee/tomee/trunk/container/openejb-core/src/test/resources/cdi-login.config (added)
+++ tomee/tomee/trunk/container/openejb-core/src/test/resources/cdi-login.config Thu Mar 13 19:36:43 2014
@@ -0,0 +1,5 @@
+CDI {
+    org.apache.openejb.core.security.jaas.CDILoginModule required
+        delegate="org.apache.openejb.core.security.CDILoginModuleTest$Delegate"
+        loginModuleAsCdiBean=true;
+};