Integrating kerberised and shibboleth based authentication
Die web authorisierung von benutzer basiert am KIT auf shibboleth und idp. Allerdings gibt es eine menge 'legacy' produkten und services wofuer eine integration mit dieses neue verfahren erforderlich ist. Damit Linux und Linux services weiterhin mit der web welt mithalten koennen soll in dieses projekt untersucht werden wie das Network File System (NFS) transparent integriert werden kan in die neue KIT authorisirung.
Test change.
General scheme how to add Kerberos authentication to service
1. Add the service account to LDAP with random password, for example nfs/iwrcgop1.fzk.de@TEST.KIT.EDU:
dn: uid=nfs1,ou=users,ou=fed,dc=test,dc=kit,dc=edu objectClass: top objectClass: organizationalUnit objectClass: krb5kdcentry objectClass: uidObject objectClass: krb5principal krb5KeyVersionNumber: 0 krb5PrincipalName: nfs1/iwrcgop1.fzk.de@TEST.KIT.EDU ou: NFS1 uid: nfs1 userPassword: KJ983432989bfjsbJHdab4
2. Get service keys in keytab format. An example of a script:
#!/usr/bin/env python2
# Alexander Bersenev, bay@hackerdom.ru, 2015
# 1. Gets a keys from the service
# 2. Prints the keys in the keytab format
# Works only with apacheDS
from pyasn1.codec.der import decoder
import ldap
import random
import sys
import user
import re
import string
import struct
import time
LDAP_URI = "ldap://host.kit.edu:10389"
USERS_DN = "ou=users,ou=fed,dc=test,dc=kit,dc=edu"
REALM = "TEST.KIT.EDU"
def get_user_keys_classes_and_passwd(user, ldap_obj):
"""Tries to get a key and password from ldap"""
keys = []
classes = []
passwd = None
user_dn = ("uid=%s," % user) + USERS_DN
# make a ldap search request
pairs = ldap_obj.search_s(user_dn, ldap.SCOPE_BASE)
if len(pairs) != 1:
# wrong LDAP scheme
print("Multiple users")
return keys, classes, passwd
dn, attrs = pairs[0]
if "krb5Key" in attrs:
keys = attrs["krb5Key"]
if "objectClass" in attrs:
classes = attrs["objectClass"]
if "userPassword" in attrs:
passwd = attrs["userPassword"]
return keys, classes, passwd
def put_and_get_keys(user):
keys = None
try:
l = ldap.initialize(LDAP_URI)
keys, classes, passwd = get_user_keys_classes_and_passwd(user, l)
if keys:
return keys
except ldap.NO_SUCH_OBJECT:
print("No such user")
return keys
except ldap.OBJECT_CLASS_VIOLATION as E:
print("Object class violation")
# print(E)
except ldap.LDAPError as E:
print("LDAP Error")
# print(E)
return keys
def gen_keytab(keys, service, host):
entries = []
for key_type, key_val in keys:
entry = ""
entry += struct.pack(">H", 2) # number of components
entry += struct.pack(">H", len(REALM))
entry += REALM
entry += struct.pack(">H", len(service))
entry += service
entry += struct.pack(">H", len(host))
entry += host
entry += struct.pack(">L", 1) # name type(1 is KRB5_NT_PRINCIPAL)
entry += struct.pack(">L", int(time.time())) # generation time
entry += struct.pack("B", 1) # key version
entry += struct.pack(">H", key_type)
entry += struct.pack(">H", len(key_val))
entry += key_val
entry = struct.pack(">L", len(entry)) + entry
entries.append(entry)
keytab = "\x05\x02" # version of the format
keytab += "".join(entries)
return keytab
def main(user, service, host):
keys = put_and_get_keys(user)
if not keys:
return
decoded_keys = []
for key in keys:
try:
key_type, key_val = decoder.decode(key)[0]
key_type = int(key_type)
key_val = str(key_val)
decoded_keys.append((key_type, key_val))
except Exception:
print("Passing a bad key")
pass
sys.stdout.write(gen_keytab(decoded_keys, service, host))
if __name__ == "__main__":
if len(sys.argv) != 4:
print("USAGE: ./get_service_key.py <user> <service> <host>")
sys.exit(1)
user, service, host = sys.argv[1:]
if not re.match(r"[ a-zA-Z0-9_-]+$", user):
print("User name validation failed")
sys.exit(1)
if len(user) > 16384:
print("User name is too long")
sys.exit(1)
main(user, service, host)
3. Specify the service to use Kerberos and provide generated keytab file(the default path is usually /etc/krb5.keytab)
4. Set up additional service-specific things. For example, in the case of NFS, make users resolvable via LDAP