You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2012/04/12 10:14:21 UTC

svn commit: r1325151 [1/2] - in /ace/trunk: ./ ace-authentication-api/ ace-authentication-api/src/ ace-authentication-api/src/main/ ace-authentication-api/src/main/java/ ace-authentication-api/src/main/java/org/ ace-authentication-api/src/main/java/org...

Author: jawi
Date: Thu Apr 12 08:14:17 2012
New Revision: 1325151

URL: http://svn.apache.org/viewvc?rev=1325151&view=rev
Log:
ACE-255: implement a uniform authentication mechanism for all public interfaces.

Added:
    ace/trunk/ace-authentication/   (with props)
    ace/trunk/ace-authentication-api/   (with props)
    ace/trunk/ace-authentication-api/pom.xml   (with props)
    ace/trunk/ace-authentication-api/src/
    ace/trunk/ace-authentication-api/src/main/
    ace/trunk/ace-authentication-api/src/main/java/
    ace/trunk/ace-authentication-api/src/main/java/org/
    ace/trunk/ace-authentication-api/src/main/java/org/apache/
    ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/
    ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/
    ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/
    ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationProcessor.java   (with props)
    ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationService.java   (with props)
    ace/trunk/ace-authentication/pom.xml   (with props)
    ace/trunk/ace-authentication/src/
    ace/trunk/ace-authentication/src/main/
    ace/trunk/ace-authentication/src/main/java/
    ace/trunk/ace-authentication/src/main/java/org/
    ace/trunk/ace-authentication/src/main/java/org/apache/
    ace/trunk/ace-authentication/src/main/java/org/apache/ace/
    ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/
    ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/
    ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/Activator.java   (with props)
    ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/AuthenticationServiceImpl.java   (with props)
    ace/trunk/ace-authentication/src/test/
    ace/trunk/ace-authentication/src/test/java/
    ace/trunk/ace-authentication/src/test/java/org/
    ace/trunk/ace-authentication/src/test/java/org/apache/
    ace/trunk/ace-authentication/src/test/java/org/apache/ace/
    ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/
    ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/
    ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/AuthenticationServiceImplTest.java   (with props)
    ace/trunk/ace-authenticationprocessor-basicauth/   (with props)
    ace/trunk/ace-authenticationprocessor-basicauth/pom.xml   (with props)
    ace/trunk/ace-authenticationprocessor-basicauth/src/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/Activator.java   (with props)
    ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessor.java   (with props)
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/
    ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessorTest.java   (with props)
    ace/trunk/ace-authenticationprocessor-clientcert/   (with props)
    ace/trunk/ace-authenticationprocessor-clientcert/pom.xml   (with props)
    ace/trunk/ace-authenticationprocessor-clientcert/src/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/Activator.java   (with props)
    ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessor.java   (with props)
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/apache/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/apache/ace/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/apache/ace/authenticationprocessor/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/apache/ace/authenticationprocessor/clientcert/
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessorTest.java   (with props)
    ace/trunk/ace-authenticationprocessor-clientcert/src/test/java/org/apache/ace/authenticationprocessor/clientcert/MemoryKeyStore.java   (with props)
    ace/trunk/ace-authenticationprocessor-password/   (with props)
    ace/trunk/ace-authenticationprocessor-password/pom.xml   (with props)
    ace/trunk/ace-authenticationprocessor-password/src/
    ace/trunk/ace-authenticationprocessor-password/src/main/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/apache/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/apache/ace/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/apache/ace/authenticationprocessor/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/apache/ace/authenticationprocessor/password/
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/apache/ace/authenticationprocessor/password/Activator.java   (with props)
    ace/trunk/ace-authenticationprocessor-password/src/main/java/org/apache/ace/authenticationprocessor/password/PasswordAuthenticationProcessor.java   (with props)
    ace/trunk/ace-authenticationprocessor-password/src/test/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/org/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/org/apache/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/org/apache/ace/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/org/apache/ace/authenticationprocessor/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/org/apache/ace/authenticationprocessor/password/
    ace/trunk/ace-authenticationprocessor-password/src/test/java/org/apache/ace/authenticationprocessor/password/PasswordAuthenticationProcessorTest.java   (with props)
Modified:
    ace/trunk/   (props changed)
    ace/trunk/ace-client-rest/pom.xml
    ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java
    ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java
    ace/trunk/ace-target-devserver/pom.xml
    ace/trunk/ace-webui-vaadin/pom.xml
    ace/trunk/ace-webui-vaadin/src/main/java/org/apache/ace/webui/vaadin/VaadinClient.java
    ace/trunk/ace-webui-vaadin/src/main/java/org/apache/ace/webui/vaadin/VaadinServlet.java
    ace/trunk/pom.xml
    ace/trunk/pom/pom.xml

Propchange: ace/trunk/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Apr 12 08:14:17 2012
@@ -7,4 +7,7 @@ target
 *.ipr
 *.iws
 *.iml
+store
+test-output
+velocity.log
 

Propchange: ace/trunk/ace-authentication/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Apr 12 08:14:17 2012
@@ -0,0 +1,13 @@
+.metadata
+.settings
+bin
+.classpath
+.project
+target
+*.ipr
+*.iws
+*.iml
+store
+test-output
+velocity.log
+

Propchange: ace/trunk/ace-authentication-api/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Apr 12 08:14:17 2012
@@ -0,0 +1,13 @@
+.metadata
+.settings
+bin
+.classpath
+.project
+target
+*.ipr
+*.iws
+*.iml
+store
+test-output
+velocity.log
+

Added: ace/trunk/ace-authentication-api/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication-api/pom.xml?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication-api/pom.xml (added)
+++ ace/trunk/ace-authentication-api/pom.xml Thu Apr 12 08:14:17 2012
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.ace.authentication.api</artifactId>
+
+    <name>Apache ACE :: Authentication :: API</name>
+    <description>Provides the API for the authentication service.</description>
+    <packaging>bundle</packaging>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-authentication-api</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-authentication-api</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-authentication-api</url>
+    </scm>
+        
+    <properties>
+        <import.package>
+            org.osgi.service.useradmin
+        </import.package>
+        <export.package>
+            org.apache.ace.authentication.api;version=${project.version}
+        </export.package>
+    </properties>
+    
+    <dependencies>
+      <dependency>
+         <groupId>org.osgi</groupId>
+         <artifactId>org.osgi.compendium</artifactId>
+      </dependency>
+    </dependencies>
+</project>

