Feature interaction problem is something that individual features look and work smoothly in your system, 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 those features are attempted to be used together.
One example of feature interaction problem in Spring Security is digest authentication 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 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 format within the database so that nobody can obtain any user’s secret password by querying the database. 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 switch user and re authenticating already authenticated user before allowing him/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, 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, and obtains the other one from current authentication token, and 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 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.