public static void addPreResponseAuthorizationCheckFilter( ServletContextHandler root, List<Authenticator> authenticators, ObjectMapper jsonMapper ) { root.addFilter( new FilterHolder( new PreResponseAuthorizationCheckFilter(authenticators, jsonMapper) ), "/*", null ); } }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { final HttpServletResponse response = (HttpServletResponse) servletResponse; final HttpServletRequest request = (HttpServletRequest) servletRequest; if (servletRequest.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT) == null) { handleUnauthenticatedRequest(response); return; } filterChain.doFilter(servletRequest, servletResponse); Boolean authInfoChecked = (Boolean) servletRequest.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED); if (authInfoChecked == null && statusIsSuccess(response.getStatus())) { // Note: rather than throwing an exception here, it would be nice to blank out the original response // since the request didn't have any authorization checks performed. However, this breaks proxying // (e.g. OverlordServletProxy), so this is not implemented for now. handleAuthorizationCheckError( "Request did not have an authorization check performed.", request, response ); } if (authInfoChecked != null && !authInfoChecked && response.getStatus() != HttpServletResponse.SC_FORBIDDEN) { handleAuthorizationCheckError( "Request's authorization check failed but status code was not 403.", request, response ); } }
private void handleUnauthenticatedRequest( final HttpServletResponse response ) throws IOException { // Since this is the last filter in the chain, some previous authentication filter // should have placed an authentication result in the request. // If not, send an authentication challenge. Set<String> supportedAuthSchemes = new HashSet<>(); for (Authenticator authenticator : authenticators) { String challengeHeader = authenticator.getAuthChallengeHeader(); if (challengeHeader != null) { supportedAuthSchemes.add(challengeHeader); } } for (String authScheme : supportedAuthSchemes) { response.addHeader("WWW-Authenticate", authScheme); } QueryInterruptedException unauthorizedError = new QueryInterruptedException( QueryInterruptedException.UNAUTHORIZED, null, null, DruidNode.getDefaultHost() ); unauthorizedError.setStackTrace(new StackTraceElement[0]); OutputStream out = response.getOutputStream(); sendJsonError(response, HttpServletResponse.SC_UNAUTHORIZED, jsonMapper.writeValueAsString(unauthorizedError), out); out.close(); return; }
@Test public void testValidRequest() throws Exception { AuthenticationResult authenticationResult = new AuthenticationResult("so-very-valid", "so-very-valid", null, null); HttpServletRequest req = EasyMock.createStrictMock(HttpServletRequest.class); HttpServletResponse resp = EasyMock.createStrictMock(HttpServletResponse.class); FilterChain filterChain = EasyMock.createNiceMock(FilterChain.class); ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class); EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(authenticationResult).once(); EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(true).once(); EasyMock.replay(req, resp, filterChain, outputStream); PreResponseAuthorizationCheckFilter filter = new PreResponseAuthorizationCheckFilter( authenticators, new DefaultObjectMapper() ); filter.doFilter(req, resp, filterChain); EasyMock.verify(req, resp, filterChain, outputStream); }
@Test public void testMissingAuthorizationCheckWithError() throws Exception { EmittingLogger.registerEmitter(EasyMock.createNiceMock(ServiceEmitter.class)); AuthenticationResult authenticationResult = new AuthenticationResult("so-very-valid", "so-very-valid", null, null); HttpServletRequest req = EasyMock.createStrictMock(HttpServletRequest.class); HttpServletResponse resp = EasyMock.createStrictMock(HttpServletResponse.class); FilterChain filterChain = EasyMock.createNiceMock(FilterChain.class); ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class); EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(authenticationResult).once(); EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once(); EasyMock.expect(resp.getStatus()).andReturn(404).once(); EasyMock.replay(req, resp, filterChain, outputStream); PreResponseAuthorizationCheckFilter filter = new PreResponseAuthorizationCheckFilter( authenticators, new DefaultObjectMapper() ); filter.doFilter(req, resp, filterChain); EasyMock.verify(req, resp, filterChain, outputStream); } }
EasyMock.replay(req, resp, filterChain, outputStream); PreResponseAuthorizationCheckFilter filter = new PreResponseAuthorizationCheckFilter( authenticators, new DefaultObjectMapper() ); filter.doFilter(req, resp, filterChain); EasyMock.verify(req, resp, filterChain, outputStream);
handleUnauthenticatedRequest(response); return; if (authInfoChecked == null && statusIsSuccess(response.getStatus())) { handleAuthorizationCheckError( "Request did not have an authorization check performed.", request, handleAuthorizationCheckError( "Request's authorization check failed but status code was not 403.", request,
public static void addPreResponseAuthorizationCheckFilter( ServletContextHandler root, List<Authenticator> authenticators, ObjectMapper jsonMapper ) { root.addFilter( new FilterHolder( new PreResponseAuthorizationCheckFilter(authenticators, jsonMapper) ), "/*", null ); } }
private void handleUnauthenticatedRequest( final HttpServletResponse response ) throws IOException { // Since this is the last filter in the chain, some previous authentication filter // should have placed an authentication result in the request. // If not, send an authentication challenge. Set<String> supportedAuthSchemes = Sets.newHashSet(); for (Authenticator authenticator : authenticators) { String challengeHeader = authenticator.getAuthChallengeHeader(); if (challengeHeader != null) { supportedAuthSchemes.add(challengeHeader); } } for (String authScheme : supportedAuthSchemes) { response.addHeader("WWW-Authenticate", authScheme); } QueryInterruptedException unauthorizedError = new QueryInterruptedException( QueryInterruptedException.UNAUTHORIZED, null, null, DruidNode.getDefaultHost() ); unauthorizedError.setStackTrace(new StackTraceElement[0]); OutputStream out = response.getOutputStream(); sendJsonError(response, Response.SC_UNAUTHORIZED, jsonMapper.writeValueAsString(unauthorizedError), out); out.close(); return; }
@Test public void testAuthenticationFailedRequest() throws Exception { HttpServletRequest req = EasyMock.createStrictMock(HttpServletRequest.class); HttpServletResponse resp = EasyMock.createStrictMock(HttpServletResponse.class); FilterChain filterChain = EasyMock.createNiceMock(FilterChain.class); ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class); EasyMock.expect(resp.getOutputStream()).andReturn(outputStream).once(); EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(null).once(); resp.setStatus(401); EasyMock.expectLastCall().once(); resp.setContentType("application/json"); EasyMock.expectLastCall().once(); resp.setCharacterEncoding("UTF-8"); EasyMock.expectLastCall().once(); EasyMock.replay(req, resp, filterChain, outputStream); PreResponseAuthorizationCheckFilter filter = new PreResponseAuthorizationCheckFilter( authenticators, new DefaultObjectMapper() ); filter.doFilter(req, resp, filterChain); EasyMock.verify(req, resp, filterChain, outputStream); }