Propchange: ace/trunk/ace-authentication-api/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationProcessor.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationProcessor.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationProcessor.java (added)
+++ ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationProcessor.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,67 @@
+/*
+ * 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.ace.authentication.api;
+
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Provides a pluggable authentication processor, responsible for the actual authentication of a
+ * user based on given context information.
+ * <p>
+ * When multiple authentication processors are implemented and used for the authentication process,
+ * an order in which they should be used is determined based on their <em>service ranking</em>.
+ * </p>
+ */
+public interface AuthenticationProcessor {
+
+    /**
+     * Returns whether or not this authentication processor can handle the given context
+     * information.
+     * <p>
+     * NOTE: this method does not need to perform the actual authentication!
+     * </p>
+     * <p>
+     * For example, for an implementation that authenticates a user based on its username
+     * and password might check whether the given context information consists of two
+     * strings.
+     * </p>
+     * 
+     * @param context the context information to check, should never be <code>null</code> or an
+     *        empty array.
+     * @return <code>true</code> if this authentication processor can handle the given context
+     *         information, <code>false</code> otherwise.
+     * @throws IllegalArgumentException in case the given context was <code>null</code> or an empty array;
+     * @throws NullPointerException in case the given array contains <code>null</code> as element(s).
+     */
+    boolean canHandle(Object... context);
+
+    /**
+     * Authenticates a user based on the given context information.
+     * 
+     * @param userAdmin the user admin service, to use for verifying/retrieving user information,
+     *        cannot be <code>null</code>;
+     * @param context the context information to authenticate the user with, should never be
+     *        <code>null</code> or an empty array.
+     * @return the authenticated user, or <code>null</code> if authentication failed.
+     * @throws IllegalArgumentException in case the given context was <code>null</code> or an empty array;
+     * @throws NullPointerException in case the given array contains <code>null</code> as element(s).
+     */
+    User authenticate(UserAdmin userAdmin, Object... context);
+}

Propchange: ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationService.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationService.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationService.java (added)
+++ ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationService.java Thu Apr 12 08:14:17 2012
@@ -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.ace.authentication.api;
+
+import org.osgi.service.useradmin.User;
+
+/**
+ * Provides a generic and pluggable authentication service.
+ * <p>
+ * This service provides the front end to all services that wish to authenticate a user. In short,
+ * this service will look up all available {@link AuthenticationProcessor}s and use them to perform
+ * the actual authentication.
+ * </p>
+ * 
+ * @see AuthenticationProcessor
+ */
+public interface AuthenticationService {
+
+    /**
+     * Authenticates a user based on the given context information.
+     * <p>
+     * The context information can be any kind of object, hence it is not exactly typed. As this
+     * service is pluggable, it is up to the authentication processors to interpret the context
+     * information.
+     * </p>
+     * <p>
+     * Implementations can decide on the strategy of authentication, whether all participating
+     * authentication processors <b>must</b> or <b>may</b> match.<br/>
+     * If multiple authentication processors are found, they <b>must</b> be ordered on their 
+     * <em>service.ranking</em> property. The one with the higest service ranking is used first,
+     * and so on.
+     * </p>
+     * 
+     * @param context the context information, cannot be <code>null</code> or an empty array.
+     * @return an authenticated {@link User}, or <code>null</code> if authentication failed
+     *         (or otherwise was not possible).
+     * @throws IllegalArgumentException in case the given context was <code>null</code> or an empty array;
+     * @throws NullPointerException in case the given array contains <code>null</code> as element(s).
+     */
+    User authenticate(Object... context);
+}

Propchange: ace/trunk/ace-authentication-api/src/main/java/org/apache/ace/authentication/api/AuthenticationService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authentication/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication/pom.xml?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication/pom.xml (added)
+++ ace/trunk/ace-authentication/pom.xml Thu Apr 12 08:14:17 2012
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.ace.authentication</artifactId>
+
+    <name>Apache ACE :: Authentication :: Impl</name>
+    <description>Provides a generic implementation of the authentication service.</description>
+    <packaging>bundle</packaging>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-authentication</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-authentication</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-authentication</url>
+    </scm>
+    
+    <properties>
+        <import.package>
+        	org.apache.ace.authentication.api;version="[0.8,1.0)",
+        	org.apache.felix.dm,
+        	org.osgi.framework,
+        	org.osgi.service.log,
+        	org.osgi.service.useradmin
+        </import.package>
+        <export.package>
+        	org.apache.ace.authentication.api;version=${project.version};-split-package:=merge-first;provide:=true
+        </export.package>
+        <private.package>
+            org.apache.ace.authentication.impl
+        </private.package>
+        <bundle.activator>org.apache.ace.authentication.impl.Activator</bundle.activator>
+    </properties>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.authentication.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+     </dependencies>
+</project>

Propchange: ace/trunk/ace-authentication/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/Activator.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/Activator.java (added)
+++ ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/Activator.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,64 @@
+/*
+ * 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.ace.authentication.impl;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.apache.ace.authentication.api.AuthenticationService;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Provides a bundle activator for the {@link AuthenticationServiceImpl}.
+ */
+public class Activator extends DependencyActivatorBase {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+// @formatter:off
+        manager.add(createComponent()
+            .setInterface(AuthenticationService.class.getName(), null)
+            .setImplementation(new AuthenticationServiceImpl())
+            .add(createServiceDependency()
+                .setRequired(true)
+                .setService(UserAdmin.class))
+            .add(createServiceDependency()
+                .setRequired(false)
+                .setService(LogService.class))
+            .add(createServiceDependency()
+                .setRequired(false)
+                .setService(AuthenticationProcessor.class)
+                .setCallbacks("addAuthenticationProcessor", "removeAuthenticationProcessor"))
+        );
+// @formatter:on
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // Nop
+    }
+}

