Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • bmi/opendesk/components/platform-development/images/user-import
1 result
Show changes
Commits on Source (3)
# [1.2.0](https://gitlab.opencode.de/bmi/opendesk/components/platform-development/images/user-import/compare/v1.1.0...v1.2.0) (2024-08-22)
### Features
* Support to set the openDesk flags (application access and admin) on commandline. ([04e4184](https://gitlab.opencode.de/bmi/opendesk/components/platform-development/images/user-import/commit/04e418411009f1bb71e6cb3dd2229bee26e2a50b))
# [1.1.0](https://gitlab.opencode.de/bmi/opendesk/components/platform-development/images/user-import/compare/v1.0.0...v1.1.0) (2024-07-01)
......
......@@ -9,9 +9,8 @@ SPDX-License-Identifier: Apache-2.0
This script allows you to either import an existing user list into an openDesk environment, or to create randomly generated fictitious users for it.
* [Prerequisites](#prerequisites)
* [Script](#script)
* [API](#api)
* [Container image](#container-image)
* [Running the script locally](#running-the-script-locally)
* [Running the script from within the container](#running-the-script-from-within-the-container)
* [Commandline](#commandline)
* [(Demo) Data](#demo-data)
* [Text files](#text-files)
......@@ -21,40 +20,27 @@ This script allows you to either import an existing user list into an openDesk e
# Prerequisites
## Script
- Credentials to use the [UDM REST API](https://docs.software-univention.de/developer-reference/latest/en/udm/rest-api.html), in openDesk the `default.admin` as well as other accounts that are part of the `Domain Admin` group are authorized to make us of the API. This will probably change in the future to use a less generic group to API use only.
- Access to the UDM REST API must be requested by the operator as by default that access is prohibited. In the openDesk deployment the attribute `functional.externalServices.nubus.udmRestApi.enabled` allows to toggle the service.
## Running the script locally
You have to have Python 3 and PIP installed. For Debian based systems you can get it done like this:
```
sudo apt install python3 python3-pip
```
Afterwards you install the script's requirements like:
```
pip install -r requirements.txt
```
## API
The account that is being used for the import has to be enabled for API usage be being part of a group that has API permissions, so we can
- create a group,
- add the API permissions to the group and
- add the user to the group
like this:
```
udm groups/group create \
--position="cn=groups,$(ucr get ldap/base)" \
--set name="UDM REST API Users"
ucr set directory/manager/rest/authorized-groups/udm-api-users="cn=UDM REST API Users,cn=groups,$(ucr get ldap/base)"
udm users/user modify --dn "uid=default.admin,cn=users,dc=swp-ldap,dc=internal" --append groups="cn=UDM REST API Users,cn=groups,$(ucr get ldap/base)"
```
In openDesk the `default.admin` account that is currently hardcoded in the script is already API enabled.
## Container image
## Running the script from within the container
You also can use the image that is build including the script and the necessary prerequisites.
```
export CONTAINER=<TDB>
export CONTAINER=registry.opencode.de/bmi/opendesk/components/platform-development/images/user-import:latest
docker run --rm -it ${CONTAINER} /bin/sh
```
......@@ -65,7 +51,7 @@ Execute
./user_import_udm_rest_api.py
```
and you will get information which parameter the script needs to run.
and you will get information which parameters the script requires and/or accepts.
**Note:** No actions will be taken if an user already exists on the import target.
......
......@@ -104,6 +104,16 @@ class Ucs:
)
logging.debug(f"{group_name}: {response}")
def __option2bool(self, string):
if isinstance(string, (bool)):
return string
elif string.lower() in ['true', 'yes', 'ok']:
return True
elif string.lower() in ['false', 'no', 'nok']:
return False
else:
sys.exit(f"Cannot convert {string} into a boolean value.")
def update_user(self, current_json, person):
# Domain Admin & Domain Users are set as primaryGroups
# The managed-by-attribute-* groups are automanaged anyway.
......@@ -125,7 +135,7 @@ class Ucs:
)
logging.debug(f"{person['username']}: has been updated.")
def create_user(self, person):
def create_user(self, person, options_object):
# https://<FQDN>/univention/udm/schema/ > users/user > POST
if 'groups' in person:
groups = self.__get_checked_groups(person['groups'])
......@@ -133,12 +143,13 @@ class Ucs:
groups = []
user_json = {
"properties": {
"isOxUser": not person['is_admin'],
"opendeskProjectmanagementAdmin": True,
"opendeskFileshareEnabled": not person['is_admin'],
"opendeskProjectmanagementEnabled": not person['is_admin'],
"opendeskKnowledgemanagementEnabled": not person['is_admin'],
"opendeskLivecollaborationEnabled": not person['is_admin'],
"isOxUser": (not person['is_admin'] and not self.__option2bool(options_object.component_disable_groupware)),
"opendeskFileshareEnabled": (not person['is_admin'] and not self.__option2bool(options_object.component_disable_fileshare)),
"opendeskProjectmanagementEnabled": (not person['is_admin'] and not self.__option2bool(options_object.component_disable_projectmanagement)),
"opendeskKnowledgemanagementEnabled": (not person['is_admin'] and not self.__option2bool(options_object.component_disable_knowledgemanagement)),
"opendeskLivecollaborationEnabled": (not person['is_admin'] and not self.__option2bool(options_object.component_disable_livecollaboration)),
"opendeskFileshareAdmin": self.__option2bool(options_object.admin_enable_fileshare),
"opendeskProjectmanagementAdmin": self.__option2bool(options_object.admin_enable_projectmanagement),
"mailPrimaryAddress": person['username']+"@"+self.maildomain,
"PasswordRecoveryEmail": person['email'],
"oxContext": 1,
......@@ -153,6 +164,7 @@ class Ucs:
},
"position": self.user_base
}
logging.debug
if 'is_admin' in person and person['is_admin'] is True:
user_json["properties"]["primaryGroup"] = "cn=Domain Admins,cn=groups,dc=swp-ldap,dc=internal"
else:
......@@ -183,21 +195,21 @@ class Ucs:
def get_counter(self):
return self.counter
def set_user(self, person, reconcile_groups = False):
def set_user(self, person, options_object):
self.user = None
self.user_updated = False
username = person['username']
dn = 'uid='+username+','+self.user_base
current_json = self.__get_object_json('user', dn)
if current_json:
if reconcile_groups:
if options_object.reconcile_groups:
logging.debug(f"Reconcile {username} groups to: {person['groups']}")
self.update_user(current_json, person)
else:
logging.warning(f"User {dn} already exists.")
else:
logging.info(f"Creating user {username}")
self.create_user(person)
self.create_user(person, options_object)
def __write_account_credentials(self, string):
file = open(self.account_output_filename, 'a')
......
......@@ -35,6 +35,13 @@ p.add('--create_admin_accounts', env_var='CREATE_ADMIN_ACCOUNTS', default=False,
p.add('--reconcile_groups', env_var='RECONCILE_GROUPS', default=False, help='Optional: Set to "True" if groups on the users should be reconciled based on the input file. Will remove all groups from the user not defined in sheet except for the standard groups: '+', '.join(non_reconcile_groups))
p.add('--set_default_password', env_var='SET_DEFAULT_PASSWORD', default='', help='Optional: When set the given password is used on the newly created accounts, otherwise a random one will be created.')
p.add('--password_recovery_email', env_var='PASSWORD_RECOVERY_EMAIL', help='Optional: When creating random accounts this password recovery email is used.')
p.add('--component_disable_groupware', env_var='COMPONENT_DISABLE_GROUPWARE', default=False, help='Optional: Set to "True" if users should not get the flag for groupware access')
p.add('--component_disable_fileshare', env_var='COMPONENT_DISABLE_FILESHARE', default=False, help='Optional: Set to "True" if users should not get the flag for fileshare access')
p.add('--component_disable_projectmanagement', env_var='COMPONENT_DISABLE_PROJECTMANAGEMENT', default=False, help='Optional: Set to "True" if users should not get the flag for projectmanagement access')
p.add('--component_disable_knowledgemanagement', env_var='COMPONENT_DISABLE_KNOWLEDGEMANAGEMENT', default=False, help='Optional: Set to "True" if users should not get the flag for knowledgemanagement access')
p.add('--component_disable_livecollaboration', env_var='COMPONENT_DISABLE_LIVECOLLABORATION', default=False, help='Optional: Set to "True" if users should not get the flag for livecollaboration access')
p.add('--admin_enable_fileshare', env_var='ADMIN_ENABLE_FILESHARE', default=False, help='Optional: Set to "True" if users should get functional admin permissions for fileshare component')
p.add('--admin_enable_projectmanagement', env_var='ADMIN_ENABLE_PROJECTMANAGEMENT', default=False, help='Optional: Set to "True" if users should get functional admin permissions for projectmanagement component')
p.add('--loglevel', env_var='LOGLEVEL', default='WARNING', help='Set the loglevel: DEBUG, INFO, WARNING, ERROR, CRITICAL. Default: WARNING')
p.add('--logpath', env_var='LOGPATH', default='./logs', help='Path where the script write its logfile to. Default: ./logs')
options = p.parse_args()
......@@ -63,7 +70,7 @@ def import_callback(person):
person['password'] = ''.join((secrets.choice('öäüÄÖÜß-+<>".,;:0123456789!$%&/()=[]{}<>|_#+*~?') for _ in range(16)))
else:
person['password'] = new_user_password
ucs.set_user(person, reconcile_groups = options.reconcile_groups)
ucs.set_user(person, options)
import_maildomain = options.import_domain if not options.import_maildomain else options.import_maildomain
......

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.