You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by gp...@apache.org on 2012/03/28 00:06:39 UTC

[4/5] DELTASPIKE-127 credential based authentication

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java
new file mode 100644
index 0000000..3e629ee
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java
@@ -0,0 +1,153 @@
+/*
+ * 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.deltaspike.security.impl.authorization;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.security.api.authorization.AccessDecisionState;
+import org.apache.deltaspike.security.api.authorization.AccessDecisionVoter;
+import org.apache.deltaspike.security.api.authorization.AccessDecisionVoterContext;
+import org.apache.deltaspike.security.api.authorization.AccessDeniedException;
+import org.apache.deltaspike.security.api.authorization.SecurityViolation;
+import org.apache.deltaspike.security.api.authorization.annotation.Secured;
+import org.apache.deltaspike.security.api.authorization.annotation.Secures;
+import org.apache.deltaspike.security.spi.authorization.EditableAccessDecisionVoterContext;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.interceptor.InvocationContext;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Authorizer implementation for the {@link @Secured} annotation
+ */
+@Dependent
+public class SecuredAnnotationAuthorizer
+{
+    @Inject
+    private AccessDecisionVoterContext voterContext;
+
+    @Secures @Secured({ })
+    public boolean doSecuredCheck(InvocationContext invocationContext) throws Exception
+    {
+        Secured secured = null;
+
+        List<Annotation> annotatedTypeMetadata = extractMetadata(invocationContext);
+
+        for (Annotation annotation : annotatedTypeMetadata)
+        {
+            if (Secured.class.isAssignableFrom(annotation.annotationType()))
+            {
+                secured = (Secured) annotation;
+            }
+            else if (voterContext instanceof EditableAccessDecisionVoterContext)
+            {
+                ((EditableAccessDecisionVoterContext) voterContext)
+                        .addMetaData(annotation.annotationType().getName(), annotation);
+            }
+        }
+
+        if (secured != null)
+        {
+            Class<? extends AccessDecisionVoter>[] voterClasses = secured.value();
+
+            invokeVoters(invocationContext, Arrays.asList(voterClasses));
+        }
+
+        //needed by @SecurityBindingType
+        //X TODO check the use-cases for it
+        return true;
+    }
+
+    private List<Annotation> extractMetadata(InvocationContext invocationContext)
+    {
+        List<Annotation> result = new ArrayList<Annotation>();
+
+        Method method = invocationContext.getMethod();
+
+        result.addAll(SecurityUtils.getAllAnnotations(method.getAnnotations()));
+        result.addAll(SecurityUtils.getAllAnnotations(method.getDeclaringClass().getAnnotations()));
+
+        return result;
+    }
+
+    /**
+     * Helper for invoking the given {@link AccessDecisionVoter}s
+     *
+     * @param invocationContext    current invocation-context (might be null in case of secured views)
+     * @param accessDecisionVoters current access-decision-voters
+     */
+    private void invokeVoters(InvocationContext invocationContext,
+                              List<Class<? extends AccessDecisionVoter>> accessDecisionVoters)
+    {
+        if (accessDecisionVoters == null)
+        {
+            return;
+        }
+
+        AccessDecisionState voterState = AccessDecisionState.VOTE_IN_PROGRESS;
+        try
+        {
+            if (voterContext instanceof EditableAccessDecisionVoterContext)
+            {
+                ((EditableAccessDecisionVoterContext) voterContext).setState(voterState);
+                ((EditableAccessDecisionVoterContext) voterContext).setSource(invocationContext);
+            }
+
+            Set<SecurityViolation> violations;
+
+            AccessDecisionVoter voter;
+            for (Class<? extends AccessDecisionVoter> voterClass : accessDecisionVoters)
+            {
+                voter = BeanProvider.getContextualReference(voterClass, false);
+
+                violations = voter.checkPermission(voterContext);
+
+                if (violations != null && violations.size() > 0)
+                {
+                    if (voterContext instanceof EditableAccessDecisionVoterContext)
+                    {
+                        voterState = AccessDecisionState.VIOLATION_FOUND;
+                        for (SecurityViolation securityViolation : violations)
+                        {
+                            ((EditableAccessDecisionVoterContext) voterContext).addViolation(securityViolation);
+                        }
+                    }
+                    throw new AccessDeniedException(violations);
+                }
+            }
+        }
+        finally
+        {
+            if (voterContext instanceof EditableAccessDecisionVoterContext)
+            {
+                if (AccessDecisionState.VOTE_IN_PROGRESS.equals(voterState))
+                {
+                    voterState = AccessDecisionState.NO_VIOLATION_FOUND;
+                }
+
+                ((EditableAccessDecisionVoterContext) voterContext).setState(voterState);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityExtension.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityExtension.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityExtension.java
new file mode 100644
index 0000000..8805166
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityExtension.java
@@ -0,0 +1,286 @@
+/*
+ * 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.deltaspike.security.impl.authorization;
+
+import org.apache.deltaspike.core.api.metadata.builder.AnnotatedTypeBuilder;
+import org.apache.deltaspike.core.spi.activation.Deactivatable;
+import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.apache.deltaspike.security.api.authorization.SecurityDefinitionException;
+import org.apache.deltaspike.security.api.authorization.annotation.Secures;
+import org.apache.deltaspike.security.spi.authentication.Authenticator;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeShutdown;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.enterprise.inject.spi.ProcessSessionBean;
+import javax.enterprise.inject.spi.SessionBeanType;
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Extension for processing typesafe security annotations
+ */
+public class SecurityExtension implements Extension, Deactivatable
+{
+    private static final SecurityInterceptorBinding INTERCEPTOR_BINDING = new SecurityInterceptorBindingLiteral();
+
+    //workaround for OWB
+    private static final Map<ClassLoader, SecurityMetaDataStorage> SECURITY_METADATA_STORAGE_MAPPING
+        = new ConcurrentHashMap<ClassLoader, SecurityMetaDataStorage>();
+
+    private Boolean isActivated = null;
+
+    //workaround for OWB
+    public static SecurityMetaDataStorage getMetaDataStorage()
+    {
+        ClassLoader classLoader = ClassUtils.getClassLoader(null);
+
+        SecurityMetaDataStorage securityMetaDataStorage = SECURITY_METADATA_STORAGE_MAPPING.get(classLoader);
+
+        if (securityMetaDataStorage == null)
+        {
+            securityMetaDataStorage = new SecurityMetaDataStorage();
+            SECURITY_METADATA_STORAGE_MAPPING.put(classLoader, securityMetaDataStorage);
+        }
+
+        return securityMetaDataStorage;
+    }
+
+    public static void removeMetaDataStorage()
+    {
+        ClassLoader classLoader = ClassUtils.getClassLoader(null);
+        SECURITY_METADATA_STORAGE_MAPPING.remove(classLoader);
+    }
+
+    protected void init(@Observes BeforeBeanDiscovery afterBeanDiscovery)
+    {
+        initActivation();
+    }
+
+    /**
+     * @param <X>
+     * @param event
+     * @param beanManager
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    public <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> event, final BeanManager beanManager)
+    {
+        if (!this.isActivated)
+        {
+            return;
+        }
+
+        AnnotatedTypeBuilder<X> builder = null;
+        AnnotatedType<X> type = event.getAnnotatedType();
+        
+        boolean isSecured = false;
+
+        // Add the security interceptor to the class if the class is annotated
+        // with a security binding type
+        for (final Annotation annotation : type.getAnnotations())
+        {
+            if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+            {
+                builder = new AnnotatedTypeBuilder<X>().readFromType(type);
+                builder.addToClass(INTERCEPTOR_BINDING);
+                isSecured = true;
+                break;
+            }
+        }
+
+        // If the class isn't annotated with a security binding type, check if
+        // any of its methods are, and if so, add the security interceptor to the
+        // method
+        if (!isSecured) 
+        {
+            for (final AnnotatedMethod<? super X> m : type.getMethods()) 
+            {
+                if (m.isAnnotationPresent(Secures.class)) 
+                {
+                    registerAuthorizer(m, beanManager);
+                    continue;
+                }
+
+                for (final Annotation annotation : m.getAnnotations()) 
+                {
+                    if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+                    {
+                        if (builder == null) 
+                        {
+                            builder = new AnnotatedTypeBuilder<X>().readFromType(type);
+                        }
+                        builder.addToMethod(m, INTERCEPTOR_BINDING);
+                        isSecured = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // If either the bean or any of its methods are secured, register it
+        if (isSecured) 
+        {
+            getMetaDataStorage().addSecuredType(type);
+        }
+
+        if (builder != null) 
+        {
+            event.setAnnotatedType(builder.create());
+        }
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    public void validateBindings(@Observes AfterBeanDiscovery event, BeanManager beanManager)
+    {
+        if (!this.isActivated)
+        {
+            return;
+        }
+
+        SecurityMetaDataStorage metaDataStorage = getMetaDataStorage();
+
+        for (final AnnotatedType<?> type : metaDataStorage.getSecuredTypes())
+        {
+            // Here we simply want to validate that each type that is annotated with
+            // one or more security bindings has a valid authorizer for each binding
+
+            for (final Annotation annotation : type.getJavaClass().getAnnotations()) 
+            {
+                boolean found = false;
+
+                if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+                {
+                    // Validate the authorizer
+                    for (Authorizer auth : metaDataStorage.getAuthorizers())
+                    {
+                        if (auth.matchesBinding(annotation)) 
+                        {
+                            found = true;
+                            break;
+                        }
+                    }
+
+                    if (!found) 
+                    {
+                        event.addDefinitionError(new SecurityDefinitionException("Secured type " +
+                                type.getJavaClass().getName() +
+                                " has no matching authorizer method for security binding @" +
+                                annotation.annotationType().getName()));
+                    }
+                }
+            }
+
+            for (final AnnotatedMethod<?> method : type.getMethods()) 
+            {
+                for (final Annotation annotation : method.getAnnotations()) 
+                {
+                    if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+                    {
+                        metaDataStorage.registerSecuredMethod(type.getJavaClass(), method.getJavaMember());
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Clear securedTypes, we don't require it any more
+        metaDataStorage.resetSecuredTypes();
+    }
+
+    protected void cleanup(@Observes BeforeShutdown beforeShutdown)
+    {
+        removeMetaDataStorage();
+    }
+
+    /**
+     * Registers the specified authorizer method (i.e. a method annotated with
+     * the @Secures annotation)
+     *
+     * @param m
+     * @param beanManager
+     * @throws SecurityDefinitionException
+     */
+    private void registerAuthorizer(AnnotatedMethod<?> m, BeanManager beanManager)
+    {
+        if (!m.getJavaMember().getReturnType().equals(Boolean.class) &&
+                !m.getJavaMember().getReturnType().equals(Boolean.TYPE))
+        {
+            throw new SecurityDefinitionException("Invalid authorizer method [" +
+                    m.getJavaMember().getDeclaringClass().getName() + "." +
+                    m.getJavaMember().getName() + "] - does not return a boolean.");
+        }
+
+        // Locate the binding type
+        Annotation binding = null;
+
+        for (Annotation annotation : m.getAnnotations())
+        {
+            if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+            {
+                if (binding != null)
+                {
+                    throw new SecurityDefinitionException("Invalid authorizer method [" +
+                            m.getJavaMember().getDeclaringClass().getName() + "." +
+                            m.getJavaMember().getName() + "] - declares multiple security binding types");
+                }
+                binding = annotation;
+            }
+        }
+
+        Authorizer authorizer = new Authorizer(binding, m, beanManager);
+        getMetaDataStorage().addAuthorizer(authorizer);
+    }
+
+    /**
+     * Ensures that any implementations of the Authenticator interface are not stateless session beans.
+     *
+     * @param event
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    public void validateAuthenticatorImplementation(@Observes ProcessSessionBean<Authenticator> event)
+    {
+        if (!this.isActivated)
+        {
+            return;
+        }
+
+        if (SessionBeanType.STATELESS.equals(event.getSessionBeanType()))
+        {
+            event.addDefinitionError(new IllegalStateException("Authenticator " + 
+                event.getBean().getClass() + " cannot be a Stateless Session Bean"));
+        }
+    }
+
+    public void initActivation()
+    {
+        if (isActivated == null)
+        {
+            isActivated = ClassDeactivationUtils.isActivated(getClass());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptor.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptor.java
new file mode 100644
index 0000000..277bac1
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.deltaspike.security.impl.authorization;
+
+import org.apache.deltaspike.security.spi.authorization.SecurityStrategy;
+
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+
+/**
+ * Interceptor for {@link SecurityInterceptorBinding} - details see {@link SecurityStrategy}
+ */
+@SecurityInterceptorBinding
+@Interceptor
+public class SecurityInterceptor implements Serializable
+{
+    private static final long serialVersionUID = -7094673146532371976L;
+
+    @Inject
+    private SecurityStrategy securityStrategy;
+
+    @AroundInvoke
+    public Object filterDeniedInvocations(InvocationContext invocationContext) throws Exception
+    {
+        return this.securityStrategy.execute(invocationContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBinding.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBinding.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBinding.java
new file mode 100644
index 0000000..0cd3dd6
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBinding.java
@@ -0,0 +1,39 @@
+/*
+ * 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.deltaspike.security.impl.authorization;
+
+import javax.interceptor.InterceptorBinding;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Interceptor binding type for SecurityInterceptor.  Users should not apply
+ * this binding themselves, it is applied by the security portable extension.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@InterceptorBinding
+@Target({ElementType.TYPE, ElementType.METHOD })
+@interface SecurityInterceptorBinding 
+{
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBindingLiteral.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBindingLiteral.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBindingLiteral.java
new file mode 100644
index 0000000..5888e0c
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityInterceptorBindingLiteral.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.apache.deltaspike.security.impl.authorization;
+
+import javax.enterprise.util.AnnotationLiteral;
+
+/**
+ * Annotation literal for SecurityInterceptorBinding 
+ */
+class SecurityInterceptorBindingLiteral extends AnnotationLiteral<SecurityInterceptorBinding> 
+    implements SecurityInterceptorBinding
+{
+    private static final long serialVersionUID = 2189092542638784524L;
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityMetaDataStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityMetaDataStorage.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityMetaDataStorage.java
new file mode 100644
index 0000000..298256e
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityMetaDataStorage.java
@@ -0,0 +1,238 @@
+/*
+ * 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.deltaspike.security.impl.authorization;
+
+import org.apache.deltaspike.security.api.authorization.SecurityDefinitionException;
+
+import javax.enterprise.inject.spi.AnnotatedType;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+class SecurityMetaDataStorage
+{
+    /**
+     * Contains all known authorizers
+     */
+    private Set<Authorizer> authorizers = new HashSet<Authorizer>();
+
+    /**
+     * Contains all known secured types
+     */
+    private Set<AnnotatedType<?>> securedTypes = new HashSet<AnnotatedType<?>>();
+
+    /**
+     * A mapping between a secured method of a class and its authorizers
+     */
+    private Map<Class<?>, Map<Method, Set<Authorizer>>> methodAuthorizers =
+        new HashMap<Class<?>, Map<Method, Set<Authorizer>>>();
+
+
+    void addAuthorizer(Authorizer authorizer)
+    {
+        this.authorizers.add(authorizer);
+    }
+
+    void addSecuredType(AnnotatedType<?> annotatedType)
+    {
+        this.securedTypes.add(annotatedType);
+    }
+
+    Set<AnnotatedType<?>> getSecuredTypes()
+    {
+        return securedTypes;
+    }
+
+    void resetSecuredTypes()
+    {
+        this.securedTypes = null;
+    }
+
+    /**
+     * This method is invoked by the security interceptor to obtain the
+     * authorizer stack for a secured method
+     *
+     * @param targetClass
+     * @param targetMethod
+     * @return
+     */
+    Set<Authorizer> getAuthorizers(Class<?> targetClass, Method targetMethod)
+    {
+        if (!isMethodMetaDataAvailable(targetClass, targetMethod))
+        {
+            registerSecuredMethod(targetClass, targetMethod);
+        }
+
+        return getMethodAuthorizers(targetClass, targetMethod);
+    }
+
+    synchronized void registerSecuredMethod(Class<?> targetClass, Method targetMethod)
+    {
+        ensureInitializedAuthorizersForClass(targetClass);
+
+        if (!containsMethodAuthorizers(targetClass, targetMethod))
+        {
+            // Build a list of all security bindings on both the method and its declaring class
+            Set<Annotation> bindings = new HashSet<Annotation>();
+
+            Class<?> cls = targetClass;
+            while (!cls.equals(Object.class))
+            {
+                for (final Annotation annotation : cls.getAnnotations())
+                {
+                    if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+                    {
+                        bindings.add(annotation);
+                    }
+                }
+                cls = cls.getSuperclass();
+            }
+
+            for (final Annotation annotation : targetMethod.getAnnotations())
+            {
+                if (SecurityUtils.isMetaAnnotatedWithSecurityBindingType(annotation))
+                {
+                    bindings.add(annotation);
+                }
+            }
+
+            Set<Authorizer> authorizerStack = new HashSet<Authorizer>();
+
+            for (Annotation binding : bindings)
+            {
+                boolean found = false;
+
+                // For each security binding, find a valid authorizer
+                for (Authorizer authorizer : this.authorizers)
+                {
+                    if (authorizer.matchesBinding(binding))
+                    {
+                        if (found)
+                        {
+                            StringBuilder sb = new StringBuilder();
+                            sb.append("Matching authorizer methods found: [");
+                            sb.append(authorizer.getImplementationMethod().getDeclaringClass().getName());
+                            sb.append(".");
+                            sb.append(authorizer.getImplementationMethod().getName());
+                            sb.append("]");
+
+                            for (Authorizer a : authorizerStack)
+                            {
+                                if (a.matchesBinding(binding))
+                                {
+                                    sb.append(", [");
+                                    sb.append(a.getImplementationMethod().getDeclaringClass().getName());
+                                    sb.append(".");
+                                    sb.append(a.getImplementationMethod().getName());
+                                    sb.append("]");
+                                }
+                            }
+
+                            throw new SecurityDefinitionException(
+                                    "Ambiguous authorizers found for security binding type [@" +
+                                            binding.annotationType().getName() + "] on method [" +
+                                            targetMethod.getDeclaringClass().getName() + "." +
+                                            targetMethod.getName() + "]. " + sb.toString());
+                        }
+
+                        authorizerStack.add(authorizer);
+                        found = true;
+                    }
+                }
+
+                if (!found)
+                {
+                    throw new SecurityDefinitionException(
+                            "No matching authorizer found for security binding type [@" +
+                                    binding.annotationType().getName() + "] on method [" +
+                                    targetMethod.getDeclaringClass().getName() + "." +
+                                    targetMethod.getName() + "].");
+                }
+            }
+            addMethodAuthorizer(targetClass, targetMethod, authorizerStack);
+        }
+    }
+
+    Set<Authorizer> getAuthorizers()
+    {
+        return authorizers;
+    }
+
+    private boolean containsMethodAuthorizers(Class<?> targetClass, Method targetMethod)
+    {
+        Map<Method, Set<Authorizer>> resultForClass = this.methodAuthorizers.get(targetClass);
+        return resultForClass.containsKey(targetMethod);
+    }
+
+    private void ensureInitializedAuthorizersForClass(Class<?> targetClass)
+    {
+        Map<Method, Set<Authorizer>> resultForClass = this.methodAuthorizers.get(targetClass);
+
+        if (resultForClass == null)
+        {
+            this.methodAuthorizers.put(targetClass, new HashMap<Method, Set<Authorizer>>());
+        }
+    }
+
+    private boolean isMethodMetaDataAvailable(Class<?> targetClass, Method targetMethod)
+    {
+        Map<Method, Set<Authorizer>> result = this.methodAuthorizers.get(targetClass);
+        return result != null && result.containsKey(targetMethod);
+    }
+
+    private void addMethodAuthorizer(Class<?> targetClass, Method targetMethod, Set<Authorizer> authorizersToAdd)
+    {
+        Map<Method, Set<Authorizer>> authorizerMapping = this.methodAuthorizers.get(targetClass);
+
+        if (authorizerMapping == null)
+        {
+            authorizerMapping = new HashMap<Method, Set<Authorizer>>();
+            this.methodAuthorizers.put(targetClass, authorizerMapping);
+        }
+
+        Set<Authorizer> authorizersForMethod = authorizerMapping.get(targetMethod);
+
+        if (authorizersForMethod == null)
+        {
+            authorizersForMethod = new HashSet<Authorizer>();
+            authorizerMapping.put(targetMethod, authorizersForMethod);
+        }
+
+        authorizersForMethod.addAll(authorizersToAdd);
+    }
+
+    private Set<Authorizer> getMethodAuthorizers(Class<?> targetClass, Method targetMethod)
+    {
+        Map<Method, Set<Authorizer>> resultForClass = this.methodAuthorizers.get(targetClass);
+
+        if (resultForClass == null)
+        {
+            throw new IllegalStateException(
+                    "no meta-data available for: " + targetClass.getName() + targetMethod.getName());
+        }
+
+        return resultForClass.get(targetMethod);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityUtils.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityUtils.java
new file mode 100644
index 0000000..4ff9880
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecurityUtils.java
@@ -0,0 +1,90 @@
+/*
+ * 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.deltaspike.security.impl.authorization;
+
+import org.apache.deltaspike.security.api.authorization.annotation.SecurityBindingType;
+
+import javax.enterprise.inject.Stereotype;
+import javax.enterprise.inject.Typed;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.List;
+
+@Typed()
+abstract class SecurityUtils
+{
+    private SecurityUtils()
+    {
+        // prevent instantiation
+    }
+
+    static boolean isMetaAnnotatedWithSecurityBindingType(Annotation annotation)
+    {
+        if (annotation.annotationType().isAnnotationPresent(SecurityBindingType.class))
+        {
+            return true;
+        }
+
+        List<Annotation> result = getAllAnnotations(annotation.annotationType().getAnnotations());
+
+        for (Annotation foundAnnotation : result)
+        {
+            if (SecurityBindingType.class.isAssignableFrom(foundAnnotation.annotationType()))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static Annotation resolveSecurityBindingType(Annotation annotation)
+    {
+        List<Annotation> result = getAllAnnotations(annotation.annotationType().getAnnotations());
+
+        for (Annotation foundAnnotation : result)
+        {
+            if (foundAnnotation.annotationType().isAnnotationPresent(SecurityBindingType.class))
+            {
+                return foundAnnotation;
+            }
+        }
+        throw new IllegalStateException(annotation.annotationType().getName() + " is a " + Stereotype.class.getName() +
+                " but it isn't annotated with " + SecurityBindingType.class.getName());
+    }
+
+    static List<Annotation> getAllAnnotations(Annotation[] annotations)
+    {
+        List<Annotation> result = new ArrayList<Annotation>();
+
+        String annotationName;
+        for (Annotation annotation : annotations)
+        {
+            annotationName = annotation.annotationType().getName();
+            if (annotationName.startsWith("java.") || annotationName.startsWith("javax."))
+            {
+                continue;
+            }
+
+            result.add(annotation);
+            result.addAll(getAllAnnotations(annotation.annotationType().getAnnotations()));
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/credential/DefaultLoginCredential.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/credential/DefaultLoginCredential.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/credential/DefaultLoginCredential.java
new file mode 100644
index 0000000..78aaedc
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/credential/DefaultLoginCredential.java
@@ -0,0 +1,93 @@
+/*
+ * 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.deltaspike.security.impl.credential;
+
+import org.apache.deltaspike.security.api.authentication.events.LoginFailedEvent;
+import org.apache.deltaspike.security.api.authentication.events.PostAuthenticateEvent;
+import org.apache.deltaspike.security.api.credential.Credential;
+import org.apache.deltaspike.security.api.credential.LoginCredential;
+
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Named;
+
+/**
+ * The default LoginCredential implementation.  This implementation allows for a
+ * username and plain text password to be set, and uses the PasswordCredential
+ * implementation of the Credential interface for authentication.
+ */
+@Named("loginCredential")
+@RequestScoped
+public class DefaultLoginCredential implements LoginCredential
+{
+    private Credential credential;
+
+    private String userId;
+
+    @Override
+    public String getUserId()
+    {
+        return userId;
+    }
+
+    @Override
+    public void setUserId(String userId)
+    {
+        this.userId = userId;
+    }
+
+    public Credential getCredential()
+    {
+        return credential;
+    }
+
+    public void setCredential(Credential credential)
+    {
+        this.credential = credential;
+        //X TODO manager.fireEvent(new CredentialsUpdatedEvent(this.credential));
+    }
+
+    public void invalidate()
+    {
+        this.credential = null;
+        this.userId = null;
+    }
+
+    protected void setValid(@Observes PostAuthenticateEvent event)
+    {
+        invalidate();
+    }
+
+    protected void afterLogin(@Observes PostAuthenticateEvent event)
+    {
+        invalidate();
+    }
+
+    //X TODO discuss
+    protected void loginFailed(@Observes LoginFailedEvent event)
+    {
+        invalidate();
+    }
+
+    @Override
+    public String toString() 
+    {
+        return "LoginCredential[" + (this.userId != null ? this.userId : "unknown" ) + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/jaas/JaasAuthenticator.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/jaas/JaasAuthenticator.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/jaas/JaasAuthenticator.java
deleted file mode 100644
index 36ea6ca..0000000
--- a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/jaas/JaasAuthenticator.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.deltaspike.security.impl.jaas;
-
-import java.io.IOException;
-
-import javax.enterprise.context.RequestScoped;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.apache.deltaspike.security.api.BaseAuthenticator;
-import org.apache.deltaspike.security.api.Credentials;
-import org.apache.deltaspike.security.api.Identity;
-import org.apache.deltaspike.security.impl.PasswordCredential;
-import org.apache.deltaspike.security.spi.Authenticator;
-
-/**
- * An authenticator for authenticating with JAAS.  The jaasConfigName property
- * _must_ be configured to point to a valid JAAS configuration name, typically
- * defined in a file called login-config.xml in the application server.
- */
-@Named
-@RequestScoped
-public class JaasAuthenticator extends BaseAuthenticator implements Authenticator 
-{
-    @Inject
-    private Identity identity;
-    
-    @Inject
-    private Credentials credentials;
-    
-    @Inject
-    private BeanManager manager;
-
-    private Subject subject;
-
-    private String jaasConfigName = null;
-
-    public JaasAuthenticator() 
-    {
-        subject = new Subject();
-    }
-
-    public void authenticate() 
-    {
-        if (getJaasConfigName() == null) 
-        {
-            throw new IllegalStateException(
-                    "jaasConfigName cannot be null.  Please set it to a valid JAAS configuration name.");
-        }
-
-        try 
-        {
-            getLoginContext().login();
-            setStatus(AuthenticationStatus.SUCCESS);
-        } 
-        catch (LoginException e) 
-        {
-            setStatus(AuthenticationStatus.FAILURE);
-            //log.error("JAAS authentication failed", e);
-        }
-    }
-
-    protected LoginContext getLoginContext() throws LoginException 
-    {
-        return new LoginContext(getJaasConfigName(), subject,
-                createCallbackHandler());
-    }
-
-    /**
-     * Creates a callback handler that can handle a standard username/password
-     * callback, using the credentials username and password properties
-     */
-    public CallbackHandler createCallbackHandler() 
-    {
-        return new CallbackHandler() 
-        {
-            public void handle(Callback[] callbacks)
-                throws IOException, UnsupportedCallbackException 
-            {
-                for (int i = 0; i < callbacks.length; i++) 
-                {
-                    if (callbacks[i] instanceof NameCallback) 
-                    {
-                        ((NameCallback) callbacks[i]).setName(credentials.getUsername());
-                    } 
-                    else if (callbacks[i] instanceof PasswordCallback) 
-                    {
-                        if (credentials.getCredential() instanceof PasswordCredential) 
-                        {
-                            PasswordCredential credential = (PasswordCredential) credentials.getCredential();
-                            ((PasswordCallback) callbacks[i]).setPassword(credential.getValue() != null ?
-                                    credential.getValue().toCharArray() : null);
-                        }
-                    } 
-                    else 
-                    {
-                        //log.warn("Unsupported callback " + callbacks[i]);
-                    }
-                }
-            }
-        };
-    }
-
-    public String getJaasConfigName() 
-    {
-        return jaasConfigName;
-    }
-
-    public void setJaasConfigName(String jaasConfigName) 
-    {
-        this.jaasConfigName = jaasConfigName;
-    }
-
-    public void postAuthenticate() 
-    {
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/management/IdmAuthenticator.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/management/IdmAuthenticator.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/management/IdmAuthenticator.java
deleted file mode 100644
index ba34374..0000000
--- a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/management/IdmAuthenticator.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.deltaspike.security.impl.management;
-
-import org.apache.deltaspike.security.api.User;
-import org.apache.deltaspike.security.spi.Authenticator;
-
-/**
- * Authenticates using the Identity Management API
- * 
- *  TODO - discuss the Identity Management API before implementing this class
- */
-public class IdmAuthenticator implements Authenticator
-{
-
-    @Override
-    public void authenticate()
-    {
-        // TODO Auto-generated method stub
-        
-    }
-
-    @Override
-    public void postAuthenticate()
-    {
-        // TODO Auto-generated method stub
-        
-    }
-
-    @Override
-    public AuthenticationStatus getStatus()
-    {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public User getUser()
-    {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/resources/META-INF/beans.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/resources/META-INF/beans.xml b/deltaspike/modules/security/impl/src/main/resources/META-INF/beans.xml
index ec7e07b..65b3b51 100644
--- a/deltaspike/modules/security/impl/src/main/resources/META-INF/beans.xml
+++ b/deltaspike/modules/security/impl/src/main/resources/META-INF/beans.xml
@@ -21,6 +21,6 @@
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
     <interceptors>
-        <class>org.apache.deltaspike.security.impl.SecurityInterceptor</class>
+        <class>org.apache.deltaspike.security.impl.authorization.SecurityInterceptor</class>
     </interceptors>
 </beans>

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/deltaspike/modules/security/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index 7973b93..8d0c21d 100644
--- a/deltaspike/modules/security/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/deltaspike/modules/security/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -17,4 +17,4 @@
 # under the License.
 #####################################################################################
 
-org.apache.deltaspike.security.impl.SecurityExtension
+org.apache.deltaspike.security.impl.authorization.SecurityExtension

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/FailedLoginFailedObserver.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/FailedLoginFailedObserver.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/FailedLoginFailedObserver.java
new file mode 100644
index 0000000..8ed2da3
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/FailedLoginFailedObserver.java
@@ -0,0 +1,40 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import org.apache.deltaspike.security.api.authentication.events.LoginFailedEvent;
+
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Observes;
+
+@RequestScoped
+public class FailedLoginFailedObserver
+{
+    private Exception observedException;
+
+    protected void onFailedLogin(@Observes LoginFailedEvent loginFailedEvent)
+    {
+        this.observedException = loginFailedEvent.getLoginException();
+    }
+
+    Exception getObservedException()
+    {
+        return observedException;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InMemoryUserStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InMemoryUserStorage.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InMemoryUserStorage.java
new file mode 100644
index 0000000..1bc9134
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InMemoryUserStorage.java
@@ -0,0 +1,40 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import org.apache.deltaspike.core.api.exclude.Exclude;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Exclude
+class InMemoryUserStorage
+{
+    private static Map<String, String> simpleUserPasswordMapping = new ConcurrentHashMap<String, String>();
+    
+    static void setPassword(String userName, String password)
+    {
+        simpleUserPasswordMapping.put(userName, password);
+    }
+    
+    static String getPassword(String userName)
+    {
+        return simpleUserPasswordMapping.get(userName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Inquiry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Inquiry.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Inquiry.java
new file mode 100644
index 0000000..7f16109
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Inquiry.java
@@ -0,0 +1,24 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+interface Inquiry
+{
+    String getInquiryId();
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryEntry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryEntry.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryEntry.java
new file mode 100644
index 0000000..bae1b86
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryEntry.java
@@ -0,0 +1,78 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import javax.enterprise.inject.Typed;
+
+@Typed()
+class InquiryEntry
+{
+    private final String userName;
+    private final Inquiry inquiry;
+
+    InquiryEntry(String userName, Inquiry inquiry)
+    {
+        this.userName = userName;
+        this.inquiry = inquiry;
+    }
+
+    String getUserName()
+    {
+        return userName;
+    }
+
+    Inquiry getInquiry()
+    {
+        return inquiry;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass())
+        {
+            return false;
+        }
+
+        InquiryEntry that = (InquiryEntry) o;
+
+        if (!inquiry.equals(that.inquiry))
+        {
+            return false;
+        }
+        if (!userName.equals(that.userName))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = userName.hashCode();
+        result = 31 * result + inquiry.hashCode();
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryStorage.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryStorage.java
new file mode 100644
index 0000000..1b19cd0
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/InquiryStorage.java
@@ -0,0 +1,24 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+public interface InquiryStorage
+{
+    boolean addInquiry(Inquiry inquiry);
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/LoginLogoutTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/LoginLogoutTest.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/LoginLogoutTest.java
new file mode 100644
index 0000000..2dbc420
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/LoginLogoutTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.impl.exclude.ExcludeExtension;
+import org.apache.deltaspike.security.api.Identity;
+import org.apache.deltaspike.security.api.authentication.UnexpectedCredentialException;
+import org.apache.deltaspike.security.api.credential.LoginCredential;
+import org.apache.deltaspike.test.util.ArchiveUtils;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.enterprise.inject.spi.Extension;
+import javax.inject.Inject;
+
+
+/**
+ * Test for {@link org.apache.deltaspike.security.api.authorization.annotation.Secured}
+ */
+@RunWith(Arquillian.class)
+public class LoginLogoutTest
+{
+    @Inject
+    private TestAuthenticator authenticator;
+
+    @Inject
+    private TestInquiryStorage testInquiryStorage;
+
+    @Inject
+    private ShopClient shopClient;
+
+    @Inject
+    private Identity identity;
+
+    @Inject
+    private FailedLoginFailedObserver failedLoginFailedObserver;
+
+    @Deployment
+    public static WebArchive deploy()
+    {
+        new BeanManagerProvider() {
+            @Override
+            public void setTestMode()
+            {
+                super.setTestMode();
+            }
+        }.setTestMode();
+
+        JavaArchive testJar = ShrinkWrap.create(JavaArchive.class, "loginLogoutTest.jar")
+                .addPackage("org.apache.deltaspike.test.security.impl.authentication")
+                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+
+        return ShrinkWrap.create(WebArchive.class)
+                .addAsLibraries(ArchiveUtils.getDeltaSpikeCoreAndSecurityArchive())
+                .addAsLibraries(testJar)
+                .addAsServiceProvider(Extension.class, ExcludeExtension.class)
+                .addAsWebInfResource(ArchiveUtils.getBeansXml(), "beans.xml");
+    }
+
+    @Test
+    public void loginAndLogout()
+    {
+        final String userName = "spike";
+        final String password = "apache";
+        
+        //init
+        this.authenticator.register(userName, password);
+
+        //start
+        this.shopClient.login(userName, password);
+
+        Assert.assertTrue(this.identity.isLoggedIn());
+        Assert.assertEquals(userName, this.identity.getUser().getId());
+
+        Assert.assertNotNull(this.shopClient.requestNewProduct("Security module for DeltaSpike"));
+
+
+        this.shopClient.logout();
+        Assert.assertFalse(this.identity.isLoggedIn());
+
+
+        Assert.assertNotNull(this.shopClient.requestNewProduct("I18n module for DeltaSpike"));
+
+        Assert.assertEquals(1, this.testInquiryStorage.getUserInquiries().size());
+        Assert.assertEquals(userName, this.testInquiryStorage.getUserInquiries().iterator().next().getUserName());
+
+        Assert.assertEquals(1, this.testInquiryStorage.getAnonymInquiries().size());
+
+        Assert.assertFalse(this.testInquiryStorage.getUserInquiries().iterator().next().getInquiry()
+                .equals(this.testInquiryStorage.getAnonymInquiries().iterator()));
+    }
+
+    @Test
+    public void failedLogin()
+    {
+        final String userName = "spike";
+        final String password = "apache";
+
+        //init
+        this.authenticator.register(userName, password);
+
+        //start
+        this.shopClient.login(userName, "123");
+
+        Assert.assertFalse(this.identity.isLoggedIn());
+    }
+
+    //TODO use context-control
+    @Test
+    public void failedForcedReLogin()
+    {
+        final String userName = "spike";
+        final String password = "apache";
+
+        //init
+        this.authenticator.register(userName, password);
+
+        //start
+        this.shopClient.login(userName, password);
+
+        Assert.assertTrue(this.identity.isLoggedIn());
+        Assert.assertEquals(userName, this.identity.getUser().getId());
+
+        //X TODO stop and start new request via ContextControl - instead of:
+        BeanProvider.getContextualReference(LoginCredential.class).invalidate();
+
+        try
+        {
+            this.shopClient.login("xyz", "123");
+        }
+        catch (UnexpectedCredentialException e)
+        {
+            //noinspection ThrowableResultOfMethodCallIgnored
+            Assert.assertTrue(this.failedLoginFailedObserver.getObservedException()
+                    instanceof UnexpectedCredentialException);
+
+            // still logged in
+            Assert.assertTrue(this.identity.isLoggedIn());
+            return;
+        }
+
+        Assert.fail();
+    }
+
+    //X TODO add tests for the events
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/NewProductInquiry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/NewProductInquiry.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/NewProductInquiry.java
new file mode 100644
index 0000000..c037f53
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/NewProductInquiry.java
@@ -0,0 +1,58 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import java.util.UUID;
+
+class NewProductInquiry implements Inquiry
+{
+    private String question;
+
+    private String id;
+    
+    NewProductInquiry(String question)
+    {
+        this.question = question;
+        this.id = UUID.randomUUID().toString();
+    }
+
+    @Override
+    public String getInquiryId()
+    {
+        return this.id;
+    }
+
+    @Override
+    public String toString()
+    {
+        return this.question;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return this.id.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return obj instanceof NewProductInquiry && this.id.equals(((NewProductInquiry) obj).id);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Shop.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Shop.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Shop.java
new file mode 100644
index 0000000..2fcbdfe
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/Shop.java
@@ -0,0 +1,43 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+/**
+ *
+ */
+@ApplicationScoped
+public class Shop
+{
+    @Inject
+    private InquiryStorage inquiryStorage;
+
+    public String sendInquiry(Inquiry inquiry)
+    {
+        if (this.inquiryStorage.addInquiry(inquiry))
+        {
+            return inquiry.getInquiryId();
+            //TODO e.g. send notification in case of inquiries of premium users,...
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/ShopClient.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/ShopClient.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/ShopClient.java
new file mode 100644
index 0000000..158aa7d
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/ShopClient.java
@@ -0,0 +1,64 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import org.apache.deltaspike.security.api.Identity;
+import org.apache.deltaspike.security.api.credential.Credential;
+import org.apache.deltaspike.security.api.credential.LoginCredential;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+@ApplicationScoped
+public class ShopClient
+{
+    @Inject
+    private LoginCredential loginCredential;
+
+    @Inject
+    private Identity identity;
+
+    @Inject
+    private Shop shop;
+
+    public void login(String userName, final String password)
+    {
+        this.loginCredential.setUserId(userName);
+        //TODO discuss #setSecurityToken
+        this.loginCredential.setCredential(new Credential<String>() {
+            @Override
+            public String getValue()
+            {
+                return password;
+            }
+        });
+
+        this.identity.login();
+    }
+
+    public void logout()
+    {
+        this.identity.logout();
+    }
+
+    public String requestNewProduct(String customText)
+    {
+        return this.shop.sendInquiry(new NewProductInquiry(customText));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestAuthenticator.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestAuthenticator.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestAuthenticator.java
new file mode 100644
index 0000000..8d4737b
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestAuthenticator.java
@@ -0,0 +1,61 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import org.apache.deltaspike.security.api.User;
+import org.apache.deltaspike.security.api.credential.LoginCredential;
+import org.apache.deltaspike.security.spi.authentication.BaseAuthenticator;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+
+@RequestScoped
+public class TestAuthenticator extends BaseAuthenticator
+{
+    @Inject
+    private LoginCredential loginCredential;
+
+    private User user;
+
+    @Override
+    public void authenticate()
+    {
+        String password = InMemoryUserStorage.getPassword(this.loginCredential.getUserId());
+
+        if (password != null && password.equals(this.loginCredential.getCredential().getValue()))
+        {
+            setStatus(AuthenticationStatus.SUCCESS);
+            this.user = new User(this.loginCredential.getUserId());
+            return;
+        }
+
+        setStatus(AuthenticationStatus.FAILURE);
+    }
+
+    @Override
+    public User getUser()
+    {
+        return this.user;
+    }
+
+    void register(String userName, String password)
+    {
+        InMemoryUserStorage.setPassword(userName, password);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestInquiryStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestInquiryStorage.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestInquiryStorage.java
new file mode 100644
index 0000000..6d2a56f
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authentication/TestInquiryStorage.java
@@ -0,0 +1,61 @@
+/*
+ * 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.deltaspike.test.security.impl.authentication;
+
+import org.apache.deltaspike.security.api.Identity;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@ApplicationScoped
+public class TestInquiryStorage implements InquiryStorage
+{
+    private Map<String, InquiryEntry> userInquiries = new ConcurrentHashMap<String, InquiryEntry>();
+
+    private Map<String, Inquiry> anonymInquiries = new ConcurrentHashMap<String, Inquiry>();
+
+    @Inject
+    private Identity identity;
+
+    public boolean addInquiry(Inquiry inquiry)
+    {
+        if(identity.isLoggedIn())
+        {
+            userInquiries.put(inquiry.getInquiryId(), new InquiryEntry(identity.getUser().getId(), inquiry));
+        }
+        else
+        {
+            this.anonymInquiries.put(inquiry.getInquiryId(), inquiry);
+        }
+        return true;
+    }
+    
+    Collection<InquiryEntry> getUserInquiries()
+    {
+        return this.userInquiries.values();
+    }
+
+    Collection<Inquiry> getAnonymInquiries()
+    {
+        return this.anonymInquiries.values();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredAnnotationTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredAnnotationTest.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredAnnotationTest.java
new file mode 100644
index 0000000..26ed4ee
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredAnnotationTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.deltaspike.test.security.impl.authorization.secured;
+
+import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.impl.exclude.ExcludeExtension;
+import org.apache.deltaspike.security.api.authorization.AccessDeniedException;
+import org.apache.deltaspike.test.util.ArchiveUtils;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.enterprise.inject.spi.Extension;
+
+
+/**
+ * Test for {@link org.apache.deltaspike.security.api.authorization.annotation.Secured}
+ */
+@RunWith(Arquillian.class)
+public class SecuredAnnotationTest
+{
+    @Deployment
+    public static WebArchive deploy()
+    {
+        new BeanManagerProvider() {
+            @Override
+            public void setTestMode()
+            {
+                super.setTestMode();
+            }
+        }.setTestMode();
+
+        JavaArchive testJar = ShrinkWrap.create(JavaArchive.class, "securedAnnotationTest.jar")
+                .addPackage("org.apache.deltaspike.test.security.impl.authorization.secured")
+                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+
+        return ShrinkWrap.create(WebArchive.class)
+                .addAsLibraries(ArchiveUtils.getDeltaSpikeCoreAndSecurityArchive())
+                .addAsLibraries(testJar)
+                .addAsServiceProvider(Extension.class, ExcludeExtension.class)
+                .addAsWebInfResource(ArchiveUtils.getBeansXml(), "beans.xml");
+    }
+
+    @Test
+    public void simpleInterceptorTest()
+    {
+        SecuredBean1 testBean = BeanProvider.getContextualReference(SecuredBean1.class, false);
+
+        Assert.assertEquals("result", testBean.getResult());
+
+        try
+        {
+            testBean.getBlockedResult();
+            Assert.fail();
+        }
+        catch (AccessDeniedException e)
+        {
+            //expected exception
+        }
+    }
+
+    @Test
+    public void interceptorTestWithStereotype()
+    {
+        SecuredBean2 testBean = BeanProvider.getContextualReference(SecuredBean2.class, false);
+
+        Assert.assertEquals("result", testBean.getResult());
+
+        try
+        {
+            testBean.getBlockedResult();
+            Assert.fail();
+        }
+        catch (AccessDeniedException e)
+        {
+            //expected exception
+        }
+    }
+
+    @Test
+    public void simpleInterceptorTestOnMethods()
+    {
+        SecuredBean3 testBean = BeanProvider.getContextualReference(SecuredBean3.class, false);
+
+        Assert.assertEquals("result", testBean.getResult());
+
+        try
+        {
+            testBean.getBlockedResult();
+            Assert.fail();
+        }
+        catch (AccessDeniedException e)
+        {
+            //expected exception
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/1a2c7ffd/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredBean1.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredBean1.java b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredBean1.java
new file mode 100644
index 0000000..41b21b1
--- /dev/null
+++ b/deltaspike/modules/security/impl/src/test/java/org/apache/deltaspike/test/security/impl/authorization/secured/SecuredBean1.java
@@ -0,0 +1,38 @@
+/*
+ * 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.deltaspike.test.security.impl.authorization.secured;
+
+import org.apache.deltaspike.security.api.authorization.annotation.Secured;
+
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+@Secured(TestAccessDecisionVoter.class)
+public class SecuredBean1
+{
+    public String getBlockedResult()
+    {
+        return "blocked result";
+    }
+
+    public String getResult()
+    {
+        return "result";
+    }
+}