[SSSD] [DESIGN] Lookup Users by Certificate

Jakub Hrozek jhrozek at redhat.com
Fri May 15 08:14:21 UTC 2015


On Wed, May 13, 2015 at 12:06:07PM +0200, Sumit Bose wrote:
> Hi,
> 
> I have created a design page for the InfoPipe method to look up users
> based on a certificate as e.g. requested by
> https://fedorahosted.org/sssd/ticket/2596 . Most of it will be needed
> for certificate based authentication
> https://fedorahosted.org/sssd/ticket/546 as well. It is available at 
> 
> https://fedorahosted.org/sssd/wiki/DesignDocs/LookupUsersByCertificate
> 
> or for your convenience below.
> 
> Comments  and suggestions are welcome.

Hi,

I only have a couple of questions and comments. Mostly I agree with you,
thanks for the design page!

> 
> bye,
> Sumit
> 
> = Lookup Users by Certificate =
> 
> Related ticket(s):
>  * https://fedorahosted.org/sssd/ticket/2596
>  * https://fedorahosted.org/sssd/ticket/546
>  * https://fedorahosted.org/freeipa/ticket/4238 (design page: http://www.freeipa.org/page/V4/User_Certificates)
> 
> === Problem statement ===
> As stated in ticket #2596 applications doing user authentication based
> on certificates, e.g. web servers, need a way to map the certificate
> presented by the client to a specific user. Although there are various
> ways to derive a user name from special entries in the certificate
> so far there is no generally accepted scheme. The most general and in
> some cases the only possible way is to look up the certificate directly
> in the LDAP server. This requires that the certificate is stored in
> the LDAP server which we will assume for this initial design. (In
> a second part user lookups based on the certificate content will be
> added, this requires that the syntax for the mapping is specified in
> http://www.freeipa.org/page/V4/User_Certificates#Certificate_Identity_Mapping)
> 
> The primary interface to lookup users by certificate would be D-BUS.
> 
> === Use cases ===
> The primary use case is described in ticket #2596. If Apache is
> configured to use certificate based client authentication modules like
> mod_lookup_identity has access to the PAM encoded certificate via environment
                                        ~~~~~~~~~~~
                                PEM encoded, right? :-)

But later the design page talks about DER only..so PEM here was just an
example, correct?

> variables. With this data as input mod_lookup_identity should call a D-BUS
> method like ''org.freedesktop.sssd.infopipe.!GetUserAttrByCert'' which
> will return the data of the user the certificate belongs similar to the
> ''!GetUserAttr'' method.
> 
> === Overview of the solution ===
> Besides adding the D-Bus method to the !InfoPipe responder the generic LDAP
> backend should be able to search and read the certificate data if available
> from a LDAP server and store it to the cache. The internal sysdb interface
> must be extended to search cached entries with the certificate as input.
> 
> === Implementation details ===
> ==== LDAP backend ====
> Reading certificate data if available just requires adding a new user
> attribute which will be requested during LDAP searches for a user. In
> general the certificate is stored as a DER encoded binary on the LDAP
> server. '''Question: should we add an option like ldap_user_cert_encoding
> to support other encodings a server might send to us, or shall we add it
> only when there is a real use case?'''

I think we should keep it simple for the time being. A middle ground
might be to add the option, so an external contributor knows where to
extend the code, but only allow one value and state in the man page that
only DER is supported at the time being.

> Internally the certificate should
> be stored DER encoded to the cache as well because this encoding is the
> most unambiguous encoding (e.g. with PEM encoding it is not clear if the
> base64 blob should have line breaks or not and if the enclosing '-----BEGIN
> CERTIFICATE-----' and '-----END CERTIFICATE-----' should be stored as well
> and if line break should be added here or not?)
> 
> To search a user with the help of the certificate the DER encoded binary
> ticket must be transformed into a search filter. In this case it would be
> something like 'userCertificate=\23\a5\3e......' where each byte from the
> certificate is is represented by a hex value pre-pendened by a '\'. The
> filter should be generated in a subroutine which accepts the DER encoded
> certificate with base64 ascii armor and returns the search filter. This
> way the subroutine can later be extended to accept configuration options
> for the identity mapping and can return different search filters for those
> cases. Since the requirement for LDAP and sysdb search filters are the same
> there should be an option indicating if a LDAP or sysdb filter is needed,
> because the attribute names might be different.

