浏览代码

Make User available from Authentication via DaoAuthenticationProvider.

Ben Alex 21 年之前
父节点
当前提交
1a0bec5bf1

+ 7 - 0
changelog.txt

@@ -1,3 +1,10 @@
+Changes in version 0.6 (2004-xx-xx)
+-----------------------------------
+
+* Added feature so DaoAuthenticationProvider returns User in Authentication
+* Fixed Linux compatibility issues (directory case sensitivity etc)
+* Documentation improvements
+
 Changes in version 0.51 (2004-06-06)
 Changes in version 0.51 (2004-06-06)
 ------------------------------------
 ------------------------------------
 
 

+ 48 - 14
core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java

@@ -51,12 +51,26 @@ import org.springframework.dao.DataAccessException;
  * <p>
  * <p>
  * Upon successful validation, a
  * Upon successful validation, a
  * <code>UsernamePasswordAuthenticationToken</code> will be created and
  * <code>UsernamePasswordAuthenticationToken</code> will be created and
- * returned to the caller. In addition, the {@link User} will be placed in the
- * {@link UserCache} so that subsequent requests with the same username can be
- * validated without needing to query the {@link AuthenticationDao}. It should
- * be noted that if a user appears to present an incorrect password, the
- * {@link AuthenticationDao} will be queried to confirm the most up-to-date
- * password was used for comparison.
+ * returned to the caller. The token will include as its principal either a
+ * <code>String</code> representation of the username, or the {@link User}
+ * that was returned from the authentication repository. Using
+ * <code>String</code> is appropriate if a container adapter is being used, as
+ * it expects <code>String</code> representations of the username. Using
+ * <code>User</code> is appropriate if you require access to additional
+ * properties of the authenticated user, such as email addresses,
+ * human-friendly names etc. As container adapters are not recommended to be
+ * used, and <code>User</code> provides additional flexibility, by default a
+ * <code>User</code> is returned. To override this default, set the {@link
+ * #setForcePrincipalAsString} to <code>true</code>.
+ * </p>
+ * 
+ * <P>
+ * Caching is handled via the <code>User</code> object being placed in the
+ * {@link UserCache}. This ensures that subsequent requests with the same
+ * username can be validated without needing to query the {@link
+ * AuthenticationDao}. It should be noted that if a user appears to present an
+ * incorrect password, the {@link AuthenticationDao} will be queried to
+ * confirm the most up-to-date password was used for comparison.
  * </p>
  * </p>
  * 
  * 
  * <P>
  * <P>
@@ -79,6 +93,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
     private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
     private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
     private SaltSource saltSource;
     private SaltSource saltSource;
     private UserCache userCache = new NullUserCache();
     private UserCache userCache = new NullUserCache();
+    private boolean forcePrincipalAsString = false;
 
 
     //~ Methods ================================================================
     //~ Methods ================================================================
 
 
@@ -95,6 +110,14 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
         return authenticationDao;
         return authenticationDao;
     }
     }
 
 
