You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2013/07/15 13:48:32 UTC

[1/2] git commit: CAMEL-6424: camel-netty-http added support for basic auth. Work in progress.

Updated Branches:
  refs/heads/master bf1f5f0cc -> f95326ec9


CAMEL-6424: camel-netty-http added support for basic auth. Work in progress.


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

Branch: refs/heads/master
Commit: f95326ec9085040ec28f2e69b237ee45412d0d1b
Parents: 3493d98
Author: Claus Ibsen <da...@apache.org>
Authored: Mon Jul 15 13:48:00 2013 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Mon Jul 15 13:48:13 2013 +0200

----------------------------------------------------------------------
 .../ConstraintMappingContextPathMatcher.java    |  87 +++++++++++++++
 .../netty/http/HttpBasicAuthSubject.java        |  45 --------
 .../component/netty/http/HttpPrincipal.java     |  52 +++++++++
 .../netty/http/JAASSecurityAuthenticator.java   | 107 ++++++++++++++++++
 .../netty/http/NettyHttpComponent.java          |  11 +-
 .../http/NettyHttpSecurityConfiguration.java    |  14 ++-
 .../netty/http/SecurityAuthenticator.java       |  58 ++++++++++
 .../http/handlers/HttpServerChannelHandler.java |  70 +++++++-----
 ...ConstraintMappingContextPathMatcherTest.java | 108 +++++++++++++++++++
 .../component/netty/http/MyLoginModule.java     |  92 ++++++++++++++++
 .../http/NettyHttpSimpleBasicAuthTest.java      |  58 ++++++++--
 .../src/test/resources/myjaas.config            |   5 +
 12 files changed, 620 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcher.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcher.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcher.java
