Feature interaction problem is something that features work smoothly and without any problem in your system individually; however, problems arise with those features when you bring them together. Bertrand Meyer has recently published his thoughts about the topic as well. While reading on it, I’ve come to realize that Spring Security has several similar issues which arise whenever we attempt to configure those features to work together in our system.
One example of feature interaction problem in Spring Security arises between digest authentication feature and keeping passwords encrypted in your database. DigestAuthenticationFilter is used to authenticate users through insecure HTTP channel by sending digested form of user credentials. Server side of digest authentication needs to lookup user realm, obtain user and her credentials and then generate digested form in order to compare it with the one sent by the client. Therefore, user credentials must be kept in plain text form in user realm. However, it is highly important to store user passwords in encrypted form within the database so that nobody, even db admins, can obtain any user’s secret password by querying the database itself. Spring Security also provides us with a PasswordEncoder in order to encode user submitted raw password prior to comparing it against the encoded one obtained from the database. At this point we are at a crossroad, we have to either choose using PasswordEncoder and keep credentials encoded in the database, hence give away from digest authentication mechanism, or choose using digest authentication and compromise from keeping passwords in secure form.
The other example is between switch user and re authenticating already authenticated user before allowing her to access any web resource. SwitchUserFilter inspects a special url to obtain username to which current authentication is to be switched into. When such a request arrives in, it extracts username, and queries user realm via UserDetailsService to obtain corresponding UserDetails info from the database. As a result, a new authentication token with the new UserDetails object is created and put into the SecurityContext. Afterwards, request is redirected to a success url. At this point, FilterSecurityInterceptor triggers a re authentication process for the redirected success url. It delegates authentication process to AuthenticationManager and DaoAuthenticationProvider in the end. DaoAuthenticationProvider loads one UserDetails from user realm, obtains the other from current authentication token, and then starts comparing their credentials. If DaoAuthenticationProvider is configured to work with PasswordEncoder, it tries to encrypt user password obtained through current authentication prior to comparing it with the one which is obtained from database during re authentication. However, as SwitchUserFilter has also loaded UserDetails from the same database, its also has encrypted password value in it. Therefore, applying password encoding process second time causes password comparison to fail, though UserDetails objects fetched from the database and obtained from current authentication token are the same. Again, you have to either give up from switch user feature, or store passwords in raw form in the database.
Those above two examples are very nice sample cases for perils of feature interaction, and how hard it may become to introduce new features in any kind of software system over time as they might cause conflicts with the already existing ones.