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 2015/01/09 11:20:32 UTC

tomee git commit: TOMEE-1490 more cdi logic for lazy realm + enhancing cdi-realm test with a sample

Repository: tomee
Updated Branches:
  refs/heads/tomee-1.7.x 0f3ae49a1 -> 12334ec61


TOMEE-1490 more cdi logic for lazy realm + enhancing cdi-realm test with a sample


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/12334ec6
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/12334ec6
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/12334ec6

Branch: refs/heads/tomee-1.7.x
Commit: 12334ec613b53d50f3bf311c09b588b8be3c9042
Parents: 0f3ae49
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Fri Jan 9 11:20:05 2015 +0100
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Fri Jan 9 11:20:05 2015 +0100

----------------------------------------------------------------------
 .../tests/realm/CdiLazyRealmTOMEE1490Test.java  |  62 ++++++++++
 .../CdiLifecycleLazyRealmTOMEE1490Test.java     |  62 ++++++++++
 .../openejb/arquillian/tests/realm/Https.java   |  44 +++++++
 .../arquillian/tests/realm/MyCdiLazyRealm.java  | 114 +++++++++++++++++++
 .../tests/realm/MyCdiRealmBaseLazyRealm.java    |  42 +++++++
 .../arquillian/tests/realm/SimpleEndpoint.java  |  33 ++++++
 examples/cdi-realm/pom.xml                      |  40 ++++++-
 .../src/main/java/org/superbiz/AuthBean.java    |  20 ++--
 .../main/java/org/superbiz/SecuredServlet.java  |  32 ++++++
 .../src/main/webapp/META-INF/context.xml        |   8 +-
 .../test/java/org/superbiz/AuthBeanTest.java    | 102 +++++++++++++++++
 .../cdi-realm/src/test/resources/arquillian.xml |  31 +++++
 .../apache/tomee/catalina/realm/LazyRealm.java  |  98 ++++++++++++----
 13 files changed, 647 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLazyRealmTOMEE1490Test.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLazyRealmTOMEE1490Test.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLazyRealmTOMEE1490Test.java