new file mode 100644
index 0000000..11667ae
--- /dev/null
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcher.java
@@ -0,0 +1,87 @@
+/**
+ * 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.netty.http;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.camel.util.EndpointHelper;
+
+public class ConstraintMappingContextPathMatcher implements ContextPathMatcher {
+
+    private Set<String> inclusions;
+    private Set<String> exclusions;
+
+    @Override
+    public boolean matches(String target) {
+        boolean matches = true;
+
+        if (inclusions != null && !inclusions.isEmpty()) {
+            boolean found = false;
+            for (String constraint : inclusions) {
+                if (EndpointHelper.matchPattern(target, constraint)) {
+                    found = true;
+                    break;
+                }
+            }
+            matches = found;
+        }
+
+        // any exclusions
+        if (exclusions != null && !exclusions.isEmpty()) {
+            for (String constraint : exclusions) {
+                if (EndpointHelper.matchPattern(target, constraint)) {
+                    // force false if this was an exclusion
+                    matches = false;
+                    break;
+                }
+            }
+        }
+
+        return matches;
+    }
+
+    public void addInclusion(String constraint) {
+        if (inclusions == null) {
+            inclusions = new LinkedHashSet<String>();
+        }
+        inclusions.add(constraint);
+    }
+
+    public void addExclusion(String constraint) {
+        if (exclusions == null) {
+            exclusions = new LinkedHashSet<String>();
+        }
+        exclusions.add(constraint);
+    }
+
+    public Set<String> getInclusions() {
+        return inclusions;
+    }
+
+    public void setInclusions(Set<String> inclusions) {
+        this.inclusions = inclusions;
+    }
+
+    public Set<String> getExclusions() {
+        return exclusions;
+    }
+
+    public void setExclusions(Set<String> exclusions) {
+        this.exclusions = exclusions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java
deleted file mode 100644
index 2809c84..0000000
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.netty.http;
-
-import java.io.Serializable;
-
-public final class HttpBasicAuthSubject implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-    private final String username;
-    private final String password;
-
-    public HttpBasicAuthSubject(String username, String password) {
-        this.username = username;
-        this.password = password;
-    }
-
-    public String getUsername() {
-        return username;
-    }
-
-    public String getPassword() {
-        return password;
-    }
-
-    @Override
-    public String toString() {
-        // do not display the password
-        return "HttpBasicAuthSubject[" + username + "]";
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpPrincipal.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpPrincipal.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpPrincipal.java
new file mode 100644
index 0000000..f6a95be
--- /dev/null
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpPrincipal.java
@@ -0,0 +1,52 @@
+/**
+ * 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.netty.http;
+
+import java.security.Principal;
+
+/**
+ * Http {@link Principal}.
+ */
+public final class HttpPrincipal implements Principal {
+
+    private final String username;
+    private final String password;
+
+    public HttpPrincipal(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    @Override
+    public String getName() {
+        return username;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public String toString() {
+        // do not display the password
+        return "HttpPrincipal[" + username + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/JAASSecurityAuthenticator.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/JAASSecurityAuthenticator.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/JAASSecurityAuthenticator.java
new file mode 100644
index 0000000..8fb4c85
--- /dev/null
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/JAASSecurityAuthenticator.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.netty.http;
+
+import java.io.IOException;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A JAAS based {@link SecurityAuthenticator} implementation.
+ */
+public class JAASSecurityAuthenticator implements SecurityAuthenticator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JAASSecurityAuthenticator.class);
+    private String name;
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Subject login(HttpPrincipal principal) throws LoginException {
+        if (ObjectHelper.isEmpty(getName())) {
+            throw new LoginException("Realm has not been configured on this SecurityAuthenticator: " + this);
+        }
+
+        LOG.debug("Login username: {} using realm: {}", principal.getName(), getName());
+        LoginContext context = new LoginContext(getName(), new HttpPrincipalCallbackHandler(principal));
+        context.login();
+        Subject subject = context.getSubject();
+        LOG.debug("Login username: {} successful returning Subject: {}", principal.getName(), subject);
+        return subject;
+    }
+
+    @Override
+    public void logout(Subject subject) throws LoginException {
+        if (ObjectHelper.isEmpty(getName())) {
+            throw new LoginException("Realm has not been configured on this SecurityAuthenticator: " + this);
+        }
+
+        String username = "";
+        if (!subject.getPrincipals().isEmpty()) {
+            username = subject.getPrincipals().iterator().next().getName();
+        }
+        LOG.debug("Logging out username: {} using realm: {}", username, getName());
+        LoginContext context = new LoginContext(getName(), subject);
+        context.logout();
+        LOG.debug("Logout username: {} successful", username);
+    }
+
+    /**
+     * {@link CallbackHandler} that provides the username and password.
+     */
+    private final class HttpPrincipalCallbackHandler implements CallbackHandler {
+
+        private final HttpPrincipal principal;
+
+        private HttpPrincipalCallbackHandler(HttpPrincipal principal) {
+            this.principal = principal;
+        }
+
+        @Override
+        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+            for (Callback callback : callbacks) {
+                LOG.trace("Callback {}", callback);
+                if (callback instanceof PasswordCallback) {
+                    PasswordCallback pc = (PasswordCallback) callback;
+                    LOG.trace("Setting password on callback {}", pc);
+                    pc.setPassword(principal.getPassword().toCharArray());
+                } else if (callback instanceof NameCallback) {
+                    NameCallback nc = (NameCallback) callback;
+                    LOG.trace("Setting username on callback {}", nc);
+                    nc.setName(principal.getName());
+                }
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
index 177ce94..5f92987 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
@@ -46,8 +46,7 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
     private final Map<String, HttpServerBootstrapFactory> bootstrapFactories = new HashMap<String, HttpServerBootstrapFactory>();
     private NettyHttpBinding nettyHttpBinding;
     private HeaderFilterStrategy headerFilterStrategy;
-    // TODO: make it easy to configure this
-    private NettyHttpSecurityConfiguration nettyHttpSecurityConfiguration;// = new NettyHttpSecurityConfiguration();
+    private NettyHttpSecurityConfiguration nettyHttpSecurityConfiguration;
 
     public NettyHttpComponent() {
         // use the http configuration and filter strategy
@@ -74,6 +73,9 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
             }
         }
 
+        // any custom security configuration
+        NettyHttpSecurityConfiguration securityConfiguration = resolveAndRemoveReferenceParameter(parameters, "nettyHttpSecurityConfiguration", NettyHttpSecurityConfiguration.class);
+
         config = parseConfiguration(config, remaining, parameters);
 
         // validate config
@@ -104,7 +106,10 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
         if (answer.getHeaderFilterStrategy() == null) {
             answer.setHeaderFilterStrategy(getHeaderFilterStrategy());
         }
-        if (answer.getNettyHttpSecurityConfiguration() == null) {
+
+        if (securityConfiguration != null) {
+            answer.setNettyHttpSecurityConfiguration(securityConfiguration);
+        } else if (answer.getNettyHttpSecurityConfiguration() == null) {
             answer.setNettyHttpSecurityConfiguration(getNettyHttpSecurityConfiguration());
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
index e04c497..9f0ebf9 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
@@ -16,12 +16,16 @@
  */
 package org.apache.camel.component.netty.http;
 
+/**
+ * Security configuration for the {@link NettyHttpConsumer}.
+ */
 public class NettyHttpSecurityConfiguration {
 
     private boolean authenticate = true;
     private String constraint = "BASIC";
-    private String realm = "Camel";
+    private String realm;
     private ContextPathMatcher contextPathMatcher;
+    private SecurityAuthenticator securityAuthenticator;
 
     public boolean isAuthenticate() {
         return authenticate;
@@ -54,4 +58,12 @@ public class NettyHttpSecurityConfiguration {
     public void setContextPathMatcher(ContextPathMatcher contextPathMatcher) {
         this.contextPathMatcher = contextPathMatcher;
     }
+
+    public SecurityAuthenticator getSecurityAuthenticator() {
+        return securityAuthenticator;
+    }
+
+    public void setSecurityAuthenticator(SecurityAuthenticator securityAuthenticator) {
+        this.securityAuthenticator = securityAuthenticator;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/SecurityAuthenticator.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/SecurityAuthenticator.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/SecurityAuthenticator.java
new file mode 100644
index 0000000..65a976b
--- /dev/null
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/SecurityAuthenticator.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.netty.http;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+/**
+ * A {@link SecurityAuthenticator} allows to plugin custom authenticators,
+ * such as JAAS based or custom implementations.
+ */
+public interface SecurityAuthenticator {
+
+    /**
+     * Sets the name of the realm to use.
+     */
+    void setName(String name);
+
+    /**
+     * Gets the name of the realm.
+     */
+    String getName();
+
+    /**
+     * Attempts to login the {@link java.security.Principal} on this realm.
+     * <p/>
+     * The login is a success if no Exception is thrown. The implementation can return
+     * a {@link Subject} instance, but is not required to do so.
+     *
+     * @param principal       the principal
+     * @return optional subject returned for successful login
+     * @throws LoginException is thrown if error logging in the {@link java.security.Principal}
+     */
+    Subject login(HttpPrincipal principal) throws LoginException;
+
+    /**
+     * Attempt to logout the subject.
+     *
+     * @param subject  subject to logout
+     * @throws LoginException is thrown if error logging out subject
+     */
+    void logout(Subject subject) throws LoginException;
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
index ccc2415..8552f66 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
@@ -19,14 +19,17 @@ package org.apache.camel.component.netty.http.handlers;
 import java.net.SocketAddress;
 import java.nio.channels.ClosedChannelException;
 import java.nio.charset.Charset;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.component.netty.NettyConsumer;
 import org.apache.camel.component.netty.NettyHelper;
 import org.apache.camel.component.netty.handlers.ServerChannelHandler;
-import org.apache.camel.component.netty.http.HttpBasicAuthSubject;
+import org.apache.camel.component.netty.http.HttpPrincipal;
 import org.apache.camel.component.netty.http.NettyHttpConsumer;
 import org.apache.camel.component.netty.http.NettyHttpSecurityConfiguration;
+import org.apache.camel.component.netty.http.SecurityAuthenticator;
 import org.apache.camel.util.ObjectHelper;
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
@@ -109,20 +112,20 @@ public class HttpServerChannelHandler extends ServerChannelHandler {
 
         // is basic auth configured
         NettyHttpSecurityConfiguration security = consumer.getEndpoint().getNettyHttpSecurityConfiguration();
-        if (security != null) {
+        if (security != null && security.isAuthenticate()) {
             String url = request.getUri();
 
             // is it a restricted resource?
             boolean restricted = security.getContextPathMatcher() == null || security.getContextPathMatcher().matches(url);
             if (restricted) {
                 // basic auth subject
-                HttpBasicAuthSubject subject = extractBasicAuthSubject(request);
-                boolean authenticated = subject != null && authenticate(subject);
-                if (subject == null || !authenticated) {
-                    if (subject == null) {
+                HttpPrincipal principal = extractBasicAuthSubject(request);
+                boolean authenticated = principal != null && authenticate(security.getSecurityAuthenticator(), principal) != null;
+                if (principal == null || !authenticated) {
+                    if (principal == null) {
                         LOG.debug("Http Basic Auth required for resource: {}", url);
                     } else {
-                        LOG.debug("Http Basic Auth not authorized for username: {}", subject.getUsername());
+                        LOG.debug("Http Basic Auth not authorized for username: {}", principal.getUsername());
                     }
                     // restricted resource, so send back 401 to require valid username/password
                     HttpResponse response = new DefaultHttpResponse(HTTP_1_1, UNAUTHORIZED);
@@ -133,7 +136,7 @@ public class HttpServerChannelHandler extends ServerChannelHandler {
                     messageEvent.getChannel().write(response);
                     return;
                 } else {
-                    LOG.debug("Http Basic Auth authorized for username: {}", subject.getUsername());
+                    LOG.debug("Http Basic Auth authorized for username: {}", principal.getUsername());
                 }
             }
         }
@@ -143,34 +146,47 @@ public class HttpServerChannelHandler extends ServerChannelHandler {
     }
 
     /**
-     * Authenticates the http basic auth subject.
+     * Extracts the username and password details from the HTTP basic header Authorization.
+     * <p/>
+     * This requires that the <tt>Authorization</tt> HTTP header is provided, and its using Basic.
+     * Currently Digest is <b>not</b> supported.
      *
-     * @param subject  the subject
-     * @return <tt>true</tt> if username and password is valid, <tt>false</tt> if not
+     * @return {@link HttpPrincipal} with username and password details, or <tt>null</tt> if not possible to extract
      */
-    protected boolean authenticate(HttpBasicAuthSubject subject) {
-        // TODO: an api for authentication
-        return subject.getPassword().equals("secret");
-        //return true;
-    }
-
-    protected static HttpBasicAuthSubject extractBasicAuthSubject(HttpRequest request) {
+    protected static HttpPrincipal extractBasicAuthSubject(HttpRequest request) {
         String auth = request.getHeader("Authorization");
         if (auth != null) {
             String constraint = ObjectHelper.before(auth, " ");
-            String decoded = ObjectHelper.after(auth, " ");
-            // the decoded part is base64 encoded, so we need to decode that
-            ChannelBuffer buf = ChannelBuffers.copiedBuffer(decoded.getBytes());
-            ChannelBuffer out = Base64.decode(buf);
-            String userAndPw = out.toString(Charset.defaultCharset());
-            String username = ObjectHelper.before(userAndPw, ":");
-            String password = ObjectHelper.after(userAndPw, ":");
-            HttpBasicAuthSubject subject = new HttpBasicAuthSubject(username, password);
-            return subject;
+            if (constraint != null) {
+                if ("Basic".equalsIgnoreCase(constraint.trim())) {
+                    String decoded = ObjectHelper.after(auth, " ");
+                    // the decoded part is base64 encoded, so we need to decode that
+                    ChannelBuffer buf = ChannelBuffers.copiedBuffer(decoded.getBytes());
+                    ChannelBuffer out = Base64.decode(buf);
+                    String userAndPw = out.toString(Charset.defaultCharset());
+                    String username = ObjectHelper.before(userAndPw, ":");
+                    String password = ObjectHelper.after(userAndPw, ":");
+                    HttpPrincipal principal = new HttpPrincipal(username, password);
+
+                    LOG.debug("Extracted Basic Auth principal from HTTP header: {}", principal);
+                    return principal;
+                }
+            }
         }
         return null;
     }
 
+    /**
+     * Authenticates the http basic auth subject.
+     *
+     * @param authenticator      the authenticator
+     * @param principal          the principal
+     * @return <tt>true</tt> if username and password is valid, <tt>false</tt> if not
+     */
+    protected Subject authenticate(SecurityAuthenticator authenticator, HttpPrincipal principal) throws LoginException {
+        return authenticator.login(principal);
+    }
+
     @Override
     protected void beforeProcess(Exchange exchange, MessageEvent messageEvent) {
         if (consumer.getConfiguration().isBridgeEndpoint()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcherTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcherTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcherTest.java
new file mode 100644
index 0000000..6914c8c
--- /dev/null
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/ConstraintMappingContextPathMatcherTest.java
@@ -0,0 +1,108 @@
+/**
+ * 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.netty.http;
+
+import junit.framework.TestCase;
+
+public class ConstraintMappingContextPathMatcherTest extends TestCase {
+
+    public void testDefault() {
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+
+        assertTrue(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+    }
+
+    public void testFoo() {
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+        matcher.addInclusion("/foo");
+
+        assertFalse(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+        assertFalse(matcher.matches("/foobar"));
+        assertFalse(matcher.matches("/foo/bar"));
+    }
+
+    public void testFooWildcard() {
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+        matcher.addInclusion("/foo*");
+
+        assertFalse(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+        assertTrue(matcher.matches("/foobar"));
+        assertTrue(matcher.matches("/foo/bar"));
+    }
+
+    public void testFooBar() {
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+        matcher.addInclusion("/foo");
+        matcher.addInclusion("/bar");
+
+        assertFalse(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+        assertFalse(matcher.matches("/foobar"));
+        assertFalse(matcher.matches("/foo/bar"));
+
+        assertTrue(matcher.matches("/bar"));
+        assertFalse(matcher.matches("/barbar"));
+        assertFalse(matcher.matches("/bar/bar"));
+    }
+
+    public void testFooBarWildcard() {
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+        matcher.addInclusion("/foo*");
+        matcher.addInclusion("/bar*");
+
+        assertFalse(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+        assertTrue(matcher.matches("/foobar"));
+        assertTrue(matcher.matches("/foo/bar"));
+
+        assertTrue(matcher.matches("/bar"));
+        assertTrue(matcher.matches("/barbar"));
+        assertTrue(matcher.matches("/bar/bar"));
+    }
+
+    public void testFooExclusion() {
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+        matcher.addInclusion("/foo/*");
+        matcher.addExclusion("/foo/public/*");
+
+        assertFalse(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+        assertTrue(matcher.matches("/foo/bar"));
+        assertFalse(matcher.matches("/foo/public"));
+        assertFalse(matcher.matches("/foo/public/open"));
+    }
+
+    public void testDefaultExclusion() {
+        // everything is restricted unless its from the public
+        ConstraintMappingContextPathMatcher matcher = new ConstraintMappingContextPathMatcher();
+        matcher.addExclusion("/public/*");
+        matcher.addExclusion("/index");
+        matcher.addExclusion("/index.html");
+
+        assertTrue(matcher.matches("/"));
+        assertTrue(matcher.matches("/foo"));
+        assertTrue(matcher.matches("/foo/bar"));
+        assertFalse(matcher.matches("/public"));
+        assertFalse(matcher.matches("/public/open"));
+        assertFalse(matcher.matches("/index"));
+        assertFalse(matcher.matches("/index.html"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/MyLoginModule.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/MyLoginModule.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/MyLoginModule.java
new file mode 100644
index 0000000..ad5143a
--- /dev/null
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/MyLoginModule.java
@@ -0,0 +1,92 @@
+/**
+ * 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.netty.http;
+
+import java.io.IOException;
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+public class MyLoginModule implements LoginModule {
+
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+
+    @Override
+    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+    }
+
+    @Override
+    public boolean login() throws LoginException {
+
+        // get username and password
+        Callback[] callbacks = new Callback[2];
+        callbacks[0] = new NameCallback("username");
+        callbacks[1] = new PasswordCallback("password", false);
+
+        try {
+            callbackHandler.handle(callbacks);
+            String username = ((NameCallback)callbacks[0]).getName();
+            char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
+            String password = new String(tmpPassword);
+            ((PasswordCallback)callbacks[1]).clearPassword();
+
+            // only allow login if password is secret
+            // as this is just for testing purpose
+            if (!"secret".equals(password)) {
+                throw new LoginException("Login denied");
+            }
+        } catch (IOException ioe) {
+            LoginException le = new LoginException(ioe.toString());
+            le.initCause(ioe);
+            throw le;
+        } catch (UnsupportedCallbackException uce) {
+            LoginException le = new LoginException("Error: " + uce.getCallback().toString()
+                    + " not available to gather authentication information from the user");
+            le.initCause(uce);
+            throw le;
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean commit() throws LoginException {
+        return true;
+    }
+
+    @Override
+    public boolean abort() throws LoginException {
+        return true;
+    }
+
+    @Override
+    public boolean logout() throws LoginException {
+        subject = null;
+        callbackHandler = null;
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
index 048f1b4..d4e0b6e 100644
--- a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
@@ -16,22 +16,58 @@
  */
 package org.apache.camel.component.netty.http;
 
+import org.apache.camel.CamelExecutionException;
 import org.apache.camel.builder.RouteBuilder;
-import org.junit.Ignore;
+import org.apache.camel.impl.JndiRegistry;
 import org.junit.Test;
 
-@Ignore
 public class NettyHttpSimpleBasicAuthTest extends BaseNettyTest {
 
+    @Override
+    public void setUp() throws Exception {
+        System.setProperty("java.security.auth.login.config", "src/test/resources/myjaas.config");
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        System.clearProperty("java.security.auth.login.config");
+        super.tearDown();
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        NettyHttpSecurityConfiguration security = new NettyHttpSecurityConfiguration();
+        security.setRealm("karaf");
+        SecurityAuthenticator auth = new JAASSecurityAuthenticator();
+        auth.setName("karaf");
+        security.setSecurityAuthenticator(auth);
+
+        jndi.bind("mySecurityConfig", security);
+
+        return jndi;
+    }
+
     @Test
-    public void testHttpSimple() throws Exception {
-//        getMockEndpoint("mock:input").expectedBodiesReceived("Hello World");
-//
-//        String out = template.requestBody("netty-http:http://localhost:{{port}}/foo", "Hello World", String.class);
-//        assertEquals("Bye World", out);
-//
-//        assertMockEndpointsSatisfied();
-//        Thread.sleep(9999999);
+    public void testBasicAuth() throws Exception {
+        try {
+            template.requestBody("netty-http:http://localhost:{{port}}/foo", "Hello World", String.class);
+            fail("Should send back 401");
+        } catch (CamelExecutionException e) {
+            NettyHttpOperationFailedException cause = assertIsInstanceOf(NettyHttpOperationFailedException.class, e.getCause());
+            assertEquals(401, cause.getStatusCode());
+        }
+
+        getMockEndpoint("mock:input").expectedBodiesReceived("Hello World");
+
+        // username:password is scott:secret
+        String auth = "Basic c2NvdHQ6c2VjcmV0";
+        String out = template.requestBodyAndHeader("netty-http:http://localhost:{{port}}/foo", "Hello World", "Authorization", auth, String.class);
+        assertEquals("Bye World", out);
+
+        assertMockEndpointsSatisfied();
     }
 
     @Override
@@ -39,7 +75,7 @@ public class NettyHttpSimpleBasicAuthTest extends BaseNettyTest {
         return new RouteBuilder() {
             @Override
             public void configure() throws Exception {
-                from("netty-http:http://0.0.0.0:{{port}}/foo")
+                from("netty-http:http://0.0.0.0:{{port}}/foo?nettyHttpSecurityConfiguration=#mySecurityConfig")
                     .to("mock:input")
                     .transform().constant("Bye World");
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/f95326ec/components/camel-netty-http/src/test/resources/myjaas.config
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/resources/myjaas.config b/components/camel-netty-http/src/test/resources/myjaas.config
new file mode 100644
index 0000000..40749ce
--- /dev/null
+++ b/components/camel-netty-http/src/test/resources/myjaas.config
@@ -0,0 +1,5 @@
+/** Test Login Configuration **/
+
+karaf {
+   org.apache.camel.component.netty.http.MyLoginModule required debug=true;
+};
\ No newline at end of file


[2/2] git commit: CAMEL-6424: camel-netty-http added support for basic auth. Work in progress.

Posted by da...@apache.org.
CAMEL-6424: camel-netty-http added support for basic auth. Work in progress.


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

Branch: refs/heads/master
Commit: 3493d980679fee253a364612148fde925b8afefd
Parents: bf1f5f0
Author: Claus Ibsen <da...@apache.org>
Authored: Mon Jul 15 10:09:36 2013 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Mon Jul 15 13:48:13 2013 +0200

----------------------------------------------------------------------
 .../netty/http/HttpBasicAuthSubject.java        | 45 +++++++++++++
 .../netty/http/NettyHttpComponent.java          | 13 ++++
 .../component/netty/http/NettyHttpEndpoint.java |  9 +++
 .../http/NettyHttpSecurityConfiguration.java    | 57 +++++++++++++++++
 .../http/handlers/HttpServerChannelHandler.java | 67 ++++++++++++++++++++
 .../http/NettyHttpSimpleBasicAuthTest.java      | 49 ++++++++++++++
 .../src/test/resources/log4j.properties         |  2 +-
 7 files changed, 241 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java
new file mode 100644
index 0000000..2809c84
--- /dev/null
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpBasicAuthSubject.java
@@ -0,0 +1,45 @@
+/**
+ * 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.netty.http;
+
+import java.io.Serializable;
+
+public final class HttpBasicAuthSubject implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private final String username;
+    private final String password;
+
+    public HttpBasicAuthSubject(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public String toString() {
+        // do not display the password
+        return "HttpBasicAuthSubject[" + username + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
index 6d5c4c3..177ce94 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java
@@ -46,6 +46,8 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
     private final Map<String, HttpServerBootstrapFactory> bootstrapFactories = new HashMap<String, HttpServerBootstrapFactory>();
     private NettyHttpBinding nettyHttpBinding;
     private HeaderFilterStrategy headerFilterStrategy;
+    // TODO: make it easy to configure this
+    private NettyHttpSecurityConfiguration nettyHttpSecurityConfiguration;// = new NettyHttpSecurityConfiguration();
 
     public NettyHttpComponent() {
         // use the http configuration and filter strategy
@@ -102,6 +104,9 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
         if (answer.getHeaderFilterStrategy() == null) {
             answer.setHeaderFilterStrategy(getHeaderFilterStrategy());
         }
+        if (answer.getNettyHttpSecurityConfiguration() == null) {
+            answer.setNettyHttpSecurityConfiguration(getNettyHttpSecurityConfiguration());
+        }
 
         answer.setNettySharedHttpServer(shared);
         return answer;
@@ -141,6 +146,14 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
         this.headerFilterStrategy = headerFilterStrategy;
     }
 
+    public NettyHttpSecurityConfiguration getNettyHttpSecurityConfiguration() {
+        return nettyHttpSecurityConfiguration;
+    }
+
+    public void setNettyHttpSecurityConfiguration(NettyHttpSecurityConfiguration nettyHttpSecurityConfiguration) {
+        this.nettyHttpSecurityConfiguration = nettyHttpSecurityConfiguration;
+    }
+
     public synchronized HttpServerConsumerChannelFactory getMultiplexChannelHandler(int port) {
         HttpServerConsumerChannelFactory answer = multiplexChannelHandlers.get(port);
         if (answer == null) {

http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
index e481d4b..1039fcf 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
@@ -46,6 +46,7 @@ public class NettyHttpEndpoint extends NettyEndpoint implements HeaderFilterStra
     private boolean traceEnabled;
     private String httpMethodRestrict;
     private NettySharedHttpServer nettySharedHttpServer;
+    private NettyHttpSecurityConfiguration nettyHttpSecurityConfiguration;
 
     public NettyHttpEndpoint(String endpointUri, NettyHttpComponent component, NettyConfiguration configuration) {
         super(endpointUri, component, configuration);
@@ -171,6 +172,14 @@ public class NettyHttpEndpoint extends NettyEndpoint implements HeaderFilterStra
         this.nettySharedHttpServer = nettySharedHttpServer;
     }
 
+    public NettyHttpSecurityConfiguration getNettyHttpSecurityConfiguration() {
+        return nettyHttpSecurityConfiguration;
+    }
+
+    public void setNettyHttpSecurityConfiguration(NettyHttpSecurityConfiguration nettyHttpSecurityConfiguration) {
+        this.nettyHttpSecurityConfiguration = nettyHttpSecurityConfiguration;
+    }
+
     @Override
     protected void doStart() throws Exception {
         super.doStart();

http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
new file mode 100644
index 0000000..e04c497
--- /dev/null
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpSecurityConfiguration.java
@@ -0,0 +1,57 @@
+/**
+ * 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.netty.http;
+
+public class NettyHttpSecurityConfiguration {
+
+    private boolean authenticate = true;
+    private String constraint = "BASIC";
+    private String realm = "Camel";
+    private ContextPathMatcher contextPathMatcher;
+
+    public boolean isAuthenticate() {
+        return authenticate;
+    }
+
+    public void setAuthenticate(boolean authenticate) {
+        this.authenticate = authenticate;
+    }
+
+    public String getConstraint() {
+        return constraint;
+    }
+
+    public void setConstraint(String constraint) {
+        this.constraint = constraint;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(String realm) {
+        this.realm = realm;
+    }
+
+    public ContextPathMatcher getContextPathMatcher() {
+        return contextPathMatcher;
+    }
+
+    public void setContextPathMatcher(ContextPathMatcher contextPathMatcher) {
+        this.contextPathMatcher = contextPathMatcher;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
index 95ca27d..ccc2415 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
@@ -18,17 +18,23 @@ package org.apache.camel.component.netty.http.handlers;
 
 import java.net.SocketAddress;
 import java.nio.channels.ClosedChannelException;
+import java.nio.charset.Charset;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.component.netty.NettyConsumer;
 import org.apache.camel.component.netty.NettyHelper;
 import org.apache.camel.component.netty.handlers.ServerChannelHandler;
+import org.apache.camel.component.netty.http.HttpBasicAuthSubject;
 import org.apache.camel.component.netty.http.NettyHttpConsumer;
+import org.apache.camel.component.netty.http.NettyHttpSecurityConfiguration;
+import org.apache.camel.util.ObjectHelper;
+import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
 import org.jboss.netty.channel.ChannelFutureListener;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ExceptionEvent;
 import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.handler.codec.base64.Base64;
 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
 import org.jboss.netty.handler.codec.http.HttpRequest;
 import org.jboss.netty.handler.codec.http.HttpResponse;
@@ -40,6 +46,7 @@ import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive;
 import static org.jboss.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
 import static org.jboss.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
 import static org.jboss.netty.handler.codec.http.HttpResponseStatus.SERVICE_UNAVAILABLE;
+import static org.jboss.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED;
 import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
 
 /**
@@ -100,10 +107,70 @@ public class HttpServerChannelHandler extends ServerChannelHandler {
             return;
         }
 
+        // is basic auth configured
+        NettyHttpSecurityConfiguration security = consumer.getEndpoint().getNettyHttpSecurityConfiguration();
+        if (security != null) {
+            String url = request.getUri();
+
+            // is it a restricted resource?
+            boolean restricted = security.getContextPathMatcher() == null || security.getContextPathMatcher().matches(url);
+            if (restricted) {
+                // basic auth subject
+                HttpBasicAuthSubject subject = extractBasicAuthSubject(request);
+                boolean authenticated = subject != null && authenticate(subject);
+                if (subject == null || !authenticated) {
+                    if (subject == null) {
+                        LOG.debug("Http Basic Auth required for resource: {}", url);
+                    } else {
+                        LOG.debug("Http Basic Auth not authorized for username: {}", subject.getUsername());
+                    }
+                    // restricted resource, so send back 401 to require valid username/password
+                    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, UNAUTHORIZED);
+                    response.setHeader("WWW-Authenticate", "Basic realm=\"" + security.getRealm() + "\"");
+                    response.setHeader(Exchange.CONTENT_TYPE, "text/plain");
+                    response.setHeader(Exchange.CONTENT_LENGTH, 0);
+                    response.setContent(ChannelBuffers.copiedBuffer(new byte[]{}));
+                    messageEvent.getChannel().write(response);
+                    return;
+                } else {
+                    LOG.debug("Http Basic Auth authorized for username: {}", subject.getUsername());
+                }
+            }
+        }
+
         // let Camel process this message
         super.messageReceived(ctx, messageEvent);
     }
 
+    /**
+     * Authenticates the http basic auth subject.
+     *
+     * @param subject  the subject
+     * @return <tt>true</tt> if username and password is valid, <tt>false</tt> if not
+     */
+    protected boolean authenticate(HttpBasicAuthSubject subject) {
+        // TODO: an api for authentication
+        return subject.getPassword().equals("secret");
+        //return true;
+    }
+
+    protected static HttpBasicAuthSubject extractBasicAuthSubject(HttpRequest request) {
+        String auth = request.getHeader("Authorization");
+        if (auth != null) {
+            String constraint = ObjectHelper.before(auth, " ");
+            String decoded = ObjectHelper.after(auth, " ");
+            // the decoded part is base64 encoded, so we need to decode that
+            ChannelBuffer buf = ChannelBuffers.copiedBuffer(decoded.getBytes());
+            ChannelBuffer out = Base64.decode(buf);
+            String userAndPw = out.toString(Charset.defaultCharset());
+            String username = ObjectHelper.before(userAndPw, ":");
+            String password = ObjectHelper.after(userAndPw, ":");
+            HttpBasicAuthSubject subject = new HttpBasicAuthSubject(username, password);
+            return subject;
+        }
+        return null;
+    }
+
     @Override
     protected void beforeProcess(Exchange exchange, MessageEvent messageEvent) {
         if (consumer.getConfiguration().isBridgeEndpoint()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
new file mode 100644
index 0000000..048f1b4
--- /dev/null
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimpleBasicAuthTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.netty.http;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class NettyHttpSimpleBasicAuthTest extends BaseNettyTest {
+
+    @Test
+    public void testHttpSimple() throws Exception {
+//        getMockEndpoint("mock:input").expectedBodiesReceived("Hello World");
+//
+//        String out = template.requestBody("netty-http:http://localhost:{{port}}/foo", "Hello World", String.class);
+//        assertEquals("Bye World", out);
+//
+//        assertMockEndpointsSatisfied();
+//        Thread.sleep(9999999);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("netty-http:http://0.0.0.0:{{port}}/foo")
+                    .to("mock:input")
+                    .transform().constant("Bye World");
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/3493d980/components/camel-netty-http/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/resources/log4j.properties b/components/camel-netty-http/src/test/resources/log4j.properties
index 7d3c19c..0bada7f 100644
--- a/components/camel-netty-http/src/test/resources/log4j.properties
+++ b/components/camel-netty-http/src/test/resources/log4j.properties
@@ -16,7 +16,7 @@
 ## ------------------------------------------------------------------------
 
 #
-# 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