So I’m trying to build a REST API that will use LDAP authentication. Basically, when my login endpoint is consumed, I want it to detect credentials using httpBasic authentication and then use those credentials against my LDAP server. I also want to take into account user roles, protecting endpoints so that only certain users with the proper roles can access said endpoints.
Is it possible to do this? In my readings so far, I haven’t seen a tutorial or article that clearly states how to implement this.
*UPDATE: I managed to configure it to be able to accept credentials using httpBasic. Now I would like to know how to set permissions for specific endpoints using user roles based on LDAP groups (e.g. managers, developers)
Advertisement
Answer
This can actually be accomplished pretty succinctly with Spring Boot.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.so</groupId> <artifactId>rest-ldap</artifactId> <version>1.0.1</version> <name>rest-ldap</name> <description>SO REST LDAP Solution</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-ldap</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
App.java
package com.so; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; 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.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @EnableWebSecurity @RestController @SpringBootApplication public class App extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .httpBasic() .and() .authorizeRequests() .anyRequest() .authenticated() .and() .csrf() .disable(); } @Override protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder .ldapAuthentication() .contextSource() .url("ldap://ldap-server.com:3268") .managerDn("CN=MGR_USERNAME") .managerPassword("MGR_PASSWORD") .and() .userSearchFilter("CN={0}"); } @RequestMapping public Authentication getAuth() { return SecurityContextHolder.getContext().getAuthentication(); } public static void main(String[] args) { SpringApplication.run(com.so.App.class, args); } }
Send request
http://USERNAME:PASSWORD@localhost:8080
Receive (successful) response
HTTP/1.1 200 Set-Cookie: JSESSIONID=COOKIE-VALUE; Path=/; HttpOnly X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 Content-Type: application/json Transfer-Encoding: chunked Date: Mon, 01 Jan 1970 00:00:00 GMT
{ "authorities": [], "details": { "remoteAddress": "127.0.0.1", "sessionId": null }, "authenticated": true, "principal": { "dn": "cn=USERNAME", "password": null, "username": "USERNAME", "authorities": [], "accountNonExpired": true, "accountNonLocked": true, "credentialsNonExpired": true, "enabled": true, "timeBeforeExpiration": 2147483647, "graceLoginsRemaining": 2147483647 }, "credentials": null, "name": "USERNAME" }
Enjoy!