new file mode 100644
index 0000000..6cffb59
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLazyRealmTOMEE1490Test.java
@@ -0,0 +1,62 @@
+/**
+ * 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.arquillian.tests.realm;
+
+import org.apache.catalina.authenticator.BasicAuthenticator;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Arquillian.class)
+public class CdiLazyRealmTOMEE1490Test {
+    @Deployment(testable = false)
+    public static WebArchive createDeployment() {
+        return ShrinkWrap.create(WebArchive.class, "example.war")
+                .addClasses(SimpleEndpoint.class, MyCdiLazyRealm.class)
+                .addAsManifestResource(new StringAsset("<Context preemptiveAuthentication=\"true\">\n" +
+                        "  <Valve className=\"" + BasicAuthenticator.class.getName() + "\" />\n" +
+                        "  <Realm cdi=\"true\"\n" +
+                        "         className=\"org.apache.tomee.catalina.realm.LazyRealm\"\n" +
+                        "         realmClass=\"" + MyCdiLazyRealm.class.getName() + "\" />\n" +
+                        "</Context>"), "context.xml")
+                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @ArquillianResource
+    private URL webapp;
+
+    @Test
+    public void success() throws IOException {
+        assertEquals("ok", Https.connection(webapp, "", "user", "pwd"));
+    }
+
+    @Test(expected = Exception.class)
+    public void failure() throws IOException {
+        Https.connection(webapp, "", "user", "wrong");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLifecycleLazyRealmTOMEE1490Test.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLifecycleLazyRealmTOMEE1490Test.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLifecycleLazyRealmTOMEE1490Test.java
new file mode 100644
index 0000000..909dcf7
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/CdiLifecycleLazyRealmTOMEE1490Test.java
@@ -0,0 +1,62 @@
+/**
+ * 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.arquillian.tests.realm;
+
+import org.apache.catalina.authenticator.BasicAuthenticator;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Arquillian.class)
+public class CdiLifecycleLazyRealmTOMEE1490Test {
+    @Deployment(testable = false)
+    public static WebArchive createDeployment() {
+        return ShrinkWrap.create(WebArchive.class, "example.war")
+                .addClasses(SimpleEndpoint.class, MyCdiRealmBaseLazyRealm.class)
+                .addAsManifestResource(new StringAsset("<Context preemptiveAuthentication=\"true\">\n" +
+                        "  <Valve className=\"" + BasicAuthenticator.class.getName() + "\" />\n" +
+                        "  <Realm cdi=\"true\"\n" +
+                        "         className=\"org.apache.tomee.catalina.realm.LazyRealm\"\n" +
+                        "         realmClass=\"" + MyCdiRealmBaseLazyRealm.class.getName() + "\" />\n" +
+                        "</Context>"), "context.xml")
+                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @ArquillianResource
+    private URL webapp;
+
+    @Test
+    public void success() throws IOException {
+        assertEquals("ok", Https.connection(webapp, "", "user", "pwd"));
+    }
+
+    @Test(expected = Exception.class)
+    public void failure() throws IOException {
+        Https.connection(webapp, "", "user", "wrong");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/Https.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/Https.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/Https.java
new file mode 100644
index 0000000..a7a4c19
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/Https.java
@@ -0,0 +1,44 @@
+/**
+ * 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.arquillian.tests.realm;
+
+import org.apache.openejb.arquillian.common.IO;
+
+import javax.xml.bind.DatatypeConverter;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class Https {
+    public static String connection(final URL webapp, final String path, final String username, final String password) throws IOException {
+        final HttpURLConnection con = (HttpURLConnection) new URL(webapp.toExternalForm() + path).openConnection();
+        String userCredentials = username + ":" + password;
+        String basicAuth = "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes());
+        con.setRequestProperty("Authorization", basicAuth);
+        con.setUseCaches(false);
+        try {
+            return IO.slurp(con.getInputStream());
+        } finally {
+            IO.close(con.getInputStream());
+            con.disconnect();
+        }
+    }
+
+    private Https() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiLazyRealm.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiLazyRealm.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiLazyRealm.java
new file mode 100644
index 0000000..2c82356
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiLazyRealm.java
@@ -0,0 +1,114 @@
+/**
+ * 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.arquillian.tests.realm;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.ietf.jgss.GSSContext;
+
+import javax.enterprise.context.ApplicationScoped;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+
+import static java.util.Arrays.asList;
+
+@ApplicationScoped // can't be request scoped cause it is a realm impl
+public class MyCdiLazyRealm implements Realm {
+    private Container container;
+
+    @Override
+    public Container getContainer() {
+        return container;
+    }
+
+    @Override
+    public void setContainer(final Container container) {
+        this.container = container;
+    }
+
+    @Override
+    public String getInfo() {
+        return null;
+    }
+
+    @Override
+    public void addPropertyChangeListener(final PropertyChangeListener listener) {
+
+    }
+
+    @Override
+    public Principal authenticate(final String username, final String credentials) {
+        return "user".equalsIgnoreCase(username) && "pwd".equalsIgnoreCase(credentials) ? new GenericPrincipal(username, "pwd", asList("role")) : null;
+    }
+
+    @Override
+    public Principal authenticate(final String username, final String digest, final String nonce,
+                                  final String nc, final String cnonce, final String qop,
+                                  final String realm, final String md5a2) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Principal authenticate(final GSSContext gssContext, final boolean storeCreds) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Principal authenticate(final X509Certificate[] certs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void backgroundProcess() {
+        // no-op
+    }
+
+    @Override
+    public SecurityConstraint[] findSecurityConstraints(final Request request, final Context context) {
+        return null;
+    }
+
+    @Override
+    public boolean hasResourcePermission(final Request request, final Response response,
+                                         final SecurityConstraint[] securityConstraints, final Context context) throws IOException {
+        return false;
+    }
+
+    @Override
+    public boolean hasRole(final Wrapper wrapper, final Principal principal, final String s) {
+        return false;
+    }
+
+    @Override
+    public boolean hasUserDataPermission(final Request request, final Response response,
+                                         final SecurityConstraint[] securityConstraints) throws IOException {
+        return false;
+    }
+
+    @Override
+    public void removePropertyChangeListener(final PropertyChangeListener listener) {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiRealmBaseLazyRealm.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiRealmBaseLazyRealm.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiRealmBaseLazyRealm.java
new file mode 100644
index 0000000..f1b5e30
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/MyCdiRealmBaseLazyRealm.java
@@ -0,0 +1,42 @@
+/**
+ * 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.arquillian.tests.realm;
+
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.realm.RealmBase;
+
+import java.security.Principal;
+
+import static java.util.Arrays.asList;
+
+// no scope cause RealmBase is not proxyable, realm impl would put a scope + implement Realm, Lifecycle
+public class MyCdiRealmBaseLazyRealm extends RealmBase {
+    @Override
+    protected String getName() {
+        return "user";
+    }
+
+    @Override
+    protected String getPassword(final String username) {
+        return "pwd";
+    }
+
+    @Override
+    protected Principal getPrincipal(final String username) {
+        return new GenericPrincipal(username, getPassword(username), asList("role"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/SimpleEndpoint.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/SimpleEndpoint.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/SimpleEndpoint.java
new file mode 100644
index 0000000..1157436
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-webprofile-tests/src/test/java/org/apache/openejb/arquillian/tests/realm/SimpleEndpoint.java
@@ -0,0 +1,33 @@
+/**
+ * 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.arquillian.tests.realm;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@WebServlet("/*")
+public class SimpleEndpoint extends HttpServlet {
+    @Override
+    protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+        resp.getWriter().write("ok");
+        resp.setContentType("text/plain");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/examples/cdi-realm/pom.xml
----------------------------------------------------------------------
diff --git a/examples/cdi-realm/pom.xml b/examples/cdi-realm/pom.xml
index 164a670..b367bb4 100644
--- a/examples/cdi-realm/pom.xml
+++ b/examples/cdi-realm/pom.xml
@@ -26,6 +26,7 @@
   <name>OpenEJB :: Examples :: CDI Realm</name>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <tomee.version>2.0.0-SNAPSHOT</tomee.version>
   </properties>
   <build>
     <defaultGoal>install</defaultGoal>
@@ -65,7 +66,44 @@
     <dependency>
       <groupId>org.apache.openejb</groupId>
       <artifactId>javaee-api</artifactId>
-      <version>6.0-6</version>
+      <version>7.0-SNAPSHOT</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.arquillian.junit</groupId>
+      <artifactId>arquillian-junit-container</artifactId>
+      <version>1.1.5.Final</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>arquillian-tomee-remote</artifactId>
+      <version>1.7.2-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <version>4.3.6</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>tomee-catalina</artifactId>
+      <version>1.7.2-SNAPSHOT</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-catalina</artifactId>
+      <version>7.0.57</version>
       <scope>provided</scope>
     </dependency>
   </dependencies>

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/examples/cdi-realm/src/main/java/org/superbiz/AuthBean.java
----------------------------------------------------------------------
diff --git a/examples/cdi-realm/src/main/java/org/superbiz/AuthBean.java b/examples/cdi-realm/src/main/java/org/superbiz/AuthBean.java
index 66fb943..bee66b9 100644
--- a/examples/cdi-realm/src/main/java/org/superbiz/AuthBean.java
+++ b/examples/cdi-realm/src/main/java/org/superbiz/AuthBean.java
@@ -19,9 +19,8 @@ package org.superbiz;
 import javax.enterprise.context.RequestScoped;
 import java.security.Principal;
 
-@RequestScoped
+@RequestScoped // just to show we can be bound to the request but @ApplicationScoped is what makes sense
 public class AuthBean {
-
     public Principal authenticate(final String username, String password) {
         if (("userA".equals(username) || "userB".equals(username)) && "test".equals(password)) {
             return new Principal() {
@@ -39,16 +38,11 @@ public class AuthBean {
         return null;
     }
 
-    public boolean hasRole(Principal principal, String role) {
-        if (principal == null) {
-            return false;
-        }
-        if (principal.getName().equals("userA") && (role.equals("admin") || role.equals("user"))) {
-            return true;
-        }
-        if (principal.getName().equals("userB") && (role.equals("user"))) {
-            return true;
-        }
-        return false;
+    public boolean hasRole(final Principal principal, final String role) {
+        return principal != null && (
+                principal.getName().equals("userA") && (role.equals("admin")
+                || role.equals("user"))
+                || principal.getName().equals("userB") && (role.equals("user"))
+            );
     }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/examples/cdi-realm/src/main/java/org/superbiz/SecuredServlet.java
----------------------------------------------------------------------
diff --git a/examples/cdi-realm/src/main/java/org/superbiz/SecuredServlet.java b/examples/cdi-realm/src/main/java/org/superbiz/SecuredServlet.java
new file mode 100644
index 0000000..884db32
--- /dev/null
+++ b/examples/cdi-realm/src/main/java/org/superbiz/SecuredServlet.java
@@ -0,0 +1,32 @@
+/**
+ * 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.superbiz;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@WebServlet("/servlet")
+public class SecuredServlet extends HttpServlet {
+    @Override
+    protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+        resp.getWriter().write("Servlet!");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/examples/cdi-realm/src/main/webapp/META-INF/context.xml
----------------------------------------------------------------------
diff --git a/examples/cdi-realm/src/main/webapp/META-INF/context.xml b/examples/cdi-realm/src/main/webapp/META-INF/context.xml
index d7959ae..367d033 100644
--- a/examples/cdi-realm/src/main/webapp/META-INF/context.xml
+++ b/examples/cdi-realm/src/main/webapp/META-INF/context.xml
@@ -15,6 +15,8 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<Context>
-  <Realm cdi="true" className="org.apache.tomee.catalina.realm.LazyRealm" realmClass="org.superbiz.AuthBean"/>
-</Context>
\ No newline at end of file
+<Context preemptiveAuthentication="true">
+  <Valve className="org.apache.catalina.authenticator.BasicAuthenticator" />
+  <Realm className="org.apache.tomee.catalina.realm.LazyRealm"
+         cdi="true" realmClass="org.superbiz.AuthBean"/>
+</Context>

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/examples/cdi-realm/src/test/java/org/superbiz/AuthBeanTest.java
----------------------------------------------------------------------
diff --git a/examples/cdi-realm/src/test/java/org/superbiz/AuthBeanTest.java b/examples/cdi-realm/src/test/java/org/superbiz/AuthBeanTest.java
new file mode 100644
index 0000000..d89d691
--- /dev/null
+++ b/examples/cdi-realm/src/test/java/org/superbiz/AuthBeanTest.java
@@ -0,0 +1,102 @@
+/**
+ * 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.superbiz;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.AuthCache;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.apache.openejb.arquillian.common.IO;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.asset.FileAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Arquillian.class)
+public class AuthBeanTest {
+    @Deployment(testable = false)
+    public static WebArchive createDeployment() {
+        return ShrinkWrap.create(WebArchive.class, "low-typed-realm.war")
+                .addClasses(SecuredServlet.class, AuthBean.class)
+                .addAsManifestResource(new FileAsset(new File("src/main/webapp/META-INF/context.xml")), "context.xml")
+                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @ArquillianResource
+    private URL webapp;
+
+    @Test
+    public void success() throws IOException {
+        assertEquals("200 Servlet!", get("userA", "test"));
+    }
+
+    @Test
+    public void failure() throws IOException {
+        assertThat(get("userA", "oops, wrong password"), startsWith("401"));
+    }
+
+    private String get(final String user, final String password) {
+        final BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider();
+        basicCredentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, password));
+        final CloseableHttpClient client = HttpClients.custom()
+                .setDefaultCredentialsProvider(basicCredentialsProvider).build();
+
+        final HttpHost httpHost = new HttpHost(webapp.getHost(), webapp.getPort(), webapp.getProtocol());
+        final AuthCache authCache = new BasicAuthCache();
+        final BasicScheme basicAuth = new BasicScheme();
+        authCache.put(httpHost, basicAuth);
+        final HttpClientContext context = HttpClientContext.create();
+        context.setAuthCache(authCache);
+
+        final HttpGet get = new HttpGet(webapp.toExternalForm() + "servlet");
+        CloseableHttpResponse response = null;
+        try {
+            response = client.execute(httpHost, get, context);
+            return response.getStatusLine().getStatusCode() + " " + EntityUtils.toString(response.getEntity());
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        } finally {
+            try {
+                IO.close(response);
+            } catch (final IOException e) {
+                // no-op
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/examples/cdi-realm/src/test/resources/arquillian.xml
----------------------------------------------------------------------
diff --git a/examples/cdi-realm/src/test/resources/arquillian.xml b/examples/cdi-realm/src/test/resources/arquillian.xml
new file mode 100644
index 0000000..1db3d40
--- /dev/null
+++ b/examples/cdi-realm/src/test/resources/arquillian.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+
+    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.
+-->
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+       <container qualifier="tomee" default="true">
+           <configuration>
+               <property name="httpPort">-1</property>
+               <property name="stopPort">-1</property>
+               <property name="ajpPort">-1</property>
+               <property name="dir">target/tomee</property>
+               <property name="appWorkingDir">target/arquillian-dump-dir</property>
+           </configuration>
+       </container>
+</arquillian>

http://git-wip-us.apache.org/repos/asf/tomee/blob/12334ec6/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/realm/LazyRealm.java
----------------------------------------------------------------------
diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/realm/LazyRealm.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/realm/LazyRealm.java
index 3eccfbe..40d40c2 100644
--- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/realm/LazyRealm.java
+++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/realm/LazyRealm.java
@@ -40,6 +40,7 @@ import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
 import java.io.IOException;
 import java.security.Principal;
 import java.security.cert.X509Certificate;
@@ -49,13 +50,21 @@ import java.util.Set;
 public class LazyRealm extends LifecycleBase implements Realm {
     private String realmClass;
     private String properties;
+    private String name;
     private boolean cdi;
 
+    private volatile boolean init;
+    private volatile boolean start;
     private volatile Realm delegate;
     private Context container;
+    private final PropertyChangeSupport support = new PropertyChangeSupport(this);
 
     private CreationalContext<Object> creationalContext;
 
+    public void setName(final String name) {
+        this.name = name;
+    }
+
     public void setRealmClass(final String realmClass) {
         this.realmClass = realmClass;
     }
@@ -103,10 +112,16 @@ public class LazyRealm extends LifecycleBase implements Realm {
                             throw new TomEERuntimeException(e);
                         }
                     } else {
-                        final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
-                        if (webBeansContext == null) {
+                        final WebBeansContext webBeansContext;
+                        try {
+                            webBeansContext = WebBeansContext.currentInstance();
+                            if (webBeansContext == null) {
+                                return null;
+                            }
+                        } catch (final IllegalStateException ise) {
                             return null; // too early to have a cdi bean, skip these methods - mainly init() but @PostConstruct works then
                         }
+
                         final BeanManager bm = webBeansContext.getBeanManagerImpl();
                         final Set<Bean<?>> beans = bm.getBeans(clazz);
                         final Bean<?> bean = bm.resolve(beans);
@@ -122,47 +137,79 @@ public class LazyRealm extends LifecycleBase implements Realm {
                     }
                     if (instance instanceof Realm) {
                         delegate = (Realm) instance;
+                        delegate.setContainer(container);
+                        if (Lifecycle.class.isInstance(delegate)) {
+                            if (init) {
+                                try {
+                                    final Lifecycle lifecycle = Lifecycle.class.cast(delegate);
+                                    lifecycle.init();
+                                    if (start) {
+                                        lifecycle.start();
+                                    }
+                                } catch (final LifecycleException e) {
+                                    // no-op
+                                }
+                            }
+                        }
                     } else {
                         delegate = new LowTypedRealm(instance);
+                        delegate.setContainer(container);
+                    }
+                    for (final PropertyChangeListener listener : support.getPropertyChangeListeners()) {
+                        delegate.addPropertyChangeListener(listener);
                     }
-                    delegate.setContainer(container);
                 }
             }
         }
         return delegate;
     }
 
+    private Class<?> loadClass() {
+        if (container != null && container.getLoader() != null && container.getLoader().getClassLoader() != null) {
+            try {
+                return container.getLoader().getClassLoader().loadClass(realmClass);
+            } catch (final ClassNotFoundException e) {
+                // no-op
+            }
+        }
+        return null;
+    }
+
     @Override
     protected void initInternal() throws LifecycleException {
-        final Realm r = instance();
-        if (r != null && Lifecycle.class.isInstance(r)) {
-            Lifecycle.class.cast(r).init();
+        final Class<?> r = loadClass();
+        if (r != null && Lifecycle.class.isAssignableFrom(r) && instance() != null) {
+            Lifecycle.class.cast(delegate).init();
+        } else {
+            init = true;
         }
     }
 
     @Override
     protected void startInternal() throws LifecycleException {
-        final Realm r = instance();
-        if (r != null && Lifecycle.class.isInstance(r)) {
-            Lifecycle.class.cast(r).start();
+        final Class<?> r = loadClass();
+        if (r != null && Lifecycle.class.isAssignableFrom(r) && instance() != null) {
+            Lifecycle.class.cast(instance()).start();
+        } else {
+            start = true;
         }
         setState(LifecycleState.STARTING);
     }
 
     @Override
     protected void stopInternal() throws LifecycleException {
-        final Realm r = instance();
-        if (r != null && Lifecycle.class.isInstance(r)) {
-            Lifecycle.class.cast(r).stop();
+        final Class<?> r = loadClass();
+        if (r != null && Lifecycle.class.isAssignableFrom(r) && instance() != null) {
+            Lifecycle.class.cast(delegate).stop();
         }
         setState(LifecycleState.STOPPING);
     }
 
     @Override
     protected void destroyInternal() throws LifecycleException {
-        final Realm r = instance();
-        if (r != null && Lifecycle.class.isInstance(r)) {
-            Lifecycle.class.cast(r).destroy();
+        final Class<?> r = loadClass();
+        if (r != null && Lifecycle.class.isAssignableFrom(r) && instance() != null) {
+            Lifecycle.class.cast(delegate).destroy();
         }
     }
 
@@ -196,6 +243,9 @@ public class LazyRealm extends LifecycleBase implements Realm {
 
     @Override
     public String getInfo() {
+        if (name != null) {
+            return name;
+        }
         final Realm instance = instance();
         if (instance == null) {
             return getClass().getName() + "/1.0";
@@ -205,11 +255,10 @@ public class LazyRealm extends LifecycleBase implements Realm {
 
     @Override
     public void addPropertyChangeListener(final PropertyChangeListener listener) {
-        final Realm instance = instance();
-        if (instance == null) {
-            return;
+        if (delegate != null) {
+            delegate.addPropertyChangeListener(listener);
         }
-        instance.addPropertyChangeListener(listener);
+        support.addPropertyChangeListener(listener);
     }
 
     @Override
@@ -235,7 +284,9 @@ public class LazyRealm extends LifecycleBase implements Realm {
 
     @Override
     public void backgroundProcess() {
-        instance().backgroundProcess();
+        if (delegate != null) {
+            instance().backgroundProcess();
+        }
     }
 
     @Override
@@ -262,10 +313,9 @@ public class LazyRealm extends LifecycleBase implements Realm {
 
     @Override
     public void removePropertyChangeListener(final PropertyChangeListener listener) {
-        final Realm instance = instance();
-        if (instance == null) {
-            return;
+        if (delegate != null) {
+            delegate.removePropertyChangeListener(listener);
         }
-        instance.removePropertyChangeListener(listener);
+        support.removePropertyChangeListener(listener);
     }
 }