On my current project, my team is using FreeIPA to implement Single Sign-On (SSO) for all the employees at Coveros.  FreeIPA is an open-source security solution for the Linux operating system which provides account management and centralized authentication, similar to Microsoft’s Active Directory. It is built on top of multiple open source projects such as the 389 Directory Server, MIT Kerberos, and SSSD. SSO is a session and user authentication service that allows a user with a set of login credentials to access multiple applications. This convenient service authenticates the end user to all the applications that the user has access to and eliminates further logins when the user switches applications during the same session.

This project required us to implement a process to add current Coveros employees into FreeIPA as well as account for any future employees that will be onboarded. In order to deal with this problem, the following Python script was written.

This Python script takes in a CSV file as a parameter. Each line of the CSV file must contain the following elements in this order: first name, last name, email, group 1, group 2, …, group X. The script attempts to create a user with the username first name.last name if the user hasn’t been added to FreeIPA previously. If the user already exists in the system, the script moves on to the next user. After the user has been added successfully, the script attempts to add the user to the groups that are specified. The user is added to all valid group names in the list, and then the script moves on to the next user. Finally, the script creates a secure alphanumeric password of 20 characters and emails it to the user along with the username using Mutt.  Mutt is a very powerful text-based email client that has the ability to send emails directly from the terminal for Unix operating systems.

import csv
import os
import string
import random
import subprocess
import sys
def main(arg):
   try:
      PWD_SIZE = 20
      #opens CSV file of desired new users
      f = open(arg)
      csv_f = csv.reader(f)
      notAddedUsers = []
      #reads csv line by line, with the syntax [First,Last,Email,Role1,...,RoleX]
      for row in csv_f:
         try:
            #creates a 20 char long random alphanumeric password
            pwd = generate_temp_password(PWD_SIZE)
            firstname = row[0].strip()
            lastname = row[1].strip()
            username = firstname+"."+lastname
            email = row[2].strip()
            #creates an array containing all the roles
            groups = row[3:]
            #command to add the user to free ipa with username, first name, last name and email
            addUserCommand = ("ipa user-add " + username + " --first " + firstname + \
                              " --last " + lastname + " --email " + email)
            #command to set password for the user created in the previous step
            setUserPassCommand = ("ipa passwd " + username + " " + pwd)
            #try-except block to check if user is already in the system.
            #If the user is in the system, subprocess.CalledProcessError exception is thrown.
            #If it's a new user, the user is added and password is initialized. Then, the user is emailed with username and password
            try:
               subprocess.check_output(addUserCommand, stderr=subprocess.STDOUT, shell=True)
               subprocess.call(setUserPassCommand, shell=True)
               for group in groups:
               #attempts to add user to a role by role name or role id with allowing spaces in role names
                  try:
                     setUserRoleCommand = ("ipa group-add-member '" + group.strip() + "' --user " + username)
                     subprocess.check_output(setUserRoleCommand, stderr=subprocess.STDOUT, shell=True)
                     print(username + " has been added to the group: " + group.strip())
                  except(subprocess.CalledProcessError):
                     print("WARNING!!! " + username + " not added to " + group.strip())
               #using mutt to send email
               emailCommand = ("echo 'Hi " + firstname + " " + lastname + ", Your account has been created in free ipa. Your username is : " + \
                               username + " and password is " + pwd + ". You will be prompted to change your password after logging in initially.' | mutt -s 'Freeipa User Account Created' " + email)
               subprocess.call(emailCommand, shell=True)
               print(username + " created successfully")
               print("------------------------------")
            except(subprocess.CalledProcessError):
               print("WARNING!!!! " + username + " already exists")
               notAddedUsers.append(username)
         except(IndexError):
            print("Index out of range error")
            notAddedUsers.append(username)
      print "Users that were not added: " + ', '.join(notAddedUsers)
   except(IOError):
      print("Error opening file. Exiting program...")

#function to create a secure password
def generate_temp_password(length):
   chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
   return "".join(chars[ord(c) % len(chars)] for c in os.urandom(length))
if __name__ == '__main__':
   main(sys.argv[1])

 

This script saved my team and I many man hours. If each employee was added to the FreeIPA system manually, the process would have consumed more time. In order to add users manually, a user would need to be created from the user interface by specifying a username, first name, last name, and email address. Then, a secure password would need to be generated manually. Afterward, the user would need to be emailed with the username and password created in the previous steps. This process would need to be followed for every single employee at Coveros. However, the automated process that our script enables allows for all of these steps to be completed in a matter of seconds.

2 thoughts to “Create FreeIPA Users Script

  • Kristian

    Why are you running bash commands and not using the Python API for FreeIPA?

    Reply
  • Jester

    I tailored the username variable to restrict it from creating long ones since some Brazilians where I work have wicked complicated long names:

    username = firstname.lower()[:1]+””+lastname.lower()[:6]

    Also restricts to lowercase. Still I always get error: WARNING!!!! user already exists
    Not sure, why. I installed Mutt, so perhaps my ipa user-add is failing because of a different syntax. How would I get this script to actually display that output?

    Reply

Leave a comment

Your email address will not be published. Required fields are marked *

X