I try to implement an client-cert-authentication to access jetty-based content. E.g. the URL http://www.example.com/testsystem/idp/spapi should be only accessed with valid client-certificate.
I get following error on jetty-start:
2021-08-12 14:25:22.967:WARN :oejuc.AbstractLifeCycle:main: FAILED org.eclipse.jetty.server.session.SessionHandler1528923159==dftMaxIdleSec=1800: java.lang.IllegalStateException: No LoginService for org.eclipse.jetty.security.authentication.SslClientCertAuthenticator@49dbaaf3 in ConstraintSecurityHandler@6c284af{STARTING}
Using:
- openjdk 11.0.12
- Jetty 10.0.6
Configuration:
start.ini
--module=server
jetty.httpConfig.sendServerVersion=false
--module=jsp
--module=annotations
--module=deploy
--module=logging-jetty
--module=console-capture
--module=ext
--module=requestlog
--module=http-forwarded
--module=plus
--module=rewrite
--module=jstl
--module=servlets
--module=http
--module=ssl
--module=https
jetty.sslContext.keyStorePath=credentials/server.keystore
jetty.sslContext.keyStorePassword=mypassword
jetty.sslContext.keyManagerPassword=mypassword
jetty.sslContext.trustStorePath=credentials/server.keystore
jetty.sslContext.trustStorePassword=mypassword
jetty.sslContext.needClientAuth=true
idp.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="war">/opt/shibboleth-idp/war/idp.war</Set>
<Set name="contextPath">/testsystem/idp</Set>
<Set name="extractWAR">false</Set>
<Set name="copyWebDir">false</Set>
<Set name="copyWebInf">true</Set>
<Set name="persistTempDirectory">false</Set>
</Configure>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>Shibboleth Identity Provider</display-name>
<!-- Spring application context files. Files are loaded in the order they appear with subsequent files overwriting
same named beans in previous files. -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/META-INF/net.shibboleth.idp/preconfig.xml,${idp.home}/system/conf/global-system.xml,classpath*:/META-INF/net.shibboleth.idp/postconfig.xml</param-value>
</context-param>
<context-param>
<param-name>contextClass</param-name>
<param-value>net.shibboleth.ext.spring.context.DelimiterAwareApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer</param-value>
</context-param>
<!-- Spring listener used to load up the configuration -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Filters and filter mappings -->
<!-- Try and force I18N, probably won't help much. -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- Automates SameSite handling until Java API catches up. -->
<filter>
<filter-name>SameSiteCookieFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shibboleth.SameSiteCookieFilter</param-value>
</init-param>
</filter>
<!-- Lets us lump repeated Set-Cookie headers into one, something containers rarely support. -->
<filter>
<filter-name>CookieBufferingFilter</filter-name>
<filter-class>net.shibboleth.utilities.java.support.net.CookieBufferingFilter</filter-class>
</filter>
<!-- Allows control of response headers from within Spring beans. -->
<filter>
<filter-name>DynamicResponseHeaderFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shibboleth.ResponseHeaderFilter</param-value>
</init-param>
</filter>
<!-- Automates TLS-based propagation of HttpServletRequest/Response into beans. -->
<filter>
<filter-name>RequestResponseContextFilter</filter-name>
<filter-class>net.shibboleth.utilities.java.support.net.RequestResponseContextFilter</filter-class>
</filter>
<!-- Manages logging MDC. -->
<filter>
<filter-name>SLF4JMDCServletFilter</filter-name>
<filter-class>net.shibboleth.idp.log.SLF4JMDCServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SameSiteCookieFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CookieBufferingFilter</filter-name>
<url-pattern>/profile/admin/*</url-pattern>
<url-pattern>/profile/Logout</url-pattern>
<url-pattern>/profile/Shibboleth/SSO</url-pattern>
<url-pattern>/profile/SAML2/Unsolicited/SSO</url-pattern>
<url-pattern>/profile/SAML2/Redirect/SSO</url-pattern>
<url-pattern>/profile/SAML2/POST/SSO</url-pattern>
<url-pattern>/profile/SAML2/POST-SimpleSign/SSO</url-pattern>
<url-pattern>/profile/SAML2/Artifact/SSO</url-pattern>
<url-pattern>/profile/SAML2/Redirect/SLO</url-pattern>
<url-pattern>/profile/SAML2/POST/SLO</url-pattern>
<url-pattern>/profile/SAML2/POST-SimpleSign/SLO</url-pattern>
<url-pattern>/profile/SAML2/Artifact/SLO</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>DynamicResponseHeaderFilter</filter-name>
<url-pattern>/profile/admin/*</url-pattern>
<url-pattern>/profile/Shibboleth/SSO</url-pattern>
<url-pattern>/profile/SAML2/Unsolicited/SSO</url-pattern>
<url-pattern>/profile/SAML2/Redirect/SSO</url-pattern>
<url-pattern>/profile/SAML2/POST/SSO</url-pattern>
<url-pattern>/profile/SAML2/POST-SimpleSign/SSO</url-pattern>
<url-pattern>/profile/SAML2/Artifact/SSO</url-pattern>
<url-pattern>/Authn/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>RequestResponseContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SLF4JMDCServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Servlets and servlet mappings -->
<servlet>
<servlet-name>idp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>${idp.home}/system/conf/mvc-beans.xml, ${idp.home}/system/conf/webflow-config.xml</param-value>
</init-param>
<init-param>
<param-name>contextClass</param-name>
<param-value>net.shibboleth.ext.spring.context.DelimiterAwareApplicationContext</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>idp</servlet-name>
<url-pattern>/status</url-pattern>
<url-pattern>/profile/*</url-pattern>
</servlet-mapping>
<!-- Servlet protected by container used for RemoteUser authentication -->
<servlet>
<servlet-name>RemoteUserAuthHandler</servlet-name>
<servlet-class>net.shibboleth.idp.authn.impl.RemoteUserAuthServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>RemoteUserAuthHandler</servlet-name>
<url-pattern>/Authn/RemoteUser</url-pattern>
</servlet-mapping>
<!-- Servlet protected by container used for X.509 authentication -->
<servlet>
<servlet-name>X509AuthHandler</servlet-name>
<servlet-class>net.shibboleth.idp.authn.impl.X509AuthServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>X509AuthHandler</servlet-name>
<url-pattern>/Authn/X509</url-pattern>
</servlet-mapping>
<!-- Send request for the EntityID to the SAML metadata echoing JSP. -->
<servlet>
<servlet-name>shibboleth_jsp</servlet-name>
<jsp-file>/WEB-INF/jsp/metadata.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>shibboleth_jsp</servlet-name>
<url-pattern>/shibboleth</url-pattern>
</servlet-mapping>
<!-- Send servlet errors through the IdP's MVC error handling. -->
<error-page>
<exception-type>net.shibboleth.idp.authn.ExternalAuthenticationException</exception-type>
<location>/profile/RaiseError</location>
</error-page>
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
<!-- Allow intended methods by using an absent auth-constraint. -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Non-API Content</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>HEAD</http-method>
<http-method>OPTIONS</http-method>
<http-method>POST</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<!-- no auth-constraint tag here -->
</security-constraint>
<!-- Disallow other methods by using an empty auth-constraint. -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Non-API Content</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>HEAD</http-method-omission>
<http-method-omission>OPTIONS</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<authn-constraint/>
</security-constraint>
<!-- Allow any HTTP methods to the API flows. -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Administrative APIs</web-resource-name>
<url-pattern>/profile/admin/*</url-pattern>
</web-resource-collection>
<!-- no auth-constraint tag here -->
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Api</web-resource-name>
<url-pattern>/spapi/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
</login-config>
</web-app>
If I remove the last security-constraint Jetty starts without any error but also without any client-cert-support.
Any hints are welcome.