-1

I am writing a program that validates the username and password sent over HTTP POST and validate against ldap and sends the response back to the user whether the validation is success or not.

My Websecurity Configurer implementation

package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.LdapShaPasswordEncoder;

import org.springframework.boot.autoconfigure.security.SecurityProperties;

@Configuration
@Order(SecurityProperties.IGNORED_ORDER)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
        http.csrf().disable();

    }

    @SuppressWarnings("deprecation")
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .ldapAuthentication()
                .userDnPatterns("uid={0},ou=people")
                .groupSearchBase("ou=groups")
                .contextSource()
                    .url("ldap://localhost:8389/dc=springframework,dc=org")
                    .and()
                .passwordCompare()
                    .passwordEncoder(new LdapShaPasswordEncoder())
                    .passwordAttribute("userPassword");
    }

}

My test-server.ldif

dn: dc=springframework,dc=org
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: springframework

dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: subgroups

dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

dn: ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: space cadets

dn: ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: "quoted people"

dn: ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: otherpeople

dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=

dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword: bobspassword
.
.

And I have this defined in my application.properties as well. spring.ldap.embedded.ldif=classpath:test-server.ldif

I am trying to post the data from the postman and I am getting 403 response for any value.

enter image description here

I cannot figure out why is it giving 403. Can anyone understand what I am doing wrong. Thanks.

Below is the updated Security logs:

2019-09-03 10:11:56.942 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 1 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 2019-09-03 10:11:56.944 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 2 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 2019-09-03 10:11:56.944 DEBUG 9040 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists 2019-09-03 10:11:56.945 DEBUG 9040 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created. 2019-09-03 10:11:56.947 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter' 2019-09-03 10:11:56.948 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 4 of 10 in additional filter chain; firing Filter: 'LogoutFilter' 2019-09-03 10:11:56.948 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET] 2019-09-03 10:11:56.949 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/rest/hello'; against '/logout' 2019-09-03 10:11:56.949 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST] 2019-09-03 10:11:56.949 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /rest/hello' doesn't match 'POST /logout' 2019-09-03 10:11:56.949 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT] 2019-09-03 10:11:56.950 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /rest/hello' doesn't match 'PUT /logout' 2019-09-03 10:11:56.950 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE] 2019-09-03 10:11:56.950 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /rest/hello' doesn't match 'DELETE /logout' 2019-09-03 10:11:56.950 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : No matches found 2019-09-03 10:11:56.951 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 5 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 2019-09-03 10:11:56.951 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.s.HttpSessionRequestCache : saved request doesn't match 2019-09-03 10:11:56.951 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 6 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 2019-09-03 10:11:56.953 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 7 of 10 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 2019-09-03 10:11:56.958 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@938ad544: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 2019-09-03 10:11:56.958 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter' 2019-09-03 10:11:56.958 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.session.SessionManagementFilter : Requested session ID 84F3D9D1165FFEE7008EDB2FA99B0D88 is invalid. 2019-09-03 10:11:56.958 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 2019-09-03 10:11:56.959 DEBUG 9040 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /rest/hello at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 2019-09-03 10:11:56.960 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /rest/hello; Attributes: [authenticated] 2019-09-03 10:11:56.960 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@938ad544: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS 2019-09-03 10:11:56.972 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@136951e, returned: -1 2019-09-03 10:11:56.983 DEBUG 9040 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) [spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) [spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]

Sree
  • 921
  • 2
  • 12
  • 31
  • 1
    set spring security logs to debug and then run it and it will tell you what it fails on https://stackoverflow.com/questions/20485059/spring-boot-how-can-i-set-the-logging-level-with-application-properties – Toerktumlare Aug 31 '19 at 13:24
  • Thanks for the response thomas and I have updated the logs – Sree Sep 03 '19 at 05:27
  • What are you trace logging? – Toerktumlare Sep 03 '19 at 06:36
  • Updated them in the description above – Sree Sep 03 '19 at 06:38
  • Read my question again, what are you trace logging, it looks like you are tracing logging spring web i want to see the debug log for spring security `logging.level.org.springframework.security=DEBUG` – Toerktumlare Sep 03 '19 at 07:40
  • How did you set TRACE logging – Toerktumlare Sep 03 '19 at 07:46
  • My bad, thanks for pointing it out Thomas. I have updated the logs after I set the security logs to DEBUG. I am seeing the Access is denied (user is anonymous); redirecting to authentication entry point exception – Sree Sep 03 '19 at 17:19
  • can you add you RESTAuthenticationEntryPoint? – stacker Sep 03 '19 at 17:57
  • @stacker I do not have RESTAuthenticationEntryPoint. Those part of the code was commented out and I removed it now. – Sree Sep 03 '19 at 18:20
  • based on test-server.ldif, can you give me a valid username and password that you tested? – stacker Sep 03 '19 at 18:27
  • What is this `/rest/hello`? – Toerktumlare Sep 03 '19 at 18:34
  • @ThomasAndolf it is my simple controller. @RequestMapping("/rest") @RestController() public class MyController { @RequestMapping(value = "/hello", method = RequestMethod.POST) public String hello() { return "success"; }} – Sree Sep 03 '19 at 19:02
  • @stacker Yes I tested with the valid credentials in test-server.ldif and I am getting the same error – Sree Sep 03 '19 at 19:03
  • @Sree i can see you are using password decoder in your configs but why this is in your test-server.ldif userPassword: bobspassword? – stacker Sep 03 '19 at 19:22
  • @stacker I am not intended to use any password decoder. And the same worked when I tried with the web login form interface. I am trying to change it to work as a RESTFUL service to call it from my angular frontend. – Sree Sep 03 '19 at 20:53
  • wait, what? you are doing a `POST` request against your `/rest/hello` endpoint with the body of `{ "username": "john123", "password": "password" }` and expect it to automagically log you in? i't doesnt work that way. – Toerktumlare Sep 04 '19 at 00:41
  • @ThomasAndolf yes, you are correct and I figured it out and forgot to update this post. There were 2 mistakes I was doing and adding them as a separate answer – Sree Sep 04 '19 at 14:35

1 Answers1

0

It's not possible to provide a definite answer without any logs and possibly more code. But I have a few hints:

  • the sample credentials don't match the sample ldif that you are showing. Maybe there's an error?

  • it seems like you're using your own entry point. It is not clear how it is supposed to work, but POSTing a JSON body with the credentials to what seems to be the secured application URL does not seem right. It might lead to sending credentials to endpoints that should not receive sensitive information. Maybe you'd be better of using standard authentication mechanisms

  • password comparison isn't as secure and flexible as using LDAP bind authentication. It only supports limited password hashing algorithms that are no longer considered secure, and in case of salted password, requires to retrieve the password from the LDAP entry. LDAP bind supports any hashing algorithms that the LDAP server supports and the existing password never needs to leave the LDAP server

Maybe addressing these issues already helps with solving the underlying problem. Otherwise add code for the RESTAuthenticationEntryPoint and logs to the question.

rainerfrey
  • 560
  • 4
  • 14
  • I dont have RESTAuthenticationEntryPoint customized. Those were commented out and removed it from the code above. – Sree Sep 03 '19 at 05:40
  • Spring (Security) does not have a class named "RESTAuthenticationEntryPoint", it must be a custom class that you brought in. – rainerfrey Sep 03 '19 at 07:49
  • Also, Spring Security does not have an authentication mechanism where you send a POST request with credentials in JSON format to any URL that is supposed to be secured. If that is supposed to work, it must be something that you brought in. – rainerfrey Sep 03 '19 at 07:52