You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2013/04/01 03:36:18 UTC

svn commit: r1463074 - in /qpid/trunk/qpid/java/broker/src: main/java/org/apache/qpid/server/security/auth/manager/ main/java/org/apache/qpid/server/security/auth/sasl/external/ test/java/org/apache/qpid/server/security/auth/manager/

Author: robbie
Date: Mon Apr  1 01:36:18 2013
New Revision: 1463074

URL: http://svn.apache.org/r1463074
Log:
QPID-4676: change External auth provider to create usernames of the form <CN>@<DC1>.<DC2>....<DCN> by default

- Allows for use of SSL Client Authentication in manner more consistent with the C++ broker
- Adds 'useFullDN' attribute to the auth provider to allow enabling use of the old behaviour

Added:
    qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties
Modified:
    qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
    qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java
    qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java
    qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java?rev=1463074&r1=1463073&r2=1463074&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java Mon Apr  1 01:36:18 2013
@@ -31,8 +31,11 @@ public class ExternalAuthenticationManag
 {
     private static final String EXTERNAL = "EXTERNAL";
 
-    ExternalAuthenticationManager()
+    private boolean _useFullDN = false;
+
+    ExternalAuthenticationManager(boolean useFullDN)
     {
+        _useFullDN = useFullDN;
     }
 
     @Override
@@ -52,7 +55,7 @@ public class ExternalAuthenticationManag
     {
         if(EXTERNAL.equals(mechanism))
         {
-            return new ExternalSaslServer(externalPrincipal);
+            return new ExternalSaslServer(externalPrincipal, _useFullDN);
         }
         else
         {

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java?rev=1463074&r1=1463073&r2=1463074&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java Mon Apr  1 01:36:18 2013
@@ -19,22 +19,32 @@
  */
 package org.apache.qpid.server.security.auth.manager;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 
 import org.apache.qpid.server.plugin.AuthenticationManagerFactory;
+import org.apache.qpid.server.util.ResourceBundleLoader;
 
 public class ExternalAuthenticationManagerFactory implements AuthenticationManagerFactory
 {
+    public static final String RESOURCE_BUNDLE = "org.apache.qpid.server.security.auth.manager.ExternalAuthenticationProviderAttributeDescriptions";
     public static final String PROVIDER_TYPE = "External";
+    public static final String ATTRIBUTE_USE_FULL_DN = "useFullDN";
+
+    public static final Collection<String> ATTRIBUTES = Collections.<String> unmodifiableList(Arrays.asList(
+            ATTRIBUTE_TYPE,
+            ATTRIBUTE_USE_FULL_DN));
 
     @Override
     public AuthenticationManager createInstance(Map<String, Object> attributes)
     {
         if (attributes != null && PROVIDER_TYPE.equals(attributes.get(ATTRIBUTE_TYPE)))
         {
-            return new ExternalAuthenticationManager();
+            boolean useFullDN = Boolean.valueOf(String.valueOf(attributes.get(ATTRIBUTE_USE_FULL_DN)));
+
+            return new ExternalAuthenticationManager(useFullDN);
         }
         return null;
     }
@@ -42,7 +52,7 @@ public class ExternalAuthenticationManag
     @Override
     public Collection<String> getAttributeNames()
     {
-        return Collections.<String>singletonList(ATTRIBUTE_TYPE);
+        return ATTRIBUTES;
     }
 
     @Override
@@ -54,7 +64,7 @@ public class ExternalAuthenticationManag
     @Override
     public Map<String, String> getAttributeDescriptions()
     {
-        return null;
+        return ResourceBundleLoader.getResources(RESOURCE_BUNDLE);
     }
 
 }

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties?rev=1463074&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties Mon Apr  1 01:36:18 2013
@@ -0,0 +1,19 @@
+#
+#  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.
+
+useFullDN=Use the full DN as the Username
\ No newline at end of file

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java?rev=1463074&r1=1463073&r2=1463074&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java Mon Apr  1 01:36:18 2013
@@ -19,19 +19,27 @@
 package org.apache.qpid.server.security.auth.sasl.external;
 
 import java.security.Principal;
+
+import javax.security.auth.x500.X500Principal;
 import javax.security.sasl.SaslException;
 import javax.security.sasl.SaslServer;
 
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
 
 public class ExternalSaslServer implements SaslServer
 {
+    private static final Logger LOGGER = Logger.getLogger(ExternalSaslServer.class);
+
     public static final String MECHANISM = "EXTERNAL";
 
     private boolean _complete = false;
     private final Principal _externalPrincipal;
+    private boolean _useFullDN = false;
 
-    public ExternalSaslServer(Principal externalPrincipal)
+    public ExternalSaslServer(Principal externalPrincipal, boolean useFullDN)
     {
+        _useFullDN = useFullDN;
         _externalPrincipal = externalPrincipal;
     }
 
@@ -77,6 +85,83 @@ public class ExternalSaslServer implemen
 
     public Principal getAuthenticatedPrincipal()
     {
-        return _externalPrincipal;
+        if (_externalPrincipal instanceof X500Principal && !_useFullDN)
+        {
+            // Construct username as <CN>@<DC1>.<DC2>.<DC3>....<DCN>
+
+            String username;
+            String dn = ((X500Principal) _externalPrincipal).getName(X500Principal.RFC2253);
+
+            if(LOGGER.isDebugEnabled())
+            {
+                LOGGER.debug("Parsing username from Principal DN: " + dn);
+            }
+
+            if (dn.contains("CN="))
+            {
+                username = dn.substring(dn.indexOf("CN=") + 3, (dn.indexOf(",", dn.indexOf("CN=")) != -1) ? dn.indexOf(",", dn.indexOf("CN=")) : dn.length());
+
+                if (username.isEmpty())
+                {
+                    // CN is empty => Cannot construct username => Authentication failed => return null
+                    if(LOGGER.isDebugEnabled())
+                    {
+                        LOGGER.debug("CN value was empty in Principal name, unable to construct username");
+                    }
+                    return null;
+                }
+                else
+                {
+                    if (dn.contains("DC="))
+                    {
+                        int start = 0;
+                        String dc = "";
+
+                        while (dn.indexOf("DC=", start) != -1)
+                        {
+                            int dcStart = dn.indexOf("DC=", start) + 3;
+                            int dcEnd = (dn.indexOf(",", dn.indexOf("DC=", start)) != -1) ? dn.indexOf(",", dn.indexOf("DC=", start)) : dn.length();
+
+                            if (dc.isEmpty())
+                            {
+                                dc = dn.substring(dcStart, dcEnd);
+                            }
+                            else
+                            {
+                                dc = dc.concat(".").concat(dn.substring(dcStart, dcEnd));
+                            }
+
+                            start = dn.indexOf("DC=", start) + 1;
+                        }
+
+                        username = username.concat("@").concat(dc);
+                    }
+                }
+
+                if(LOGGER.isDebugEnabled())
+                {
+                    LOGGER.debug("Constructing Principal with username: " + username);
+                }
+                return new UsernamePrincipal(username);
+            }
+            else
+            {
+                // No CN => Cannot construct username => Authentication failed => return null
+                if(LOGGER.isDebugEnabled())
+                {
+                    LOGGER.debug("No CN= present in DN, unable to construct username");
+                }
+                return null;
+            }
+        }
+        else
+        {
+            if(LOGGER.isDebugEnabled())
+            {
+                LOGGER.debug("Using external Principal: " + _externalPrincipal);
+            }
+
+            return _externalPrincipal;
+        }
     }
 }
\ No newline at end of file

Modified: qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java?rev=1463074&r1=1463073&r2=1463074&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java (original)
+++ qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java Mon Apr  1 01:36:18 2013
@@ -25,11 +25,13 @@ import javax.security.sasl.SaslException
 import javax.security.sasl.SaslServer;
 
 import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
 import org.apache.qpid.test.utils.QpidTestCase;
 
 public class ExternalAuthenticationManagerTest extends QpidTestCase
 {
-    private AuthenticationManager _manager = new ExternalAuthenticationManager();
+    private AuthenticationManager _manager = new ExternalAuthenticationManager(false);
+    private AuthenticationManager _managerUsingFullDN = new ExternalAuthenticationManager(true);
 
     public void testGetMechanisms() throws Exception
     {
@@ -38,13 +40,23 @@ public class ExternalAuthenticationManag
 
     public void testCreateSaslServer() throws Exception
     {
-        SaslServer server = _manager.createSaslServer("EXTERNAL", "example.example.com", null);
+        createSaslServerTestImpl(_manager);
+    }
+
+    public void testCreateSaslServerUsingFullDN() throws Exception
+    {
+        createSaslServerTestImpl(_managerUsingFullDN);
+    }
+
+    public void createSaslServerTestImpl(AuthenticationManager manager) throws Exception
+    {
+        SaslServer server = manager.createSaslServer("EXTERNAL", "example.example.com", null);
 
         assertEquals("Sasl Server mechanism name is not as expected", "EXTERNAL", server.getMechanismName());
 
         try
         {
-            server = _manager.createSaslServer("PLAIN", "example.example.com", null);
+            server = manager.createSaslServer("PLAIN", "example.example.com", null);
             fail("Expected creating SaslServer with incorrect mechanism to throw an exception");
         }
         catch (SaslException e)
@@ -53,12 +65,16 @@ public class ExternalAuthenticationManag
         }
     }
 
-    public void testAuthenticate() throws Exception
+    /**
+     * Test behaviour of the authentication when the useFullDN attribute is set true
+     * and the username is taken directly as the externally supplied Principal
+     */
+    public void testAuthenticateWithFullDN() throws Exception
     {
         X500Principal principal = new X500Principal("CN=person, DC=example, DC=com");
-        SaslServer saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
+        SaslServer saslServer = _managerUsingFullDN.createSaslServer("EXTERNAL", "example.example.com", principal);
 
-        AuthenticationResult result = _manager.authenticate(saslServer, new byte[0]);
+        AuthenticationResult result = _managerUsingFullDN.authenticate(saslServer, new byte[0]);
         assertNotNull(result);
         assertEquals("Expected authentication to be successful",
                      AuthenticationResult.AuthenticationStatus.SUCCESS,
@@ -66,15 +82,102 @@ public class ExternalAuthenticationManag
 
         assertOnlyContainsWrapped(principal, result.getPrincipals());
 
+        saslServer = _managerUsingFullDN.createSaslServer("EXTERNAL", "example.example.com", null);
+        result = _managerUsingFullDN.authenticate(saslServer, new byte[0]);
+
+        assertNotNull(result);
+        assertEquals("Expected authentication to be unsuccessful",
+                     AuthenticationResult.AuthenticationStatus.ERROR,
+                     result.getStatus());
+    }
+
+    /**
+     * Test behaviour of the authentication when parsing the username from
+     * the Principals DN as <CN>@<DC1>.<DC2>.<DC3>....<DCN>
+     */
+    public void testAuthenticateWithUsernameBasedOnCNAndDC() throws Exception
+    {
+        X500Principal principal;
+        SaslServer saslServer;
+        AuthenticationResult result;
+        UsernamePrincipal expectedPrincipal;
+
+        // DN contains only CN
+        principal = new X500Principal("CN=person");
+        expectedPrincipal = new UsernamePrincipal("person");
+        saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
+
+        result = _manager.authenticate(saslServer, new byte[0]);
+        assertNotNull(result);
+        assertEquals("Expected authentication to be successful",
+                     AuthenticationResult.AuthenticationStatus.SUCCESS,
+                     result.getStatus());
+        assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals());
+
+        // Null princial
         saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", null);
         result = _manager.authenticate(saslServer, new byte[0]);
 
         assertNotNull(result);
-                assertEquals("Expected authentication to be unsuccessful",
-                             AuthenticationResult.AuthenticationStatus.ERROR,
-                             result.getStatus());
+        assertEquals("Expected authentication to be unsuccessful",
+                AuthenticationResult.AuthenticationStatus.ERROR,
+                result.getStatus());
+
+        // DN doesn't contain CN
+        principal = new X500Principal("DC=example, DC=com, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB");
+        saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
+        result = _manager.authenticate(saslServer, new byte[0]);
 
-    }
+        assertNotNull(result);
+        assertEquals("Expected authentication to be unsuccessful",
+                AuthenticationResult.AuthenticationStatus.ERROR,
+                result.getStatus());
+
+        // DN contains empty CN
+        principal = new X500Principal("CN=, DC=example, DC=com, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB");
+        saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
+        result = _manager.authenticate(saslServer, new byte[0]);
+
+        assertNotNull(result);
+        assertEquals("Expected authentication to be unsuccessful",
+                AuthenticationResult.AuthenticationStatus.ERROR,
+                result.getStatus());
+
+        // DN contains CN and DC
+        principal = new X500Principal("CN=person, DC=example, DC=com");
+        expectedPrincipal = new UsernamePrincipal("person@example.com");
+        saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
+
+        result = _manager.authenticate(saslServer, new byte[0]);
+        assertNotNull(result);
+        assertEquals("Expected authentication to be successful",
+                AuthenticationResult.AuthenticationStatus.SUCCESS,
+                result.getStatus());
+        assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals());
+
+        // DN contains CN and DC and other components
+        principal = new X500Principal("CN=person, DC=example, DC=com, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB");
+        expectedPrincipal = new UsernamePrincipal("person@example.com");
+        saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
+
+        result = _manager.authenticate(saslServer, new byte[0]);
+        assertNotNull(result);
+        assertEquals("Expected authentication to be successful",
+                AuthenticationResult.AuthenticationStatus.SUCCESS,
+                result.getStatus());
+        assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals());
+
+        // DN contains CN and DC and other components
+        principal = new X500Principal("CN=person, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB");
+        expectedPrincipal = new UsernamePrincipal("person");
+        saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal);
 
+        result = _manager.authenticate(saslServer, new byte[0]);
+        assertNotNull(result);
+        assertEquals("Expected authentication to be successful",
+                AuthenticationResult.AuthenticationStatus.SUCCESS,
+                result.getStatus());
+        assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals());
+    }
 
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org