Propchange: ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/AuthenticationServiceImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/AuthenticationServiceImpl.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/AuthenticationServiceImpl.java (added)
+++ ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/AuthenticationServiceImpl.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,193 @@
+/*
+ * 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.ace.authentication.impl;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.apache.ace.authentication.api.AuthenticationService;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Provides a basic implementation for {@link AuthenticationService} that returns the first matching user.
+ */
+public class AuthenticationServiceImpl implements AuthenticationService {
+
+    /**
+     * Provides a small container for {@link AuthenticationProcessor} instances.
+     */
+    private static class AuthenticationProcessorHolder implements Comparable<AuthenticationProcessorHolder> {
+        private final ServiceReference m_serviceRef;
+        private final WeakReference<AuthenticationProcessor> m_processor;
+
+        public AuthenticationProcessorHolder(ServiceReference serviceRef, AuthenticationProcessor processor) {
+            m_serviceRef = serviceRef;
+            m_processor = new WeakReference<AuthenticationProcessor>(processor);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public int compareTo(AuthenticationProcessorHolder other) {
+            ServiceReference thatServiceRef = other.m_serviceRef;
+            ServiceReference thisServiceRef = m_serviceRef;
+            // Sort in reverse order so that the highest rankings come first...
+            return thatServiceRef.compareTo(thisServiceRef);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof AuthenticationProcessorHolder)) {
+                return false;
+            }
+            AuthenticationProcessorHolder other = (AuthenticationProcessorHolder) obj;
+            return m_serviceRef.equals(other.m_serviceRef);
+        }
+
+        /**
+         * @return the {@link AuthenticationProcessor}, can be <code>null</code> if it has been GC'd before this method call.
+         */
+        public AuthenticationProcessor getAuthenticationProcessor() {
+            return m_processor.get();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int hashCode() {
+            return m_serviceRef.hashCode() ^ m_processor.hashCode();
+        }
+    }
+
+    private volatile UserAdmin m_userAdmin;
+    private volatile LogService m_log;
+
+    private final List<AuthenticationProcessorHolder> m_processors;
+
+    /**
+     * Creates a new {@link AuthenticationServiceImpl} instance.
+     */
+    public AuthenticationServiceImpl() {
+        m_processors = new ArrayList<AuthenticationServiceImpl.AuthenticationProcessorHolder>();
+    }
+
+    /**
+     * Creates a new {@link AuthenticationServiceImpl} instance.
+     */
+    AuthenticationServiceImpl(LogService log) {
+        m_log = log;
+        m_processors = new ArrayList<AuthenticationServiceImpl.AuthenticationProcessorHolder>();
+    }
+
+    /**
+     * Authenticates a user based on the given context information.
+     * <p>
+     * This implementation returns the first {@link User}-object that is returned by a {@link AuthenticationProcessor} instance that can handle the given context.
+     * </p>
+     */
+    public User authenticate(Object... context) {
+        if (context == null || context.length == 0) {
+            throw new IllegalArgumentException("Invalid context!");
+        }
+
+        User result = null;
+
+        m_log.log(LogService.LOG_DEBUG, "Authenticating user for: " + context);
+
+        final List<AuthenticationProcessor> processors = getProcessors(context);
+        for (AuthenticationProcessor processor : processors) {
+            result = processor.authenticate(m_userAdmin, context);
+            if (result != null) {
+                m_log.log(LogService.LOG_DEBUG, "Authenticated user (" + context + ") as: " + result.getName());
+                break;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns all applicable {@link AuthenticationProcessor}s for the given context.
+     * 
+     * @param context the context for which to return all applicable authentication processors, cannot be <code>null</code> or an empty array.
+     * @return an array of applicable authentication processors, never <code>null</code>.
+     */
+    final List<AuthenticationProcessor> getProcessors(Object... context) {
+        final List<AuthenticationProcessorHolder> processors;
+        synchronized (m_processors) {
+            processors = new ArrayList<AuthenticationProcessorHolder>(m_processors);
+        }
+        // Sort on service ranking...
+        Collections.sort(processors);
+
+        int size = processors.size();
+        
+        List<AuthenticationProcessor> result = new ArrayList<AuthenticationProcessor>(size);
+        for (int i = 0; i < size; i++) {
+            AuthenticationProcessor authenticationProcessor = processors.get(i).getAuthenticationProcessor();
+            // Can be null if it is already GC'd for some reason...
+            if ((authenticationProcessor != null) && authenticationProcessor.canHandle(context)) {
+                result.add(authenticationProcessor);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Called by {@link DependencyManager} upon adding a new {@link AuthenticationProcessor}.
+     * 
+     * @param serviceRef the service reference of the authentication processor to add;
+     * @param processor the authentication processor to add.
+     */
+    protected void addAuthenticationProcessor(ServiceReference serviceRef, AuthenticationProcessor processor) {
+        synchronized (m_processors) {
+            m_processors.add(new AuthenticationProcessorHolder(serviceRef, processor));
+        }
+    }
+
+    /**
+     * Called by {@link DependencyManager} upon removal of a {@link AuthenticationProcessor}.
+     * 
+     * @param serviceRef the service reference of the authentication processor to remove;
+     * @param processor the authentication processor to remove.
+     */
+    protected void removeAuthenticationProcessor(ServiceReference serviceRef, AuthenticationProcessor processor) {
+        synchronized (m_processors) {
+            m_processors.remove(new AuthenticationProcessorHolder(serviceRef, processor));
+        }
+    }
+}

Propchange: ace/trunk/ace-authentication/src/main/java/org/apache/ace/authentication/impl/AuthenticationServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/AuthenticationServiceImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/AuthenticationServiceImplTest.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/AuthenticationServiceImplTest.java (added)
+++ ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/AuthenticationServiceImplTest.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,218 @@
+/*
+ * 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.ace.authentication.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Test cases for {@link AuthenticationServiceImpl}.
+ */
+public class AuthenticationServiceImplTest {
+    
+    private LogService m_log;
+
+    @Before
+    public void setUp() {
+        m_log = mock(LogService.class);
+    }
+
+    /**
+     * Tests that an exception is thrown if a null context is given.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthenticateFailsWithNullContext() {
+        new AuthenticationServiceImpl().authenticate((Object[]) null);
+    }
+
+    /**
+     * Tests that without any authentication processors, no authentication will take place.
+     */
+    @Test
+    public void testAuthenticateFailsWithoutAuthProcessors() {
+        assertNull(createAuthenticationService().authenticate("foo", "bar"));
+    }
+
+    /**
+     * Tests that an exception is thrown if no context is given.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthenticateFailsWithoutContext() {
+        new AuthenticationServiceImpl().authenticate();
+    }
+
+    /**
+     * Tests that with a single authentication processors, no authentication will take place if it is the wrong context.
+     */
+    @Test
+    public void testAuthenticateFailsWithSingleAuthProcessorAndWrongContext() {
+        AuthenticationServiceImpl authService = createAuthenticationService();
+        
+        AuthenticationProcessor authProc = mock(AuthenticationProcessor.class);
+        when(authProc.canHandle(anyString())).thenReturn(Boolean.TRUE);
+
+        registerAuthProcessor(authService, authProc);
+
+        assertNull(authService.authenticate("foo", "bar"));
+    }
+
+    /**
+     * Tests that with multiple authentication processors, authentication will take place if it is given the correct context.
+     */
+    @Test
+    public void testAuthenticateSucceedsWithMultipleAuthProcessors() {
+        Date now = new Date();
+        
+        User user1 = mock(User.class);
+        User user2 = mock(User.class);
+
+        AuthenticationProcessor authProc1 = mock(AuthenticationProcessor.class);
+        when(authProc1.canHandle(any())).thenAnswer(new Answer<Boolean>() {
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                return (args.length == 1 && args[0] instanceof Date);
+            }
+        });
+        when(authProc1.authenticate(Mockito.<UserAdmin>any(), eq(now))).thenReturn(user1);
+
+        AuthenticationProcessor authProc2 = mock(AuthenticationProcessor.class);
+        when(authProc2.canHandle(anyString())).thenAnswer(new Answer<Boolean>() {
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                return (args.length == 1 && args[0] instanceof String);
+            }
+        });
+        when(authProc2.authenticate(Mockito.<UserAdmin>any(), eq("foo"))).thenReturn(user2);
+
+        AuthenticationServiceImpl authService = createAuthenticationService();
+
+        registerAuthProcessor(authService, authProc1);
+        registerAuthProcessor(authService, authProc2);
+
+        User result = authService.authenticate("foo");
+        assertNotNull(result);
+        assertSame(user2, result);
+        
+        result = authService.authenticate(now);
+        assertNotNull(result);
+        assertSame(user1, result);
+    }
+
+    /**
+     * Tests that with a single authentication processors, authentication will take place if it is given the correct context.
+     */
+    @Test
+    public void testAuthenticateSucceedsWithSingleAuthProcessorAndCorrectContext() {
+        AuthenticationServiceImpl authService = createAuthenticationService();
+
+        User user = mock(User.class);
+
+        AuthenticationProcessor authProc = mock(AuthenticationProcessor.class);
+        when(authProc.canHandle(anyString())).thenReturn(Boolean.TRUE);
+        when(authProc.authenticate(Mockito.<UserAdmin>any(), eq("foo"))).thenReturn(user);
+
+        registerAuthProcessor(authService, authProc);
+
+        assertNotNull(authService.authenticate("foo"));
+    }
+
+    /**
+     * Tests that with multiple authentication processors, the correct ones are returned based on the given context.
+     */
+    @Test
+    public void testGetProcessorsSelectsCorrectProcessorsBasedOnContext() {
+        Date now = new Date();
+        
+        User user1 = mock(User.class);
+        User user2 = mock(User.class);
+
+        AuthenticationProcessor authProc1 = mock(AuthenticationProcessor.class);
+        when(authProc1.canHandle(any())).thenAnswer(new Answer<Boolean>() {
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                return (args.length == 1 && args[0] instanceof Date);
+            }
+        });
+        when(authProc1.authenticate(Mockito.<UserAdmin>any(), eq(now))).thenReturn(user1);
+
+        AuthenticationProcessor authProc2 = mock(AuthenticationProcessor.class);
+        when(authProc2.canHandle(anyString())).thenAnswer(new Answer<Boolean>() {
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                return (args.length == 1 && args[0] instanceof String);
+            }
+        });
+        when(authProc2.authenticate(Mockito.<UserAdmin>any(), eq("foo"))).thenReturn(user2);
+
+        AuthenticationServiceImpl authService = createAuthenticationService();
+
+        registerAuthProcessor(authService, authProc1);
+        registerAuthProcessor(authService, authProc2);
+
+        List<AuthenticationProcessor> processors = authService.getProcessors("foo");
+        assertNotNull(processors);
+        assertEquals(1, processors.size());
+        
+        processors = authService.getProcessors(now);
+        assertNotNull(processors);
+        assertEquals(1, processors.size());
+        
+        processors = authService.getProcessors(new Object());
+        assertNotNull(processors);
+        assertEquals(0, processors.size());
+    }
+
+    /**
+     * @return a new {@link AuthenticationServiceImpl} instance, never <code>null</code>.
+     */
+    private AuthenticationServiceImpl createAuthenticationService() {
+        return new AuthenticationServiceImpl(m_log);
+    }
+    
+    /**
+     * @param authService
+     * @param authProcessor
+     */
+    private void registerAuthProcessor(AuthenticationServiceImpl authService, AuthenticationProcessor authProcessor) {
+        ServiceReference sr = mock(ServiceReference.class);
+        authService.addAuthenticationProcessor(sr, authProcessor);
+    }
+}

Propchange: ace/trunk/ace-authentication/src/test/java/org/apache/ace/authentication/impl/AuthenticationServiceImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ace/trunk/ace-authenticationprocessor-basicauth/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Apr 12 08:14:17 2012
@@ -0,0 +1,13 @@
+.metadata
+.settings
+bin
+.classpath
+.project
+target
+*.ipr
+*.iws
+*.iml
+store
+test-output
+velocity.log
+

Added: ace/trunk/ace-authenticationprocessor-basicauth/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-basicauth/pom.xml?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-basicauth/pom.xml (added)
+++ ace/trunk/ace-authenticationprocessor-basicauth/pom.xml Thu Apr 12 08:14:17 2012
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.ace.authenticationprocessor.basicauth</artifactId>
+
+    <name>Apache ACE :: Authentication :: HTTP Basic Auth</name>
+    <description>Provides an authentication processor that can handle HTTP basic authentication.</description>
+    <packaging>bundle</packaging>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-authentication-basicauth</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-authentication-basicauth</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-authentication-basicauth</url>
+    </scm>
+        
+    <properties>
+        <import.package>
+        	org.apache.ace.authentication.api,
+        	javax.servlet.http,
+        	org.apache.felix.dm,
+        	org.osgi.framework,
+        	org.osgi.service.cm,
+        	org.osgi.service.useradmin
+        </import.package>
+        <private.package>
+            org.apache.ace.authenticationprocessor.basicauth,
+            org.apache.commons.codec,
+			org.apache.commons.codec.binary
+        </private.package>
+        <bundle.activator>org.apache.ace.authenticationprocessor.basicauth.Activator</bundle.activator>
+    </properties>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.authentication.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+		</dependency>
+    </dependencies>
+</project>

Propchange: ace/trunk/ace-authenticationprocessor-basicauth/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/Activator.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/Activator.java (added)
+++ ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/Activator.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,59 @@
+/*
+ * 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.ace.authenticationprocessor.basicauth;
+
+import java.util.Properties;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * Provides a bundle activator for the {@link BasicHttpAuthenticationProcessor}.
+ */
+public class Activator extends DependencyActivatorBase {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_PID, BasicHttpAuthenticationProcessor.PID);
+        
+// @formatter:off
+        manager.add(createComponent()
+            .setInterface(new String[]{ AuthenticationProcessor.class.getName(), ManagedService.class.getName() }, props)
+            .setImplementation(new BasicHttpAuthenticationProcessor())
+        );
+// @formatter:on
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // Nop
+    }
+}

