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;
+};