Repository: aries-jax-rs-whiteboard
Updated Branches:
  refs/heads/master 3ffc07222 -> 16da11274


Add an integration for Apache Shiro to the JAX-RS Whiteboard


Project: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/commit/16da1127
Tree: 
http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/tree/16da1127
Diff: 
http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/diff/16da1127

Branch: refs/heads/master
Commit: 16da11274073e47dbdc633d31c14631219729d2c
Parents: 3ffc072
Author: Tim Ward <[email protected]>
Authored: Tue Aug 7 16:07:48 2018 +0100
Committer: Tim Ward <[email protected]>
Committed: Wed Aug 8 10:32:32 2018 +0100

----------------------------------------------------------------------
 README.md                                       |   8 +-
 integrations/README.md                          |  40 +++
 integrations/pom.xml                            |  44 +++
 integrations/shiro/README.md                    |  23 ++
 integrations/shiro/pom.xml                      |  51 ++++
 integrations/shiro/shiro-authc/bnd.bnd          |  27 ++
 integrations/shiro/shiro-authc/pom.xml          |  68 +++++
 .../impl/SecurityManagerAssociatingFilter.java  | 161 ++++++++++
 .../impl/ShiroAuthenticationActivator.java      | 137 +++++++++
 .../authc/impl/ShiroAuthenticationFeature.java  | 128 ++++++++
 .../ShiroAuthenticationFeatureProvider.java     |  43 +++
 integrations/shiro/shiro-authz/bnd.bnd          |  27 ++
 integrations/shiro/shiro-authz/pom.xml          |  68 +++++
 .../authz/impl/ShiroAuthorizationActivator.java |  94 ++++++
 .../authz/impl/ShiroAuthorizationFeature.java   | 101 ++++++
 integrations/shiro/shiro-itest/bnd.bnd          |  22 ++
 integrations/shiro/shiro-itest/itest.bndrun     |  72 +++++
 integrations/shiro/shiro-itest/pom.xml          | 208 +++++++++++++
 .../src/main/java/test/ShiroTest.java           | 192 ++++++++++++
 .../src/main/java/test/types/TestHelper.java    | 306 +++++++++++++++++++
 .../java/test/types/TestShiroAnnotations.java   |  58 ++++
 .../shiro-itest/src/test/resources/logback.xml  |  35 +++
 22 files changed, 1911 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 0c61a81..3c5345a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,10 @@
 ## JAX-RS Whiteboard
 
