Updated Branches:
  refs/heads/master f22d973d7 -> 17b2306d9

CAMEL-6352: Added base64 option to camel-shiro so we can transfer tokens over 
JMS out of the box.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/17b2306d
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/17b2306d
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/17b2306d

Branch: refs/heads/master
Commit: 17b2306d92cd85fe9c5f1b17367858696046de31
Parents: f22d973
Author: Claus Ibsen <davscl...@apache.org>
Authored: Sun May 12 12:45:13 2013 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Sun May 12 12:45:13 2013 +0200

----------------------------------------------------------------------
 .../component/shiro/security/ShiroConstants.java   |   29 ++++
 .../shiro/security/ShiroSecurityPolicy.java        |   21 +++-
 .../shiro/security/ShiroSecurityTokenInjector.java |   20 +++-
 .../security/ShiroAuthenticationBase64Test.java    |  107 +++++++++++++++
 ...nticationReauthenticateFalseAndNewUserTest.java |    2 +-
 .../shiro/security/ShiroAuthenticationTest.java    |    2 +-
 .../shiro/security/ShiroAuthorizationTest.java     |    2 +-
 tests/camel-itest/pom.xml                          |    5 +
 .../apache/camel/itest/shiro/ShiroOverJmsTest.java |   96 +++++++++++++
 .../src/test/resources/securityconfig.ini          |   36 +++++
 10 files changed, 314 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroConstants.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroConstants.java
 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroConstants.java
