Add Spring Boot Example

Closes gh-558
This commit is contained in:
Josh Cummings
2022-02-09 14:18:08 -07:00
parent da79e610ea
commit 3bdb4402b3
8 changed files with 301 additions and 0 deletions

23
samples/boot/build.gradle Normal file
View File

@@ -0,0 +1,23 @@
plugins {
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management'
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-ldap'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.security:spring-security-ldap'
implementation 'com.unboundid:unboundid-ldapsdk'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}

31
samples/boot/readme.md Normal file
View File

@@ -0,0 +1,31 @@
A Hello World Spring LDAP application using Spring Boot
The application is protected by Spring Security and uses an embedded UnboundID container for its LDAP server.
You can authenticate with HTTP basic using `bob`/`bobspassword`:
```bash
curl --user bob:bobspassword localhost:8080
```
And you should see the response:
```bash
Hello, bob
```
Also, you can hit the `cn` endpoint which uses `LdapTemplate` to query the datastore for the user's `cn` attribute value, like so:
```bash
curl --user bob:bobspassword localhost:8080/cn
```
This should result in:
```bash
[
"Bob Hamilton"
]
```
To run the example, do `./gradlew :bootRun`.

View File

@@ -0,0 +1,27 @@
package sample;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
LdapTemplate ldap;
@GetMapping
public String hello(Authentication authentication) {
return "Hello, " + authentication.getName();
}
@GetMapping("/cn")
public List<String> cn(Authentication authentication) {
AttributesMapper<String> mapper = (attrs) -> attrs.get("cn").get().toString();
return this.ldap.search("ou=people", "uid=" + authentication.getName(), mapper);
}
}

View File

@@ -0,0 +1,42 @@
package sample;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.LdapAuthenticator;
import org.springframework.security.ldap.server.UnboundIdContainer;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
@Configuration
public class SecurityConfig {
@Bean
UnboundIdContainer ldapContainer() {
UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:users.ldif");
container.setPort(0);
return container;
}
@Bean
ContextSource contextSource(UnboundIdContainer container) {
int port = container.getPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
}
@Bean
BindAuthenticator authenticator(BaseLdapPathContextSource contextSource) {
BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserDnPatterns(new String[] { "uid={0},ou=people" });
return authenticator;
}
@Bean
LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticator) {
LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator);
provider.setUserDetailsContextMapper(new PersonContextMapper());
return provider;
}
}

View File

@@ -0,0 +1,13 @@
package sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringLdapSimpleSampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringLdapSimpleSampleApplication.class, args);
}
}

View File

@@ -0,0 +1,124 @@
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: $2a$10$c6bSeWPhg06xB1lvmaWNNe4NROmZiSpYhlocU/98HNr2MhIOiSt36
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
dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe Smeth
sn: Smeth
uid: joe
userPassword: joespassword
dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Mouse, Jerry
sn: Mouse
uid: jerry
userPassword: jerryspassword
dn: cn=slash/guy,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: slash/guy
sn: Slash
uid: slashguy
userPassword: slashguyspassword
dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: quote\"guy
sn: Quote
uid: quoteguy
userPassword: quoteguyspassword
dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Space Cadet
sn: Cadet
uid: space cadet
userPassword: spacecadetspassword
dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: developers
ou: developer
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: uid=bob,ou=people,dc=springframework,dc=org
dn: cn=managers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: managers
ou: manager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: submanagers
ou: submanager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org

View File

@@ -0,0 +1,40 @@
package sample;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class SpringLdapSimpleSampleApplicationTests {
@Autowired
MockMvc mvc;
@Test
void indexWhenCorrectUsernameAndPasswordThenAuthenticates() throws Exception {
HttpHeaders http = new HttpHeaders();
http.setBasicAuth("bob", "bobspassword");
this.mvc.perform(get("/").headers(http))
.andExpect(status().isOk())
.andExpect(content().string("Hello, bob"));
}
@Test
void cnWhenCorrectUsernameAndPasswordThenShowsCommonName() throws Exception {
HttpHeaders http = new HttpHeaders();
http.setBasicAuth("bob", "bobspassword");
this.mvc.perform(get("/cn").headers(http))
.andExpect(status().isOk())
.andExpect(jsonPath("$.[0]").value("Bob Hamilton"));
}
}

View File

@@ -37,6 +37,7 @@ include 'test/integration-tests-sunone'
include 'test/integration-tests-ad'
include 'samples/plain'
include 'samples/odm'
include 'samples/boot'
rootProject.children.each { p->