-This is an implementation of a JAX-RS Services whiteboard [OSGi 
RFC-217](https://github.com/osgi/design/tree/master/rfcs/rfc0217).
+Aries JAX-RS Whiteboard is the reference implementation of the [OSGi JAX-RS 
Services Whiteboard 
1.0](https://osgi.org/specification/osgi.cmpn/7.0.0/service.jaxrs.html).
+
+## Integrations
+
+The `integrations` folder contains OSGi enabled integrations for a variety of 
useful libraries that you might want to use with JAX-RS. In many cases these 
are just adding OSGi lifecycle and configuration to existing JAX-RS enabled 
libraries.
 
 ## Building
 
@@ -31,4 +35,4 @@ java -jar jax-rs.example-run/example.jar
   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. 
\ No newline at end of file
+  limitations under the License. 

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/README.md
----------------------------------------------------------------------
diff --git a/integrations/README.md b/integrations/README.md
new file mode 100644
index 0000000..16ede67
--- /dev/null
+++ b/integrations/README.md
@@ -0,0 +1,40 @@
+## Integrations
+
+This folder contains OSGi enabled integrations for a variety of useful 
libraries that you might want to use with JAX-RS. In many cases these are just 
adding OSGi lifecycle and configuration to existing JAX-RS enabled libraries.
+
+### Building the integration projects
+
+There is a single reactor pom which builds all of the integration projects, 
however as each project will evolve at different rates they are designed to be 
built and released separately from the whiteboard and other integration 
projects.
+
+## Apache Shiro
+
+[Apache Shiro](https://shiro.apache.org) is an authentication and 
authorization framework. This integration provides:
+
+Authentication:
+
+* Support for authenticating users using Apache Shiro
+* Cookie based user memory
+* Session based logout
+
+Authorization:
+
+* Support for injection of Shiro Security Contexts into your JAX-RS resources
+* Support for Shiro authorization annotations on your JAX-RS resources 
+
+
+## License
+
+  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. 

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/pom.xml
----------------------------------------------------------------------
diff --git a/integrations/pom.xml b/integrations/pom.xml
new file mode 100644
index 0000000..d3004f3
--- /dev/null
+++ b/integrations/pom.xml
@@ -0,0 +1,44 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.aries.jax.rs</groupId>
+    <artifactId>integration</artifactId>
+    <name>Apache Aries JAX-RS Integration Projects Reactor</name>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    
+    <properties>
+        <maven.deploy.skip>true</maven.deploy.skip>
+        <maven.install.skip>true</maven.install.skip>
+    </properties>
+
+    <scm>
+        
<connection>scm:git:https://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard.git</connection>
+        
<developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard.git</developerConnection>
+        
<url>https://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard.git</url>
+      <tag>HEAD</tag>
+  </scm>
+
+    <modules>
+        <module>shiro</module>
+       </modules>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/README.md
----------------------------------------------------------------------
diff --git a/integrations/shiro/README.md b/integrations/shiro/README.md
new file mode 100644
index 0000000..9957d4f
--- /dev/null
+++ b/integrations/shiro/README.md
@@ -0,0 +1,23 @@
+## Apache Shiro
+
+[Apache Shiro](https://shiro.apache.org) is an authentication and 
authorization framework. This integration provides two separate bundles which 
do not necessarily both need to be deployed (although they integrate well 
together
+
+### Shiro Authc
+
+This bundle provides a Shiro-based authentication REST resource for your users.
+
+Key features
+
+* Support for authenticating users using Apache Shiro
+* Cookie based user memory
+* Http Session based
+* Logout support
+
+
+### Shiro Authz
+
+This bundle provides Shiro-based authorization for your REST resources. This 
can be used with the Shiro Authc component, or Shiro authentication can be 
achieved using other means, such as the Shiro Servlet Filter.
+
+* Support for injection of Shiro Security Contexts into your JAX-RS resources
+* Support for Shiro authorization annotations on your JAX-RS resources 
+

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/pom.xml
----------------------------------------------------------------------
diff --git a/integrations/shiro/pom.xml b/integrations/shiro/pom.xml
new file mode 100644
index 0000000..7b460d4
--- /dev/null
+++ b/integrations/shiro/pom.xml
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>org.apache.aries.jax.rs</groupId>
+      <artifactId>org.apache.aries.jax.rs</artifactId>
+      <version>1.0.0</version>
+      <relativePath />
+    </parent>
+
+    <artifactId>shiro-integration</artifactId>
+    <name>Apache Shiro JAX-RS Integration Project</name>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <properties>
+        <aries.jaxrs.version>1.0.0</aries.jaxrs.version>
+        <shiro.version>1.4.0</shiro.version>
+    </properties>
+
+    <scm>
+        
<connection>scm:git:https://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard.git</connection>
+        
<developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard.git</developerConnection>
+        
<url>https://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard.git</url>
+      <tag>HEAD</tag>
+  </scm>
+
+    <modules>
+        <module>shiro-authc</module>
+        <module>shiro-authz</module>
+        <module>shiro-itest</module>
+       </modules>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authc/bnd.bnd
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-authc/bnd.bnd 
b/integrations/shiro/shiro-authc/bnd.bnd
new file mode 100644
index 0000000..b84fda6
--- /dev/null
+++ b/integrations/shiro/shiro-authc/bnd.bnd
@@ -0,0 +1,27 @@
+#    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.
+
+# Ideally we would not include this, but for some reason the Shiro JAX-RS
+# Support is not an OSGi bundle
+
+Export-Package: org.apache.shiro.web.jaxrs;version=${shiro.version}
+
+Conditional-Package: org.apache.aries.component.dsl.*
+
+-contract: *
+
+Bundle-Activator: 
org.apache.aries.jax.rs.shiro.authc.impl.ShiroAuthenticationActivator
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authc/pom.xml
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-authc/pom.xml 
b/integrations/shiro/shiro-authc/pom.xml
new file mode 100644
index 0000000..5ec42c4
--- /dev/null
+++ b/integrations/shiro/shiro-authc/pom.xml
@@ -0,0 +1,68 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.jax.rs</groupId>
+        <artifactId>shiro-integration</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.jax.rs.shiro.authc</artifactId>
+    <description>Apache Aries JAX-RS Shiro Authentication 
Provider</description>
+    <name>Apache Aries JAX-RS Shiro Authentication</name>
+
+       <dependencies>
+           <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>6.0.0</version>
+        </dependency>
+           <dependency>
+            <groupId>org.apache.aries.component-dsl</groupId>
+            
<artifactId>org.apache.aries.component-dsl.component-dsl</artifactId>
+            <version>1.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+           <dependency>
+            <groupId>org.apache.aries.spec</groupId>
+            <artifactId>org.apache.aries.javax.jax.rs-api</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-jaxrs</artifactId>
+            <version>${shiro.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.jaxrs</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+       </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/SecurityManagerAssociatingFilter.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/SecurityManagerAssociatingFilter.java
 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/SecurityManagerAssociatingFilter.java
new file mode 100644
index 0000000..6fa1d82
--- /dev/null
+++ 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/SecurityManagerAssociatingFilter.java
@@ -0,0 +1,161 @@
+/*
+ * 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.aries.jax.rs.shiro.authc.impl;
+
+import static javax.ws.rs.core.HttpHeaders.SET_COOKIE;
+import static 
org.apache.aries.jax.rs.shiro.authc.impl.ShiroAuthenticationFeature.SESSION_COOKIE_NAME;
+
+import java.io.IOException;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.container.PreMatching;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Filter is used to:
+ * 
+ * <ul>
+ *   <li>Associate a SecurityManager with the request</li>
+ *   <li>Set up the current user if a cookie is detected</li>
+ *   <li>Remove the user cookie after the request if the user is logged 
out</li>
+ * </ul>
+ */
+@PreMatching
+public class SecurityManagerAssociatingFilter implements 
ContainerRequestFilter, ContainerResponseFilter {
+
+    private static final Logger _LOG = LoggerFactory.getLogger(
+            SecurityManagerAssociatingFilter.class);
+    
+    private final SecurityManager manager;
+    
+    public SecurityManagerAssociatingFilter(SecurityManager manager) {
+        this.manager = manager;
+    }
+
+    /**
+     * Set up the incoming request context
+     */
+    @Override
+    public void filter(ContainerRequestContext requestContext) throws 
IOException {
+        
+        _LOG.debug("Establishing Shiro Security Context");
+        
+        // Bind the security manager
+        ThreadContext.bind(manager);
+        
+        Cookie cookie = requestContext.getCookies().get(SESSION_COOKIE_NAME);
+        
+        // If we have a session cookie then use it to prime the session value
+        if(cookie != null) {
+            _LOG.debug("Found a Shiro Security Context cookie: {}. 
Establishing user context", cookie);
+            
+            _LOG.debug("Establishing user context:");
+            Subject subject = new 
Subject.Builder(manager).sessionId(cookie.getValue()).buildSubject();
+            ThreadContext.bind(subject);
+            if(_LOG.isDebugEnabled()) {
+                _LOG.debug("Established user context for: {}", 
subject.getPrincipal());
+            }
+        }
+        
+        UriInfo info = requestContext.getUriInfo();
+        
+        if("security/authenticate".equals(info.getPath())) {
+            requestContext.abortWith(authenticate(info, 
requestContext.getHeaderString("user"), 
requestContext.getHeaderString("password")));
+        } else if("security/logout".equals(info.getPath())) {
+            logout();
+        }
+    }
+    
+    /**
+     * Clean up after the request
+     */
+    @Override
+    public void filter(ContainerRequestContext requestContext, 
ContainerResponseContext responseContext)
+            throws IOException {
+        _LOG.debug("Cleaning up the Shiro Security Context");
+        Subject subject = ThreadContext.getSubject();
+        ThreadContext.unbindSecurityManager();
+        ThreadContext.unbindSubject();
+        
+        if(subject != null && !subject.isAuthenticated()) {
+            // Not authenticated. Check for incoming session cookie
+            Cookie cookie = 
requestContext.getCookies().get(SESSION_COOKIE_NAME);
+            
+            // If we have a session cookie then it should be deleted
+            if(cookie != null) {
+                _LOG.debug("The subject associated with this request is not 
authenticated, removing the session cookie");
+                responseContext.getHeaders().add(SET_COOKIE, 
getDeletionCookie(requestContext));
+            }
+        }
+        
+    }
+
+    private NewCookie getDeletionCookie(ContainerRequestContext 
requestContext) {
+        return new NewCookie(SESSION_COOKIE_NAME, "deleteMe", 
+                        requestContext.getUriInfo().getBaseUri().getPath(), 
null, -1, null, -1, null, false, true);
+    }
+    
+    private Response authenticate(UriInfo info, String user, String password) {
+        
+        _LOG.debug("Received a login request for user {}", user);
+        
+        Subject currentUser = SecurityUtils.getSubject();
+        
+        ResponseBuilder rb;
+        
+        if (!currentUser.isAuthenticated()) {
+            _LOG.debug("Authenticating user {}", user);
+            UsernamePasswordToken token = new UsernamePasswordToken(user, 
password);
+            token.setRememberMe(true);
+            currentUser.login(token);
+            
+            rb = Response.ok()
+                    .cookie(new NewCookie(SESSION_COOKIE_NAME, 
currentUser.getSession().getId().toString(), 
+                            info.getBaseUri().getPath(), null, -1, null, -1, 
null, false, true));
+        } else {
+            _LOG.debug("The login request for user {} was already 
authenticated as user {}", user, currentUser.getPrincipal());
+            rb = Response.status(Status.CONFLICT);
+        }
+        return rb.build();
+    }
+
+    private void logout() {
+        _LOG.debug("Received a logout request");
+        Subject currentUser = SecurityUtils.getSubject();
+        
+        if (currentUser.isAuthenticated()) {
+            _LOG.debug("Logging out user {}", currentUser.getPrincipal());
+            currentUser.logout();
+        } 
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationActivator.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationActivator.java
 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationActivator.java
new file mode 100644
index 0000000..8fde563
--- /dev/null
+++ 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationActivator.java
@@ -0,0 +1,137 @@
+/*
+ * 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.aries.jax.rs.shiro.authc.impl;
+
+import static java.lang.Boolean.TRUE;
+import static org.apache.aries.component.dsl.OSGi.coalesce;
+import static org.apache.aries.component.dsl.OSGi.configuration;
+import static org.apache.aries.component.dsl.OSGi.just;
+import static org.apache.aries.component.dsl.OSGi.register;
+import static org.apache.aries.component.dsl.OSGi.serviceReferences;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_EXTENSION;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import javax.ws.rs.core.Feature;
+
+import org.apache.aries.component.dsl.CachingServiceReference;
+import org.apache.aries.component.dsl.OSGi;
+import org.apache.aries.component.dsl.OSGiResult;
+import org.apache.shiro.realm.Realm;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ShiroAuthenticationActivator implements BundleActivator {
+
+    private static final Logger _LOG = LoggerFactory.getLogger(
+            ShiroAuthenticationActivator.class);
+    
+    private OSGiResult registration;
+
+    private BundleContext context;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        
+        this.context = context;
+        _LOG.debug("Starting the Shiro JAX-RS Authentication Feature");
+        
+        registration = coalesce(
+                configuration("org.apache.aries.jax.rs.shiro.authentication"),
+                just(() -> {
+                    
+                    _LOG.debug("Using the default configuration for the Shiro 
JAX-RS Authentication Feature");
+                    
+                    Dictionary<String, Object> properties =
+                        new Hashtable<>();
+
+                    properties.put(
+                        Constants.SERVICE_PID,
+                        "org.apache.aries.jax.rs.shiro.authentication");
+
+                    return properties;
+                })
+        ).map(this::filter)
+         .flatMap(this::setupRealms)
+         .run(context);
+    }
+
+    Map<String, Object> filter(Dictionary<String, ?> props) {
+        Map<String, Object> serviceProps = new Hashtable<>();
+        
+        Enumeration<String> keys = props.keys();
+        while(keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            if(!key.startsWith(".")) {
+                serviceProps.put(key, props.get(key));
+            }
+        }
+        
+        serviceProps.put(JAX_RS_EXTENSION, TRUE);
+        
+        _LOG.debug("Shiro JAX-RS Authentication Feature service properties 
are: {}", serviceProps);
+        
+        return serviceProps;
+    }
+    
+    OSGi<?> setupRealms(Map<String, Object> properties) {
+        
+        Object filter = properties.get("realms.target");
+        
+        ConcurrentSkipListMap<CachingServiceReference<Realm>, Realm> 
discovered = new ConcurrentSkipListMap<>();
+        
+        OSGi<List<Realm>> realms;
+        if(filter == null) {
+            _LOG.debug("The Shiro JAX-RS Authentication Feature is accepting 
all realms");
+            realms = serviceReferences(Realm.class)
+                .effects(csr -> discovered.put(csr, 
context.getService(csr.getServiceReference())), 
+                        csr -> {
+                            discovered.remove(csr);
+                            context.ungetService(csr.getServiceReference());
+                        })
+                .map(x -> new ArrayList<>(discovered.values()));
+        } else {
+            _LOG.debug("The Shiro JAX-RS Authentication Feature is filtering 
realms using the filter {}", filter);
+            realms = serviceReferences(Realm.class, String.valueOf(filter))
+                    .effects(csr -> discovered.put(csr, 
context.getService(csr.getServiceReference())), 
+                            csr -> {
+                                discovered.remove(csr);
+                                
context.ungetService(csr.getServiceReference());
+                            })
+                    .map(x -> new ArrayList<>(discovered.values()));
+        }
+        
+        return realms.map(ShiroAuthenticationFeatureProvider::new)
+                .flatMap(f -> register(Feature.class, f,  properties)
+                        .effects(x -> {}, x -> f.close()));
+    }
+    
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        _LOG.debug("Stopping the Shiro JAX-RS Authentication Feature");
+       registration.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeature.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeature.java
 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeature.java
new file mode 100644
index 0000000..f294a0b
--- /dev/null
+++ 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeature.java
@@ -0,0 +1,128 @@
+/*
+ * 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.aries.jax.rs.shiro.authc.impl;
+
+import static javax.ws.rs.Priorities.AUTHENTICATION;
+import static javax.ws.rs.Priorities.AUTHORIZATION;
+import static javax.ws.rs.Priorities.USER;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SERVICE_PROPERTIES;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_NAME;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.web.jaxrs.ExceptionMapper;
+import org.apache.shiro.web.jaxrs.ShiroFeature;
+import org.apache.shiro.web.jaxrs.SubjectPrincipalRequestFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This type adds support for establishing Shiro Authentication in a JAX-RS 
container
+ * using native JAX-RS features, rather than relying on an external Servlet 
Container.
+ * As a result some common features of the ShiroFilter are not supported, but 
native
+ * JAX-RS containers (i.e. ones that don't support Servlets) are able to be 
used. 
+ * 
+ * <p> Where possible we reuse types from the {@link ShiroFeature}, and where 
these
+ * overlap with types used in authorization we must register carefully, as it 
is not
+ * allowed to register the same extension twice. Also the ShiroFeature does 
not make 
+ * correct use of priorities when registering. This Feature therefore:
+ * 
+ * <ul>
+ *   <li>Avoids duplicate registrations with extension types that are also 
used in authorization.</li>
+ *   <li>Uses priorities to indicate that these are authentication 
extensions</li>
+ * </ul>
+ *
+ */
+public class ShiroAuthenticationFeature implements Feature {
+
+    private static final Logger _LOG = LoggerFactory.getLogger(
+            ShiroAuthenticationFeature.class);
+    
+    public static final String SESSION_COOKIE_NAME = "JAXRSSESSIONID";
+    
+    private final List<Realm> realms;
+    
+    private final DefaultSecurityManager manager;
+    
+    public ShiroAuthenticationFeature(List<Realm> realms) {
+        this.realms = realms;
+        this.manager = realms.isEmpty() ? new DefaultSecurityManager() : new 
DefaultSecurityManager(realms);
+    }
+
+    @Override
+    public boolean configure(FeatureContext fc) {
+        
+        Configuration configuration = fc.getConfiguration();
+        
+        if(_LOG.isInfoEnabled()) {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> applicationProps = (Map<String, Object>) 
configuration.getProperty(JAX_RS_APPLICATION_SERVICE_PROPERTIES);
+            _LOG.info("Registering the Shiro Authentication feature with 
application {}", 
+                    applicationProps.getOrDefault(JAX_RS_NAME, "<No Name found 
in application configuration>"));
+        }
+        
+        if(realms.isEmpty()) {
+            _LOG.warn("There are no authentication realms available. Users may 
not be able to authenticate.");
+        } else {
+            _LOG.debug("Using the authentication realms {}.", realms);
+        }
+
+        _LOG.debug("Registering the Shiro SecurityManagerAssociatingFilter");
+        fc.register(new SecurityManagerAssociatingFilter(manager), 
AUTHENTICATION);
+
+        Map<Class<?>, Integer> contracts = 
configuration.getContracts(ExceptionMapper.class);
+        if(contracts.isEmpty()) {
+            _LOG.debug("Registering the Shiro ExceptionMapper");
+            // Only register the ExceptionMapper if it isn't already registered
+            fc.register(ExceptionMapper.class, AUTHENTICATION);
+        } else if(AUTHENTICATION < 
contracts.getOrDefault(javax.ws.rs.ext.ExceptionMapper.class, USER)) {
+            _LOG.debug("Updating the priority of the Shiro ExceptionMapper 
from {} to {}",
+                    
contracts.getOrDefault(javax.ws.rs.ext.ExceptionMapper.class, USER),
+                    AUTHORIZATION);
+            // Update the priority if it's registered too low
+            contracts.put(javax.ws.rs.ext.ExceptionMapper.class, 
AUTHENTICATION);
+        }
+
+        contracts = 
configuration.getContracts(SubjectPrincipalRequestFilter.class);
+        if(contracts.isEmpty()) {
+            _LOG.debug("Registering the Shiro SubjectPrincipalRequestFilter");
+            // Only register the SubjectPrincipalRequestFilter if it isn't 
already registered
+            // and make sure it always comes after the 
SecurityManagerAssociatingFilter
+            fc.register(SubjectPrincipalRequestFilter.class, AUTHENTICATION + 
1);
+        } else if(AUTHENTICATION < 
contracts.getOrDefault(ContainerRequestFilter.class, USER)) {
+            _LOG.debug("Updating the priority of the Shiro 
SubjectPrincipalRequestFilter from {} to {}",
+                    contracts.getOrDefault(ContainerRequestFilter.class, USER),
+                    AUTHENTICATION + 1);
+            // Update the priority if it's registered too low
+            contracts.put(ContainerRequestFilter.class, AUTHENTICATION + 1);
+        }
+        
+        return true;
+    }
+
+    public void close() {
+        manager.destroy();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeatureProvider.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeatureProvider.java
 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeatureProvider.java
new file mode 100644
index 0000000..ae5bf42
--- /dev/null
+++ 
b/integrations/shiro/shiro-authc/src/main/java/org/apache/aries/jax/rs/shiro/authc/impl/ShiroAuthenticationFeatureProvider.java
@@ -0,0 +1,43 @@
+package org.apache.aries.jax.rs.shiro.authc.impl;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.Feature;
+
+import org.apache.shiro.realm.Realm;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.PrototypeServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+public class ShiroAuthenticationFeatureProvider implements 
PrototypeServiceFactory<Feature> {
+
+    private final List<Realm> realms;
+    
+    private final Set<ShiroAuthenticationFeature> features = 
Collections.synchronizedSet(new HashSet<>());
+    
+    public ShiroAuthenticationFeatureProvider(List<Realm> realms) {
+        this.realms = realms;
+    }
+    
+    @Override
+    public ShiroAuthenticationFeature getService(Bundle bundle, 
ServiceRegistration<Feature> registration) {
+        ShiroAuthenticationFeature authenticationFeature = new 
ShiroAuthenticationFeature(realms);
+        features.add(authenticationFeature);
+        return authenticationFeature;
+    }
+
+    @Override
+    public void ungetService(Bundle bundle, ServiceRegistration<Feature> 
registration, Feature service) {
+        if(features.remove(service)) {
+            ((ShiroAuthenticationFeature) service).close();
+        }
+    }
+
+    public void close() {
+        features.forEach(ShiroAuthenticationFeature::close);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authz/bnd.bnd
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-authz/bnd.bnd 
b/integrations/shiro/shiro-authz/bnd.bnd
new file mode 100644
index 0000000..a29ec70
--- /dev/null
+++ b/integrations/shiro/shiro-authz/bnd.bnd
@@ -0,0 +1,27 @@
+#    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.
+
+# Ideally we would not include this, but for some reason the Shiro JAX-RS
+# Support is not an OSGi bundle
+
+Export-Package: org.apache.shiro.web.jaxrs;version=${shiro.version}
+
+Conditional-Package: org.apache.aries.component.dsl.*
+
+-contract: *
+
+Bundle-Activator: 
org.apache.aries.jax.rs.shiro.authz.impl.ShiroAuthorizationActivator
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authz/pom.xml
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-authz/pom.xml 
b/integrations/shiro/shiro-authz/pom.xml
new file mode 100644
index 0000000..375350b
--- /dev/null
+++ b/integrations/shiro/shiro-authz/pom.xml
@@ -0,0 +1,68 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.jax.rs</groupId>
+        <artifactId>shiro-integration</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.jax.rs.shiro.authz</artifactId>
+    <description>Apache Aries JAX-RS Shiro Authorization Provider</description>
+    <name>Apache Aries JAX-RS Shiro Authorization</name>
+
+       <dependencies>
+               <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>6.0.0</version>
+        </dependency>
+               <dependency>
+            <groupId>org.apache.aries.component-dsl</groupId>
+            
<artifactId>org.apache.aries.component-dsl.component-dsl</artifactId>
+            <version>1.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+           <dependency>
+            <groupId>org.apache.aries.spec</groupId>
+            <artifactId>org.apache.aries.javax.jax.rs-api</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-jaxrs</artifactId>
+            <version>${shiro.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.jaxrs</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+       </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationActivator.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationActivator.java
 
b/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationActivator.java
new file mode 100644
index 0000000..06476df
--- /dev/null
+++ 
b/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationActivator.java
@@ -0,0 +1,94 @@
+/*
+ * 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.aries.jax.rs.shiro.authz.impl;
+
+import static java.lang.Boolean.TRUE;
+import static org.apache.aries.component.dsl.OSGi.coalesce;
+import static org.apache.aries.component.dsl.OSGi.configuration;
+import static org.apache.aries.component.dsl.OSGi.just;
+import static org.apache.aries.component.dsl.OSGi.register;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_EXTENSION;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.ws.rs.core.Feature;
+
+import org.apache.aries.component.dsl.OSGiResult;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ShiroAuthorizationActivator implements BundleActivator {
+    
+    private static final Logger _LOG = LoggerFactory.getLogger(
+            ShiroAuthorizationActivator.class);
+
+    private OSGiResult _registration;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        
+        _LOG.debug("Starting the Shiro JAX-RS Authorization Feature");
+        
+        _registration = coalesce(
+                configuration("org.apache.aries.jax.rs.shiro.authorization"),
+                just(() -> {
+                    
+                    _LOG.debug("Using the default configuration for the Shiro 
JAX-RS Authorization Feature");
+                    
+                    Dictionary<String, Object> properties =
+                        new Hashtable<>();
+
+                    properties.put(
+                        Constants.SERVICE_PID,
+                        "org.apache.aries.jax.rs.shiro.authorization");
+
+                    return properties;
+                })
+        ).map(this::filter)
+         .flatMap(p -> register(Feature.class, new 
ShiroAuthorizationFeature(), p))
+         .run(context);
+    }
+
+    Map<String, Object> filter(Dictionary<String, ?> props) {
+        Map<String, Object> serviceProps = new Hashtable<>();
+        
+        Enumeration<String> keys = props.keys();
+        while(keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            if(!key.startsWith(".")) {
+                serviceProps.put(key, props.get(key));
+            }
+        }
+        
+        serviceProps.put(JAX_RS_EXTENSION, TRUE);
+
+        _LOG.debug("Shiro JAX-RS Authorization Feature service properties are: 
{}", serviceProps);
+        return serviceProps;
+    }
+    
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        _LOG.debug("Stopping the Shiro JAX-RS Authorization Feature");
+       _registration.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationFeature.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationFeature.java
 
b/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationFeature.java
new file mode 100644
index 0000000..a0fd4f8
--- /dev/null
+++ 
b/integrations/shiro/shiro-authz/src/main/java/org/apache/aries/jax/rs/shiro/authz/impl/ShiroAuthorizationFeature.java
@@ -0,0 +1,101 @@
+/*
+ * 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.aries.jax.rs.shiro.authz.impl;
+
+import static javax.ws.rs.Priorities.AUTHORIZATION;
+import static javax.ws.rs.Priorities.USER;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SERVICE_PROPERTIES;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_NAME;
+
+import java.util.Map;
+
+import javax.ws.rs.Priorities;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+
+import org.apache.shiro.web.jaxrs.ExceptionMapper;
+import org.apache.shiro.web.jaxrs.ShiroAnnotationFilterFeature;
+import org.apache.shiro.web.jaxrs.ShiroFeature;
+import org.apache.shiro.web.jaxrs.SubjectPrincipalRequestFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This type mirrors {@link ShiroFeature}, by registering an {@link 
ExceptionMapper},
+ * {@link SubjectPrincipalRequestFilter} and {@link 
ShiroAnnotationFilterFeature}.
+ * 
+ * <p>We cannot use the {@link ShiroFeature} directly because several of the 
extension 
+ * types it registers are also used to enable authentication, and it is not 
allowed to 
+ * register the same extension twice. Also the ShiroFeature does not make 
correct use
+ * of priorities when registering. This Feature therefore:
+ * 
+ * <ul>
+ *   <li>Avoids duplicate registrations with extension types that are also 
used in authentication.</li>
+ *   <li>Uses priorities to indicate that these are authorization 
extensions</li>
+ * </ul>
+ *
+ */
+public class ShiroAuthorizationFeature implements Feature {
+
+    private static final Logger _LOG = LoggerFactory.getLogger(
+            ShiroAuthorizationFeature.class);
+    
+    @Override
+    public boolean configure(FeatureContext fc) {
+
+        Configuration configuration = fc.getConfiguration();
+        
+        if(_LOG.isInfoEnabled()) {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> applicationProps = (Map<String, Object>) 
configuration.getProperty(JAX_RS_APPLICATION_SERVICE_PROPERTIES);
+            _LOG.info("Registering the Shiro Authorization feature with 
application {}", 
+                    applicationProps.getOrDefault(JAX_RS_NAME, "<No Name found 
in application configuration>"));
+        }
+        
+        Map<Class<?>, Integer> contracts = 
configuration.getContracts(ExceptionMapper.class);
+        if(contracts.isEmpty()) {
+            _LOG.debug("Registering the Shiro ExceptionMapper");
+            // Only register the ExceptionMapper if it isn't already registered
+            fc.register(ExceptionMapper.class, AUTHORIZATION);
+        } else if(AUTHORIZATION < 
contracts.getOrDefault(javax.ws.rs.ext.ExceptionMapper.class, USER)) {
+            _LOG.debug("Updating the priority of the Shiro ExceptionMapper 
from {} to {}",
+                    
contracts.getOrDefault(javax.ws.rs.ext.ExceptionMapper.class, USER),
+                    AUTHORIZATION);
+            // Update the priority if it's registered too low
+            contracts.put(javax.ws.rs.ext.ExceptionMapper.class, 
AUTHORIZATION);
+        }
+
+        contracts = 
configuration.getContracts(SubjectPrincipalRequestFilter.class);
+        if(contracts.isEmpty()) {
+            _LOG.debug("Registering the Shiro SubjectPrincipalRequestFilter");
+            // Only register the SubjectPrincipalRequestFilter if it isn't 
already registered
+            fc.register(SubjectPrincipalRequestFilter.class, AUTHORIZATION);
+        } else if(AUTHORIZATION < 
contracts.getOrDefault(ContainerRequestFilter.class, USER)) {
+            _LOG.debug("Updating the priority of the Shiro 
SubjectPrincipalRequestFilter from {} to {}",
+                    contracts.getOrDefault(ContainerRequestFilter.class, USER),
+                    AUTHORIZATION);
+            // Update the priority if it's registered too low
+            contracts.put(ContainerRequestFilter.class, AUTHORIZATION);
+        }
+        
+        _LOG.debug("Registering the Shiro ShiroAnnotationFilterFeature");
+        fc.register(ShiroAnnotationFilterFeature.class, 
Priorities.AUTHORIZATION);
+        return true;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/bnd.bnd
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-itest/bnd.bnd 
b/integrations/shiro/shiro-itest/bnd.bnd
new file mode 100644
index 0000000..25ba42e
--- /dev/null
+++ b/integrations/shiro/shiro-itest/bnd.bnd
@@ -0,0 +1,22 @@
+#    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.
+
+Bundle-Description: Integration Test bundle for the JSON-P Whiteboard support
+
+Test-Cases: ${classes;CONCRETE;EXTENDS;test.types.TestHelper}
+
+Require-Capability: 
osgi.service;filter:="(objectClass=org.osgi.service.cm.ConfigurationAdmin)"

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/itest.bndrun
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-itest/itest.bndrun 
b/integrations/shiro/shiro-itest/itest.bndrun
new file mode 100644
index 0000000..2de44aa
--- /dev/null
+++ b/integrations/shiro/shiro-itest/itest.bndrun
@@ -0,0 +1,72 @@
+#    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.
+
+-standalone: ${.}/target/index.xml
+
+-runrequires: \
+       
osgi.identity;filter:='(osgi.identity=org.apache.aries.jax.rs.shiro.itest)',\
+       
osgi.identity;filter:='(osgi.identity=org.apache.aries.jax.rs.whiteboard)',\
+       osgi.identity;filter:='(osgi.identity=ch.qos.logback.classic)',\
+       
osgi.identity;filter:='(osgi.identity=org.apache.aries.jax.rs.shiro.authc)',\
+       
osgi.identity;filter:='(osgi.identity=org.apache.aries.jax.rs.shiro.authz)',\
+       bnd.identity;id='org.apache.felix.gogo.command',\
+       bnd.identity;id='org.apache.felix.gogo.runtime',\
+       bnd.identity;id='org.apache.felix.gogo.shell'
+
+-runfw: org.apache.felix.framework;version='[6.0.0,6.0.1]'
+
+-runtrace: true
+
+-runee: JavaSE-1.8
+-resolve.effective: resolve, active
+
+-runsystemcapabilities: ${native_capability}
+-runproperties: \
+       logback.configurationFile=file:${.}/src/test/resources/logback.xml,\
+       org.apache.felix.http.host=localhost,\
+       org.osgi.service.http.port=*
+-runblacklist:\
+       osgi.identity;filter:='(osgi.identity=org.osgi.compendium)',\
+       osgi.identity;filter:='(osgi.identity=osgi.cmpn)'
+-runbundles: \
+       ch.qos.logback.classic;version='[1.2.3,1.2.4)',\
+       ch.qos.logback.core;version='[1.2.3,1.2.4)',\
+       org.apache.felix.configadmin;version='[1.8.14,1.8.15)',\
+       org.apache.felix.eventadmin;version='[1.4.8,1.4.9)',\
+       org.apache.felix.http.jetty;version='[3.4.0,3.4.1)',\
+       org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
+       org.osgi.service.jaxrs;version='[1.0.0,1.0.1)',\
+       org.osgi.util.function;version='[1.1.0,1.1.1)',\
+       org.osgi.util.promise;version='[1.1.0,1.1.1)',\
+       osgi.enroute.hamcrest.wrapper;version='[1.3.0,1.3.1)',\
+       osgi.enroute.junit.wrapper;version='[4.12.0,4.12.1)',\
+       slf4j.api;version='[1.7.25,1.7.26)',\
+       org.apache.servicemix.specs.annotation-api-1.3;version='[1.3.0,1.3.1)',\
+       org.apache.aries.jax.rs.shiro.authc;version='[1.0.0,1.0.1)',\
+       org.apache.aries.jax.rs.shiro.authz;version='[1.0.0,1.0.1)',\
+       org.apache.aries.jax.rs.shiro.itest;version='[1.0.0,1.0.1)',\
+       org.apache.commons.configuration;version='[2.2.0,2.2.1)',\
+       org.apache.commons.lang3;version='[3.6.0,3.6.1)',\
+       org.apache.commons.logging;version='[1.2.0,1.2.1)',\
+       org.apache.shiro.core;version='[1.4.0,1.4.1)',\
+       org.apache.felix.gogo.command;version='[1.0.2,1.0.3)',\
+       org.apache.felix.gogo.runtime;version='[1.1.0,1.1.1)',\
+       org.apache.felix.gogo.shell;version='[1.1.0,1.1.1)',\
+       org.apache.shiro.crypto.core;version='[1.4.0,1.4.1)',\
+       org.apache.aries.javax.jax.rs-api;version='[1.0.0,1.0.1)',\
+       org.apache.aries.jax.rs.whiteboard;version='[1.0.0,1.0.1)'
+-include: -personal.bnd

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/pom.xml
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-itest/pom.xml 
b/integrations/shiro/shiro-itest/pom.xml
new file mode 100644
index 0000000..7cd1d78
--- /dev/null
+++ b/integrations/shiro/shiro-itest/pom.xml
@@ -0,0 +1,208 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.apache.aries.jax.rs</groupId>
+               <artifactId>shiro-integration</artifactId>
+               <version>1.0.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>org.apache.aries.jax.rs.shiro.itest</artifactId>
+       <description>Apache Aries JAX-RS Shiro Integration Tests</description>
+       <name>Apache Aries JAX-RS Shiro Integration Tests</name>
+
+       <properties>
+               <maven.deploy.skip>true</maven.deploy.skip>
+               <maven.install.skip>true</maven.install.skip>
+       </properties>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>biz.aQute.bnd</groupId>
+                               
<artifactId>bnd-indexer-maven-plugin</artifactId>
+                               <configuration>
+                                       <includeJar>true</includeJar>
+                                       <localURLs>REQUIRED</localURLs>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>biz.aQute.bnd</groupId>
+                               <artifactId>bnd-maven-plugin</artifactId>
+                       </plugin>
+                       <plugin>
+                               <groupId>biz.aQute.bnd</groupId>
+                               
<artifactId>bnd-resolver-maven-plugin</artifactId>
+                               <configuration>
+                                       <failOnChanges>false</failOnChanges>
+                                       <bndruns>
+                                               <bndrun>itest.bndrun</bndrun>
+                                       </bndruns>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>biz.aQute.bnd</groupId>
+                               
<artifactId>bnd-testing-maven-plugin</artifactId>
+                               <configuration>
+                                       <failOnChanges>true</failOnChanges>
+                                       <resolve>false</resolve>
+                                       <bndruns>
+                                               <bndrun>itest.bndrun</bndrun>
+                                       </bndruns>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+       <dependencies>
+               <dependency>
+                       <groupId>ch.qos.logback</groupId>
+                       <artifactId>logback-classic</artifactId>
+                       <version>1.2.3</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>osgi.core</artifactId>
+                       <version>6.0.0</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>osgi.annotation</artifactId>
+                       <version>7.0.0</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.shiro</groupId>
+                       <artifactId>shiro-core</artifactId>
+                       <version>${shiro.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.aries.spec</groupId>
+                       
<artifactId>org.apache.aries.javax.jax.rs-api</artifactId>
+                       <version>${aries.jaxrs.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.service.cm</artifactId>
+                       <version>1.5.0</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.aries.jax.rs</groupId>
+                       
<artifactId>org.apache.aries.jax.rs.shiro.authc</artifactId>
+                       <version>${project.version}</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.aries.jax.rs</groupId>
+                       
<artifactId>org.apache.aries.jax.rs.shiro.authz</artifactId>
+                       <version>${project.version}</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.commons</groupId>
+                       <artifactId>commons-configuration2</artifactId>
+                       <version>2.2</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.aries.jax.rs</groupId>
+                       
<artifactId>org.apache.aries.jax.rs.whiteboard</artifactId>
+                       <version>${aries.jaxrs.version}</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.configadmin</artifactId>
+                       <version>1.8.14</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.eventadmin</artifactId>
+                       <version>1.4.8</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.http.jetty</artifactId>
+                       <version>3.4.0</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.scr</artifactId>
+                       <version>2.1.0</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.framework</artifactId>
+                       <version>6.0.0</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.log</artifactId>
+                       <version>1.0.1</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.service.jaxrs</artifactId>
+                       <version>1.0.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.util.function</artifactId>
+                       <version>1.1.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.util.promise</artifactId>
+                       <version>1.1.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>osgi.enroute.junit.wrapper</artifactId>
+                       <version>4.12.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>osgi.enroute.hamcrest.wrapper</artifactId>
+                       <version>1.3.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.gogo.runtime</artifactId>
+                       <version>1.1.0</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.gogo.shell</artifactId>
+                       <version>1.1.0</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.felix</groupId>
+                       <artifactId>org.apache.felix.gogo.command</artifactId>
+                       <version>1.0.2</version>
+                       <scope>runtime</scope>
+               </dependency>
+       </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/src/main/java/test/ShiroTest.java
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-itest/src/main/java/test/ShiroTest.java 
b/integrations/shiro/shiro-itest/src/main/java/test/ShiroTest.java
new file mode 100644
index 0000000..2ea3e83
--- /dev/null
+++ b/integrations/shiro/shiro-itest/src/main/java/test/ShiroTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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 test;
+
+import static java.lang.Boolean.TRUE;
+import static org.junit.Assert.assertEquals;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_EXTENSION_SELECT;
+
+import java.util.Hashtable;
+
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.realm.SimpleAccountRealm;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.annotation.bundle.Capability;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+
+import test.types.TestHelper;
+import test.types.TestShiroAnnotations;
+
+@Capability(namespace="osgi.service", 
attribute="objectClass=org.apache.shiro.realm.Realm")
+public class ShiroTest extends TestHelper {
+
+    private Configuration authzConfig, authcConfig;
+    
+    SimpleAccountRealm realm;
+    
+    ServiceRegistration<Realm> reg;
+
+    @Before
+    public void setupConfigs() throws Exception {
+        authzConfig = getConfigurationAdmin()
+                
.getConfiguration("org.apache.aries.jax.rs.shiro.authorization");
+        
+        Hashtable<String, Object> table = new Hashtable<>();
+        table.put("shiro.authz", TRUE);
+        table.put(JAX_RS_EXTENSION_SELECT, "(shiro.authc=true)");
+        authzConfig.update(table);
+
+        authcConfig = getConfigurationAdmin()
+                
.getConfiguration("org.apache.aries.jax.rs.shiro.authentication");
+        
+        table = new Hashtable<>();
+        table.put("shiro.authc", TRUE);
+        authcConfig.update(table);
+        
+        realm = new SimpleAccountRealm();
+        
+        reg = bundleContext.registerService(Realm.class, realm, null);
+
+        Thread.sleep(1000);
+    }
+
+    @After
+    public void cleanUp() throws Exception {
+        authzConfig.delete();
+        
+        authcConfig.delete();
+        
+        reg.unregister();
+    }
+    
+    @Test
+    public void testGuestNoAuthPresent() throws Exception {
+        WebTarget webTarget = createDefaultTarget().path("test/guest");
+
+        registerAddon(new TestShiroAnnotations(), JAX_RS_EXTENSION_SELECT, 
"(shiro.authz=true)");
+        
+        assertEquals("Welcome Guest", webTarget.request().get(String.class));
+    }
+
+    @Test
+    public void testAuthenticatedNoAuthPresent() throws Exception {
+        WebTarget webTarget = createDefaultTarget().path("test/authenticated");
+        
+        registerAddon(new TestShiroAnnotations(), JAX_RS_EXTENSION_SELECT, 
"(shiro.authz=true)");
+        
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), 
webTarget.request().get().getStatus());
+    }
+
+    
+    @Test
+    public void testGuestAuthPresent() throws Exception {
+        
+        realm.addAccount("Bill", "Ben");
+        
+        WebTarget target = createDefaultTarget();
+        
+        registerAddon(new TestShiroAnnotations(), JAX_RS_EXTENSION_SELECT, 
"(shiro.authz=true)");
+
+        Response authenticate = target.path("security/authenticate").request()
+                .header("user", "Bill")
+                .header("password", "Ben")
+                .post(null);
+        assertEquals(Status.OK.getStatusCode(), authenticate.getStatus());
+    
+    
+        Builder request = target.path("test/guest").request();
+        authenticate.getCookies().values().forEach(c -> 
request.cookie(c.getName(), c.getValue()));
+        
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), 
request.get().getStatus());
+    }
+    
+    @Test
+    public void testAuthenticatedAuthPresent() throws Exception {
+        
+        realm.addAccount("Bill", "Ben");
+        
+        WebTarget target = createDefaultTarget();
+        
+        registerAddon(new TestShiroAnnotations(), JAX_RS_EXTENSION_SELECT, 
"(shiro.authz=true)");
+
+        Response authenticate = target.path("security/authenticate").request()
+                    .header("user", "Bill")
+                    .header("password", "Ben")
+                    .post(null);
+        assertEquals(Status.OK.getStatusCode(), authenticate.getStatus());
+        
+        
+        Builder request = target.path("test/authenticated").request();
+        authenticate.getCookies().values().forEach(c -> 
request.cookie(c.getName(), c.getValue()));
+        
+        assertEquals("Welcome Bill", request.get(String.class));
+    }
+
+    @Test
+    public void testRoleAuthPresent() throws Exception {
+        
+        realm.addAccount("Bill", "Ben");
+        
+        WebTarget target = createDefaultTarget();
+        
+        registerAddon(new TestShiroAnnotations(), JAX_RS_EXTENSION_SELECT, 
"(shiro.authz=true)");
+        
+        Response authenticate = target.path("security/authenticate").request()
+                .header("user", "Bill")
+                .header("password", "Ben")
+                .post(null);
+        assertEquals(Status.OK.getStatusCode(), authenticate.getStatus());
+        
+        
+        Builder request = target.path("test/admin").request();
+        authenticate.getCookies().values().forEach(c -> 
request.cookie(c.getName(), c.getValue()));
+        
+        assertEquals(Status.FORBIDDEN.getStatusCode(), 
request.get().getStatus());
+    }
+
+    @Test
+    public void testRoleAuthWithRolePresent() throws Exception {
+        
+        realm.addAccount("Bill", "Ben", "admin");
+        
+        WebTarget target = createDefaultTarget();
+        
+        registerAddon(new TestShiroAnnotations(), JAX_RS_EXTENSION_SELECT, 
"(shiro.authz=true)");
+        
+        Response authenticate = target.path("security/authenticate").request()
+                .header("user", "Bill")
+                .header("password", "Ben")
+                .post(null);
+        assertEquals(Status.OK.getStatusCode(), authenticate.getStatus());
+        
+        
+        Builder request = target.path("test/admin").request();
+        authenticate.getCookies().values().forEach(c -> 
request.cookie(c.getName(), c.getValue()));
+        
+        assertEquals("Welcome Admin", request.get(String.class));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/src/main/java/test/types/TestHelper.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-itest/src/main/java/test/types/TestHelper.java 
b/integrations/shiro/shiro-itest/src/main/java/test/types/TestHelper.java
new file mode 100644
index 0000000..0dc5652
--- /dev/null
+++ b/integrations/shiro/shiro-itest/src/main/java/test/types/TestHelper.java
@@ -0,0 +1,306 @@
+/*
+ * 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 test.types;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Application;
+
+import org.junit.After;
+import org.junit.Before;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.jaxrs.client.SseEventSourceFactory;
+import org.osgi.service.jaxrs.runtime.JaxrsServiceRuntime;
+import org.osgi.service.jaxrs.runtime.dto.RuntimeDTO;
+import org.osgi.util.tracker.ServiceTracker;
+
+import static org.junit.Assert.assertTrue;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_EXTENSION;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_NAME;
+import static 
org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_RESOURCE;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public abstract class TestHelper {
+
+    public static BundleContext bundleContext =
+        FrameworkUtil.
+            getBundle(TestHelper.class).
+            getBundleContext();
+
+    protected Collection<ServiceRegistration<?>> _registrations =
+        new ArrayList<>();
+    protected ServiceTracker<JaxrsServiceRuntime, JaxrsServiceRuntime>
+        _runtimeTracker;
+    protected ServiceTracker<ClientBuilder, ClientBuilder>
+        _clientBuilderTracker;
+    protected JaxrsServiceRuntime _runtime;
+    protected ServiceReference<JaxrsServiceRuntime> _runtimeServiceReference;
+
+    @After
+    public void tearDown() {
+        Iterator<ServiceRegistration<?>> iterator = _registrations.iterator();
+
+        while (iterator.hasNext()) {
+            ServiceRegistration<?> registration =  iterator.next();
+
+            try {
+                registration.unregister();
+            }
+            catch(Exception e) {
+            }
+            finally {
+                iterator.remove();
+            }
+        }
+
+        if (_runtimeTracker != null) {
+            _runtimeTracker.close();
+        }
+
+        _clientBuilderTracker.close();
+
+        _configurationAdminTracker.close();
+
+        _sseEventSourceFactoryTracker.close();
+    }
+
+    @Before
+    public void before() {
+        _clientBuilderTracker = new ServiceTracker<>(
+            bundleContext, ClientBuilder.class, null);
+
+        _clientBuilderTracker.open();
+
+        _configurationAdminTracker = new ServiceTracker<>(
+            bundleContext, ConfigurationAdmin.class, null);
+
+        _configurationAdminTracker.open();
+
+        _sseEventSourceFactoryTracker = new ServiceTracker<>(
+            bundleContext, SseEventSourceFactory.class, null);
+
+        _sseEventSourceFactoryTracker.open();
+
+        _runtimeTracker = new ServiceTracker<>(
+            bundleContext, JaxrsServiceRuntime.class, null);
+
+        _runtimeTracker.open();
+
+        try {
+            _runtime = _runtimeTracker.waitForService(15000L);
+        }
+        catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        _runtimeServiceReference = _runtimeTracker.getServiceReference();
+    }
+
+    private ServiceTracker<ConfigurationAdmin, ConfigurationAdmin>
+        _configurationAdminTracker;
+
+    private ServiceTracker<SseEventSourceFactory, SseEventSourceFactory>
+        _sseEventSourceFactoryTracker;
+
+    @SuppressWarnings("unchecked")
+    private static String[] canonicalize(Object propertyValue) {
+        if (propertyValue == null) {
+            return new String[0];
+        }
+        if (propertyValue instanceof String[]) {
+            return (String[]) propertyValue;
+        }
+        if (propertyValue instanceof Collection) {
+            return ((Collection<String>) propertyValue).toArray(new String[0]);
+        }
+
+        return new String[]{propertyValue.toString()};
+    }
+
+    public ConfigurationAdmin getConfigurationAdmin() {
+
+        try {
+            return _configurationAdminTracker.waitForService(5000);
+        }
+        catch (InterruptedException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    protected Client createClient() {
+        ClientBuilder clientBuilder;
+
+        try {
+            clientBuilder = _clientBuilderTracker.waitForService(5000);
+
+            return clientBuilder.build();
+        }
+        catch (InterruptedException ie) {
+            throw new RuntimeException(ie);
+        }
+    }
+
+    protected SseEventSourceFactory createSseFactory() {
+        try {
+            return _sseEventSourceFactoryTracker.waitForService(5000);
+        }
+        catch (InterruptedException ie) {
+            throw new RuntimeException(ie);
+        }
+    }
+
+    protected WebTarget createDefaultTarget() {
+        Client client = createClient();
+
+        String[] runtimes = canonicalize(
+            _runtimeServiceReference.getProperty("osgi.jaxrs.endpoint"));
+
+        if (runtimes.length == 0) {
+            throw new IllegalStateException(
+                "No runtimes could be found on \"osgi.jaxrs.endpoint\" " +
+                    "runtime service property ");
+        }
+
+        String runtime = runtimes[0];
+
+        return client.target(runtime);
+    }
+
+    protected static long getServiceId(ServiceRegistration<?> propertyHolder) {
+        return (long)propertyHolder.getReference().getProperty("service.id");
+    }
+
+    protected <T> void assertThatInRuntime(
+        Function<RuntimeDTO, T[]> getter, Predicate<T> predicate) {
+
+        assertTrue(
+            Arrays.stream(getter.apply(getRuntimeDTO())).anyMatch(predicate));
+    }
+
+    protected JaxrsServiceRuntime getJaxrsServiceRuntime()
+        throws InterruptedException {
+
+        _runtimeTracker = new ServiceTracker<>(
+            bundleContext, JaxrsServiceRuntime.class, null);
+
+        _runtimeTracker.open();
+
+        return _runtimeTracker.waitForService(15000L);
+    }
+
+    protected RuntimeDTO getRuntimeDTO() {
+        return _runtime.getRuntimeDTO();
+    }
+
+    protected ServiceRegistration<?> registerAddon(
+        Object instance, Object... keyValues) {
+
+        Dictionary<String, Object> properties = new Hashtable<>();
+
+        properties.put(JAX_RS_RESOURCE, "true");
+
+        for (int i = 0; i < keyValues.length; i = i + 2) {
+            properties.put(keyValues[i].toString(), keyValues[i + 1]);
+        }
+
+        ServiceRegistration<Object> serviceRegistration =
+            bundleContext.registerService(Object.class, instance, properties);
+
+        _registrations.add(serviceRegistration);
+
+        return serviceRegistration;
+    }
+
+    protected ServiceRegistration<Application> registerApplication(
+        Application application, Object... keyValues) {
+
+        Dictionary<String, Object> properties = new Hashtable<>();
+
+        for (int i = 0; i < keyValues.length; i = i + 2) {
+            properties.put(keyValues[i].toString(), keyValues[i + 1]);
+        }
+
+        if (properties.get(JAX_RS_APPLICATION_BASE) == null) {
+            properties.put(JAX_RS_APPLICATION_BASE, "/test-application");
+        }
+
+        ServiceRegistration<Application> serviceRegistration =
+            bundleContext.registerService(
+                Application.class, application, properties);
+
+        _registrations.add(serviceRegistration);
+
+        return serviceRegistration;
+    }
+
+    protected ServiceRegistration<Application> registerApplication(
+        ServiceFactory<Application> serviceFactory, Object... keyValues) {
+
+        Dictionary<String, Object> properties = new Hashtable<>();
+
+        properties.put(JAX_RS_APPLICATION_BASE, "/test-application");
+
+        for (int i = 0; i < keyValues.length; i = i + 2) {
+            properties.put(keyValues[i].toString(), keyValues[i + 1]);
+        }
+
+        ServiceRegistration<Application> serviceRegistration =
+            bundleContext.registerService(
+                Application.class, serviceFactory, properties);
+
+        _registrations.add(serviceRegistration);
+
+        return serviceRegistration;
+    }
+
+    protected <T> ServiceRegistration<T> registerExtension(
+        Class<T> clazz, T extension, String name, Object... keyValues) {
+
+        Dictionary<String, Object> properties = new Hashtable<>();
+
+        properties.put(JAX_RS_EXTENSION, true);
+        properties.put(JAX_RS_NAME, name);
+
+        for (int i = 0; i < keyValues.length; i = i + 2) {
+            properties.put(keyValues[i].toString(), keyValues[i + 1]);
+        }
+
+        ServiceRegistration<T> serviceRegistration =
+            bundleContext.registerService(clazz, extension, properties);
+
+        _registrations.add(serviceRegistration);
+
+        return serviceRegistration;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/src/main/java/test/types/TestShiroAnnotations.java
----------------------------------------------------------------------
diff --git 
a/integrations/shiro/shiro-itest/src/main/java/test/types/TestShiroAnnotations.java
 
b/integrations/shiro/shiro-itest/src/main/java/test/types/TestShiroAnnotations.java
new file mode 100644
index 0000000..6b21e45
--- /dev/null
+++ 
b/integrations/shiro/shiro-itest/src/main/java/test/types/TestShiroAnnotations.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 test.types;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authz.annotation.RequiresAuthentication;
+import org.apache.shiro.authz.annotation.RequiresGuest;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+
+@Path("/test")
+public class TestShiroAnnotations {
+
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @Path("/guest")
+    @RequiresGuest
+    public String guest() {
+        return "Welcome Guest";
+    }
+    
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @Path("/authenticated")
+    @RequiresAuthentication
+    public String authenticated() {
+        return "Welcome " + 
SecurityUtils.getSubject().getPrincipal().toString();
+    }
+    
+
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @Path("/admin")
+    @RequiresRoles("admin")
+    public String admin() {
+        return "Welcome Admin";
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/16da1127/integrations/shiro/shiro-itest/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/integrations/shiro/shiro-itest/src/test/resources/logback.xml 
b/integrations/shiro/shiro-itest/src/test/resources/logback.xml
new file mode 100644
index 0000000..b5db67b
--- /dev/null
+++ b/integrations/shiro/shiro-itest/src/test/resources/logback.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+
+<configuration>
+  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+    <resetJUL>true</resetJUL>
+  </contextListener>
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - 
%msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+  <logger name="org.apache.aries.jax.rs" level="DEBUG"/>
+</configuration>
\ No newline at end of file

Reply via email to