I have a legacy application which I am converting from user-password to use certificate-based authentication. I am using Tomcat 7, and my application needs to support 4 types of security based on the URL in the application the user is trying to access
For instance: A few servlets will use HTTP A few servlets will use HTTPS without any authentication a few servlets will use mutual authentication using PKI, but the users will not be known in advance, so any user with a valid cert in the cert chain would be granted access. The reset of the application is management, so it would have role based access based on pre-defined user Certificate CNs.
I have a connector running HTTPS at 443 with clientAuth="want" in my Tomcat server.xml
I have my application web.xml which has a springSecurityFilterChain that lists any URLS that I want to require HTTPS
My springSecurityContext.xml has a x509 section which has subject-principal-regex="CN=(.*?)," user-service-ref="userDetailsService" which reads pre-registered users and roles from a property file. From there, I list the intercept-url patterns where i want to have a requires-channel="https" with what patterns require which roles.
I also added the URLs where I wanted it to require HTTPS only by setting access="IS_AUTHENTICATED_ANONYMOUSLY" as an intercept-url
This gets me 3 of the 4 requirements I need since any of the URLs above will automatically re-direct from HTTP to HTTPS using spring security, and enforce user credentials against roles, or not check the client certificate at all. The url-patterns not put into the web.xml springSecurityFilterChain will accept HTTP connections.
What I can't figure out is the final pattern, which is for the application to ask for the client certificate, which would be validated against the CA in the certificate chain, but not against my known user-database with roles. They would have valid certs, which I need to access the client cert to discover, but not actually be known in my system, since they are just general users to the application. I'm not quite sure how to accomplish this.
Here are some snippets from my 3 XML files to show what I am talking about. I only included the httpsandcertlink in the springSecurity to show which one I am trying to add, but can't get to work.
server.xml
<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme"https" secure="true"
clientAuth="want" sslProtocol"TLS"
keystoreFile="doesntmatter"
truststoreFile="doesntmatter" />
web.xml
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>MYAPP</realm-name>
</login-config>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>*.go</url-pattern>
<url-pattern>/httpsonlylink</url-pattern>
<url-pattern>/httpsandcertlink</url-pattern>
</filter-mapping>
springSecurityContext.xml
<security:http xmlns="http://www.springframework.org/schema/security" >
<security:x509 subject-principal-regex="CN=(.*?)," user-service-ref="userDetailsService" />
<security:intercept-url pattern="/management**" requires-channel="https" access="ROLE_MGMT" />
<security:intercept-url pattern="/httpsonlylink**" requires-channel="https" access="IS_AUTHENTICAED_ANONYMOUSLY" />
<security:intercept-url pattern="/httpsandcertlink**" requires-channel="https" --not sure what to change here-- />
</security:http>
<security:authentication-manager xmlns="http://www.springframework.org/schema/security" alias="authenticationManager">
<security:authentication-provider>
<security:user-service id="userDetailsService" properties="\WEB-INF\users.properties" />
</security:authentication-provider>
</security:authentication-manager>
One approach would be to piggyback the missing requirement on the roles requirement by creating an additional "valid certificate" role that all users are automatically assigned. A valid certificate chain should already be required, so all that should be required is to set up an intercept-url pattern that would match any URL that requires a valid certificate and require the "valid certificate" role, making sure that this rule matched after the ones requiring specific roles.