camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From davscl...@apache.org
Subject [1/2] git commit: CAMEL-6424: camel-netty-http added support for basic auth. Work in progress.
Date Mon, 15 Jul 2013 11:48:32 GMT
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 <davsclaus@apache.org>
Authored: Mon Jul 15 13:48:00 2013 +0200
Committer: Claus Ibsen <davsclaus@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


Mime
View raw message