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

CAMEL-6354: Polished camel-shiro


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

Branch: refs/heads/master
Commit: f3d14298d4914525f2ac4e9a79216a2c0638e668
Parents: 17b2306
Author: Claus Ibsen <[email protected]>
Authored: Sun May 12 13:17:27 2013 +0200
Committer: Claus Ibsen <[email protected]>
Committed: Sun May 12 13:24:14 2013 +0200

----------------------------------------------------------------------
 .../shiro/security/ShiroSecurityHelper.java        |   53 +++++
 .../shiro/security/ShiroSecurityPolicy.java        |  154 +--------------
 .../shiro/security/ShiroSecurityProcessor.java     |  156 +++++++++++++++
 .../shiro/security/ShiroSecurityTokenInjector.java |   24 +--
 .../src/test/resources/log4j.properties            |   21 ++-
 5 files changed, 235 insertions(+), 173 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/f3d14298/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityHelper.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityHelper.java
 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityHelper.java
new file mode 100644
index 0000000..1f64723
--- /dev/null
+++ 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityHelper.java
@@ -0,0 +1,53 @@
+/**
+ * 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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+
+import org.apache.camel.util.IOHelper;
+import org.apache.shiro.crypto.CipherService;
+import org.apache.shiro.util.ByteSource;
+
+public final class ShiroSecurityHelper {
+
+    private ShiroSecurityHelper() {
+    }
+
+    public static ByteSource encrypt(ShiroSecurityToken securityToken, byte[] 
passPhrase, CipherService cipherService) throws Exception {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        ObjectOutput serialStream = new ObjectOutputStream(stream);
+        try {
+            serialStream.writeObject(securityToken);
+            return cipherService.encrypt(stream.toByteArray(), passPhrase);
+        } finally {
+            close(serialStream);
+            IOHelper.close(stream);
+        }
+    }
+
+    private static void close(ObjectOutput output) {
+        try {
+            output.close();
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f3d14298/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 b0e6b51..4e8fff5 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
@@ -16,44 +16,26 @@
  */
 package org.apache.camel.component.shiro.security;
 
-import java.io.ByteArrayInputStream;
-import java.io.ObjectInputStream;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.camel.AsyncCallback;
-import org.apache.camel.AsyncProcessor;
-import org.apache.camel.CamelAuthorizationException;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.spi.AuthorizationPolicy;
 import org.apache.camel.spi.RouteContext;
-import org.apache.camel.util.AsyncProcessorConverterHelper;
-import org.apache.camel.util.AsyncProcessorHelper;
-import org.apache.camel.util.ExchangeHelper;
-import org.apache.camel.util.IOHelper;
 import org.apache.shiro.SecurityUtils;
-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.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;
 import org.apache.shiro.crypto.CipherService;
 import org.apache.shiro.mgt.SecurityManager;
