FreeIPA web call from Python

This was a response to a post of mine in 2010. The comment was unformatted in the response, and I wanted to get it readable. Its a great example of making a Kerberized web call.

Courtesy of Rich Megginson

Note: requires MIT kerberos 1.11 or later if you want to skip doing the kinit, and just let the script do the kinit implicitly with the keytab.

import kerberos
import sys
import os
from requests.auth import AuthBase
import requests
import json
 
class IPAAuth(AuthBase):
    def __init__(self, hostname, keytab):
        self.hostname = hostname
        self.keytab = keytab
        self.token = None
 
        self.refresh_auth()
 
    def __call__(self, request):
        if not self.token:
            self.refresh_auth()
 
        request.headers['Authorization'] = 'negotiate ' + self.token
 
        return request
 
    def refresh_auth(self):
        if self.keytab:
            os.environ['KRB5_CLIENT_KTNAME'] = self.keytab
        else:
            LOG.warn('No IPA client kerberos keytab file given')
        service = "HTTP@" + self.hostname
        flags = kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG
        try:
            (_, vc) = kerberos.authGSSClientInit(service, flags)
        except kerberos.GSSError, e:
            LOG.error("caught kerberos exception %r" % e)
            raise e
        try:
            kerberos.authGSSClientStep(vc, "")
        except kerberos.GSSError, e:
            LOG.error("caught kerberos exception %r" % e)
            raise e
        self.token = kerberos.authGSSClientResponse(vc)
 
 
hostname, url, keytab, cacert = sys.argv[1:]
 
request = requests.Session()
request.auth = IPAAuth(hostname, keytab)
ipaurl = 'https://%s/ipa' % hostname
jsonurl = url % {'hostname': hostname}
request.headers.update({'Content-Type': 'application/json',
                        'Referer': ipaurl})
request.verify = cacert
 
myargs = {'method': 'dnsrecord_add',
          'params': [["testdomain.com", "test4.testdomain.com"],
                     {'a_part_ip_address': '172.31.11.4'}],
          'id': 0}
resp = request.post(jsonurl, data=json.dumps(myargs))
print resp.json()
 
myargs = {'method': 'dnsrecord_find', 'params': [["testdomain.com"], {}], 'id': 0}
resp = request.post(jsonurl, data=json.dumps(myargs))
print resp.json()

Run the script like this:

python script.py ipahost.domain.tld ‘https://%(hostname)s/ipa/json’ myuser.keytab /etc/ipa/ca.crt

Using Certmonger to Generate a selfsign Cert for CMS

We want to replace the shell call to openssl for certificate generation in Keystone (and the rest of OpenStack) with calls to Certmonger. Certmonger supports both OpenSSL and NSS. Certmonger can support a selfsigned approach, as well as tie in to a real Certificate Authority. Here are the steps I took to test out selfsigning, as well as my notes for follow on work.
Continue reading

Splitting a patch

To make things easier for your code reviewer, each patch should be small, and hold one well defined change. I break this rule all the time, and it comes back to bite me. What happens is that I get heads down coding, and I have a solution that involves changes to wide number of files and subsystems, new abstractions, etc. Here is how I am currently dealing with breaking down a big patch.

Continue reading

Using the Openstack common client with Keystone

My last post showed how to load the user data using curl. This is only interesting if you love curl. Its pretty easy to do the same thing from the command line. Now, we at Keystone central hate responsibility. We have no desire to do more than we have to. That includes wrint the Command Line Client.

There is an effort afoot to move to a unified command line. Here is a sneak peek:

To get this to work took a little finagling: When a user gets a token, it contains the URL for the Keystone admin port, and the CLI uses this to perform the user create action. There is work going to to do better discoverability (figure out which version of the API is supported), but until then, you can do the following hack (not recommended for production)

Edit the database

 mysql --user keystone --password=keystone keystone

Make the admin URL V3 specific:

update endpoint set url='http://127.0.0.1:35357/v3'  where url like 'http://127.0.0.1:35357/%';

Restart Keystone.

And you can use the command:

export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=freeipa4all
export OS_TENANT_NAME=admin
openstack --os-identity-api-version=3  user create testname2 --password=testme --project=demo  --domain=default

So my previous example would be reduced to:

 while read USERNAME ; do openstack --os-identity-api-version=3    user create  $USERNAME  --password=changeme --project=demo  ; done  < usernames.txt