Propchange: ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessor.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessor.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessor.java (added)
+++ ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessor.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,144 @@
+/*
+ * 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.ace.authenticationprocessor.basicauth;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Dictionary;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.apache.commons.codec.binary.Base64;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Provides an {@link AuthenticationProcessor} that implements basic HTTP authentication and looks
+ * up a user in the {@link UserAdmin} service using (by default, can be configured otherwise) the
+ * keys "username" and "password".
+ */
+public class BasicHttpAuthenticationProcessor implements AuthenticationProcessor, ManagedService {
+
+    public static final String PID = "org.apache.ace.authenticationprocessor.basicauth";
+
+    /** The name of the HTTP-header used for HTTP authentication. */
+    static final String AUTHORIZATION_HEADER = "Authorization";
+
+    static final String PROPERTY_KEY_USERNAME = "key.username";
+    static final String PROPERTY_KEY_PASSWORD = "key.password";
+
+    private static final String DEFAULT_PROPERTY_KEY_USERNAME = "username";
+    private static final String DEFAULT_PROPERTY_KEY_PASSWORD = "password";
+
+    private volatile String m_keyUsername = DEFAULT_PROPERTY_KEY_USERNAME;
+    private volatile String m_keyPassword = DEFAULT_PROPERTY_KEY_PASSWORD;
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canHandle(Object... context) {
+        if (context == null || context.length == 0) {
+            throw new IllegalArgumentException("Invalid context!");
+        }
+
+        return (context[0] instanceof HttpServletRequest);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public User authenticate(UserAdmin userAdmin, Object... context) {
+        final HttpServletRequest request = (HttpServletRequest) context[0];
+
+        String header = request.getHeader(AUTHORIZATION_HEADER);
+        if (header == null || header.length() < 6) {
+            // No authorization header obtained; cannot authorize...
+            return null;
+        }
+
+        // Form = 'Basic ' + base64 encoded credentials
+        String packedCredentials = decodeBase64(header);
+        if (packedCredentials == null) {
+            // No credentials obtained; cannot authenticate...
+            return null;
+        }
+
+        // Form = <user>:<password>
+        String[] credentials = packedCredentials.split(":");
+        if (credentials.length != 2) {
+            // A colon should always be present!
+            return null;
+        }
+
+        User user = userAdmin.getUser(m_keyUsername, credentials[0]);
+        if (user == null || !user.hasCredential(m_keyPassword, credentials[1])) {
+            // Invalid/unknown user!
+            return null;
+        }
+
+        return user;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void updated(Dictionary dictionary) throws ConfigurationException {
+        if (dictionary != null) {
+            String keyUsername = (String) dictionary.get(PROPERTY_KEY_USERNAME);
+            if (keyUsername == null || "".equals(keyUsername.trim())) {
+                throw new ConfigurationException(PROPERTY_KEY_USERNAME, "Missing property");
+            }
+
+            String keyPassword = (String) dictionary.get(PROPERTY_KEY_PASSWORD);
+            if (keyPassword == null || "".equals(keyPassword.trim())) {
+                throw new ConfigurationException(PROPERTY_KEY_PASSWORD, "Missing property");
+            }
+
+            m_keyUsername = keyUsername;
+            m_keyPassword = keyPassword;
+        }
+        else {
+            m_keyUsername = DEFAULT_PROPERTY_KEY_USERNAME;
+            m_keyPassword = DEFAULT_PROPERTY_KEY_PASSWORD;
+        }
+    }
+
+    /**
+     * Decodes a given base64-encoded string.
+     * 
+     * @param header the base64 encoded header to decode.
+     * @return the base64 decoded string, can be <code>null</code>.
+     */
+    private String decodeBase64(String header) {
+        byte[] array = Base64.decodeBase64(header.substring(6));
+        if (array == null) {
+            return null;
+        }
+
+        try {
+            return new String(array, "UTF-8");
+        }
+        catch (UnsupportedEncodingException e) {
+            // Should never occur, as Java is always capable of handling UTF-8!
+            throw new RuntimeException(e);
+        }
+    }
+}

Propchange: ace/trunk/ace-authenticationprocessor-basicauth/src/main/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessorTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessorTest.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessorTest.java (added)
+++ ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessorTest.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,264 @@
+/*
+ * 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.ace.authenticationprocessor.basicauth;
+
+import static org.apache.ace.authenticationprocessor.basicauth.BasicHttpAuthenticationProcessor.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.codec.binary.Base64;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Test cases for {@link BasicHttpAuthenticationProcessor}.
+ */
+public class BasicHttpAuthenticationProcessorTest {
+    
+    private UserAdmin m_userAdmin;
+    private HttpServletRequest m_servletRequest;
+
+    @Before
+    public void setUp() {
+        m_userAdmin = mock(UserAdmin.class);
+        m_servletRequest = mock(HttpServletRequest.class);
+    }
+
+    /**
+     * Tests that a null authentication header will yield null.
+     */
+    @Test
+    public void testAuthenticateEmptyAuthenticationHeaderYieldsNull() {
+        User result = new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, m_servletRequest);
+        assertNull(result);
+    }
+
+    /**
+     * Tests that an invalid authentication header will yield null.
+     */
+    @Test
+    public void testAuthenticateInvalidAuthenticationHeaderYieldsNull() {
+        when(m_servletRequest.getHeader(AUTHORIZATION_HEADER)).thenReturn(createAuthHeaderValue("bob"));
+        
+        User user = mock(User.class);
+        when(user.getName()).thenReturn("bob");
+        when(user.hasCredential(eq("password"), eq("secret"))).thenReturn(Boolean.TRUE);
+
+        when(m_userAdmin.getUser(eq("username"), eq("bob"))).thenReturn(user);
+        
+        User result = new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, m_servletRequest);
+        assertNull(result);
+    }
+
+    /**
+     * Tests that a known user with an invalid password will yield null.
+     */
+    @Test
+    public void testAuthenticateKnownUserWithInvalidPasswordYieldsNull() {
+        when(m_servletRequest.getHeader(AUTHORIZATION_HEADER)).thenReturn(createAuthHeaderValue("bob:secret"));
+        
+        User user = mock(User.class);
+        when(user.getName()).thenReturn("bob");
+        when(user.hasCredential(eq("password"), eq("otherSecret"))).thenReturn(Boolean.TRUE);
+
+        when(m_userAdmin.getUser(eq("username"), eq("bob"))).thenReturn(user);
+
+        User result = new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, m_servletRequest);
+        assertNull(result);
+    }
+
+    /**
+     * Tests that a known user will not yield null.
+     */
+    @Test
+    public void testAuthenticateKnownUserYieldsValidResult() {
+        when(m_servletRequest.getHeader(AUTHORIZATION_HEADER)).thenReturn(createAuthHeaderValue("bob:secret"));
+        
+        User user = mock(User.class);
+        when(user.getName()).thenReturn("bob");
+        when(user.hasCredential(eq("password"), eq("secret"))).thenReturn(Boolean.TRUE);
+
+        when(m_userAdmin.getUser(eq("username"), eq("bob"))).thenReturn(user);
+
+        User result = new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, m_servletRequest);
+        assertNotNull(result);
+        
+        assertEquals("bob", user.getName());
+    }
+
+    /**
+     * Tests that a non Base64 authentication header will yield null.
+     */
+    @Test
+    public void testAuthenticateNonBase64AuthenticationHeaderYieldsNull() {
+        when(m_servletRequest.getHeader(AUTHORIZATION_HEADER)).thenReturn("foo");
+        
+        User result = new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, m_servletRequest);
+        assertNull(result);
+    }
+
+    /**
+     * Tests that a class cast exception is thrown for invalid context when calling authenticate.
+     */
+    @Test(expected = ClassCastException.class)
+    public void testAuthenticateThrowsClassCastForInvalidContext() {
+        new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, new Object());
+    }
+
+    /**
+     * Tests that an unknown user will yield null.
+     */
+    @Test
+    public void testAuthenticateUnknownUserYieldsNull() {
+        when(m_servletRequest.getHeader(AUTHORIZATION_HEADER)).thenReturn(createAuthHeaderValue("bob:secret"));
+        
+        User result = new BasicHttpAuthenticationProcessor().authenticate(m_userAdmin, m_servletRequest);
+        assertNull(result);
+    }
+
+    /**
+     * Tests that canHandle yields false for any object other than {@link HttpServletRequest}.
+     */
+    @Test
+    public void testCanHandleDoesAcceptServletRequest() {
+        assertTrue(new BasicHttpAuthenticationProcessor().canHandle(mock(HttpServletRequest.class)));
+    }
+
+    /**
+     * Tests that canHandle throws an {@link IllegalArgumentException} for an empty context.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testCanHandleDoesNotAcceptEmptyArray() {
+        new BasicHttpAuthenticationProcessor().canHandle(new Object[0]);
+    }
+
+    /**
+     * Tests that canHandle throws an {@link IllegalArgumentException} for a null context.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testCanHandleDoesNotAcceptNull() {
+        new BasicHttpAuthenticationProcessor().canHandle((Object[]) null);
+    }
+    
+    /**
+     * Tests that canHandle yields false for any object other than {@link HttpServletRequest}.
+     */
+    @Test
+    public void testCanHandleDoesNotAcceptUnhandledContext() {
+        assertFalse(new BasicHttpAuthenticationProcessor().canHandle(new Object()));
+    }
+    
+    /**
+     * Tests that updated throws an exception for missing "key.username" property. 
+     */
+    @Test(expected = ConfigurationException.class)
+    public void testUpdatedDoesNotAcceptEmptyKeyUsername() throws ConfigurationException {
+        Properties props = new Properties();
+        props.put(PROPERTY_KEY_USERNAME, "");
+        props.put(PROPERTY_KEY_PASSWORD, "foo");
+        
+        new BasicHttpAuthenticationProcessor().updated(props);
+    }
+    
+    /**
+     * Tests that updated throws an exception for missing "key.username" property. 
+     */
+    @Test(expected = ConfigurationException.class)
+    public void testUpdatedDoesNotAcceptMissingKeyUsername() throws ConfigurationException {
+        Properties props = new Properties();
+        props.put(PROPERTY_KEY_PASSWORD, "foo");
+        
+        new BasicHttpAuthenticationProcessor().updated(props);
+    }
+    
+    /**
+     * Tests that updated throws an exception for missing "key.password" property. 
+     */
+    @Test(expected = ConfigurationException.class)
+    public void testUpdatedDoesNotAcceptMissingKeyPassword() throws ConfigurationException {
+        Properties props = new Properties();
+        props.put(PROPERTY_KEY_USERNAME, "foo");
+        
+        new BasicHttpAuthenticationProcessor().updated(props);
+    }
+    
+    /**
+     * Tests that updated throws an exception for missing "key.password" property. 
+     */
+    @Test(expected = ConfigurationException.class)
+    public void testUpdatedDoesNotAcceptEmptyKeyPassword() throws ConfigurationException {
+        Properties props = new Properties();
+        props.put(PROPERTY_KEY_USERNAME, "foo");
+        props.put(PROPERTY_KEY_PASSWORD, "");
+        
+        new BasicHttpAuthenticationProcessor().updated(props);
+    }
+    
+    /**
+     * Tests that updated does not throw an exception for a correct configuration.
+     */
+    @Test
+    public void testUpdatedDoesAcceptCorrectProperties() throws ConfigurationException {
+        final String keyUsername = "foo";
+        final String keyPassword = "bar";
+        
+        Properties props = new Properties();
+        props.put(PROPERTY_KEY_USERNAME, keyUsername);
+        props.put(PROPERTY_KEY_PASSWORD, keyPassword);
+        
+        BasicHttpAuthenticationProcessor processor = new BasicHttpAuthenticationProcessor();
+
+        processor.updated(props);
+        
+        // Test whether we can use the new properties...
+        when(m_servletRequest.getHeader(AUTHORIZATION_HEADER)).thenReturn(createAuthHeaderValue("bob:secret"));
+        
+        User user = mock(User.class);
+        when(user.getName()).thenReturn("bob");
+        when(user.hasCredential(eq(keyPassword), eq("secret"))).thenReturn(Boolean.TRUE);
+
+        when(m_userAdmin.getUser(eq(keyUsername), eq("bob"))).thenReturn(user);
+
+        User result = processor.authenticate(m_userAdmin, m_servletRequest);
+        assertNotNull(result);
+        
+        assertEquals("bob", user.getName());
+    }
+
+
+    /**
+     * @return the basic authentication header, never <code>null</code>.
+     */
+    private String createAuthHeaderValue(String credentials) {
+        return "Basic " + new Base64().encodeAsString(credentials.getBytes());
+    }
+}

