diff --git a/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/10validate_ldap_provider b/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/10validate_ldap_provider new file mode 100755 index 000000000..df2488d12 --- /dev/null +++ b/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/10validate_ldap_provider @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2021 Nethesis S.r.l. +# http://www.nethesis.it - nethserver@nethesis.it +# +# This script is part of NethServer. +# +# NethServer is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, +# or any later version. +# +# NethServer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with NethServer. If not, see COPYING. +# + +import sys +import json +import agent +import os +import cluster.userdomains + +# +# Sample request: +# { +# "domain":"example.com", +# "protocol": "ldap", +# "host":"18.19.20.21", +# "port": 636, +# "schema": "rfc2307", +# "bind_dn": "cn=ldapservice,dc=example,dc=com", +# "bind_password": "s3cret", +# "base_dn": "dc=example,dc=com", +# "tls": true, +# "tls_verify": true +# } +request = json.load(sys.stdin) + +domain = request['domain'] +protocol = request['protocol'] + +agent.set_weight(os.path.basename(__file__), 0) # Validation step, no task progress at all + +if protocol == 'ldap': + errors, logex = cluster.userdomains.validate_ldap(request) + + if logex: + print(agent.SD_ERR + f"{logex.__class__.__name__}: {logex}", file=sys.stderr) + + if errors: + agent.set_status('validation-failed') + json.dump(errors, fp=sys.stdout) + sys.exit(3) diff --git a/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/50add_ldap_domain b/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/50add_ldap_domain new file mode 100755 index 000000000..785f6e551 --- /dev/null +++ b/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/50add_ldap_domain @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2021 Nethesis S.r.l. +# http://www.nethesis.it - nethserver@nethesis.it +# +# This script is part of NethServer. +# +# NethServer is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, +# or any later version. +# +# NethServer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with NethServer. If not, see COPYING. +# + +import sys +import json +import agent +import cluster.userdomains +import os + +# +# Sample request: +# { +# "domain":"example.com", +# "protocol": "ldap", +# "host":"18.19.20.21", +# "port": 636, +# "schema": "rfc2307", +# "bind_dn": "cn=ldapservice,dc=example,dc=com", +# "bind_password": "s3cret", +# "base_dn": "dc=example,dc=com", +# "tls": true, +# "tls_verify": true +# } +request = json.load(sys.stdin) +domain = request['domain'] +protocol = request['protocol'] + +rdb = agent.redis_connect(privileged=True) + +if protocol == 'ldap': + trx = rdb.pipeline() + trx.hset(f"cluster/user_domain/ldap/{domain}/conf", mapping={ + 'schema': request.get('schema') or cluster.userdomains.probe_ldap_schema(request), + 'bind_dn': request['bind_dn'], + 'bind_password': request['bind_password'], + 'base_dn': request['base_dn'] or cluster.userdomains.probe_ldap_basedn(request), + 'tls': 'on' if request['tls'] else 'off', + 'tls_verify': 'on' if request['tls_verify'] else 'off', + }) + trx.rpush(f"cluster/user_domain/ldap/{domain}/providers", f"{request['host']}:{request['port']}") + + # + # Advertise new account provider setup + # + trx.publish(os.getenv('AGENT_ID') + '/event/ldap-provider-changed', json.dumps({ + 'domain': domain, + 'key': f"cluster/user_domain/ldap/{domain}/providers", + })) + trx.execute() diff --git a/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/validate-input.json b/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/validate-input.json new file mode 100644 index 000000000..cfb21bcc9 --- /dev/null +++ b/core/imageroot/var/lib/nethserver/cluster/actions/alter-external-domain/validate-input.json @@ -0,0 +1,140 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "alter-external-domain input", + "description": "Configure an external user domain", + "$id": "http://schema.nethserver.org/cluster/alter-external-domain-input.json", + "examples": [ + { + "domain": "example.com", + "protocol": "ldap", + "host": "18.19.20.21", + "port": 636, + "schema": "rfc2307", + "bind_dn": "cn=ldapservice,dc=example,dc=com", + "bind_password": "s3cret", + "base_dn": "dc=example,dc=com", + "tls": true, + "tls_verify": true + } + ], + "type": "object", + "required": [ + "domain", + "protocol" + ], + "properties": { + "domain": { + "type": "string", + "title": "User domain name", + "minLength": 1 + }, + "protocol": { + "type": "string", + "title": "Provider protocol", + "description": "Protocol used to communicate with the domain providers.", + "enum": [ + "ldap" + ] + } + }, + "anyOf": [ + { + "not": { + "type": "object", + "title": "Protocol property is ldap", + "properties": { + "protocol": { + "type": "string", + "const": "ldap" + } + } + } + }, + { + "type": "object", + "title": "LDAP-specific subschemas", + "allOf": [ + { + "$ref": "#/$defs/tcp-service-endpoint" + }, + { + "$ref": "#/$defs/additional-properties-of-ldap" + } + ] + } + ], + "$defs": { + "tcp-service-endpoint": { + "type": "object", + "title": "TCP service endpoint", + "description": "Initial TCP backend endpoint configuration", + "properties": { + "host": { + "type": "string", + "oneOf": [ + { + "format": "hostname" + }, + { + "format": "ipv6" + } + ] + }, + "port": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": [ + "host", + "port" + ] + }, + "additional-properties-of-ldap": { + "type": "object", + "title": "LDAP domain properties", + "description": "Additional required properties of LDAP-based domains", + "properties": { + "schema": { + "type": [ + "string", + "null" + ], + "title": "LDAP database schema", + "description": "The LDAP schema is probed automatically if the value is `null` or the property is missing", + "enum": [ + "ad", + "rfc2307" + ] + }, + "base_dn": { + "title": "Base DN", + "description": "The LDAP base DN is probed automatically if the value is `\"\"` (empty string)", + "type": "string" + }, + "bind_dn": { + "type": "string", + "minLength": 1 + }, + "bind_password": { + "type": "string", + "minLength": 1 + }, + "tls": { + "type": "boolean" + }, + "tls_verify": { + "type": "boolean" + } + }, + "required": [ + "base_dn", + "bind_dn", + "bind_password", + "tls", + "tls_verify" + ] + } + } +}