My code is as follows (referenced Embedded Jetty - Programatically add form based authentication):
ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS | ServletContextHandler.SECURITY);
context.addServlet(new ServletHolder(new DefaultServlet() {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().append("Hello " + request.getUserPrincipal().getName());
}
}), "/*");
context.addServlet(new ServletHolder(new DefaultServlet() {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().append("<html><form method='POST' action='/j_security_check'>"
+ "<input type='text' name='j_username'/>"
+ "<input type='password' name='j_password'/>"
+ "<input type='submit' value='Login'/></form></html>");
}
}), "/login");
context.addServlet(new ServletHolder(new DefaultServlet(){
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().append("This is the metrics page!");
}
}), "/metrics");
Constraint constraint = new Constraint();
constraint.setName(Constraint.__FORM_AUTH);
constraint.setRoles(new String[]{"admin"});
constraint.setAuthenticate(true);
ConstraintMapping constraintMapping = new ConstraintMapping();
constraintMapping.setConstraint(constraint);
constraintMapping.setPathSpec("/*");
ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
securityHandler.addConstraintMapping(constraintMapping);
TestingLoginService loginService = new TestingLoginService();
securityHandler.setLoginService(loginService);
FormAuthenticator authenticator = new FormAuthenticator("/login", "/login", false);
securityHandler.setAuthenticator(authenticator);
context.setSecurityHandler(securityHandler);
This works, but I want the /metrics servlet not require the user to be authenticated. However, I still want all other paths go to the login & the "Hello" servlet.
The only other solution I can think of is to move the "Hello" servlet to a different path and have the root path just redirect to that path. That way I can set the ConstraintMapping's pathSpec to something that doesn't encompass the /metrics path as well.
ConstraintMapping constraintMapping = new ConstraintMapping();
constraintMapping.setConstraint(constraint);
constraintMapping.setPathSpec("/*");
Unfortunately, there's no concept of "exclude" with Server Constraint Mappings.
You'll have to add multiple path specs that cover what you want, and just not include the /metrics
path spec in that list of path specs.