Propchange: ace/trunk/ace-authenticationprocessor-basicauth/src/test/java/org/apache/ace/authenticationprocessor/basicauth/BasicHttpAuthenticationProcessorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ace/trunk/ace-authenticationprocessor-clientcert/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Apr 12 08:14:17 2012
@@ -0,0 +1,13 @@
+.metadata
+.settings
+bin
+.classpath
+.project
+target
+*.ipr
+*.iws
+*.iml
+store
+test-output
+velocity.log
+

Added: ace/trunk/ace-authenticationprocessor-clientcert/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-clientcert/pom.xml?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-clientcert/pom.xml (added)
+++ ace/trunk/ace-authenticationprocessor-clientcert/pom.xml Thu Apr 12 08:14:17 2012
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.ace.authenticationprocessor.clientcert</artifactId>
+
+    <name>Apache ACE :: Authentication :: Client certificate</name>
+    <description>Provides an authentication processor that can handle client certificate authentication.</description>
+    <packaging>bundle</packaging>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-authentication-clientcert</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-authentication-clientcert</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-authentication-clientcert</url>
+    </scm>
+        
+    <properties>
+        <import.package>
+            *
+        </import.package>
+        <private.package>
+            org.apache.ace.authenticationprocessor.clientcert
+        </private.package>
+        <bundle.activator>org.apache.ace.authenticationprocessor.clientcert.Activator</bundle.activator>
+    </properties>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.authentication.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+		<dependency>
+			<groupId>bouncycastle</groupId>
+			<artifactId>bcprov-jdk14</artifactId>
+			<version>140</version>
+			<scope>test</scope>
+		</dependency>
+    </dependencies>
+</project>