-import org.apache.shiro.subject.Subject;
-import org.apache.shiro.util.ByteSource;
 import org.apache.shiro.util.Factory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class ShiroSecurityPolicy implements AuthorizationPolicy {
-    private static final transient Logger LOG = 
LoggerFactory.getLogger(ShiroSecurityPolicy.class);  
+    private static final transient Logger LOG = 
LoggerFactory.getLogger(ShiroSecurityPolicy.class);
     private final byte[] bits128 = {
         (byte) 0x08, (byte) 0x09, (byte) 0x0A, (byte) 0x0B,
         (byte) 0x0C, (byte) 0x0D, (byte) 0x0E, (byte) 0x0F,
@@ -119,138 +101,16 @@ public class ShiroSecurityPolicy implements 
AuthorizationPolicy {
     }
 
     public void beforeWrap(RouteContext routeContext, ProcessorDefinition<?> 
definition) {  
-        //Not implemented
+        // noop
     }
     
-    public Processor wrap(RouteContext routeContext, final Processor 
processor) {        
-        return new AsyncProcessor() {
-            public boolean process(Exchange exchange, final AsyncCallback 
callback)  {
-                boolean sync;
-                try {
-                    applySecurityPolicy(exchange);
-                } catch (Exception e) {
-                    // exception occurred so break out
-                    exchange.setException(e);
-                    callback.done(true);
-                    return true;
-                }
-                
-                // If here, then user is authenticated and authorized
-                // Now let the original processor continue routing supporting 
the async routing engine
-                AsyncProcessor ap = 
AsyncProcessorConverterHelper.convert(processor);
-                sync = AsyncProcessorHelper.process(ap, exchange, new 
AsyncCallback() {
-                    public void done(boolean doneSync) {
-                        // we only have to handle async completion of this 
policy
-                        if (doneSync) {
-                            return;
-                        }
-                        callback.done(false);
-                    }
-                });                    
-                
-                if (!sync) {
-                    // if async, continue routing async
-                    return false;
-                }
-
-                // we are done synchronously, so do our after work and invoke 
the callback
-                callback.done(true);
-                return true;                
-            }
-
-            public void process(Exchange exchange) throws Exception {
-                applySecurityPolicy(exchange);               
-                processor.process(exchange);
-            }
-            
-            private void applySecurityPolicy(Exchange exchange) throws 
Exception {
-                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());
-                ObjectInputStream objectInputStream = new 
ObjectInputStream(byteArrayInputStream);
-                ShiroSecurityToken securityToken;
-                try {
-                    securityToken = 
(ShiroSecurityToken)objectInputStream.readObject();
-                } finally {
-                    IOHelper.close(objectInputStream, byteArrayInputStream);
-                }
-
-                Subject currentUser = SecurityUtils.getSubject();
-
-                // Authenticate user if not authenticated
-                try {
-                    authenticateUser(currentUser, securityToken);
-                
-                    // Test whether user's role is authorized to perform 
functions in the permissions list  
-                    authorizeUser(currentUser, exchange);
-                } finally {
-                    if (alwaysReauthenticate) {
-                        currentUser.logout();
-                    }
-                }
-            }
-        };
-    }
-
-    private void authenticateUser(Subject currentUser, ShiroSecurityToken 
securityToken) {
-        boolean authenticated = currentUser.isAuthenticated();
-        boolean sameUser = 
securityToken.getUsername().equals(currentUser.getPrincipal());
-        LOG.debug("Authenticated: {}, same Username: {}", authenticated, 
sameUser);
-
-        if (!authenticated || !sameUser) {
-            UsernamePasswordToken token = new 
UsernamePasswordToken(securityToken.getUsername(), securityToken.getPassword());
-            if (alwaysReauthenticate) {
-                token.setRememberMe(false);
-            } else {
-                token.setRememberMe(true);
-            }
-            
-            try {
-                currentUser.login(token);
-                LOG.debug("Current User {} successfully authenticated", 
currentUser.getPrincipal());
-            } catch (UnknownAccountException uae) {
-                throw new UnknownAccountException("Authentication Failed. 
There is no user with username of " + token.getPrincipal(), uae.getCause());
-            } catch (IncorrectCredentialsException ice) {
-                throw new IncorrectCredentialsException("Authentication 
Failed. Password for account " + token.getPrincipal() + " was incorrect!", 
ice.getCause());
-            } catch (LockedAccountException lae) {
-                throw new LockedAccountException("Authentication Failed. The 
account for username " + token.getPrincipal() + " is locked."
-                    + "Please contact your administrator to unlock it.", 
lae.getCause());
-            } catch (AuthenticationException ae) {
-                throw new AuthenticationException("Authentication Failed.", 
ae.getCause());
-            }
-        }
-    }
-    
-    private void authorizeUser(Subject currentUser, Exchange exchange) throws 
CamelAuthorizationException {
-        boolean authorized = false;
-        if (!permissionsList.isEmpty()) {
-            for (Permission permission : permissionsList) {
-                if (currentUser.isPermitted(permission)) {
-                    authorized = true;
-                    break;
-                }
-            }
-        } else {
-            LOG.debug("Valid Permissions List not specified for 
ShiroSecurityPolicy. No authorization checks will be performed for current 
user");
-            authorized = true;
+    public Processor wrap(RouteContext routeContext, final Processor 
processor) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Securing route {} using Shiro policy {}", 
routeContext.getRoute().getId(), this);
         }
-        
-        if (!authorized) {
-            throw new CamelAuthorizationException("Authorization Failed. 
Subject's role set does not have the necessary permissions to perform further 
processing", exchange);
-        } 
-        
-        LOG.debug("Current User {} is successfully authorized. The exchange 
will be allowed to proceed", currentUser.getPrincipal());
+        return new ShiroSecurityProcessor(processor, this);
     }
-    
+
     public CipherService getCipherService() {
         return cipherService;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/f3d14298/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityProcessor.java
----------------------------------------------------------------------
diff --git 
a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityProcessor.java
 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityProcessor.java
new file mode 100644
index 0000000..d353234
--- /dev/null
+++ 
b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityProcessor.java
@@ -0,0 +1,156 @@
+/**
+ * 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 java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelAuthorizationException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.processor.DelegateAsyncProcessor;
+import org.apache.camel.util.ExchangeHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.shiro.SecurityUtils;
+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.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.ByteSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link Processor} that executes the authentication and authorization of the 
{@link Subject} accordingly
+ * to the {@link ShiroSecurityPolicy}.
+ */
+public class ShiroSecurityProcessor extends DelegateAsyncProcessor {
+
+    private static final transient Logger LOG = 
LoggerFactory.getLogger(ShiroSecurityProcessor.class);
+    private final ShiroSecurityPolicy policy;
+
+    public ShiroSecurityProcessor(Processor processor, ShiroSecurityPolicy 
policy) {
+        super(processor);
+        this.policy = policy;
+    }
+
+    @Override
+    protected boolean processNext(Exchange exchange, AsyncCallback callback) {
+        try {
+            applySecurityPolicy(exchange);
+        } catch (Exception e) {
+            // exception occurred so break out
+            exchange.setException(e);
+            callback.done(true);
+            return true;
+        }
+
+        return super.processNext(exchange, callback);
+    }
+
+    private void applySecurityPolicy(Exchange exchange) throws Exception {
+        ByteSource encryptedToken;
+        if (policy.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 = 
policy.getCipherService().decrypt(encryptedToken.getBytes(), 
policy.getPassPhrase());
+
+        ByteArrayInputStream byteArrayInputStream = new 
ByteArrayInputStream(decryptedToken.getBytes());
+        ObjectInputStream objectInputStream = new 
ObjectInputStream(byteArrayInputStream);
+        ShiroSecurityToken securityToken;
+        try {
+            securityToken = (ShiroSecurityToken)objectInputStream.readObject();
+        } finally {
+            IOHelper.close(objectInputStream, byteArrayInputStream);
+        }
+
+        Subject currentUser = SecurityUtils.getSubject();
+
+        // Authenticate user if not authenticated
+        try {
+            authenticateUser(currentUser, securityToken);
+
+            // Test whether user's role is authorized to perform functions in 
the permissions list
+            authorizeUser(currentUser, exchange);
+        } finally {
+            if (policy.isAlwaysReauthenticate()) {
+                currentUser.logout();
+            }
+        }
+    }
+
+    private void authenticateUser(Subject currentUser, ShiroSecurityToken 
securityToken) {
+        boolean authenticated = currentUser.isAuthenticated();
+        boolean sameUser = 
securityToken.getUsername().equals(currentUser.getPrincipal());
+        LOG.trace("Authenticated: {}, same Username: {}", authenticated, 
sameUser);
+
+        if (!authenticated || !sameUser) {
+            UsernamePasswordToken token = new 
UsernamePasswordToken(securityToken.getUsername(), securityToken.getPassword());
+            if (policy.isAlwaysReauthenticate()) {
+                token.setRememberMe(false);
+            } else {
+                token.setRememberMe(true);
+            }
+
+            try {
+                currentUser.login(token);
+                LOG.debug("Current user {} successfully authenticated", 
currentUser.getPrincipal());
+            } catch (UnknownAccountException uae) {
+                throw new UnknownAccountException("Authentication Failed. 
There is no user with username of " + token.getPrincipal(), uae.getCause());
+            } catch (IncorrectCredentialsException ice) {
+                throw new IncorrectCredentialsException("Authentication 
Failed. Password for account " + token.getPrincipal() + " was incorrect!", 
ice.getCause());
+            } catch (LockedAccountException lae) {
+                throw new LockedAccountException("Authentication Failed. The 
account for username " + token.getPrincipal() + " is locked."
+                        + "Please contact your administrator to unlock it.", 
lae.getCause());
+            } catch (AuthenticationException ae) {
+                throw new AuthenticationException("Authentication Failed.", 
ae.getCause());
+            }
+        }
+    }
+
+    private void authorizeUser(Subject currentUser, Exchange exchange) throws 
CamelAuthorizationException {
+        boolean authorized = false;
+        if (!policy.getPermissionsList().isEmpty()) {
+            for (Permission permission : policy.getPermissionsList()) {
+                if (currentUser.isPermitted(permission)) {
+                    authorized = true;
+                    break;
+                }
+            }
+        } else {
+            LOG.trace("Valid Permissions List not specified for 
ShiroSecurityPolicy. No authorization checks will be performed for current 
user.");
+            authorized = true;
+        }
+
+        if (!authorized) {
+            throw new CamelAuthorizationException("Authorization Failed. 
Subject's role set does not have the necessary permissions to perform further 
processing.", exchange);
+        }
+
+        LOG.debug("Current user {} is successfully authorized.", 
currentUser.getPrincipal());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f3d14298/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 e01eb66..cf1d2ea 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
@@ -16,14 +16,8 @@
  */
 package org.apache.camel.component.shiro.security;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutput;
-import java.io.ObjectOutputStream;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
-import org.apache.camel.util.IOHelper;
 import org.apache.shiro.crypto.AesCipherService;
 import org.apache.shiro.crypto.CipherService;
 import org.apache.shiro.util.ByteSource;
@@ -58,15 +52,7 @@ public class ShiroSecurityTokenInjector implements Processor 
{
     }
 
     public ByteSource encrypt() throws Exception {
-        ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        ObjectOutput serialStream = new ObjectOutputStream(stream);
-        try {
-            serialStream.writeObject(securityToken);
-            return cipherService.encrypt(stream.toByteArray(), passPhrase);
-        } finally {
-            close(serialStream);
-            IOHelper.close(stream);
-        }
+        return ShiroSecurityHelper.encrypt(securityToken, passPhrase, 
cipherService);
     }
 
     public void process(Exchange exchange) throws Exception {
@@ -114,12 +100,4 @@ public class ShiroSecurityTokenInjector implements 
Processor {
         this.base64 = base64;
     }
 
-    private static void close(ObjectOutput output) {
-        try {
-            output.close();
-        } catch (IOException e) {
-            // ignore
-        }
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f3d14298/components/camel-shiro/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-shiro/src/test/resources/log4j.properties 
b/components/camel-shiro/src/test/resources/log4j.properties
index 7153e32..baf0bb6 100644
--- a/components/camel-shiro/src/test/resources/log4j.properties
+++ b/components/camel-shiro/src/test/resources/log4j.properties
@@ -1,11 +1,26 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
 
 #
-# The logging properties used for eclipse testing, We want to see debug output 
on the console.
+# The logging properties used for testing.
 #
 log4j.rootLogger=INFO, file
 
-log4j.logger.org.springframework=WARN
-#log4j.logger.org.apache.camel=DEBUG
+log4j.logger.org.apache.camel.component.shiro.security=DEBUG
 
 # CONSOLE appender not used by default
 log4j.appender.out=org.apache.log4j.ConsoleAppender

Reply via email to