Skip to content

Commit 4968624

Browse files
committed
fix for groups and case sensitive, enable https support, improve readme
1 parent c3b3313 commit 4968624

File tree

4 files changed

+42
-16
lines changed

4 files changed

+42
-16
lines changed

Dockerfile

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ ENV LDAP_SEARCH_BASE=""
88
ENV LDAP_SEARCH_FILTER=""
99
ENV LDAP_REQUIRED_GROUPS=""
1010
ENV LDAP_REQUIRED_GROUPS_CONDITIONAL="and"
11+
ENV LDAP_REQUIRED_GROUPS_CASE_SENSITIVE="enabled"
12+
ENV LDAP_HTTPS_SUPPORT="disabled"
1113

1214
ENV PYTHONUNBUFFERED=0
1315

14-
RUN apk --no-cache add build-base openldap-dev
15-
RUN pip install --no-cache-dir flask Flask-HTTPAuth python-ldap
16+
RUN apk --no-cache add build-base openldap-dev libffi-dev
17+
RUN pip install --no-cache-dir flask Flask-HTTPAuth python-ldap pyopenssl
1618
COPY files/* /opt/
1719

1820
EXPOSE 9000

README.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,20 @@
44

55
**Another LDAP Authentication** is an implementation of the `ldap-auth-daemon` services described in the official blog from Nginx in the [following article](https://www.nginx.com/blog/nginx-plus-authenticate-users/).
66

7-
**Another LDAP Authentication** it's prepared to run inside a Docker container, also you can run the Python script without the Docker container. Supports `ldap` and `ldaps` and provide a simple cache.
7+
**Another LDAP Authentication** it's prepared to run inside a Docker container, also you can run the Python script without the Docker container.
88

99
[![Docker Hub](https://img.shields.io/badge/Docker-Hub-blue.svg)](https://hub.docker.com/r/dignajar/another-ldap-auth)
1010

11-
[![Kubernetes](https://img.shields.io/badge/Kubernetes-Deployment-blue.svg)](https://github.com/dignajar/another-ldap-auth#deploy-in-kubernetes-with-nginx-ingress-controller)
11+
[![Kubernetes YAML manifests](https://img.shields.io/badge/Kubernetes-Deployment-blue.svg)](https://github.com/dignajar/another-ldap-auth/tree/master/kubernetes)
12+
13+
## Features
14+
- Supports `ldap` and `ldaps`.
15+
- Provide a cache for users, you can limit the time of the cache.
16+
- Supports validation groups.
17+
- Supports validation groups with conditionals and regex.
18+
- Supports configuration via headers or via environment variables.
19+
- Supports HTTP response headers such as username and matched groups.
20+
- Log format in Plain-Text or JSON.
1221

1322
## Diagram
1423
![Another LDAP Authentication](https://i.ibb.co/Fn1ncbP/another-ldap-authentication.jpg)
@@ -33,8 +42,9 @@ All values type are `string`.
3342
| LDAP_REQUIRED_GROUPS_CONDITIONAL | `and` | `and`, `or` | Conditional to match all the groups in the list or just one of them. | `or` |
3443
| LDAP_REQUIRED_GROUPS_CASE_SENSITIVE | `enabled` | `enabled`, `disabled` | Enabled or disabled case sensitive groups matches. | `disabled` |
3544
| CACHE_EXPIRATION | `5` | | Cache expiration time in minutes. | `10` |
36-
| LOG_LEVEL | `INFO` | `DEBUG`, `INFO`, `WARN`, `ERROR` | Logger level. | `DEBUG` |
45+
| LOG_LEVEL | `INFO` | `INFO`, `WARNING`, `ERROR` | Logger level. | `DEBUG` |
3746
| LOG_FORMAT | `TEXT` | `TEXT`, `JSON` | Output format of the logger. | `JSON` |
47+
| LDAP_HTTPS_SUPPORT | `disabled`| `enabled`, `disabled` | Enabled or disabled HTTPS support with self signed certificate. | |
3848

3949
### HTTP request headers
4050
The variables send via HTTP headers take precedence over environment variables.

files/aldap.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def findMatch(self, group:str, ADGroup:str):
7878
ADGroup = re.match('CN=((\w*\s?_?]*)*)', ADGroup).group(1)
7979

8080
if not self.groupCaseSensitive:
81-
group = group.lower()
81+
ADGroup = ADGroup.lower()
8282

8383
# return match against supplied group/pattern (None if there is no match)
8484
try:
@@ -110,21 +110,21 @@ def validateGroups(self, groups):
110110
matchesByGroup.append((group,matches))
111111
matchedGroups.extend(matches)
112112

113-
self.logs.info({'message':'Validating groups.', 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
113+
self.logs.info({'message':'Validating groups.', 'username': self.username, 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
114114

115115
# Conditiona OR, true if just 1 group match
116116
if self.groupConditional == 'or':
117117
if matchedGroups:
118-
self.logs.info({'message':'At least one group is valid for the user.', 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
118+
self.logs.info({'message':'At least one group is valid for the user.', 'username': self.username, 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
119119
return True,matchedGroups
120120
# Conditiona AND, true if all the groups match
121121
elif self.groupConditional == 'and':
122122
if len(groups) == len(matchesByGroup):
123-
self.logs.info({'message':'All groups are valid for the user.', 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
123+
self.logs.info({'message':'All groups are valid for the user.', 'username': self.username, 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
124124
return True,matchedGroups
125125
else:
126-
self.logs.warning({'message':'Invalid group conditional.', 'conditional': self.groupConditional})
126+
self.logs.error({'message':'Invalid group conditional.', 'username': self.username, 'conditional': self.groupConditional})
127127
return False,[]
128128

129+
self.logs.error({'message':'Invalid groups for the user.', 'username': self.username, 'matchedGroups': ','.join(matchedGroups), 'groups': ','.join(groups), 'conditional': self.groupConditional})
129130
return False,[]
130-

files/main.py

+19-5
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,23 @@ def login(username, password):
7070
LDAP_REQUIRED_GROUPS_CONDITIONAL = environ["LDAP_REQUIRED_GROUPS_CONDITIONAL"]
7171

7272
# The default is "enabled", another option is "disabled"
73-
LDAP_REQUIRED_GROUPS_CASE_SENSITIVE = "enabled"
73+
LDAP_REQUIRED_GROUPS_CASE_SENSITIVE = True
7474
if "Ldap-Required-Groups-Case-Sensitive" in request.headers:
75-
LDAP_REQUIRED_GROUPS_CASE_SENSITIVE = request.headers["Ldap-Required-Groups-Case-Sensitive"] =='enabled'
75+
LDAP_REQUIRED_GROUPS_CASE_SENSITIVE = (request.headers["Ldap-Required-Groups-Case-Sensitive"] == "enabled")
7676
elif "LDAP_REQUIRED_GROUPS_CASE_SENSITIVE" in environ:
77-
LDAP_REQUIRED_GROUPS_CASE_SENSITIVE = environ["LDAP_REQUIRED_GROUPS_CASE_SENSITIVE"] =='enabled'
77+
LDAP_REQUIRED_GROUPS_CASE_SENSITIVE = (environ["LDAP_REQUIRED_GROUPS_CASE_SENSITIVE"] == "enabled")
7878

7979
LDAP_SERVER_DOMAIN = ""
8080
if "Ldap-Server-Domain" in request.headers:
8181
LDAP_SERVER_DOMAIN = request.headers["Ldap-Server-Domain"]
8282
elif "LDAP_SERVER_DOMAIN" in environ:
8383
LDAP_SERVER_DOMAIN = environ["LDAP_SERVER_DOMAIN"]
84+
85+
LDAP_HTTPS_SUPPORT = False
86+
if "Ldap-Http-Support" in request.headers:
87+
LDAP_HTTPS_SUPPORT = (request.headers["Ldap-Http-Support"] == "disabled")
88+
elif "LDAP_HTTPS_SUPPORT" in environ:
89+
LDAP_HTTPS_SUPPORT = (environ["LDAP_HTTPS_SUPPORT"] == "disabled")
8490
except KeyError as e:
8591
logs.error({'message': 'Invalid parameter'})
8692
return False
@@ -115,7 +121,8 @@ def login(username, password):
115121
groups = LDAP_REQUIRED_GROUPS.split(",") # Split the groups by comma and trim
116122
groups = [x.strip() for x in groups] # Remove spaces
117123
if not LDAP_REQUIRED_GROUPS_CASE_SENSITIVE:
118-
groups = groups.lower()
124+
groups = [x.lower() for x in groups] # Convert to lowercase
125+
print(groups)
119126
validGroups, matchesGroups = aldap.validateGroups(groups)
120127
if not validGroups:
121128
return False
@@ -137,4 +144,11 @@ def index(path):
137144

138145
# Main
139146
if __name__ == '__main__':
140-
app.run(host='0.0.0.0', port=9000, debug=False)
147+
LDAP_HTTPS_SUPPORT = False
148+
if "LDAP_HTTPS_SUPPORT" in environ:
149+
LDAP_HTTPS_SUPPORT = (environ["LDAP_HTTPS_SUPPORT"] == "enabled")
150+
151+
if LDAP_HTTPS_SUPPORT:
152+
app.run(host='0.0.0.0', port=9000, debug=False, ssl_context='adhoc')
153+
else:
154+
app.run(host='0.0.0.0', port=9000, debug=False)

0 commit comments

Comments
 (0)