/** * Constructs a request object wrapping the given request. * * @param request The request to wrap * @throws IllegalArgumentException if the request is null */ public LdapRoleCheckingRequest(final HttpServletRequest request, final LDAPInterface ldapInterface, final String userDN, final LdapProperties ldapProperties) throws LDAPException { super(request); this.ldapInterface = ldapInterface; this.userDN = userDN; this.roleBaseDN = ldapProperties.getRoleBaseDn(); this.userRoles = getRoles(); }
@Override protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException { Optional<Credentials> optionalCredentials = readFrom(request); if (optionalCredentials.isPresent()) { final Optional<HttpServletRequest> authRequest = tryToGetAuthenticatedRequest(request, optionalCredentials.get()); if (authRequest.isPresent()) { filterChain.doFilter(authRequest.get(), response); } else { unauthorized(response); } } else { unauthorized(response); } }
private Optional<HttpServletRequest> tryToGetAuthenticatedRequest(final HttpServletRequest request, final Credentials credentials) { try (final LDAPConnection ldap = ldapConnectionFactory.buildLdapConnection()) { for (String baseDN : ldapProperties.getBaseDn()) { final String userDN = userDnFrom(credentials, baseDN); try { if (authenticate(ldap, userDN, credentials.getPassword())) { return ldapProperties.getRoleBaseDn() != null ? Optional.of(new LdapRoleCheckingRequest(request, ldap, userDN, ldapProperties)) : Optional.of(request); } } catch (LDAPBindException e) { LOG.debug("LDAPBindException for userDN: {}", userDN); } } LOG.warn("Could not bind to LDAP: {}", credentials.getUsername()); } catch (LDAPException | GeneralSecurityException e) { LOG.warn("Authentication error: ", e); } return Optional.empty(); }
@Test public void shouldReturnCorrectCredentialsIfPasswordContainsColons() { // given mockHttpServletRequestWithAuthentication("user:pass:word"); // when final Optional<Credentials> credentials = Credentials.readFrom(httpServletRequest); // then assertThat(credentials.isPresent(), is(true)); assertThat(credentials.get().getUsername(), is("user")); assertThat(credentials.get().getPassword(), is("pass:word")); } }
@Test public void shouldContinueFilterChainWhenUserHasRequiredRole() throws ServletException, IOException { // given final LdapProperties ldapProperties = mockLdapPropertiesWithRequiredRole("roleB"); final LdapRoleAuthenticationFilter filter = new LdapRoleAuthenticationFilter(ldapProperties); final HttpServletRequest request = mockRequestWithAvailableRoles("roleA", "roleB", "roleC"); final HttpServletResponse response = mockResponse(); final FilterChain filterChain = mockFilterChain(); // when filter.doFilterInternal(request, response, filterChain); // then verify(filterChain).doFilter(request, response); verifyZeroInteractions(response); }
@Test public void shouldNotInvokeFilterLogicWhenRequestIsForWhitelistedPath() throws ServletException { // given final LdapProperties ldapProperties = mockLdapPropertiesWithProtecedAndWhiteListedPath("/internal", "/internal/public"); final LdapRoleAuthenticationFilter filter = new LdapRoleAuthenticationFilter(ldapProperties); final HttpServletRequest request = mockRequestWithPath("/internal/public"); // when final boolean shouldInvokeFilterLogic = !filter.shouldNotFilter(request); // then assertFalse(shouldInvokeFilterLogic); }
@Test public void shouldBeUnauthenticatedIfLdapConnectionFails() throws Exception { final LDAPConnection ldapConnection = someLdapConnectionReturning(SERVER_DOWN); when(ldapConnectionFactory.buildLdapConnection()).thenReturn(ldapConnection); testee.doFilter(requestWithAuthorizationHeader(), response, mock(FilterChain.class)); assertUnauthorized(); }
@Test public void shouldReturnUserRoles() throws LDAPException { final HttpServletRequest mockRequest = mock(HttpServletRequest.class); final LDAPInterface ldap = someLdapInterfaceReturning("foo"); final LdapRoleCheckingRequest request = new LdapRoleCheckingRequest(mockRequest, ldap, "uid=test", someLdapProperties()); assertThat(request.getRoles()).contains("foo"); }
@Test public void shouldCheckUserRoles() throws LDAPException { final HttpServletRequest mockRequest = mock(HttpServletRequest.class); final LDAPInterface ldap = someLdapInterfaceReturning("foo", "bar"); final LdapRoleCheckingRequest request = new LdapRoleCheckingRequest(mockRequest, ldap, "uid=test", someLdapProperties()); assertThat(request.isUserInRole("foo")).isEqualTo(true); assertThat(request.isUserInRole("foobar")).isEqualTo(false); }
@Test public void shouldReturnEmptyCredentialsIfUsernameNotSet() { // given mockHttpServletRequestWithAuthentication(":password"); // when final Optional<Credentials> credentials = Credentials.readFrom(httpServletRequest); // then assertThat(credentials.isPresent(), is(false)); }
@Test public void shouldBuildUserDnFromCredentials() { final String userDn = testee.userDnFrom(new Credentials("user", "password"), "someBaseDn"); assertThat(userDn).isEqualTo("someRdnIdentifier=user,someBaseDn"); }
@Test public void shouldAuthenticateUser() throws LDAPException { final boolean authenticated = testee.authenticate(someLdapConnectionReturning(SUCCESS), "user", "password"); assertThat(authenticated).isEqualTo(true); }
@Test public void shouldFailToStartIfAuthorizationHeaderIsMissing() throws Exception { testee.doFilter(requestWithoutAuthorizationHeader(), response, mock(FilterChain.class)); assertUnauthorized(); }
@Test public void shouldNotApplyFilterToWhitelistedEndpoint() throws Exception { final HttpServletRequest request = requestWithoutAuthorizationHeader(); when(request.getServletPath()).thenReturn(WHITELISTED_PATH + "/etc"); final FilterChain filterChain = mock(FilterChain.class); testee.doFilter(request, response, filterChain); verify(filterChain).doFilter(request, response); }
@Test public void shouldBeAbleToReadCredentialsFromRequest() { // given mockHttpServletRequestWithAuthentication("someUsername:somePassword"); // when final Optional<Credentials> credentials = Credentials.readFrom(httpServletRequest); // then assertThat(credentials.isPresent(), is(true)); assertThat(credentials.get().getUsername(), is("someUsername")); assertThat(credentials.get().getPassword(), is("somePassword")); }
@Test public void shouldRejectUserThatHasNotRequiredRole() throws ServletException, IOException { // given final LdapProperties ldapProperties = mockLdapPropertiesWithRequiredRole("roleX"); final LdapRoleAuthenticationFilter filter = new LdapRoleAuthenticationFilter(ldapProperties); final HttpServletRequest request = mockRequestWithAvailableRoles("roleA", "roleB"); final HttpServletResponse response = mockResponse(); final FilterChain filterChain = mockFilterChain(); // when filter.doFilterInternal(request, response, filterChain); // then verifyZeroInteractions(filterChain); verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); }
@Test public void shouldInvokeFilterLogicWhenRequestIsForSecuredPath() throws ServletException { // given final LdapProperties ldapProperties = mockLdapPropertiesWithProtecedAndWhiteListedPath("/internal", "/internal/public"); final LdapRoleAuthenticationFilter filter = new LdapRoleAuthenticationFilter(ldapProperties); final HttpServletRequest request = mockRequestWithPath("/internal"); // when final boolean shouldInvokeFilterLogic = !filter.shouldNotFilter(request); // then assertTrue(shouldInvokeFilterLogic); }
@Test public void shouldReturnEmptyCredentialsIfPasswordNotSet() { // given mockHttpServletRequestWithAuthentication("someUsername:"); // when final Optional<Credentials> credentials = Credentials.readFrom(httpServletRequest); // then assertThat(credentials.isPresent(), is(false)); }
@Test public void shouldNotAuthenticateUser() throws LDAPException { final boolean authenticated = testee.authenticate(someLdapConnectionReturning(AUTHORIZATION_DENIED), "user", "password"); assertThat(authenticated).isEqualTo(false); }
@Test public void shouldNotApplyFilterToInternalJavascript() throws Exception { final HttpServletRequest request = requestWithoutAuthorizationHeader(); when(request.getServletPath()).thenReturn("/internal/js/foo.js"); final FilterChain filterChain = mock(FilterChain.class); testee.doFilter(request, response, filterChain); verify(filterChain).doFilter(request, response); }