Downloads Documentation Community Contribute Demo






Show Sidebar
Login | Register

Changeset 5370

Show
Ignore:
Timestamp:
08/26/08 22:38:30 (3 months ago)
Author:
bwolfe
Message:

Changing authentication error messages to match between username/password failures

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • openmrs/trunk/src/api/org/openmrs/api/db/ContextDAO.java

    r5366 r5370  
    2929         * Authenticate user with the given username and password. 
    3030         *  
    31          * @param username 
    32          * @param password 
    33          * @return 
     31         * @param username user's username or systemId 
     32         * @param password user's password 
     33         * @return a valid user if authentication succeeds 
    3434         * @throws ContextAuthenticationException 
    3535         *  
     
    4646         * @should not authenticate given non null password when password in database is null 
    4747         * @should not authenticate when password in database is empty 
     48         * @should give identical error messages between username and password mismatch 
    4849         */ 
    4950        @Transactional(readOnly=true) 
  • openmrs/trunk/src/api/org/openmrs/api/db/hibernate/HibernateContextDAO.java

    r5366 r5370  
    3232import org.openmrs.GlobalProperty; 
    3333import org.openmrs.User; 
     34import org.openmrs.api.context.Context; 
    3435import org.openmrs.api.context.ContextAuthenticationException; 
    3536import org.openmrs.api.db.ContextDAO; 
     
    4041import org.springframework.transaction.support.TransactionSynchronizationManager; 
    4142 
     43/** 
     44 * Hibernate specific implementation of the {@link ContextDAO}. 
     45 *  
     46 * These methods should not be used directly, instead, the methods 
     47 * on the static {@link Context} file should be used. 
     48 *  
     49 * @see ContextDAO 
     50 * @see Context 
     51 */ 
    4252public class HibernateContextDAO implements ContextDAO { 
    4353 
     
    5060 
    5161        /** 
    52          * Default public constructor 
    53          */ 
    54         public HibernateContextDAO() { 
    55         } 
    56  
    57         /** 
    58          * Set session factory 
     62         * Session factory to use for this DAO.  This is usually 
     63         * injected by spring and its application context. 
    5964         *  
    6065         * @param sessionFactory 
     
    101106                        } 
    102107                } 
    103  
    104                 if (candidateUser == null) 
    105                         throw new ContextAuthenticationException("User not found: " + login); 
    106                  
    107                 if (log.isDebugEnabled()) 
    108                         log.debug("Candidate user id: " + candidateUser.getUserId()); 
    109                  
    110                 if (password == null) 
    111                         throw new ContextAuthenticationException("Password cannot be null"); 
    112                  
    113                 String passwordOnRecord = (String) session.createSQLQuery( 
    114                                 "select password from users where user_id = ?") 
    115                                         .addScalar("password", Hibernate.STRING) 
     108                 
     109                // only continue if this is a valid username and a nonempty password 
     110                if (candidateUser != null && password != null) { 
     111                                         
     112                        if (log.isDebugEnabled()) 
     113                                log.debug("Candidate user id: " + candidateUser.getUserId()); 
     114                         
     115                        String passwordOnRecord = (String) session.createSQLQuery( 
     116                                        "select password from users where user_id = ?") 
     117                                                .addScalar("password", Hibernate.STRING) 
     118                                                .setInteger(0, candidateUser.getUserId()) 
     119                                                .uniqueResult(); 
     120                         
     121                        String saltOnRecord = (String) session.createSQLQuery( 
     122                                        "select salt from users where user_id = ?") 
     123                                        .addScalar("salt", Hibernate.STRING) 
    116124                                        .setInteger(0, candidateUser.getUserId()) 
    117125                                        .uniqueResult(); 
    118                  
    119                 String saltOnRecord = (String) session.createSQLQuery( 
    120                                 "select salt from users where user_id = ?") 
    121                                 .addScalar("salt", Hibernate.STRING) 
    122                                 .setInteger(0, candidateUser.getUserId()) 
    123                                 .uniqueResult(); 
    124  
    125                 String hashedPassword = Security.encodeString(password + saltOnRecord); 
    126                  
    127                 User user = null; 
    128                  
    129                 if (hashedPassword != null && hashedPassword.equals(passwordOnRecord)) 
    130                         user = candidateUser; 
    131  
    132                 if (user == null) { 
    133                         log.info("Failed login attempt (login=" + login + ") - " 
    134                                                 + errorMsg); 
    135                         throw new ContextAuthenticationException(errorMsg); 
    136                 } 
    137  
    138                 // hydrate the user object 
    139                 user.getAllRoles().size(); 
    140                 user.getUserProperties().size(); 
    141                 user.getPrivileges().size(); 
    142                 // 
    143  
    144                 return user; 
     126         
     127                        String hashedPassword = Security.encodeString(password + saltOnRecord); 
     128                         
     129                        // if the username and password match, hydrate the user and return it 
     130                        if (hashedPassword != null && hashedPassword.equals(passwordOnRecord)) { 
     131                                // hydrate the user object 
     132                                candidateUser.getAllRoles().size(); 
     133                                candidateUser.getUserProperties().size(); 
     134                                candidateUser.getPrivileges().size(); 
     135                                // 
     136         
     137                                return candidateUser; 
     138                        } 
     139                } 
     140                 
     141                // throw this exception only once in the same place with the same 
     142                // message regardless of username/pw combo entered 
     143                log.info("Failed login attempt (login=" + login + ") - " 
     144                                        + errorMsg); 
     145                throw new ContextAuthenticationException(errorMsg); 
     146                 
    145147        } 
    146148 
  • openmrs/trunk/test/api/org/openmrs/test/api/db/ContextDAOTest.java

    r5354 r5370  
    1616import org.junit.Assert; 
    1717import org.junit.Before; 
    18 import org.junit.Ignore; 
    1918import org.junit.Test; 
    2019import org.openmrs.User; 
     
    168167                dao.authenticate("emptypassword", ""); 
    169168        } 
    170  
     169         
     170        /** 
     171         * This does not use the "expected=Exception" paradigm because it  
     172         * is comparing the actual error messages thrown 
     173         *  
     174         * @verifies {@link ContextDAO#authenticate(String, String)} 
     175         *      test = give identical error messages between username and password mismatch 
     176         */ 
     177        @Test() 
     178        public void authenticate_shouldGiveIdenticalErrorMessagesBetweenUsernameAndPasswordMismatch() throws Exception { 
     179                User user = dao.authenticate("admin", "test"); 
     180                Assert.assertNotNull("This test depends on there being an admin:test user", user); 
     181                 
     182                String invalidUsernameErrorMessage = null; 
     183                String invalidPasswordErrorMessage = null; 
     184                 
     185                try { 
     186                        dao.authenticate("some invalid username", "and an invalid password"); 
     187                } 
     188                catch (ContextAuthenticationException authException) { 
     189                        invalidUsernameErrorMessage = authException.getMessage(); 
     190                        invalidUsernameErrorMessage = invalidUsernameErrorMessage.replace("some invalid username", ""); 
     191                } 
     192                 
     193                try { 
     194                        // a valid username but an invalid password for that user 
     195                        dao.authenticate("admin", "and an invalid password"); 
     196                } 
     197                catch (ContextAuthenticationException authException) { 
     198                        invalidPasswordErrorMessage = authException.getMessage(); 
     199                        invalidPasswordErrorMessage = invalidPasswordErrorMessage.replace("admin", ""); 
     200                } 
     201                 
     202                Assert.assertEquals(invalidUsernameErrorMessage, invalidPasswordErrorMessage); 
     203        } 
     204         
    171205}