Propchange: ace/trunk/ace-authenticationprocessor-clientcert/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/Activator.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/Activator.java (added)
+++ ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/Activator.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,64 @@
+/*
+ * 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.ace.authenticationprocessor.clientcert;
+
+import java.util.Properties;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+
+/**
+ * Provides a bundle activator for the {@link ClientCertAuthenticationProcessor}.
+ */
+public class Activator extends DependencyActivatorBase {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_PID, ClientCertAuthenticationProcessor.PID);
+
+// @formatter:off
+        manager.add(createComponent()
+            .setInterface(new String[]{ AuthenticationProcessor.class.getName(), ManagedService.class.getName() }, props)
+            .setImplementation(new ClientCertAuthenticationProcessor())
+            .add(createServiceDependency()
+                .setService(LogService.class)
+                .setRequired(false)
+            )
+        );
+// @formatter:on
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // Nop
+    }
+}

Propchange: ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessor.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessor.java?rev=1325151&view=auto
==============================================================================
--- ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessor.java (added)
+++ ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessor.java Thu Apr 12 08:14:17 2012
@@ -0,0 +1,209 @@
+/*
+ * 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.ace.authenticationprocessor.clientcert;
+
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Dictionary;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ace.authentication.api.AuthenticationProcessor;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Provides an {@link AuthenticationProcessor} that implements basic HTTP authentication and looks
+ * up a user in the {@link UserAdmin} service using (by default, can be configured otherwise) the
+ * keys "username" and "publickey". Only if the public key of the user in UserAdmin equals to the
+ * public key of the obtained certificate, the user is considered authenticated.
+ */
+public class ClientCertAuthenticationProcessor implements AuthenticationProcessor, ManagedService {
+
+    public static final String PID = "org.apache.ace.authenticationprocessor.clientcert";
+
+    static final String ATTRIBUTE_X509_CERTIFICATE = "javax.servlet.request.X509Certificate";
+    static final String ATTRIBUTE_CIPHER_SUITE = "javax.servlet.request.cipher_suite";
+
+    static final String PROPERTY_KEY_USERNAME = "key.username";
+    static final String PROPERTY_KEY_PUBLICKEY = "key.publickey";
+
+    private static final String DEFAULT_PROPERTY_KEY_USERNAME = "username";
+    private static final String DEFAULT_PROPERTY_KEY_PUBLICKEY = "publickey";
+
+    private volatile String m_keyUsername = DEFAULT_PROPERTY_KEY_USERNAME;
+    private volatile String m_keyPublicKey = DEFAULT_PROPERTY_KEY_PUBLICKEY;
+    private volatile LogService m_log;
+
+    /**
+     * Creates a new {@link ClientCertAuthenticationProcessor} instance.
+     */
+    public ClientCertAuthenticationProcessor() {
+        // Nop
+    }
+
+    /**
+     * Creates a new {@link ClientCertAuthenticationProcessor} with a given logger.
+     */
+    ClientCertAuthenticationProcessor(LogService log) {
+        m_log = log;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canHandle(Object... context) {
+        if (context == null || context.length == 0) {
+            throw new IllegalArgumentException("Invalid context!");
+        }
+
+        return (context[0] instanceof HttpServletRequest);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public User authenticate(UserAdmin userAdmin, Object... context) {
+        final HttpServletRequest request = (HttpServletRequest) context[0];
+
+        String cipherSuite = (String) request.getAttribute(ATTRIBUTE_CIPHER_SUITE);
+        if (cipherSuite == null) {
+            // No SSL connection?!
+            m_log.log(LogService.LOG_DEBUG, "No SSL connection (no cipher suite found)?!");
+            return null;
+        }
+
+        X509Certificate certificateChain[] = (X509Certificate[]) request.getAttribute(ATTRIBUTE_X509_CERTIFICATE);
+        if (certificateChain == null || certificateChain.length == 0) {
+            // No certificates given...
+            m_log.log(LogService.LOG_DEBUG, "Failed to obtain X509 certificate chain from request!");
+            return null;
+        }
+
+        // Validate the certificate chain...
+        // TODO there should be more checks performed here...
+        final X509Certificate cert = validateCertificateChain(certificateChain);
+        if (cert == null) {
+            // Invalid certificate(chain)...
+            m_log.log(LogService.LOG_DEBUG, "Failed to validate X509 certificate chain!");
+            return null;
+        }
+
+        String username = getCommonName(cert);
+        if (username == null) {
+            // No common name given; cannot retrieve user credentials...
+            m_log.log(LogService.LOG_DEBUG, "Failed to obtain common name of X509 certificate!");
+            return null;
+        }
+
+        User user = userAdmin.getUser(m_keyUsername, username);
+        if (user == null || !user.hasCredential(m_keyPublicKey, cert.getPublicKey().getEncoded())) {
+            // Invalid/unknown user!
+            m_log.log(LogService.LOG_DEBUG, "Failed to validate user using certificate!");
+            return null;
+        }
+
+        return user;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void updated(Dictionary dictionary) throws ConfigurationException {
+        if (dictionary != null) {
+            String keyUsername = (String) dictionary.get(PROPERTY_KEY_USERNAME);
+            if (keyUsername == null || "".equals(keyUsername.trim())) {
+                throw new ConfigurationException(PROPERTY_KEY_USERNAME, "Missing property");
+            }
+
+            String keyPassword = (String) dictionary.get(PROPERTY_KEY_PUBLICKEY);
+            if (keyPassword == null || "".equals(keyPassword.trim())) {
+                throw new ConfigurationException(PROPERTY_KEY_PUBLICKEY, "Missing property");
+            }
+
+            m_keyUsername = keyUsername;
+            m_keyPublicKey = keyPassword;
+        }
+        else {
+            m_keyUsername = DEFAULT_PROPERTY_KEY_USERNAME;
+            m_keyPublicKey = DEFAULT_PROPERTY_KEY_PUBLICKEY;
+        }
+    }
+
+    /**
+     * Retrieves the common name for the given certificate.
+     * 
+     * @param certificate the certificate to get its common name for, cannot be <code>null</code>.
+     * @return the common name for the given certificate, can be <code>null</code>.
+     */
+    private String getCommonName(X509Certificate certificate) {
+        try {
+            String dn = certificate.getSubjectX500Principal().getName();
+
+            LdapName ldapDN = new LdapName(dn);
+            for (Rdn rdn : ldapDN.getRdns()) {
+                if ("CN".equals(rdn.getType())) {
+                    return (String) rdn.getValue();
+                }
+            }
+        }
+        catch (InvalidNameException e) {
+            // Ignore...
+        }
+        return null;
+    }
+
+    /**
+     * Validates the certificate chain whether all certificates are valid and not expired.
+     * 
+     * @param certificateChain the chain of certificates to validate, cannot be <code>null</code>.
+     * @return if the chain is valid, the first certificate, <code>null</code> otherwise.
+     */
+    private X509Certificate validateCertificateChain(X509Certificate[] certificateChain) {
+        try {
+            for (X509Certificate cert : certificateChain) {
+                if (cert == null) {
+                    // Bogus certificate given...
+                    return null;
+                }
+                cert.checkValidity();
+            }
+        }
+        catch (CertificateExpiredException e) {
+            // Refuse to go further with expired certificates...
+            m_log.log(LogService.LOG_DEBUG, "Certificate expired!", e);
+            return null;
+        }
+        catch (CertificateNotYetValidException e) {
+            // Refuse to go further with invalid certificates...
+            m_log.log(LogService.LOG_DEBUG, "Certificate not yet valid!", e);
+            return null;
+        }
+
+        // This *might* be a valid certificate chain; return the first certificate...
+        return certificateChain[0];
+    }
+}

Propchange: ace/trunk/ace-authenticationprocessor-clientcert/src/main/java/org/apache/ace/authenticationprocessor/clientcert/ClientCertAuthenticationProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native