+    public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
+        this.forcePrincipalAsString = forcePrincipalAsString;
+    }
+
+    public boolean isForcePrincipalAsString() {
+        return forcePrincipalAsString;
+    }
+
     /**
     /**
      * Sets the PasswordEncoder instance to be used to encode and validate
      * Sets the PasswordEncoder instance to be used to encode and validate
      * passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
      * passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
@@ -148,13 +171,19 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
 
 
     public Authentication authenticate(Authentication authentication)
     public Authentication authenticate(Authentication authentication)
         throws AuthenticationException {
         throws AuthenticationException {
+        // Determine username
+        String username = authentication.getPrincipal().toString();
+
+        if (authentication.getPrincipal() instanceof User) {
+            username = ((User) authentication.getPrincipal()).getUsername();
+        }
+
         boolean cacheWasUsed = true;
         boolean cacheWasUsed = true;
-        User user = this.userCache.getUserFromCache(authentication.getPrincipal()
-                                                                  .toString());
+        User user = this.userCache.getUserFromCache(username);
 
 
         if (user == null) {
         if (user == null) {
             cacheWasUsed = false;
             cacheWasUsed = false;
-            user = getUserFromBackend(authentication);
+            user = getUserFromBackend(username);
         }
         }
 
 
         if (!user.isEnabled()) {
         if (!user.isEnabled()) {
@@ -170,7 +199,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
             // Password incorrect, so ensure we're using most current password
             // Password incorrect, so ensure we're using most current password
             if (cacheWasUsed) {
             if (cacheWasUsed) {
                 cacheWasUsed = false;
                 cacheWasUsed = false;
-                user = getUserFromBackend(authentication);
+                user = getUserFromBackend(username);
             }
             }
 
 
             if (!isPasswordCorrect(authentication, user)) {
             if (!isPasswordCorrect(authentication, user)) {
@@ -194,9 +223,15 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
             }
             }
         }
         }
 
 
+        Object principalToReturn = user;
+
+        if (forcePrincipalAsString) {
+            principalToReturn = user.getUsername();
+        }
+
         // Ensure we return the original credentials the user supplied,
         // Ensure we return the original credentials the user supplied,
         // so subsequent attempts are successful even with encoded passwords
         // so subsequent attempts are successful even with encoded passwords
-        return new UsernamePasswordAuthenticationToken(user.getUsername(),
+        return new UsernamePasswordAuthenticationToken(principalToReturn,
             authentication.getCredentials(), user.getAuthorities());
             authentication.getCredentials(), user.getAuthorities());
     }
     }
 
 
@@ -220,10 +255,9 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
             authentication.getCredentials().toString(), salt);
             authentication.getCredentials().toString(), salt);
     }
     }
 
 
-    private User getUserFromBackend(Authentication authentication) {
+    private User getUserFromBackend(String username) {
         try {
         try {
-            return this.authenticationDao.loadUserByUsername(authentication.getPrincipal()
-                                                                           .toString());
+            return this.authenticationDao.loadUserByUsername(username);
         } catch (UsernameNotFoundException notFound) {
         } catch (UsernameNotFoundException notFound) {
             throw new BadCredentialsException("Bad credentials presented");
             throw new BadCredentialsException("Bad credentials presented");
         } catch (DataAccessException repositoryProblem) {
         } catch (DataAccessException repositoryProblem) {

+ 1 - 0
core/src/main/resources/org/acegisecurity/adapters/acegisecurity.xml

@@ -36,6 +36,7 @@
 	<!-- Authentication provider that queries our data access object  -->
 	<!-- Authentication provider that queries our data access object  -->
 	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
 	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
      	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
      	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+     	<property name="forcePrincipalAsString"><value>true</value></property>
 	</bean>
 	</bean>
 
 
 	<!-- The authentication manager that iterates through our only authentication provider -->
 	<!-- The authentication manager that iterates through our only authentication provider -->

+ 1 - 0
core/src/test/java/org/acegisecurity/adapters/adaptertest-valid.xml

@@ -36,6 +36,7 @@
 	<!-- Authentication provider that queries our data access object  -->
 	<!-- Authentication provider that queries our data access object  -->
 	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
 	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
      	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
      	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+     	<property name="forcePrincipalAsString"><value>true</value></property>
 	</bean>
 	</bean>
 
 
 	<!-- The authentication manager that iterates through our only authentication provider -->
 	<!-- The authentication manager that iterates through our only authentication provider -->

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java

@@ -166,7 +166,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
         }
         }
 
 
         UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
         UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
-        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals(User.class, castResult.getPrincipal().getClass());
         assertEquals("koala", castResult.getCredentials());
         assertEquals("koala", castResult.getCredentials());
         assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
         assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
         assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
         assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
@@ -192,7 +192,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
         }
         }
 
 
         UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
         UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
-        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals(User.class, castResult.getPrincipal().getClass());
 
 
         // We expect original credentials user submitted to be returned
         // We expect original credentials user submitted to be returned
         assertEquals("koala", castResult.getCredentials());
         assertEquals("koala", castResult.getCredentials());

+ 5 - 4
core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java

@@ -24,6 +24,7 @@ import net.sf.acegisecurity.MockFilterConfig;
 import net.sf.acegisecurity.MockHttpServletRequest;
 import net.sf.acegisecurity.MockHttpServletRequest;
 import net.sf.acegisecurity.MockHttpServletResponse;
 import net.sf.acegisecurity.MockHttpServletResponse;
 import net.sf.acegisecurity.MockHttpSession;
 import net.sf.acegisecurity.MockHttpSession;
+import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
 import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
 
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.binary.Base64;
@@ -199,8 +200,8 @@ public class BasicProcessingFilterTests extends TestCase {
 
 
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertEquals("marissa",
         assertEquals("marissa",
-            ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal()
-             .toString());
+            ((User) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal())
+             .getUsername());
     }
     }
 
 
     public void testOtherAuthorizationSchemeIsIgnored()
     public void testOtherAuthorizationSchemeIsIgnored()
@@ -291,8 +292,8 @@ public class BasicProcessingFilterTests extends TestCase {
 
 
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertEquals("marissa",
         assertEquals("marissa",
-            ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal()
-             .toString());
+                ((User) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal())
+                 .getUsername());
 
 
         // NOW PERFORM FAILED AUTHENTICATION
         // NOW PERFORM FAILED AUTHENTICATION
         // Setup our HTTP request
         // Setup our HTTP request

+ 7 - 2
core/src/test/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPointTests.java

@@ -20,6 +20,8 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.MockHttpServletRequest;
 import net.sf.acegisecurity.MockHttpServletRequest;
 import net.sf.acegisecurity.MockHttpServletResponse;
 import net.sf.acegisecurity.MockHttpServletResponse;
 
 
+import java.net.URLEncoder;
+
 
 
 /**
 /**
  * Tests {@link CasProcessingFilterEntryPoint}.
  * Tests {@link CasProcessingFilterEntryPoint}.
@@ -99,8 +101,11 @@ public class CasProcessingFilterEntryPointTests extends TestCase {
 
 
         ep.afterPropertiesSet();
         ep.afterPropertiesSet();
         ep.commence(request, response);
         ep.commence(request, response);
-        assertEquals("https://cas/login?service=https://mycompany.com/bigWebApp/j_acegi_cas_security_check",
-            response.getRedirect());
+
+        assertEquals("https://cas/login?service="
+            + URLEncoder.encode(
+                "https://mycompany.com/bigWebApp/j_acegi_cas_security_check",
+                "UTF-8"), response.getRedirect());
     }
     }
 
 
     public void testNormalOperationWithRenewTrue() throws Exception {
     public void testNormalOperationWithRenewTrue() throws Exception {

+ 25 - 6
docs/reference/src/index.xml

@@ -7,7 +7,7 @@
 
 
     <subtitle>Reference Documentation</subtitle>
     <subtitle>Reference Documentation</subtitle>
 
 
-    <releaseinfo>0.51</releaseinfo>
+    <releaseinfo>0.6</releaseinfo>
 
 
     <authorgroup>
     <authorgroup>
       <author>
       <author>
@@ -946,10 +946,24 @@
         increased the complexity of the <literal>AuthenticationDao</literal>
         increased the complexity of the <literal>AuthenticationDao</literal>
         interface. For instance, a method would be required to increase the
         interface. For instance, a method would be required to increase the
         count of unsuccessful authentication attempts. Such functionality
         count of unsuccessful authentication attempts. Such functionality
-        could be easily provided in a new
-        <literal>AuthenticationManager</literal> or
-        <literal>AuthenticationProvider</literal> implementation if it were
-        desired.</para>
+        could be easily provided by leveraging the application event
+        publishing features discussed below.</para>
+
+        <para><literal>DaoAuthenticationProvider</literal> returns an
+        <literal>Authentication</literal> object which in turn has its
+        <literal>principal</literal> property set. The principal will be
+        either a <literal>String</literal> (which is essentially the username)
+        or a <literal>User</literal> object (which was looked up from the
+        <literal>AuthenticationDao</literal>). By default the
+        <literal>User</literal> is returned, as this enables applications to
+        subclass <literal>User</literal> and add extra properties potentially
+        of use in applications, such as the user's full name, email address
+        etc. If using container adapters, or if your applications were written
+        to operate with <literal>String</literal>s (as was the case for
+        releases prior to Acegi Security 0.6), you should set the
+        <literal>DaoAuthenticationProvider.forcePrincipalAsString</literal>
+        property to <literal>true</literal> in your application
+        context.</para>
       </sect2>
       </sect2>
 
 
       <sect2 id="security-authentication-provider-events">
       <sect2 id="security-authentication-provider-events">
@@ -1927,6 +1941,11 @@ public boolean supports(Class clazz);</programlisting></para>
         provided below. Once installed, please take the time to try the sample
         provided below. Once installed, please take the time to try the sample
         application to ensure your container adapter is properly
         application to ensure your container adapter is properly
         configured.</para>
         configured.</para>
+
+        <para>When using container adapters with the
+        <literal>DaoAuthenticationProvider</literal>, ensure you set its
+        <literal>forcePrincipalAsString</literal> property to
+        <literal>true</literal>.</para>
       </sect2>
       </sect2>
 
 
       <sect2 id="security-container-adapters-catalina">
       <sect2 id="security-container-adapters-catalina">
@@ -2497,7 +2516,7 @@ $CATALINA_HOME/bin/startup.sh</programlisting></para>
         <literal>PasswordHandler</literal> will do).</para>
         <literal>PasswordHandler</literal> will do).</para>
 
 
         <para>To install, you will need to download and extract the CAS server
         <para>To install, you will need to download and extract the CAS server
-        archive. We used version 2.0.12 Beta 3. There will be a
+        archive. We used version 2.0.12. There will be a
         <literal>/web</literal> directory in the root of the deployment. Copy
         <literal>/web</literal> directory in the root of the deployment. Copy
         an <literal>applicationContext.xml</literal> containing your
         an <literal>applicationContext.xml</literal> containing your
         <literal>AuthenticationManager</literal> as well as the
         <literal>AuthenticationManager</literal> as well as the

+ 1 - 1
project.properties

@@ -6,7 +6,7 @@
 # $Id$
 # $Id$
 
 
 # Project version
 # Project version
-acegi-security-version=0.51
+acegi-security-version=0.6
 
 
 # Project name
 # Project name
 name=acegi-security-system-for-spring
 name=acegi-security-system-for-spring

+ 1 - 0
samples/contacts/etc/ca/resin-acegisecurity.xml

@@ -33,6 +33,7 @@
 	<!-- Authentication provider that queries our data access object  -->
 	<!-- Authentication provider that queries our data access object  -->
 	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
 	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
      	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
      	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+     	<property name="forcePrincipalAsString"><value>true</value></property>
 	</bean>
 	</bean>
 
 
 	<!-- The authentication manager that iterates through our only authentication provider -->
 	<!-- The authentication manager that iterates through our only authentication provider -->

+ 8 - 1
samples/contacts/src/main/java/sample/contact/ContactManagerFacade.java

@@ -19,6 +19,7 @@ import net.sf.acegisecurity.AccessDeniedException;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContext;
+import net.sf.acegisecurity.providers.dao.User;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 
 
@@ -88,7 +89,13 @@ public class ContactManagerFacade implements ContactManager, InitializingBean {
         Authentication auth = ((SecureContext) ContextHolder.getContext())
         Authentication auth = ((SecureContext) ContextHolder.getContext())
             .getAuthentication();
             .getAuthentication();
 
 
-        if (auth.getPrincipal().toString().equals(result.getOwner())) {
+        String username = auth.getPrincipal().toString();
+
+        if (auth.getPrincipal() instanceof User) {
+            username = ((User) auth.getPrincipal()).getUsername();
+        }
+
+        if (username.equals(result.getOwner())) {
             return result;
             return result;
         } else {
         } else {
             throw new AccessDeniedException(
             throw new AccessDeniedException(

+ 9 - 2
samples/contacts/src/main/java/sample/contact/ContactSecurityVoter.java

@@ -18,6 +18,7 @@ package sample.contact;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.ConfigAttribute;
 import net.sf.acegisecurity.ConfigAttribute;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
+import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.vote.AccessDecisionVoter;
 import net.sf.acegisecurity.vote.AccessDecisionVoter;
 
 
 import org.aopalliance.intercept.MethodInvocation;
 import org.aopalliance.intercept.MethodInvocation;
@@ -96,9 +97,15 @@ public class ContactSecurityVoter implements AccessDecisionVoter {
                 }
                 }
 
 
                 if (passedOwner != null) {
                 if (passedOwner != null) {
+                    String username = authentication.getPrincipal().toString();
+
+                    if (authentication.getPrincipal() instanceof User) {
+                        username = ((User) authentication.getPrincipal())
+                            .getUsername();
+                    }
+
                     // Check the authentication principal matches the passed owner
                     // Check the authentication principal matches the passed owner
-                    if (passedOwner.equals(authentication.getPrincipal()
-                                                         .toString())) {
+                    if (passedOwner.equals(username)) {
                         return ACCESS_GRANTED;
                         return ACCESS_GRANTED;
                     }
                     }
                 }
                 }

+ 12 - 5
samples/contacts/src/main/java/sample/contact/SecureIndexController.java

@@ -20,6 +20,7 @@ import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContext;
+import net.sf.acegisecurity.providers.dao.User;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 
 
@@ -74,10 +75,17 @@ public class SecureIndexController implements Controller, InitializingBean {
                 + "SecureContext");
                 + "SecureContext");
         }
         }
 
 
-        final Authentication currentUser = secureContext.getAuthentication();
+        // Lookup username. As we must accommodate DaoAuthenticationProvider,
+        // CAS and container based authentication, we take care with casting
+        Authentication auth = secureContext.getAuthentication();
+        String username = auth.getPrincipal().toString();
+
+        if (auth.getPrincipal() instanceof User) {
+            username = ((User) auth.getPrincipal()).getUsername();
+        }
 
 
         boolean supervisor = false;
         boolean supervisor = false;
-        GrantedAuthority[] granted = currentUser.getAuthorities();
+        GrantedAuthority[] granted = auth.getAuthorities();
 
 
         for (int i = 0; i < granted.length; i++) {
         for (int i = 0; i < granted.length; i++) {
             if (granted[i].getAuthority().equals("ROLE_SUPERVISOR")) {
             if (granted[i].getAuthority().equals("ROLE_SUPERVISOR")) {
@@ -85,13 +93,12 @@ public class SecureIndexController implements Controller, InitializingBean {
             }
             }
         }
         }
 
 
-        Contact[] myContacts = contactManager.getAllByOwner(currentUser.getPrincipal()
-                                                                       .toString());
+        Contact[] myContacts = contactManager.getAllByOwner(username);
 
 
         Map model = new HashMap();
         Map model = new HashMap();
         model.put("contacts", myContacts);
         model.put("contacts", myContacts);
         model.put("supervisor", new Boolean(supervisor));
         model.put("supervisor", new Boolean(supervisor));
-        model.put("user", currentUser.getPrincipal().toString());
+        model.put("user", username);
 
 
         return new ModelAndView("index", "model", model);
         return new ModelAndView("index", "model", model);
     }
     }

+ 10 - 2
samples/contacts/src/main/java/sample/contact/WebContactAddController.java

@@ -15,8 +15,10 @@
 
 
 package sample.contact;
 package sample.contact;
 
 
+import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContext;
+import net.sf.acegisecurity.providers.dao.User;
 
 
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.SimpleFormController;
 import org.springframework.web.servlet.mvc.SimpleFormController;
@@ -54,8 +56,14 @@ public class WebContactAddController extends SimpleFormController {
     public ModelAndView onSubmit(Object command) throws ServletException {
     public ModelAndView onSubmit(Object command) throws ServletException {
         String name = ((WebContact) command).getName();
         String name = ((WebContact) command).getName();
         String email = ((WebContact) command).getEmail();
         String email = ((WebContact) command).getEmail();
-        String owner = ((SecureContext) ContextHolder.getContext()).getAuthentication()
-                        .getPrincipal().toString();
+
+        Authentication auth = ((SecureContext) ContextHolder.getContext())
+            .getAuthentication();
+        String owner = auth.getPrincipal().toString();
+
+        if (auth.getPrincipal() instanceof User) {
+            owner = ((User) auth.getPrincipal()).getUsername();
+        }
 
 
         Contact contact = new Contact(contactManager.getNextId(), name, email,
         Contact contact = new Contact(contactManager.getNextId(), name, email,
                 owner);
                 owner);

+ 27 - 0
upgrade-05-06.txt

@@ -0,0 +1,27 @@
+===============================================================================
+          ACEGI SECURITY SYSTEM FOR SPRING - UPGRADING FROM 0.5 TO 0.6
+===============================================================================
+
+The following should help most casual users of the project update their
+applications:
+
+- Locate and remove all property references to 
+  DaoAuthenticationProvider.key and 
+  DaoAuthenticationProvider.refreshTokenInterval.
+
+- If you are using DaoAuthenticationProvider and either (i) you are using
+  container adapters or (ii) your code relies on the Authentication object
+  having its getPrincipal() return a String, you must set the new
+  DaoAuthenticationProvider property, forcePrincipalAsString, to true.
+  By default DaoAuthenticationProvider returns an Authentication object
+  containing the relevant User, which allows access to additional properties.
+  Where possible, we recommend you change your code to something like this,
+  so that you can leave forcePrincipalAsString to the false default:
+  
+    String username = authentication.getPrincipal();
+    if (authentication.getPrincipal() instanceof User) {
+      username = ((User) authentication.getPrincipal()).getUsername();
+    }
+
+
+$Id$