External authentication: MVC controller as alternative to servlet
Daniel Lutz
daniel.lutz at switch.ch
Thu Sep 17 10:38:02 EDT 2015
Our implementation of the SPNEGO/Kerberos login flow
uses the ExternalAuthentication API. We would prefer
implementing the external authentication as an
MVC controller [1] instead of a servlet, mainly because
this would allow more flexible testing and a cleaner
implementation, we think.
The controller makes use of @RequestMapping annotations
to map specific request URLs to specific methods in
our controller.
Scott recently made me aware of the fact that no annotations
should be used for any of the Spring support in the code
to avoid implicit behavior. All should be configured with
XML wiring.
As our goal is that our implementation gets part of the IdP,
we want to fulfill this requirement.
I found the following solution that explicitly registers our
controller and sets up an explicit URL mapping in XML configuration,
but still uses annotations to map relative paths to specific methods
inside the controller:
We can register our MVC controller in system/conf/mvc-beans.xml
as a bean and setup an URL mapping using a SimpleUrlHandlerMapping:
(at the end of system/conf/mvc-beans.xml:)
<!-- Explicit mappings to controllers -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/Authn/SPNEGOKerberos/**">shibboleth.SPNEGOKerberosAuthnController</prop>
</props>
</property>
</bean>
<bean id="shibboleth.SPNEGOKerberosAuthnController" class="net.shibboleth.idp.authn.impl.spnego.SPNEGOKerberosAuthnController" />
This will dispatch all requests to /idp/profile/Authn/SPNEGOKerberos/** to our controller.
The controller then defines methods that handle specific requests.
Annotations specify the mapping to these methods inside the
/idp/profile/Authn/SPNEGOKerberos/ path:
Class net.shibboleth.idp.authn.impl.spnego.SPNEGOKerberosAuthnController:
...
public class SPNEGOKerberosAuthnController {
...
@RequestMapping(value = "/{conversationKey}", method = RequestMethod.GET)
public ResponseEntity<String> startSPNEGO(@PathVariable String conversationKey,
@Nonnull HttpServletRequest httpRequest, @Nonnull HttpServletResponse httpResponse)
throws ExternalAuthenticationException, IOException {
...
}
@RequestMapping(value = "/{conversationKey}", method = RequestMethod.GET, headers = "Authorization")
public ResponseEntity<String> continueSPNEGO(@PathVariable String conversationKey,
@Nonnull HttpServletRequest httpRequest, @Nonnull HttpServletResponse httpResponse)
throws ExternalAuthenticationException, IOException{
...
}
@RequestMapping(value = "/{conversationKey}/error", method = RequestMethod.GET)
public void handleError(@PathVariable String conversationKey,
@Nonnull HttpServletRequest httpRequest, @Nonnull HttpServletResponse httpResponse)
throws ExternalAuthenticationException, IOException {
...
}
...
}
For example, the URL https://idp.example.org/idp/profile/Authn/SPNEGOKerberos/e1s2?conversation=e1s2
is handled by the method SPNEGOKerberosAuthnController.startSPNEGO(), while the URL
https://idp.example.org/idp/profile/Authn/SPNEGOKerberos/e1s2/error?conversation=e1s2
is handled by the method SPNEGOKerberosAuthnController.handleError().
Is this solution acceptable?
Or do we need to switch to an implementation based on a servlet?
- Daniel
[1] http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/mvc.html#mvc-controller
More information about the dev
mailing list