LDAP authentication for Gitolite

On my server I have an LDAP directory where all the users are stored. To use this for user authentication for GIT using Gitolite you will need 3 things…

First – Getting usergroup information from LDAP

The first source you should bounce in when trying to do this is . There you can read that you will need a script and setting 2 properties in .gitolite.rc:

  • $GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups"
  • $GL_BIG_CONFIG = 1;

The script is, as you can see, in out case located at: /usr/local/bin/expand-ldap-user-to-groups. It accepts one parameter and that is the user name. It searches the LDAP directory for the user’s primary group and all secondary groups. The result will be returned as a space separated list of group names. The script:

#!/bin/bash

USER=$1
GID=""
groups=""

BIND_DN="cn=admin,dc=poterion,dc=com"
BIND_PW="*****"

USERS_DN="ou=users,dc=poterion,dc=com"
GROUPS_DN="ou=groups,dc=poterion,dc=com"

LOGIN_KEY="uid"
GID_KEY="gidNumber"
GROUP_KEY="cn"
MEMBER_KEY="memberUid"

IFS="
"

currentLogin=""
currentGID=""
for line in `ldapsearch -h localhost -s one -D "${BIND_DN}" -w ${BIND_PW} -b ${USERS_DN} ${LOGIN_KEY} ${GID_KEY}`; do
        if [ "${line:0:1}" = "#" ]; then
                if [ ! -z $currentLogin ]; then
                        if [ "${currentLogin}" = "${USER}" ]; then
                                GID=$currentGID
                        fi
                        currentLogin=""
                        currentGID=""
                fi
        fi

        if [ "${line:0:${#LOGIN_KEY}}: " = "${LOGIN_KEY}: " ]; then
                currentLogin=`echo ${line} | cut -d":" -f2`
                currentLogin=${currentLogin:1}
        elif [ "${line:0:${#GID_KEY}}: " = "${GID_KEY}: " ]; then
                currentGID=`echo ${line} | cut -d":" -f2`
                currentGID=${currentGID:1}
        fi
done

currentGroup=""
currentMembers=""
currentGID=""
for line in `ldapsearch -h localhost -D "${BIND_DN}" -w ${BIND_PW} -b ${GROUPS_DN} ${GROUP_KEY} ${MEMBER_KEY} ${GID_KEY}`; do
        if [ "${line:0:1}" = "#" ]; then
                if [ ! -z $currentGroup ]; then
                        IFS=" "
                        for user in $currentMembers; do
                                if [ "${user}" = "${USER}" ]; then
                                        groups="${groups} ${currentGroup}"
                                        currentGID=""
                                fi
                        done
                        if [ "${currentGID}" = "${GID}" ]; then
                                groups="${groups} ${currentGroup}"
                        fi
                        currentGroup=""
                        currentMembers=""
                        currentGID=""
                fi
        fi

        if [ "${line:0:${#GROUP_KEY}}: " = "${GROUP_KEY}: " ]; then
                currentGroup=`echo ${line} | cut -d":" -f2`
                currentGroup=${currentGroup:1}
        elif [ "${line:0:${#MEMBER_KEY}}: " = "${MEMBER_KEY}: " ]; then
                user=`echo ${line} | cut -d":" -f2`
                user=${user:1}
                currentMembers="${currentMembers} ${user}"
        elif [ "${line:0:${#GID_KEY}}: " = "${GID_KEY}: " ]; then
                currentGID=`echo ${line} | cut -d":" -f2`
                currentGID=${currentGID:1}
        fi
        IFS="
"
done

if [ ! -z "${groups}" ]; then
        echo ${groups:1}
fi

Second – Password authentication with gitolite

You need to authenticate using a public key with Gitolite. This is neccessary since gitolite uses only one system user. Another option is to create each user on the system and hook the authentication as described in Enabling git access via password authentication with gitolite. The only difference in my script was adding an extra check for “virt-shell” group. This allows me to have a user who is able to use GIT via SSH but is not able to login to the shell controlled just by his membership in “virt-shell”. The resulting script is stored in /usr/bin/bash which should be also a shell in passwd for every user in the system.

#!/bin/bash
shift # get rid of -c

# if no commands, just open a shell
if [[ $# -eq 0 ]]; then
        if groups 2> /dev/null | grep -Eq ' host-diderma ' && groups 2> /dev/null | grep -Eq ' virt-shell ' ; then
                /bin/bash -l
        else
                echo "Error: Not member of host-diderma or virt-shell groups." >&2
        fi;

# if the first arg is a git- command, that means it is something like git-push, etc... so forward it
elif [[ $1 == git-* ]]; then
        ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no git@localhost $*

# if the first arg is SET_ENV_ONLY, we sourced this file in order to set up the gitolite function
elif [[ $1 == "SET_ENV_ONLY" ]]; then
        gitolite () {
                ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no git@localhost $*
        }

# if there is at least one non-git command, source this file in a new shell and create the 'gitolite' function
else
        /bin/bashplain -c "source $0 shiftme SET_ENV_ONLY; $*"
fi

Thirds

Last thing todo is to be able to add new user to Gitolite just by addind them to the LDAP directory. This can be accomplished using pam_script. I added a /var/lib/pam/scripts/onsessionopen/create-gitolite-user.sh:

#!/bin/bash

USERID=$1
GROUPID=$(getent group `getent passwd verena.geist | cut -d":" -f4` | cut -d":" -f1)
HOMEDIR=`getent passwd $USERID | cut -d":" -f6`
REPOS="/srv/git/repositories/"
REPO="gitolite-admin"
MACHINE="poterion-com"

if [ ! -f ${HOMEDIR}/.ssh/id_rsa.pub ]; then
        rm -rf ${HOMEDIR}/.ssh/id_rsa
        ssh-keygen -t rsa -N "" -f ${HOMEDIR}/.ssh/id_rsa
        chown ${USERID} ${HOMEDIR}/.ssh/id_rsa
        chgrp ${GROUPID} ${HOMEDIR}/.ssh/id_rsa
        chown ${USERID} ${HOMEDIR}/.ssh/id_rsa.pub
        chgrp ${GROUPID} ${HOMEDIR}/.ssh/id_rsa.pub
fi

CURDIR=`pwd`
cd /tmp
git clone ${REPOS}${REPO}.git ${REPO}
cd ${REPO}
KEY=keydir/${USERID}@${MACHINE}.pub

if [[ ! -f ${KEY} || -n `diff ${KEY} ${HOMEDIR}/.ssh/id_rsa.pub` ]]; then
       cp ${HOMEDIR}/.ssh/id_rsa.pub ${KEY};read
       git add -A;read
       git commit --author='PAM Script ' -m "Add/Update user ${USERID}.";read
       git push
fi

cd ..
rm -rf ${REPO}
cd $CURDIR

As soon as the user’s session is opened a ssh-key will be generated for him and added to Gitolite.

Leave a Reply

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