Skip to content

Commit

Permalink
Merge pull request #166 from devatherock/no-auth
Browse files Browse the repository at this point in the history
feat: Added support for anonymous access
  • Loading branch information
devatherock authored Dec 12, 2024
2 parents 912e134 + 2061d39 commit 4b1cb1f
Show file tree
Hide file tree
Showing 16 changed files with 196 additions and 45 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ jobs:
- v1-integration-{{ checksum "build.gradle" }}
- v1-integration
- run: |
make integration-test remote-integration-test
make integration-test no-auth-integration-test remote-integration-test
- save_cache:
paths:
- ~/.gradle
Expand Down Expand Up @@ -284,4 +284,4 @@ workflows:
- jumpcloud-credentials
<<: *pr_filter
requires:
- validate_yamls
- validate_yamls
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ checkstyle.xml
codenarc.xml
logs-intg.txt
logs-intg-remote.txt
logs-intg-no-auth.txt
16 changes: 4 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
# Changelog

## [Unreleased]
### Added
- [#164](https://github.com/devatherock/ldap-search-api/issues/164): Support for anonymous access

### Changed
- chore(deps): update plugin io.micronaut.application to v4.4.3
- fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.9
- fix(deps): update dependency net.bytebuddy:byte-buddy to v1.15.4
- fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.10
- fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.11
- fix(deps): update dependency net.bytebuddy:byte-buddy to v1.15.5
- fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.12
- fix(deps): update dependency net.bytebuddy:byte-buddy to v1.15.7
- fix(deps): update dependency net.bytebuddy:byte-buddy to v1.15.8
- fix(deps): update dependency net.bytebuddy:byte-buddy to v1.15.9
- chore(deps): update plugin io.micronaut.application to v4.4.4
- fix(deps): update dependency net.bytebuddy:byte-buddy to v1.15.10
- fix(deps): update dependency org.apache.groovy:groovy-json to v4.0.24
- fix(deps): update dependency org.projectlombok:lombok to v1.18.36
- chore(deps): update dependency gradle to v8.11
- chore(deps): update dependency gradle to v8.11.1
- chore(deps): update plugin org.sonarqube to v6
- chore(deps): update plugin org.sonarqube to v6.0.1.5171
- fix(deps): update dependency com.unboundid:unboundid-ldapsdk to v7.0.2
- chore(deps): update alpine docker tag to v3.21.0
Expand Down Expand Up @@ -133,4 +125,4 @@ with `LOGGER_LEVELS` prefix supported out of the box by micronaut
- Initial version. REST endpoint to query a LDAP server

### Changed
- The response to a `List` of maps from a `Map`
- The response to a `List` of maps from a `Map`
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ integration-test:
docker logs -f ldap-search-api-intg > logs-intg.txt &
./gradlew integrationTest --tests '*ControllerIntegrationSpec*'
docker-compose down
no-auth-integration-test:
rm -rf logs-intg-no-auth.txt
DOCKER_TAG=$(docker_tag) docker compose -f docker-compose-no-auth.yml up --wait
docker logs -f ldap-search-api-intg-no-auth > logs-intg-no-auth.txt &
./gradlew integrationTest --tests '*LdapSearchControllerNoAuthIntegrationSpec*'
docker compose -f docker-compose-no-auth.yml down
remote-integration-test:
rm -rf logs-intg-remote.txt
DOCKER_TAG=$(docker_tag) docker compose -f docker-compose-remote.yml up --wait
docker logs -f ldap-search-api-intg-remote > logs-intg-remote.txt &
./gradlew integrationTest --tests '*RemoteUrlsIntegrationSpec*'
docker-compose down
docker compose -f docker-compose-remote.yml down
build-all:
./gradlew build
fast-build:
Expand Down
39 changes: 20 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,25 @@ docker run --rm \

### Configurable properties

| Environment Variable Name | YAML Variable Name | Required | Default | Description |
|---------------------------------------|---------------------------------------|----------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| LDAP_HOST | ldap.host | true | (None) | The full host name of the LDAP server. Example: `ldaps://ldap.jumpcloud.com:636` |
| LDAP_USERNAME | ldap.username | true | (None) | The LDAP bind username. Could be a simple username like `devatherock` or a DN like `uid=devatherock,ou=Users,dc=jumpcloud,dc=com` depending on how the LDAP server is configured |
| LDAP_PASSWORD | ldap.password | true | (None) | The LDAP bind password |
| LDAP_BASE_DN | ldap.base-dn | false | (None) | The default base DN to search against |
| LDAP_BINARY_ATTRIBUTES | ldap.binary-attributes | false | (None) | Attributes in the search result that have binary values |
| LDAP_READ_TIMEOUT_MILLIS | ldap.read-timeout-millis | false | 10000 | Read timeout for the search, in milliseconds. Defaults to 10 seconds |
| LDAP_CONNECTION_POOL_ENABLED | ldap.connection-pool.enabled | false | true | Indicates if a connection pool should be used |
| LDAP_CONNECTION_POOL_CORE_SIZE | ldap.connection-pool.core-size | false | 8 | Initial size of the connection pool |
| LDAP_CONNECTION_POOL_MAX_SIZE | ldap.connection-pool.max-size | false | 8 | Maximum size of the connection pool |
| LDAP_CONNECTION_POOL_TIME_TO_LIVE_MILLIS | ldap.connection-pool.timeToLiveMillis | false | 1,800,000 | The total time a connection in the pool will be kept open, in milliseconds. Defaults to 30 minutes |
| LOGGER_LEVELS_ROOT | (None) | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for all(framework and custom) code |
| LOGGER_LEVELS_IO_GITHUB_DEVATHEROCK | (None) | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for custom code |
| MICRONAUT_SERVER_PORT | micronaut.server.port | false | 8080 | Port in which the app listens on |
| MICRONAUT_CONFIG_FILES | (None) | false | (None) | Path to YAML config files. The YAML files can be used to specify complex, object and array properties |
| JACKSON_SERIALIZATION_INDENT_OUTPUT | jackson.serialization.indent-output | false | (None) | Set to `true` to enable JSON pretty-print of response |
| LOGBACK_CONFIGURATION_FILE | (None) | false | (None) | Path to logback configuration file |
| Environment Variable Name | YAML Variable Name | Required | Default | Description |
|------------------------------------------|---------------------------------------|----------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| LDAP_HOST | ldap.host | true | (None) | The full host name of the LDAP server. Example: `ldaps://ldap.jumpcloud.com:636` |
| LDAP_USERNAME | ldap.username | false | (None) | The LDAP bind username. Could be a simple username like `devatherock` or a DN like `uid=devatherock,ou=Users,dc=jumpcloud,dc=com` depending on how the LDAP server is configured |
| LDAP_PASSWORD | ldap.password | false | (None) | The LDAP bind password |
| LDAP_AUTH_TYPE | ldap.auth-type | false | simple | Value for the `java.naming.security.authentication` property. Supported values are `none`, `simple`. Defaults to `simple` |
| LDAP_BASE_DN | ldap.base-dn | false | (None) | The default base DN to search against |
| LDAP_BINARY_ATTRIBUTES | ldap.binary-attributes | false | (None) | Attributes in the search result that have binary values |
| LDAP_READ_TIMEOUT_MILLIS | ldap.read-timeout-millis | false | 10000 | Read timeout for the search, in milliseconds. Defaults to 10 seconds |
| LDAP_CONNECTION_POOL_ENABLED | ldap.connection-pool.enabled | false | true | Indicates if a connection pool should be used |
| LDAP_CONNECTION_POOL_CORE_SIZE | ldap.connection-pool.core-size | false | 8 | Initial size of the connection pool |
| LDAP_CONNECTION_POOL_MAX_SIZE | ldap.connection-pool.max-size | false | 8 | Maximum size of the connection pool |
| LDAP_CONNECTION_POOL_TIME_TO_LIVE_MILLIS | ldap.connection-pool.timeToLiveMillis | false | 1,800,000 | The total time a connection in the pool will be kept open, in milliseconds. Defaults to 30 minutes |
| LOGGER_LEVELS_ROOT | (None) | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for all(framework and custom) code |
| LOGGER_LEVELS_IO_GITHUB_DEVATHEROCK | (None) | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for custom code |
| MICRONAUT_SERVER_PORT | micronaut.server.port | false | 8080 | Port in which the app listens on |
| MICRONAUT_CONFIG_FILES | (None) | false | (None) | Path to YAML config files. The YAML files can be used to specify complex, object and array properties |
| JACKSON_SERIALIZATION_INDENT_OUTPUT | jackson.serialization.indent-output | false | (None) | Set to `true` to enable JSON pretty-print of response |
| LOGBACK_CONFIGURATION_FILE | (None) | false | (None) | Path to logback configuration file |

### API spec
When the app is running, detailed API documentation can be accessed at `{host}/swagger-ui` or `{host}/swagger/ldap-search-api-{version}.yml`. The available endpoints are listed below for reference:
Expand Down Expand Up @@ -80,4 +81,4 @@ and set the environment variable `LOGBACK_CONFIGURATION_FILE` to `/path/to/custo

### JSON logs

Refer [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) documentation to customize the field names and formats in the log. To output logs as JSON, set the environment variable `LOGBACK_CONFIGURATION_FILE` to `logback-json.xml`
Refer [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) documentation to customize the field names and formats in the log. To output logs as JSON, set the environment variable `LOGBACK_CONFIGURATION_FILE` to `logback-json.xml`
28 changes: 28 additions & 0 deletions docker-compose-no-auth.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: '3.7'
services:

ldap-search-api:
image: devatherock/ldap-search-api:${DOCKER_TAG:-latest}
container_name: ldap-search-api-intg-no-auth
network_mode: "host"
environment:
LDAP_HOST: ldap://localhost:33389
LDAP_AUTH_TYPE: none
LOGBACK_CONFIGURATION_FILE: logback-json.xml
JACKSON_SERIALIZATION_INDENT_OUTPUT: true

health:
image: alpine:3.21.0
network_mode: "host"
depends_on:
- ldap-search-api
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:8080/health"]
interval: 2s
timeout: 60s
retries: 30
command: |
sh -c '
wget -q -O - http://localhost:8080/health
sleep 120
'
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package io.github.devatherock.ldapsearch.controllers

import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig
import io.micronaut.test.extensions.spock.annotation.MicronautTest

/**
* Integration test for {@link LdapSearchController}
* Integration test for {@link LdapSearchController} with auth
*/
@MicronautTest(propertySources = 'classpath:application-integration.yml', startApplication = false)
class LdapSearchControllerIntegrationSpec extends LdapSearchControllerSpec {

protected void customizeLdapConfig(InMemoryDirectoryServerConfig config) {
config.addAdditionalBindCredentials('cn=Directory Manager', 'testpwd')
}

protected String getExpectedJson() {
'''
[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.github.devatherock.ldapsearch.controllers

import io.micronaut.test.extensions.spock.annotation.MicronautTest

/**
* Integration test for {@link LdapSearchController} without auth
*/
@MicronautTest(propertySources = 'classpath:application-integration.yml', startApplication = false)
class LdapSearchControllerNoAuthIntegrationSpec extends LdapSearchControllerSpec {

protected String getExpectedJson() {
'''
[
{
"userPassword" : "YWJjZGU=",
"uid" : "sclaus",
"objectClass" : [
"top",
"person",
"organizationalPerson",
"inetOrgPerson"
],
"sn" : "Claus",
"cn" : "Santa Claus"
}
]
'''.stripIndent().trim()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.context.annotation.Context;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.core.util.StringUtils;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotBlank;
import lombok.AccessLevel;
import lombok.Getter;
Expand Down Expand Up @@ -37,15 +39,19 @@ public class LdapProperties {
* or a DN like {@code uid=devatherock,ou=Users,dc=jumpcloud,dc=com} depending
* on how the LDAP server is configured
*/
@NotBlank(message = "ldap.username not specified")
private String username;

/**
* The LDAP bind password
*/
@NotBlank(message = "ldap.password not specified")
private String password;

/**
* Value for the {@code java.naming.security.authentication} property. Defaults
* to {@code simple}
*/
private AuthenticationType authType = AuthenticationType.SIMPLE;

/**
* The default base DN to search against
*/
Expand All @@ -65,6 +71,12 @@ public class LdapProperties {

private LdapConnectionPoolProperties connectionPool = new LdapConnectionPoolProperties();

@AssertTrue(message = "ldap.username or ldap.password not specified")
public boolean isValidLdapCredentials() {
return AuthenticationType.NONE.equals(authType) ||
(StringUtils.hasText(username) && StringUtils.hasText(password));
}

/**
* Connection pool configuration
*
Expand Down Expand Up @@ -97,6 +109,18 @@ public static class LdapConnectionPoolProperties {
private long timeToLiveMillis = 1_800_000;
}

@Getter
public enum AuthenticationType {
NONE("none"),
SIMPLE("simple");

private final String code;

AuthenticationType(String code) {
this.code = code;
}
}

@PostConstruct
public void init() {
combinedBinaryAttributes = String.join(" ", binaryAttributes);
Expand Down
Loading

0 comments on commit 4b1cb1f

Please sign in to comment.