new file mode 100644
index 0000000..745899e
--- /dev/null
+++ 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroConstants.java
@@ -0,0 +1,29 @@
+/**
+ * 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.camel.component.shiro.security;
+
+/**
+ * Shiro constants.
+ */
+public final class ShiroConstants {
+
+    public static final String SHIRO_SECURITY_TOKEN = "SHIRO_SECURITY_TOKEN";
+
+    private ShiroConstants() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityPolicy.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityPolicy.java
 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityPolicy.java
index 9b13e03..b0e6b51 100644
--- 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityPolicy.java
+++ 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityPolicy.java
@@ -40,6 +40,7 @@ import org.apache.shiro.authc.LockedAccountException;
 import org.apache.shiro.authc.UnknownAccountException;
 import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.authz.Permission;
+import org.apache.shiro.codec.Base64;
 import org.apache.shiro.config.Ini;
 import org.apache.shiro.config.IniSecurityManagerFactory;
 import org.apache.shiro.crypto.AesCipherService;
@@ -63,6 +64,7 @@ public class ShiroSecurityPolicy implements 
AuthorizationPolicy {
     private SecurityManager securityManager;
     private List<Permission> permissionsList;
     private boolean alwaysReauthenticate;
+    private boolean base64;
     
     public ShiroSecurityPolicy() {
         this.passPhrase = bits128;
@@ -162,7 +164,15 @@ public class ShiroSecurityPolicy implements 
AuthorizationPolicy {
             }
             
             private void applySecurityPolicy(Exchange exchange) throws 
Exception {
-                ByteSource encryptedToken = 
ExchangeHelper.getMandatoryHeader(exchange, "SHIRO_SECURITY_TOKEN", 
ByteSource.class);
+                ByteSource encryptedToken;
+                if (isBase64()) {
+                    String base64 = 
ExchangeHelper.getMandatoryHeader(exchange, 
ShiroConstants.SHIRO_SECURITY_TOKEN, String.class);
+                    byte[] bytes = Base64.decode(base64);
+                    encryptedToken = ByteSource.Util.bytes(bytes);
+                } else {
+                    encryptedToken = 
ExchangeHelper.getMandatoryHeader(exchange, 
ShiroConstants.SHIRO_SECURITY_TOKEN, ByteSource.class);
+                }
+
                 ByteSource decryptedToken = 
getCipherService().decrypt(encryptedToken.getBytes(), getPassPhrase());
                 
                 ByteArrayInputStream byteArrayInputStream = new 
ByteArrayInputStream(decryptedToken.getBytes());
@@ -280,5 +290,12 @@ public class ShiroSecurityPolicy implements 
AuthorizationPolicy {
     public void setAlwaysReauthenticate(boolean alwaysReauthenticate) {
         this.alwaysReauthenticate = alwaysReauthenticate;
     }
- 
+
+    public boolean isBase64() {
+        return base64;
+    }
+
+    public void setBase64(boolean base64) {
+        this.base64 = base64;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityTokenInjector.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityTokenInjector.java
 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityTokenInjector.java
index 9ced6dc..e01eb66 100644
--- 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityTokenInjector.java
+++ 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityTokenInjector.java
@@ -37,6 +37,7 @@ public class ShiroSecurityTokenInjector implements Processor {
     private byte[] passPhrase;
     private ShiroSecurityToken securityToken;
     private CipherService cipherService;
+    private boolean base64;
     
     public ShiroSecurityTokenInjector() {
         this.passPhrase = bits128;
@@ -69,7 +70,16 @@ public class ShiroSecurityTokenInjector implements Processor 
{
     }
 
     public void process(Exchange exchange) throws Exception {
-        exchange.getIn().setHeader("SHIRO_SECURITY_TOKEN", encrypt());
+        ByteSource bytes = encrypt();
+
+        Object token;
+        if (isBase64()) {
+            token = bytes.toBase64();
+        } else {
+            token = bytes;
+        }
+
+        exchange.getIn().setHeader(ShiroConstants.SHIRO_SECURITY_TOKEN, token);
     }
 
     public byte[] getPassPhrase() {
@@ -96,6 +106,14 @@ public class ShiroSecurityTokenInjector implements 
Processor {
         this.cipherService = cipherService;
     }
 
+    public boolean isBase64() {
+        return base64;
+    }
+
+    public void setBase64(boolean base64) {
+        this.base64 = base64;
+    }
+
     private static void close(ObjectOutput output) {
         try {
             output.close();

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationBase64Test.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationBase64Test.java
 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationBase64Test.java
new file mode 100644
index 0000000..db0bbc1
--- /dev/null
+++ 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationBase64Test.java
@@ -0,0 +1,107 @@
+/**
+ * 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.camel.component.shiro.security;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.IncorrectCredentialsException;
+import org.apache.shiro.authc.LockedAccountException;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.junit.Test;
+
+public class ShiroAuthenticationBase64Test extends CamelTestSupport {
+
+    @EndpointInject(uri = "mock:success")
+    protected MockEndpoint successEndpoint;
+
+    @EndpointInject(uri = "mock:authenticationException")
+    protected MockEndpoint failureEndpoint;
+
+    private byte[] passPhrase = {
+        (byte) 0x08, (byte) 0x09, (byte) 0x0A, (byte) 0x0B,
+        (byte) 0x0C, (byte) 0x0D, (byte) 0x0E, (byte) 0x0F,
+        (byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x13,
+        (byte) 0x14, (byte) 0x15, (byte) 0x16, (byte) 0x17};    
+    
+    @Test
+    public void testShiroAuthenticationFailure() throws Exception {        
+        //Incorrect password
+        ShiroSecurityToken shiroSecurityToken = new 
ShiroSecurityToken("ringo", "stirr");
+        TestShiroSecurityTokenInjector shiroSecurityTokenInjector = new 
TestShiroSecurityTokenInjector(shiroSecurityToken, passPhrase);
+        
+        successEndpoint.expectedMessageCount(0);
+        failureEndpoint.expectedMessageCount(1);
+        
+        template.send("direct:secureEndpoint", shiroSecurityTokenInjector);
+        
+        successEndpoint.assertIsSatisfied();
+        failureEndpoint.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testSuccessfulShiroAuthenticationWithNoAuthorization() throws 
Exception {        
+        ShiroSecurityToken shiroSecurityToken = new 
ShiroSecurityToken("ringo", "starr");
+        TestShiroSecurityTokenInjector shiroSecurityTokenInjector = new 
TestShiroSecurityTokenInjector(shiroSecurityToken, passPhrase);
+        
+        successEndpoint.expectedMessageCount(2);
+        failureEndpoint.expectedMessageCount(0);
+        
+        template.send("direct:secureEndpoint", shiroSecurityTokenInjector);
+        template.send("direct:secureEndpoint", shiroSecurityTokenInjector);
+
+        successEndpoint.assertIsSatisfied();
+        failureEndpoint.assertIsSatisfied();
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        final ShiroSecurityPolicy securityPolicy = new 
ShiroSecurityPolicy("src/test/resources/securityconfig.ini", passPhrase);
+        securityPolicy.setBase64(true);
+        
+        return new RouteBuilder() {
+            @SuppressWarnings("unchecked")
+            public void configure() {
+                onException(UnknownAccountException.class, 
IncorrectCredentialsException.class,
+                        LockedAccountException.class, 
AuthenticationException.class).
+                    to("mock:authenticationException");
+
+                from("direct:secureEndpoint").
+                    policy(securityPolicy).
+                    to("log:incoming payload").
+                    to("mock:success");
+            }
+        };
+    }
+
+    
+    private static class TestShiroSecurityTokenInjector extends 
ShiroSecurityTokenInjector {
+
+        public TestShiroSecurityTokenInjector(ShiroSecurityToken 
shiroSecurityToken, byte[] bytes) {
+            super(shiroSecurityToken, bytes);
+            setBase64(true);
+        }
+        
+        public void process(Exchange exchange) throws Exception {
+            super.process(exchange);
+            exchange.getIn().setBody("Beatle Mania");
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationReauthenticateFalseAndNewUserTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationReauthenticateFalseAndNewUserTest.java
 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationReauthenticateFalseAndNewUserTest.java
index 66dcc68..b0e8362 100644
--- 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationReauthenticateFalseAndNewUserTest.java
+++ 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationReauthenticateFalseAndNewUserTest.java
@@ -85,7 +85,7 @@ public class 
ShiroAuthenticationReauthenticateFalseAndNewUserTest extends CamelT
         }
         
         public void process(Exchange exchange) throws Exception {
-            exchange.getIn().setHeader("SHIRO_SECURITY_TOKEN", encrypt());
+            exchange.getIn().setHeader(ShiroConstants.SHIRO_SECURITY_TOKEN, 
encrypt());
             exchange.getIn().setBody("Beatle Mania");
         }
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationTest.java
 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationTest.java
index 118c62d..db8c483 100644
--- 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationTest.java
+++ 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthenticationTest.java
@@ -96,7 +96,7 @@ public class ShiroAuthenticationTest extends CamelTestSupport 
{
         }
         
         public void process(Exchange exchange) throws Exception {
-            exchange.getIn().setHeader("SHIRO_SECURITY_TOKEN", encrypt());
+            exchange.getIn().setHeader(ShiroConstants.SHIRO_SECURITY_TOKEN, 
encrypt());
             exchange.getIn().setBody("Beatle Mania");
         }
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthorizationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthorizationTest.java
 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthorizationTest.java
index d000db5..30cb9d6 100644
--- 
a/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthorizationTest.java
+++ 
b/components/camel-shiro/src/test/java/org/apache/camel/component/shiro/security/ShiroAuthorizationTest.java
@@ -119,7 +119,7 @@ public class ShiroAuthorizationTest extends 
CamelTestSupport {
         }
         
         public void process(Exchange exchange) throws Exception {
-            exchange.getIn().setHeader("SHIRO_SECURITY_TOKEN", encrypt());
+            exchange.getIn().setHeader(ShiroConstants.SHIRO_SECURITY_TOKEN, 
encrypt());
             exchange.getIn().setBody("Beatle Mania");
         }
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/tests/camel-itest/pom.xml
----------------------------------------------------------------------
diff --git a/tests/camel-itest/pom.xml b/tests/camel-itest/pom.xml
index 770d792..78a943a 100644
--- a/tests/camel-itest/pom.xml
+++ b/tests/camel-itest/pom.xml
@@ -170,6 +170,11 @@
          <artifactId>camel-netty</artifactId>
          <scope>test</scope>
        </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-shiro</artifactId>
+      <scope>test</scope>
+    </dependency>
 
          <dependency>
       <groupId>org.apache.camel</groupId>

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java
----------------------------------------------------------------------
diff --git 
a/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java
 
b/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java
new file mode 100644
index 0000000..453b1ca
--- /dev/null
+++ 
b/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java
@@ -0,0 +1,96 @@
+/**
+ * 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.camel.itest.shiro;
+
+import javax.naming.Context;
+
+import org.apache.activemq.camel.component.ActiveMQComponent;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.shiro.security.ShiroSecurityPolicy;
+import org.apache.camel.component.shiro.security.ShiroSecurityToken;
+import org.apache.camel.component.shiro.security.ShiroSecurityTokenInjector;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.jndi.JndiContext;
+import org.junit.Test;
+
+public class ShiroOverJmsTest extends CamelTestSupport {
+
+    private byte[] passPhrase = {
+            (byte) 0x08, (byte) 0x09, (byte) 0x0A, (byte) 0x0B,
+            (byte) 0x0C, (byte) 0x0D, (byte) 0x0E, (byte) 0x0F,
+            (byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x13,
+            (byte) 0x14, (byte) 0x15, (byte) 0x16, (byte) 0x17};
+
+    @Test
+    public void testShiroOverJms() throws Exception {
+        getMockEndpoint("mock:error").expectedMessageCount(0);
+        getMockEndpoint("mock:foo").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        ShiroSecurityToken token = new ShiroSecurityToken("ringo", "starr");
+
+        final ShiroSecurityTokenInjector injector = new 
ShiroSecurityTokenInjector(token, passPhrase);
+        injector.setBase64(true);
+
+        template.request("direct:start", new Processor() {
+            @Override
+            public void process(Exchange exchange) throws Exception {
+                exchange.getIn().setBody("Hello World");
+                injector.process(exchange);
+            }
+        });
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected Context createJndiContext() throws Exception {
+        JndiContext answer = new JndiContext();
+
+        // add ActiveMQ with embedded broker
+        ActiveMQComponent amq = 
ActiveMQComponent.activeMQComponent("vm://localhost?broker.persistent=false");
+        amq.setCamelContext(context);
+        answer.bind("jms", amq);
+        return answer;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                final ShiroSecurityPolicy securityPolicy = new 
ShiroSecurityPolicy("src/test/resources/securityconfig.ini", passPhrase);
+                securityPolicy.setBase64(true);
+
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from("direct:start")
+                        .policy(securityPolicy)
+                        .to("jms:queue:foo")
+                        .to("mock:result");
+
+                from("jms:queue:foo")
+                        .to("log:foo?showHeaders=true")
+                        .policy(securityPolicy)
+                        .to("mock:foo")
+                        .transform().constant("Bye World");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/17b2306d/tests/camel-itest/src/test/resources/securityconfig.ini
----------------------------------------------------------------------
diff --git a/tests/camel-itest/src/test/resources/securityconfig.ini 
b/tests/camel-itest/src/test/resources/securityconfig.ini
new file mode 100644
index 0000000..e72072e
--- /dev/null
+++ b/tests/camel-itest/src/test/resources/securityconfig.ini
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+[users]
+# user 'ringo' with password 'starr' and the 'hero' role
+ringo = starr, sec-level1
+george = harrison, sec-level2
+john = lennon, sec-level3
+paul = mccartney, sec-level3
+
+[roles]
+# 'sec-level3' role has all permissions, indicated by the wildcard '*'
+sec-level3 = *
+
+# The 'sec-level2' role can do anything with access of permission readonly (*) 
to help
+sec-level2 = zone1:*
+
+# The 'sec-level1' role can do anything with access of permission readonly
+sec-level1 = zone1:readonly:*
+

Reply via email to