swri-robotics / bag-database

A server that catalogs bag files and provides a web-based UI for accessing them.
Other
342 stars 71 forks source link

Setting up BagDB with Webviz and external LDAP server #166

Closed Jan-Blaha closed 2 years ago

Jan-Blaha commented 2 years ago

Hey,

I wanted to set up your nice tool for managing data in our lab, but i was just unable to figure out, how to tie this to our LDAP server. Even digging quite deep in the sources did not get me an answer, so I'm writing this to ask for help.

I build my own docker-compose.yml file to meet my needs and set all the variables and everything. It is based on the https://swri-robotics.github.io/bag-database/installation/docker/with-webviz set up, but i already have an ldap server and a reverse proxy set up elsewhere.

Now, for some reason, when I then try to login (/ldap_login) using a user only in ldap (default BagDB admin works fine), I get the following exception

2021-11-29 00:17:20.284 [http-nio-8080-exec-15] DEBUG c.g.s.account.AccountRepository - Looking up user by email: test_user
 2021-11-29 00:17:20.291 [http-nio-8080-exec-15] WARN  c.g.s.account.AccountRepository - No user found
 javax.persistence.NoResultException: No entity found for query
    at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1583)
    at com.github.swrirobotics.account.AccountRepository.findByEmail(AccountRepository.java:70)
    at com.github.swrirobotics.account.AccountRepository$$FastClassBySpringCGLIB$$b7d2a610.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.github.swrirobotics.account.AccountRepository$$EnhancerBySpringCGLIB$$84af9286.findByEmail(<generated>)
    at com.github.swrirobotics.account.UserService.loadUserByUsername(UserService.java:73)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:104)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    ...

which i basically read as "there is no such user in the database", but what I don't understand is, why there is no effort to connect to the ldap. I can try to fix the connection parameters all day long, but if the application is not even trying to query the ldap I'm not getting anywhere.

The docker-compose file i have (with replaced details):

version: '3.6'
services:
    docker:
        image: docker:dind
        privileged: yes 
        networks:
            - bagdb
        volumes:
            - bags:/bags:ro # Needs to match the path in the bagdb container
            - scripts:/scripts
            - docker_cache:/var/lib/docker
        command: ["dockerd", "--host=tcp://0.0.0.0:2375"]
    bagdb:
        image: swrirobotics/bag-database:latest
        networks:
            - bagdb
        depends_on:
            - postgres
        ports:
            - "10000:8080"
        volumes:
            - bags:/bags
            - indexes:/root/.ros-bag-database/indexes
            - scripts:/scripts
        environment:
            ADMIN_PASSWORD: ${BAGSDB_ADMIN_PASSWORD}
            DB_PASS: ${POSTGRES_BAGS_PASS}
            LDAP_BIND_PASSWORD: ${LDAP_BIND_PASSWORD}
            DB_DRIVER: org.postgresql.Driver
            DB_URL: jdbc:postgresql://postgres/bag_database
            DB_USER: bag_database
            DOCKER_HOST: http://docker:2375
            GPS_TOPICS: /gps
            LDAP_BINDDN: "cn=binddn,dc=example,dc=com"
            LDAP_SEARCH_BASE: cn=user,dc=example,dc=com
            LDAP_SERVER: ldap://ldap.example.com/
            LDAP_USER_PATTERN: "uid={0},cn=user,dc=example,dc=com"
            METADATA_TOPICS: 
            OPEN_WITH_URLS: "{'Webviz':['http://bags.example.com/webviz/?', 'remote-bag-url']}"
            VEHICLE_NAME_TOPICS: 
    postgres:
        image: postgis/postgis:11-2.5
        networks:
            - bagdb
        volumes:
            - postgres:/var/lib/postgresql/data
        environment:
            POSTGRES_PASSWORD: ${POSTGRES_BAGS_PASS}
            POSTGRES_USER: bag_database
            POSTGRES_DB: bag_database
    webviz:
        image: cruise/webviz
        networks:
            - bagdb
        ports:
            - "10001:80"
        volumes:
            - ./webviz-default.conf:/etc/nginx/conf.d/default.conf:ro

networks:
    bagdb: {}

volumes:
    bags:
        driver: local
        driver_opts:
            o: bind
            type: none
            device: /example/path1
    docker_cache:
    postgres:
        driver: local
        driver_opts:
            o: bind
            type: none
            device: /example/path2
    indexes:
    scripts:
        driver_opts:
            type: 'tmpfs'
            device: 'tmpfs'

So could you please tell me what am I doing wrong? I don't even know what to look for anymore.

pjreed commented 2 years ago

Does your LDAP server have any logs you can check to see if it's attempting to authenticate? Your configuration looks fine to me. Unfortunately, Spring's LDAP framework is notoriously hard to debug, as the actual authentication is all handled inside the library and it logs very little information regardless of whether it succeeds or fails...

I suspect that it is trying to connect to your LDAP server but either failing to authenticate as the BINDDN or it is authenticating but failing to find a user that matches the given user name; then it tries to look up the user in its internal users table, which only has the admin user in it, and it prints out that exception when it fails.

The first thing I would do is check to make sure that you can connect to your LDAP server from the machine that is running the BagDB and test that your search criteria are correct. If you are trying to log in as test_user, then install the ldap-utils package and try running ldapsearch with these parameters, based on what you provided in your example config:

ldapsearch -D 'cn=binddn,dc=example,dc=com' -w '${LDAP_BIND_PASSWORD}' -h ldap.example.com:389 -b 'cn=user,dc=example,dc=com' uid=test_user

If it works, you'll see the LDAP entry for that user; otherwise, it will probably print ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1).

For reference, if you want to experiment with the source code, the configuration is all handled inside the com.github.swrirobotics.config.SecurityConfig class; it gets all of the configuration values and uses them to create an instance of Spring's BindAuthenticator, which handles all of the actual communication with the LDAP server.

Jan-Blaha commented 2 years ago

I tested the server accessibility with ldapsearch before and it worked fine. But based on your suggestion, I further tried some traffic analysis and the BagDB really unsuccessfully tries to authenticate with the ldap server and fails only after the fallback to the local user table. So there is something wrong with the settings I'm using.. I have no idea what, given that it works in other applications, but the problem seems to be elsewhere, so I'm closing this. Thank you for your time!

pjreed commented 2 years ago

Ok, no problem. Let me know if you have any other issues!