2

I have Karaf 3.0.2 as my container, which uses pax web (which again uses jetty, I think). I have several servlets which I register as an OSGi service under a certain alias.

By default, etc/jetty.xml is configured so that I can use a JAASLoginService, which is already the one I wish to use, too.

The problem is, that I want to use both, basic and form authentication:

  • Everything matching /ui/* should use form authentication
  • Everything matching /rest/* should use basic authentication

I tried a lot, but I didn't even find a point, where I could start. I think it is possible to configure each servlet, but I want to do it globally.

Any ideas?

palador
  • 37
  • 5

1 Answers1

2

You have do differentiate here a bit. If you use a WebApplicationBundle (WAB) to deploy your Servlets you have all regular elements of a Web Application. Including Basic or Form based authentication.

Since you are using the OSGi way of registering Servlets you only can do this by the means of the HttpContext. The below example is taken from the Pax Web Samples, it uses Basic Authentication.

public class AuthHttpContext implements HttpContext {

    public boolean handleSecurity(HttpServletRequest req,
        HttpServletResponse res) throws IOException {

        if (req.getHeader("Authorization") == null) {
            res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        if (authenticated(req)) {
            return true;
        } else {
            res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

    }

    protected boolean authenticated(HttpServletRequest request) {
        request.setAttribute(AUTHENTICATION_TYPE, HttpServletRequest.BASIC_AUTH);

        String authzHeader = request.getHeader("Authorization");
        String usernameAndPassword = new String(Base64.decodeBase64(authzHeader.substring(6).getBytes()));

        int userNameIndex = usernameAndPassword.indexOf(":");
        String username = usernameAndPassword.substring(0, userNameIndex);
        String password = usernameAndPassword.substring(userNameIndex + 1);

        // Here I will do lame hard coded credential check. HIGHLY NOT RECOMMENDED! 
        boolean success = ((username.equals("admin") && password
            .equals("admin")));
        if (success)
            request.setAttribute(REMOTE_USER, "admin");
        return success;
        }

...
}

For Form-based you'll need an extra HttpContext. For every matching path you need to make sure to have the right HttpContext registered, the following code can also be found at the Pax Web Samples.

public final class Activator implements BundleActivator {

...

    public void start(BundleContext bc) throws Exception {
        httpServiceRef = bc.getServiceReference(HttpService.class);
        if (httpServiceRef != null) {
            httpService = (HttpService) bc.getService(httpServiceRef);

            ...

            httpService.registerServlet("/status-with-auth",
                new StatusServlet(), null, new AuthHttpContext());
        }
    }
...
}
Achim Nierbeck
  • 5,265
  • 2
  • 14
  • 22
  • I tried it out, but at /status-with-auth it just shows the values of the attributes modified by the custom context. There was no login-dialog. – palador Oct 28 '14 at 15:35
  • The corresponding integration test does test this and it still works. https://github.com/ops4j/org.ops4j.pax.web/blob/master/pax-web-itest/pax-web-itest-container/pax-web-itest-container-jetty/src/test/java/org/ops4j/pax/web/itest/jetty/AuthenticationIntegrationTest.java – Achim Nierbeck Oct 28 '14 at 19:56
  • but it just tests the actual content at /status-with-auth and it doesn't even perform a login - that's what I want. I want that everybody accessing a servlet has to authenticate hisself via basic or form authentication. – palador Oct 29 '14 at 09:07
  • If that's the case plz file a bug at Pax Web – Achim Nierbeck Oct 29 '14 at 10:03
  • looks like you found a bug ... I'll fix it asap – Achim Nierbeck Nov 01 '14 at 09:12