Any reason to not just pass in the attr name and create a wrapper? Like:

const char *sss_cert_filter(const char *filter, const char *base64cert);

const char *sdap_cert_filter(struct sdap_options *opts, const char *base64cert)
{
    return sss_cert_filter(opts[SDAP_USER_CERT].name, base64cert);
}

const char *sysdb_cert_filter(const char *base64cert)
{
    return sss_cert_filter(SYSDB_USER_CERT, base64cert);
}

> 
> Although it would be possible to handle the binary DER data directly I think using a base64 ascii armor to handle the data as a string is useful to avoid adding code for handling binaries e.g. in the S-BUS requests to the backends.

Yes, I think this is a good idea to use an ASCII representation..

> 
> ==== SYSDB API ====
> A new call sysdb_search_user_by_cert() should be added which get the DER encoded certificate with base64 ascii armor as input and use the function described above to get a proper search filter. Currently it will be only the search filter for the binary certificate. Other than that the new call will act like to other sysdb_search_user_by_*() calls.
> 
> ==== !InfoPipe ====
> A new method GetUSerAttrByCert() must be implemented which expected

I agree with Pavel about object paths..

> the PEM encoded certificate and an array of attrbute names. '''Question:
> Should we only support PEM here or other formats as well? In this case
> we need a third parameter indicating the encoding of the certificate
> data.'''. 

I think it would make the API future-proof to add another parameter
where only one value would be supported. If anything else than DER is
used, than we throw an error. Pavel even adds support for custom D-Bus
errors in his latest patchset (currently still pending review).

Do you see any other extension we'd have to make in the API if we
decided to support other formats in the future?

> InfoPipe will convert the certificate into DER encoding with
> base64 ascii armor, search the cache and eventually forward the request to
> the backend. The request to the backend is processed similar to a request
> by name, only that a new filter name, e.g. DP_CERT_ID "cert", is needed.
> 
> Since it is in general not obvious to which domain a certificate belongs,
> the search must iterate over all domains in case no matching certificate
> was found. For the cases where there is a strong 1:1 relationship between
> the issuer of a certificate and a domain, configuration options for this
> can be added later.

What about default_domain_suffix? Do you plan to support domain-specific
searches in the code at all?

> 
> === Configuration changes ===
> A new user attribute open 'ldap_user_certificate' will be added to the
> LDAP provider. By default only the IPA provider will set a value for
> it to avoid reading about 1k of data which is not needed in the other
> providers. '''Question: Does this make sense or shall we enable it for
> other providers as well?'''

No, not in the beginning. From the experience with SSH keys I assume
we'll be asked sooner or later, so we shouldn't make it hard for
contributors to extend the support to the LDAP provider, but I don't
think we need to do it ourselves, not now.

> 
> === How To Test ===
> First a certificate must be load to a IPA user entry, it can be any kind of
> certificate as long as it is valid an DER or PEM encoded.

So..which encoding do we support? The ldap_user_cert_encoding proposal
made it sound like only DER would be?

> Until IPA has some
> import utilities ldapmodify should be used. A LDIF file might look like this:
> {{{
> dn: uid=cert_user,cn=users,cn=accounts,dc=ipa,dc=devel
> changetype: modify
> add: userCertificate
> userCertificate::MII...=
> }}}
> 
> where MII...= indicates the base64 encoded certificate data. If you have a PEM encoded certificate you can just use the base64 part here. If the certificate is DER encoded it can be transformed to base64 with
> {{{
> base64 < ./certificate_file.der | tr -d '\n'
> }}}
> 
> Testing can be done with the help of the dbus-send utility:
> {{{
> # dbus-send --system --print-reply  --dest=org.freedesktop.sssd.infopipe \
>                                          /org/freedesktop/sssd/infopipe \
>                                          org.freedesktop.sssd.infopipe.GetUserAttrByCert
>                                          string:"-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----" \
>                                          array:string:"name","uidNumber"
> method return sender=:1.1807 -> dest=:1.1819 reply_serial=2
>    array [
>       dict entry(
>          string "name"
>          variant             array [
>                string "cert_user"
>             ]
>       )
>       dict entry(
>          string "uidNumber"
>          variant             array [
>                string "1234567"
>             ]
>       )
>    ]
> 
> }}}

This would return an object path, but otherwise ACK
> 
> 
> === Authors ===
> * Sumit Bose <sbose at redhat.com>



More information about the sssd-devel mailing list