├── .gitignore ├── README ├── ldap-schema ├── README ├── schema2olc ├── yubikey-SunDS.ldif ├── yubikey-add.ldif ├── yubikey.ldif └── yubikey.schema ├── microsoft-schema ├── README.md ├── adminContextMenuUpdate.ldif ├── ms-yubikey.ldif └── yubikeyid.vbs ├── samba4-schema ├── README.md ├── s4-updateUserClass.ldif ├── s4-yubikeyid.ldif └── s4-yubikeyuser.ldif ├── yubikey-ldap └── yubikey-ldap.conf.sample /.gitignore: -------------------------------------------------------------------------------- 1 | # Local config file 2 | yubikey-ldap.conf 3 | 4 | # compiled Python modules 5 | *.py[co] 6 | 7 | # Packages 8 | *.egg 9 | *.egg-info 10 | dist 11 | build 12 | eggs 13 | parts 14 | bin 15 | var 16 | sdist 17 | develop-eggs 18 | .installed.cfg 19 | 20 | # Installer logs 21 | pip-log.txt 22 | 23 | # Unit test / coverage reports 24 | .coverage 25 | .tox 26 | 27 | #Translations 28 | *.mo 29 | 30 | #Mr Developer 31 | .mr.developer.cfg 32 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | yubikey-ldap tool 2 | ================= 3 | 4 | This tool simplifies the management of YubiKeys stored in LDAP 5 | for user authentication. It can easily do the following: 6 | 7 | * Add/Remove 'yubiKeyId' attribute to/from users 8 | * Search for users who have a yubiKeyId assigned 9 | 10 | That's about it, really :) 11 | 12 | Behind the scenes it does a little more to facilitate the above: 13 | 14 | * Autocompletes usernames 15 | * Adds 'yubiKeyUser' objectClass to the user's record before when needed 16 | 17 | YubiKey LDAP schema 18 | ------------------- 19 | 20 | As a prerequisite the YubiKey LDAP schema must be installed in your 21 | server. Refer to 'ldap-schema/README' for more details. 22 | 23 | Configuration 24 | ------------- 25 | 26 | At the moment the config file 'yubikey-ldap.conf' must be in your current 27 | working directory at the time you launch yubikey-ldap. Later on we will 28 | add some more intelligence and configurable config location. 29 | 30 | Use the provided 'yubikey-ldap.conf.sample' as a template. 31 | 32 | Example 33 | ------- 34 | 35 | $HOME/yubikey-ldap # ./yubikey-ldap 36 | Use to exit at any time 37 | Use to return one level up 38 | 39 | Enter username ( to autocomplete) or YubiKey Id to manage 40 | Username or YubiKey: test 41 | Username or YubiKey: test.user 42 | 43 | Test User [test.user] has no assigned YubiKeys 44 | (a) add / change user 45 | Command: a 46 | Enter YubiKey ID (12 chars minimum, best way is to touch the key) 47 | YubiKey ID: ccccccbhkiivinkrcvfkdkttbfjkhtvggnvdchfjkvgt 48 | 49 | Assigning YubiKey 'ccccccbhkiiv' to 'test.user' 50 | Commit? [Y/n] 51 | 52 | Test User [test.user] has 1 assigned YubiKey 53 | 1) ccccccbhkiiv 54 | (a) add / (d) delete / change user 55 | Command: d 56 | Test User [test.user] has 1 assigned YubiKey 57 | 1) ccccccbhkiiv 58 | 59 | Enter YubiKey or the index number. Enter when done. 60 | YubiKey to Delete: 1 61 | 62 | Test User [test.user] has no assigned YubiKeys 63 | (a) add / change user 64 | Command: 65 | 66 | $HOME/yubikey-ldap # 67 | 68 | Credits 69 | ------- 70 | 71 | Have you found this tool useful? 72 | Please consider a small PayPal donation at: 73 | 74 | http://logix.cz/michal/devel/yubikey-ldap/ 75 | 76 | Thanks! 77 | 78 | Michal Ludvig 79 | 80 | -------------------------------------------------------------------------------- /ldap-schema/README: -------------------------------------------------------------------------------- 1 | YubiKey schema for LDAP 2 | ======================= 3 | 4 | What? Why? 5 | ---------- 6 | 7 | PAM authentication with YubiKey requires a list of YubiKey IDs 8 | for each user who is allowed to login. Typically in the form of 9 | a system file, for example /etc/yubikeys with entries similar to 10 | these: 11 | 12 | joe.user:abcdefgh1234:xyzxyz123456:... 13 | some.one:hgfedcba9876:hijklmnopqrs:... 14 | 15 | The pam_yubico module is then used with authfile=/etc/yubikeys 16 | parameter: 17 | 18 | auth require pam_yubico.so authfile=/etc/yubikeys ... 19 | 20 | That works well for one or two servers. However once you begin 21 | deploying YubiKey authentication across a handful or more servers 22 | you soon realise that a manual synchronisation of /etc/yubikeys 23 | file is PITA. 24 | 25 | Since you already authenticate your users against LDAP it would 26 | only make sense to keep these YubiKey IDs in LDAP as well, 27 | together with all other user details. 28 | 29 | Sadly there seems to be no "official" LDAP schema provided by 30 | Yubico, the company behind YubiKeys. Their official stance, as of 31 | the time of this writing, is to store the YubiKey IDs in one of 32 | the unused LDAP attributes. What? Seriously? 33 | 34 | Search no more. Follow the instructions below to _cleanly_ add 35 | YubiKey IDs to your LDAP database: 36 | 37 | dn: uid=joe.user,ou=People,cn=example,cn=com 38 | objectClass: posixAccount 39 | objectClass: yubiKeyUser 40 | objectClass: ... 41 | uid: joe.user 42 | ... 43 | yubiKeyId: abcdefgh1234 44 | yubiKeyId: xyzxyz123456 45 | 46 | _This_ is the way to keep the YubiKey IDs in LDAP. Not through 47 | exploiting some 'department' or 'favouriteColour' attribute, OMG! 48 | 49 | 50 | Installation - OLC aka cn=config 51 | -------------------------------- 52 | 53 | Have you already migrated your LDAP server to OLC aka OnLine 54 | Configuration aka cn=schema? If you did your job is easy: 55 | 56 | ~$ ldapadd -W -x -D cn=admin,cn=config -f yubikey.ldif 57 | adding new entry "cn=yubikey,cn=schema,cn=config" 58 | 59 | (substitute cn=admin with whatever your cn=config RootDN is) 60 | 61 | To be sure it worked check out this new file: 62 | /etc/openldap/slapd.d/cn=config/cn=schema/cn={*}yubikey.ldif 63 | 64 | 65 | Installation - slapd.conf 66 | ------------------------- 67 | 68 | If you are still using the ancient slapd.conf based config and 69 | can't be bothered to meet the 21st century, well, here are the 70 | instructions: 71 | 72 | 1) Copy yubikey.schema to /etc/openldap/schema/ 73 | (make sure it's got the same permissions and if SELinux 74 | context [if used] as the other files in that directory). 75 | 76 | 2) Open /etc/openldap/slapd.conf and locate the section with 77 | schema includes. Add yubikey.schema at the end: 78 | include /etc/openldap/schema/yubikey.schema 79 | 80 | 3) Restart the slapd daemon. 81 | 82 | Installation - OpenDJ or Sun Directory Server 83 | --------------------------------------------- 84 | 85 | Copy the yubikey-SunDS.ldif file under the schema directory 86 | /config/schema/05-yubikey.ldif 87 | Restart the directory server. 88 | 89 | 90 | Figure out the YubiKey ID 91 | ------------------------- 92 | 93 | This is very simple - insert YubiKey to your USB slot, open a 94 | text editor and touch the key. You'll see something like: 95 | 96 | abcdefgh1234uunnvfjueirijbtkneubfdefgddkgflv 97 | ^^^^^^^^^^^^ 98 | 99 | The first 12 characters are the ID: abcdefgh1234 100 | Simple as that. 101 | 102 | 103 | Storing the YubiKey IDs 104 | ----------------------- 105 | 106 | Now that we've got the yubico schema installed it's time to 107 | store some keys. There are two steps involved: 108 | 109 | 1) Add 'objectClass: yubiKeyUser' to each .. well .. YubiKey User 110 | object. 111 | 2) Store his YubiKey IDs to .. well .. yubiKeyID attributes 112 | 113 | (Quite a self-explanatory naming, isn't it? ;) 114 | 115 | You can indeed use your LDAP manager of choice, or rely on the 116 | classic proven command line tools as we do here. 117 | 118 | Open yubikey-add.ldif and enter the following few lines (change 119 | the dn: and they yubiKeyId: values of course!): 120 | 121 | # 122 | # Sample LDIF that stores two YubiKey IDs to uid=joe.user 123 | # 124 | dn: uid=joe.user,ou=People,dc=example,dc=com 125 | changetype: modify 126 | add: objectClass 127 | objectClass: yubiKeyUser 128 | - 129 | add: yubiKeyId 130 | yubiKeyId: abcdefgh1234 131 | yubiKeyId: xyzxyz123456 132 | 133 | (no indentation, each line must start at the beginning of the row) 134 | 135 | Now run 'ldapmodify' to make the changes: 136 | ~# ldapmodify -W -x -D cn=Manager,dc=example,dc=com -f yubikey-add.ldif 137 | modifying entry "uid=joe.user,ou=People,dc=example,dc=com" 138 | 139 | Verify with ldapsearch: 140 | 141 | ~# ldapsearch -W -x -D cn=Manager,dc=example,dc=com '(uid=joe.user)' 142 | 143 | dn: uid=joe.user,ou=People,cn=example,cn=com 144 | objectClass: posixAccount 145 | objectClass: yubiKeyUser 146 | objectClass: ... 147 | uid: joe.user 148 | ... 149 | yubiKeyId: abcdefgh1234 150 | yubiKeyId: xyzxyz123456 151 | 152 | 153 | Using it in PAM 154 | --------------- 155 | 156 | Again this change is very simple. Simply replace authfile= with 157 | the LDAP parameters, i.e. from: 158 | 159 | auth require pam_yubico.so authfile=/etc/yubikeys ... 160 | 161 | To (ideally all on one line): 162 | 163 | auth require pam_yubico.so \ 164 | ldap_uri=ldap://ldap.example.com/ \ 165 | ldapdn=ou=People,dc=example,dc=com \ 166 | user_attr=uid \ 167 | yubi_attr=yubiKeyId ... 168 | 169 | That's it. Try to SSH to the target system as joe.user, enter the 170 | password immediately followed by the YubiKey and you should be 171 | logged in :) 172 | 173 | 174 | Troubleshooting 175 | --------------- 176 | 177 | If things don't quite work as expected check the following: 178 | 179 | - Is SELinux enabled? Are egress firewalls enabled? 180 | Note that for YubiCloud authentication the server daemon (e.g. 181 | sshd) has to make a HTTPS connection to the YubiCloud servers. 182 | Firewalls or SELinux may prevent it to do that. 183 | 184 | - Can the SSH server connect to LDAP server? 185 | Again, there could be a firewall, broken DNS, etc. 186 | 187 | - Can each user read its yubiKeyId LDAP attributes? 188 | Your LDAP access control lists (ACL) may prevent that (by 189 | default they shouldn't but check that with ldapsearch logging 190 | in as uid=joe.user. 191 | 192 | - Temporarily add 'debug' at the end of pam_yubico parameters 193 | list. It will spit out a lot of potentially useful debug 194 | informations. 195 | 196 | 197 | Credits 198 | ------- 199 | 200 | Have you found this schema & document useful? 201 | Then consider a small PayPal donation at: 202 | 203 | http://logix.cz/michal/devel/yubikey-ldap/ 204 | 205 | Thanks! 206 | 207 | Michal Ludvig 208 | 209 | -------------------------------------------------------------------------------- /ldap-schema/schema2olc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # Author: Michal Ludvig 4 | # Consider a small PayPal donation: 5 | # http://logix.cz/michal/devel/yubikey-ldap/ 6 | 7 | # License: Public Domain 8 | 9 | use strict; 10 | 11 | open SCH, $ARGV[0] or die("Usage: schema2oid \n"); 12 | 13 | my ($basename) = ($ARGV[0] =~ /\/*?([^\/]+)$/); 14 | my ($schemaname) = ($basename =~ /(.*)\.schema$/); 15 | 16 | my $cntObjectIdentifiers = 0; 17 | my $cntAttributeTypes = 0; 18 | my $cntObjectClasses = 0; 19 | 20 | print("# 21 | # >> automatically generated from: ${basename} << 22 | # 23 | 24 | dn: cn=$schemaname,cn=schema,cn=config 25 | objectClass: olcSchemaConfig 26 | cn: $schemaname 27 | "); 28 | 29 | while(<>) { 30 | next if /^\s*$/; 31 | $_ =~ s/^objectIdentifier\W/olcObjectIdentifier: {$cntObjectIdentifiers}/i and $cntObjectIdentifiers++; 32 | $_ =~ s/^attributeType\W/olcAttributeTypes: {$cntAttributeTypes}/i and $cntAttributeTypes++; 33 | $_ =~ s/^objectClass\W/olcObjectClasses: {$cntObjectClasses}/i and $cntObjectClasses++; 34 | print $_; 35 | } 36 | -------------------------------------------------------------------------------- /ldap-schema/yubikey-SunDS.ldif: -------------------------------------------------------------------------------- 1 | dn: cn=schema 2 | objectclass: top 3 | # 4 | # YubiKey LDAP schema for Sun Directory Server and OpenDJ 5 | # 6 | # Copy this file to /config/schema/05-yubikey.ldif 7 | # 8 | # Author: Michal Ludvig 9 | # Consider a small PayPal donation: 10 | # http://logix.cz/michal/devel/yubikey-ldap/ 11 | # 12 | # Converted for OpenDJ and Sun Directory Server by 13 | # Ludovic Poitou 14 | # 15 | attributeTypes: ( 1.3.6.1.4.1.40789.2012.11.1.2.1.1 16 | NAME 'yubiKeyId' 17 | DESC 'Yubico YubiKey ID' 18 | EQUALITY caseIgnoreIA5Match 19 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} ) 20 | objectClasses: ( 1.3.6.1.4.1.40789.2012.11.1.2.2.1 21 | NAME 'yubiKeyUser' 22 | DESC 'Yubico YubiKey User' 23 | SUP top 24 | AUXILIARY 25 | MAY ( yubiKeyId ) ) 26 | -------------------------------------------------------------------------------- /ldap-schema/yubikey-add.ldif: -------------------------------------------------------------------------------- 1 | # 2 | # Sample LDIF that stores two YubiKey IDs to uid=joe.user 3 | # 4 | dn: uid=joe.user,ou=People,dc=example,dc=com 5 | changetype: modify 6 | add: objectClass 7 | objectClass: yubiKeyUser 8 | - 9 | add: yubiKeyId 10 | yubiKeyId: abcdefgh1234 11 | yubiKeyId: xyzxyz123456 12 | -------------------------------------------------------------------------------- /ldap-schema/yubikey.ldif: -------------------------------------------------------------------------------- 1 | # 2 | # >> automatically generated from: yubikey.schema << 3 | # 4 | 5 | dn: cn=yubikey,cn=schema,cn=config 6 | objectClass: olcSchemaConfig 7 | cn: yubikey 8 | # 9 | # YubiKey LDAP schema 10 | # 11 | # Author: Michal Ludvig 12 | # Consider a small PayPal donation: 13 | # http://logix.cz/michal/devel/yubikey-ldap/ 14 | # 15 | # Common Logix OID structure 16 | # 1.3.6.1.4.1.40789..<1=SNMP/2=LDAP>.<...> 17 | olcObjectIdentifier: {0}lxYubiKeyPrj 1.3.6.1.4.1.40789.2012.11.1 18 | olcObjectIdentifier: {1}lxYkSNMP lxYubiKeyPrj:1 19 | olcObjectIdentifier: {2}lxYkLDAP lxYubiKeyPrj:2 20 | # YubiKey schema sub-tree 21 | olcObjectIdentifier: {3}lxYkAttribute lxYkLDAP:1 22 | olcObjectIdentifier: {4}lxYkObjectClass lxYkLDAP:2 23 | olcAttributeTypes: {0}( lxYkAttribute:1 24 | NAME 'yubiKeyId' 25 | DESC 'Yubico YubiKey ID' 26 | EQUALITY caseIgnoreIA5Match 27 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} ) 28 | olcObjectClasses: {0}( lxYkObjectClass:1 29 | NAME 'yubiKeyUser' 30 | DESC 'Yubico YubiKey User' 31 | SUP top 32 | AUXILIARY 33 | MAY ( yubiKeyId ) ) 34 | -------------------------------------------------------------------------------- /ldap-schema/yubikey.schema: -------------------------------------------------------------------------------- 1 | # 2 | # YubiKey LDAP schema 3 | # 4 | # Author: Michal Ludvig 5 | # Consider a small PayPal donation: 6 | # http://logix.cz/michal/devel/yubikey-ldap/ 7 | # 8 | 9 | # Common Logix OID structure 10 | # 1.3.6.1.4.1.40789..<1=SNMP/2=LDAP>.<...> 11 | objectIdentifier lxYubiKeyPrj 1.3.6.1.4.1.40789.2012.11.1 12 | objectIdentifier lxYkSNMP lxYubiKeyPrj:1 13 | objectIdentifier lxYkLDAP lxYubiKeyPrj:2 14 | 15 | # YubiKey schema sub-tree 16 | objectIdentifier lxYkAttribute lxYkLDAP:1 17 | objectIdentifier lxYkObjectClass lxYkLDAP:2 18 | 19 | attributetype ( lxYkAttribute:1 20 | NAME 'yubiKeyId' 21 | DESC 'Yubico YubiKey ID' 22 | EQUALITY caseIgnoreIA5Match 23 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} ) 24 | 25 | objectclass ( lxYkObjectClass:1 26 | NAME 'yubiKeyUser' 27 | DESC 'Yubico YubiKey User' 28 | SUP top 29 | AUXILIARY 30 | MAY ( yubiKeyId ) ) 31 | -------------------------------------------------------------------------------- /microsoft-schema/README.md: -------------------------------------------------------------------------------- 1 | YubiKey Implimentation in Microsft Active Directory 2 | =================================================== 3 | This is an implimentation of the Openldap implimentation by Michal Ludvig applied to Microsft Active Directory. 4 | 5 | Notes 6 | ----- 7 | 8 | You can use tools like ADSI Edit to manage the keys for users. 9 | There are also tutorials on the internet explaining how to crate a dialogue box / context menu tool for updating custom attributes in the Active Directory Server Admin tool. (dsa.msc) 10 | 11 | The included updateAdminContextMenu.ldif can be used to apply the required change to the context menu in ADUC. 12 | The included yubikey.vbs script is used by the new Admin Context Menu. 13 | 14 | For a complete tutorial on all of this look at: 15 | 16 | 17 | Attribute and Class Implimentation 18 | ---------------------------------- 19 | 20 | Log into a Windows Server 2003 as a domain administrator and start a 21 | command prompt. 22 | 23 | Then execute: 24 | 25 | ldifde -i -f path\to\ms-yubikey.ldif -j . 26 | 27 | You should see something like: 28 | 29 | 6 entries modified successfully 30 | 31 | The command has completed successfully 32 | 33 | To test if this is all working you could add some kuys using the ADSI Edit snap-in. 34 | 35 | * Browse to your Domain -> CN=Users 36 | * Right mouse click the username you want to edit 37 | * Select Properties 38 | * Scroll down to and select YubiKeyId 39 | * Click Edit 40 | * Add values until you are done 41 | * Click OK until you are finished. 42 | 43 | Update ADUC User Admin Context Menu 44 | ----------------------------------- 45 | 46 | Log into a Windows Server 2003 as a domain administrator and start a 47 | command prompt. 48 | 49 | Then execute: 50 | 51 | ldifde -i -f path\to\updateAdminContextMenu.ldif 52 | 53 | You should see something like: 54 | 55 | 2 entries modified successfully 56 | 57 | The command completed successfully 58 | 59 | Then copy yubikeyid.vbs to c:\yubikeyid.vbs 60 | 61 | To test: 62 | 63 | * To test if this works, open up the ADUC snap-in (dsa.msc) 64 | * browse to your Domain -> Users and Computers 65 | * right click on a user 66 | * select YubiKey ID 67 | * A dialogue box should appear where you can enter a semi-colon (;) seperated list of YubiKey IDs 68 | * Click OK to save. 69 | * To test if the key is saved, you can execute these preceeding steps again and view the key(s) displayed in the message box. 70 | 71 | Tested 72 | ------ 73 | 74 | 1. This ldif was successfully imported into a Samba4 AD from a Windows Server 2003 R2 Client. 75 | 2. This ldif was successfully imported into a Windows Server 2003 R2 Active Directory Domain. (IE: No Samba4 or Linux in site.) 76 | -------------------------------------------------------------------------------- /microsoft-schema/adminContextMenuUpdate.ldif: -------------------------------------------------------------------------------- 1 | # updateAdminContextMenu.ldif 2 | # 3 | # This ldif adds an entry into the Admin Context Menu on the US-English Display 4 | # sepcifier (CN=409) on User entries in ADUC. The context menu calls yubikeyid.vbs 5 | # that in-turn is used to add yubiKeyIds to the User. 6 | # 7 | # Implimentation: 8 | # ldifde -i -f updateAdminContextMenu.ldif -j . 9 | # 10 | # Author: David Latham 11 | # 12 | # 13 | # 14 | dn: CN=User-Display,CN=409,CN=DisplaySpecifiers,CN=Configuration,DC=LATHAM,DC=INTERNAL 15 | changetype: modify 16 | add: adminContextMenu 17 | adminContextMenu: 100,yubiKeyId,c:\yubikeyid.vbs 18 | - 19 | 20 | dn: 21 | changetype: modify 22 | add: schemaUpdateNow 23 | schemaUpdateNow: 1 24 | - 25 | -------------------------------------------------------------------------------- /microsoft-schema/ms-yubikey.ldif: -------------------------------------------------------------------------------- 1 | # 2 | # YubiKey LDAP schema for Microsoft Active Directory Server 3 | # 4 | # Install with ldifde -i -f path\to\yubikey-ads.ldif -j . 5 | # on a Windows Command prompt 6 | # 7 | # 8 | # Author: Michal Ludvig 9 | # Consider a small PayPal donation: 10 | # http://logix.cz/michal/devel/yubikey-ldap/ 11 | # 12 | # Converted to Microsoft Active Directory Server format by 13 | # David Latham 14 | # 15 | dn: CN=yubiKeyId,CN=Schema,CN=Configuration,DC=samba4,DC=internal 16 | changetype: add 17 | objectClass: top 18 | objectClass: attributeSchema 19 | cn: yubiKeyId 20 | description: Yubico YubiKey ID 21 | attributeID: 1.3.6.1.4.1.40789.2012.11.1.2.1.1 22 | attributeSyntax: 2.5.5.5 23 | isSingleValued: FALSE 24 | oMSyntax: 22 25 | lDAPDisplayName: yubiKeyId 26 | name: yubiKeyId 27 | 28 | dn: 29 | changetype: modify 30 | add: schemaUpdateNow 31 | schemaUpdateNow: 1 32 | - 33 | 34 | dn: CN=yubiKeyUser,CN=Schema,CN=Configuration,DC=samba4,DC=internal 35 | changetype: add 36 | objectClass: top 37 | objectClass: classSchema 38 | cn: yubiKeyUser 39 | description: Yubico YubiKey User 40 | subClassOf: top 41 | governsID: 1.3.6.1.4.1.40789.2012.11.1.2.2.1 42 | mayContain: yubiKeyId 43 | rDNAttID: cn 44 | objectClassCategory: 3 45 | lDAPDisplayName: yubiKeyUser 46 | name: yubiKeyUser 47 | 48 | dn: 49 | changetype: modify 50 | add: schemaUpdateNow 51 | schemaUpdateNow: 1 52 | - 53 | 54 | dn: CN=User,CN=Schema,CN=Configuration,DC=samba4,DC=internal 55 | changetype: modify 56 | add: auxiliaryClass 57 | auxiliaryClass: yubiKeyUser 58 | - 59 | 60 | dn: 61 | changetype: modify 62 | add: schemaUpdateNow 63 | schemaUpdateNow: 1 64 | - 65 | -------------------------------------------------------------------------------- /microsoft-schema/yubikeyid.vbs: -------------------------------------------------------------------------------- 1 | 'VBScript to add a semi-colon list of yubiKeyIds to a user via 2 | ' the right click menu (adminContextMenu) in ADUC. 3 | ' 4 | 'Please save this file in C:\yubikeyid.vbs 5 | 'and make sure you have updated the Schema Configuration with updateAdminContextMenu.ldif 6 | ' 7 | 'Author: David Latham 8 | ' 9 | 'Credits: 10 | ' Stack Overflow User: http://stackoverflow.com/users/107929/sh-beta 11 | ' 12 | ' 13 | Dim objYubikey 14 | Dim objUser 15 | Dim temp1, title, message, default 16 | Dim yubikeys 17 | title = "YubiKeys" 18 | 19 | Set objYubiKey = Wscript.Arguments 20 | Set objUser = GetObject(objYubiKey(0)) 21 | 22 | 'Find our current yubikeys 23 | yubikeys = objUser.yubiKeyId 24 | If Not isArray(yubikeys) Then 25 | yubikeys = Array(yubikeys) 26 | End If 27 | 28 | 'Setup our message box 29 | default = arrayToStr(yubikeys) 30 | message = "Semicolon-delimited list of YubiKeyIds" & vbCRLF & vbCRLF & default 31 | temp1 = InputBox(message, title, default) 32 | 33 | 'catch cancels 34 | if IsEmpty(temp1) Then 35 | WScript.Quit 36 | End If 37 | 38 | ' update our data 39 | yubikeys = strToArray(temp1) 40 | objUser.Put "yubiKeyId",yubikeys 41 | objUser.SetInfo 42 | 43 | 'Clean up and quit 44 | Set yubikeys = Nothing 45 | Set objUser = Nothing 46 | Set objProject = Nothing 47 | Set temp1 = Nothing 48 | Set title = Nothing 49 | Set message = Nothing 50 | Set default = Nothing 51 | WScript.Quit 52 | 53 | 'Functions 54 | Function strToArray(s) 55 | Dim a 56 | Dim token 57 | 58 | ' discard blank entries 59 | For Each token in split(s, ";") 60 | token = trim(token) 61 | If token <> "" Then 62 | If isEmpty(a) Then 63 | a = token 64 | Else 65 | a = a & ";" & token 66 | End If 67 | End If 68 | Next 69 | 70 | ' return array 71 | strToArray = split(a, ";") 72 | End Function 73 | Function arrayToStr(a) 74 | Dim s 75 | Dim token 76 | 77 | For Each token in a 78 | If isEmpty(s) Then 79 | s = token 80 | Else 81 | s = s & ";" & token 82 | End If 83 | Next 84 | 85 | ' return string 86 | arrayToStr = s 87 | End Function 88 | -------------------------------------------------------------------------------- /samba4-schema/README.md: -------------------------------------------------------------------------------- 1 | YubiKey LDIF Implimentation Into Samba4 Active Directory 2 | ======================================================= 3 | 4 | This is an implimentation of the Openldap implimentation by Michal Ludvig applied to Samba4 Active Directory. 5 | 6 | CAUTION 7 | ------- 8 | This process will permanently modify your schema. If it breaks you will not be able to recover unless from a backup. Please backup your schema files before starting. On a default install they can be found at /usr/local/samba/private/sam.ldb and all the files in /usr/local/samba/private/sam.ldb.d/ 9 | 10 | yubikeyid.ldif 11 | -------------- 12 | dn: CN=yubiKeyId,CN=Schema,CN=Configuration,dc=samba4,dc=internal 13 | changetype: add 14 | objectClass: top 15 | objectClass: attributeSchema 16 | attributeID: 1.3.6.1.4.1.40789.2012.11.1.2.1.1 17 | cn: yubiKeyId 18 | name: yubiKeyId 19 | lDAPDisplayName: yubiKeyId 20 | description: Yubico YubiKey ID 21 | attributeSyntax: 2.5.5.5 22 | oMSyntax: 22 23 | isSingleValued: FALSE 24 | 25 | Add the yubiKeyId attribute into the Schema Configuration first with: 26 | 27 | ldbadd -H /usr/local/samba/private/sam.ldb s4-yubikeyid.lidf --option="dsdb:schema update allowed"=true 28 | 29 | yubikeyuser.ldif 30 | ---------------- 31 | dn: CN=yubiKeyUser,CN=Schema,CN=Configuration,dc=samba4,dc=internal 32 | changetype: add 33 | objectClass: top 34 | objectClass: classSchema 35 | governsID: 1.3.6.1.4.1.40789.2012.11.1.2.2.1 36 | cn: yubiKeyUser 37 | name: yubiKeyUser 38 | lDAPDisplayName: yubiKeyUser 39 | description: Yubico YubiKey User 40 | subClassOf: top 41 | objectClassCategory: 3 42 | mayContain: yubiKeyId 43 | 44 | Next add the yubiKeyUser class into the Schema Configuration with: 45 | 46 | ldbadd -H /usr/local/samba/private/sam.ldb s4-yubikeyuser.lidf --option="dsdb:schema update allowed"=true 47 | 48 | updateUserClass.ldif 49 | -------------------- 50 | dn: CN=User,CN=Schema,CN=Configuration,DC=samba4,DC=internal 51 | changetype: modify 52 | add: auxiliaryClass 53 | auxiliaryClass: yubiKeyUser 54 | 55 | Apply the User class update with: 56 | 57 | ldbmodify -H /usr/local/samba/private/sam.ldb s4-updateUserClass.ldif --option="dsdb:schema update allowed"=true 58 | 59 | Add YubiKeys to Users 60 | --------------------- 61 | An example ldif: 62 | 63 | dn: CN=David Latham,CN=Users,DC=samba4,DC=internal 64 | changetype: modify 65 | add: objectClass 66 | objectClass: yubiKeyUser 67 | - 68 | add: yubiKeyId 69 | yubiKeyId: abcdefgh1234 70 | yubiKeyId: xyzxyz123456 71 | 72 | Apply it with: 73 | 74 | ldapmodify -h samba -f addKeyToUser.ldif 75 | 76 | Test it with: 77 | 78 | ldapsearch -h samba -b "CN=David Latham,CN=Users,DC=samba4,DC=internal" yubiKeyId 79 | 80 | SASL/GSSAPI authentication started 81 | SASL username: administrator@SAMBA4.INTERNAL 82 | SASL SSF: 56 83 | SASL data security layer installed. 84 | # extended LDIF 85 | # 86 | # LDAPv3 87 | # base with scope subtree 88 | # filter: (objectclass=*) 89 | # requesting: yubiKeyId 90 | # 91 | 92 | # David Latham, Users, samba4.internal 93 | dn: CN=David Latham,CN=Users,DC=samba4,DC=internal 94 | yubiKeyId: abcdefgh1234 95 | yubiKeyId: xyzxyz123456 96 | 97 | # search result 98 | search: 5 99 | result: 0 Success 100 | 101 | # numResponses: 2 102 | # numEntries: 1 103 | 104 | Acknowledgments 105 | =============== 106 | Michal Ludvig for defining the schema. 107 | Microsoft Documentation for information on attributeSyntax, oMSyntax and objecClassCategory 108 | -------------------------------------------------------------------------------- /samba4-schema/s4-updateUserClass.ldif: -------------------------------------------------------------------------------- 1 | # Update User schema to include yubiKeyUser Auxiliary class 2 | # for Samba4 Active Directory. 3 | # Ported from mludvig/yubikey-ldap and includes the logixOID 4 | # By David Latham 5 | # Install with: 6 | # ldbmodify -H /usr/local/samba/private/sam.ldb \ 7 | # s4-updateUserClass.ldif \ 8 | # --option="dsdb:schema update allowed"=true 9 | dn: CN=User,CN=Schema,CN=Configuration,DC=samba4,DC=internal 10 | changetype: modify 11 | add: auxiliaryClass 12 | auxiliaryClass: yubiKeyUser 13 | -------------------------------------------------------------------------------- /samba4-schema/s4-yubikeyid.ldif: -------------------------------------------------------------------------------- 1 | # yubiKeyId Schema Attribute for Samba4 Active Directory 2 | # Ported from mludvig/yubikey-ldap and includes the logixOID 3 | # By David Latham 4 | # Install with: 5 | # ldbadd -H /usr/local/samba/private/sam.ldb \ 6 | # s4-yubikeyid.lidf \ 7 | # --option="dsdb:schema update allowed"=true 8 | # 9 | dn: CN=yubiKeyId,CN=Schema,CN=Configuration,dc=samba4,dc=internal 10 | changetype: add 11 | objectClass: top 12 | objectClass: attributeSchema 13 | attributeID: 1.3.6.1.4.1.40789.2012.11.1.2.1.1 14 | cn: yubiKeyId 15 | name: yubiKeyId 16 | lDAPDisplayName: yubiKeyId 17 | description: Yubico YubiKey ID 18 | attributeSyntax: 2.5.5.5 19 | oMSyntax: 22 20 | isSingleValued: FALSE 21 | -------------------------------------------------------------------------------- /samba4-schema/s4-yubikeyuser.ldif: -------------------------------------------------------------------------------- 1 | # yubiKeyUser Schema Class for Samba4 Active Directory 2 | # Ported from mludvig/yubikey-ldap and includes the logixOID 3 | # By David Latham 4 | # Install with: 5 | # ldbadd -H /usr/local/samba/private/sam.ldb \ 6 | # s4-yubikeyuser.lidf \ 7 | # --option="dsdb:schema update allowed"=true 8 | # 9 | dn: CN=yubiKeyUser,CN=Schema,CN=Configuration,dc=samba4,dc=internal 10 | changetype: add 11 | objectClass: top 12 | objectClass: classSchema 13 | governsID: 1.3.6.1.4.1.40789.2012.11.1.2.2.1 14 | cn: yubiKeyUser 15 | name: yubiKeyUser 16 | lDAPDisplayName: yubiKeyUser 17 | description: Yubico YubiKey User 18 | subClassOf: top 19 | objectClassCategory: 3 20 | mayContain: yubiKeyId 21 | -------------------------------------------------------------------------------- /yubikey-ldap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # yubikey-ldap - script for managing YubiKeys stored in LDAP 4 | # Author: Michal Ludvig - http://logix.cz/michal/devel/yubikey-ldap/ 5 | # 6 | # Prereq: 7 | # - yubikey.schema installed in your LDAP server 8 | # - yubikey-ldap.conf configured (for now in the current directory) 9 | 10 | import sys 11 | import re 12 | import ldap 13 | import readline 14 | 15 | config_file = "yubikey-ldap.conf" 16 | 17 | class conf(object): 18 | uri = "" 19 | bind_dn = "" 20 | bind_pw = "" 21 | base_dn = "" 22 | start_tls = False 23 | tls_cacertfile = "" 24 | tls_cacertpath = "" 25 | yubi_id_len = 12 26 | 27 | class bcolours: 28 | YELLOW = '\033[93m' 29 | WHITE = '\033[97m' 30 | OKBLUE = '\033[94m' 31 | OKGREEN = '\033[92m' 32 | PURPLE = '\033[95m' 33 | RED = '\033[91m' 34 | BOLD = '\033[1m' 35 | PROMPT = '\033[96m' 36 | RESET = '\033[0m' 37 | 38 | @staticmethod 39 | def fmt(message, code): 40 | return code + message + bcolours.RESET 41 | 42 | @staticmethod 43 | def prompt_fmt(message): 44 | return bcolours.PROMPT + message + bcolours.RESET 45 | 46 | @staticmethod 47 | def header_fmt(message): 48 | return bcolours.WHITE + message + bcolours.RESET 49 | 50 | def debug(message): 51 | print("DEBUG: %s" % message) 52 | 53 | def info(message): 54 | print(bcolours.BOLD + bcolours.fmt("INFO: ", bcolours.YELLOW) + bcolours.RESET + bcolours.fmt(message, bcolours.YELLOW)) 55 | 56 | def warning(message): 57 | print(bcolours.BOLD + bcolours.fmt("WARNING: ", bcolours.PURPLE) + bcolours.RESET + bcolours.fmt(message, bcolours.PURPLE)) 58 | 59 | def error(message): 60 | print(bcolours.BOLD + bcolours.fmt("ERROR: ", bcolours.RED) + bcolours.RESET + bcolours.fmt(message, bcolours.RED)) 61 | 62 | def fatal(message, exitcode = 1): 63 | print(bcolours.BOLD + bcolours.fmt("FATAL: ", bcolours.RED) + bcolours.RESET + bcolours.fmt(message, bcolours.RED)) 64 | sys.exit(exitcode) 65 | 66 | def header(message): 67 | print bcolours.header_fmt(message) 68 | 69 | def our_input(prompt, **kwargs): 70 | return raw_input(bcolours.prompt_fmt(prompt), **kwargs) 71 | 72 | def uid2dn(uid): 73 | return "uid=%s,%s" % (uid, conf.base_dn) 74 | 75 | class LdapUidCompleter: 76 | def __init__(self, ldap_con, conf): 77 | self.words = [] 78 | self.prefix = None 79 | self.ldap_con = ldap_con 80 | self.conf = conf 81 | 82 | readline.set_completer(self.complete) 83 | readline.parse_and_bind("tab: complete") 84 | 85 | def get_uids_for_prefix(self, prefix): 86 | filterstr = "(uid=%s*)" % prefix 87 | attrlist = [ 'uid' ] 88 | res = self.ldap_con.search_s(self.conf.base_dn, ldap.SCOPE_SUBTREE, filterstr, attrlist) 89 | matches = [r[1]['uid'][0] for r in res] 90 | return matches 91 | 92 | def complete(self, prefix, index): 93 | if prefix != self.prefix: 94 | self.matching_words = self.get_uids_for_prefix(prefix) 95 | self.prefix = prefix 96 | 97 | try: 98 | return self.matching_words[index] 99 | except IndexError: 100 | return None 101 | 102 | class YubiKeyManager(object): 103 | def __init__(self, conf): 104 | self.conf = conf 105 | 106 | # Connect to the LDAP server 107 | try: 108 | self.con = ldap.initialize(conf.uri) 109 | if conf.start_tls: 110 | if conf.tls_cacertpath: 111 | self.con.set_option(ldap.OPT_X_TLS_CACERTPATH, conf.tls_cacertpath) 112 | if conf.tls_cacertfile: 113 | self.con.set_option(ldap.OPT_X_TLS_CACERTFILE, conf.tls_cacertfile) 114 | self.con.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND) 115 | self.con.start_tls_s() 116 | debug("STARTTLS succeeded. The connection is now secured.") 117 | self.con.bind_s(conf.bind_dn, conf.bind_pw, ldap.AUTH_SIMPLE) 118 | except ldap.INVALID_CREDENTIALS: 119 | fatal("Invalid credentials. Check bind_dn [%s] and bind_pw [%s] values." % (conf.bind_dn, conf.bind_pw)) 120 | except ldap.SERVER_DOWN: 121 | fatal("Connection error. Check conf.uri value.") 122 | except ldap.LDAPError, e: 123 | fatal("%s %s" % (e.args[0]["desc"], "info" in e.args[0] and "- " + e.args[0]['info'] or "")) 124 | 125 | self.menu = { 126 | 'a' : { 'label' : 'add', 'callback' : self.cmd_add_yubikey }, 127 | 'd' : { 'label' : 'delete', 'callback' : self.cmd_del_yubikey }, 128 | '\n' : { 'label' : 'change user' }, 129 | } 130 | 131 | completer = LdapUidCompleter(self.con, self.conf) 132 | 133 | def cmd_add_yubikey(self): 134 | # Read YubiKey id, chop conf.yubi_id_len chars 135 | while True: 136 | header("Enter YubiKey ID (%d chars minimum, best way is to touch the key)" % self.conf.yubi_id_len) 137 | ykid = our_input("YubiKey ID: ") 138 | if not ykid: 139 | return 140 | if not self.is_modhex(ykid): 141 | warning("Invalid YubiKey ID. Please try again.") 142 | continue 143 | if len(ykid) < conf.yubi_id_len: 144 | warning("YubiKey ID must be at least %d characters. Please try again." % conf.yubi_id_len) 145 | continue 146 | ykid = ykid[:conf.yubi_id_len] 147 | 148 | # Check YubiKey id is already there if exists 149 | if ykid in self.user_record['yubiKeyIds']: 150 | warning("YubiKey '%s' is already assigned to '%s'. Please try again." % (ykid, self.user_record['uid'])) 151 | continue 152 | 153 | header("\nAssigning YubiKey '%s' to '%s'" % (ykid, self.user_record['uid'])) 154 | yesno = our_input("Commit? [Y/n] ") 155 | if yesno == '' or yesno[0] in ('y', 'Y'): 156 | break 157 | 158 | # Check yubiKeyUser objectClass and Add if doesn't exist 159 | if 'yubiKeyUser' not in self.user_record['objectClasses']: 160 | debug("Adding objectClass:yubiKeyUser to dn:%(dn)s" % self.user_record) 161 | mod_attrs = [( ldap.MOD_ADD, 'objectClass', 'yubiKeyUser' )] 162 | self.con.modify_s(self.user_record['dn'], mod_attrs) 163 | self.refresh_user_record() 164 | 165 | # Save yubiKey data to LDAP 166 | debug("Adding yubiKeyId:%s to dn:%s" % (ykid, self.user_record['dn'])) 167 | mod_attrs = [( ldap.MOD_ADD, 'yubiKeyId', ykid)] 168 | self.con.modify_s(self.user_record['dn'], mod_attrs) 169 | self.refresh_user_record() 170 | 171 | def cmd_del_yubikey(self): 172 | def _del_ykid(ykid): 173 | debug("Removing yubiKeyId:%s from dn:%s" % (ykid, self.user_record['dn'])) 174 | mod_attrs = [( ldap.MOD_DELETE, 'yubiKeyId', ykid)] 175 | self.con.modify_s(self.user_record['dn'], mod_attrs) 176 | self.refresh_user_record() 177 | 178 | self.display_user_info() 179 | while True: 180 | print "Enter YubiKey or the index number. Enter when done. " 181 | ykid = our_input("YubiKey to Delete: ") 182 | if not ykid: 183 | break 184 | if ykid[:conf.yubi_id_len] in self.user_record['yubiKeyIds']: 185 | _del_ykid(ykid[:conf.yubi_id_len]) 186 | else: 187 | try: 188 | index = int(ykid) - 1 189 | ykid = self.user_record['yubiKeyIds'][index] 190 | _del_ykid(ykid) 191 | except: 192 | continue 193 | if not self.user_record['yubiKeyIds']: 194 | print "No more YubiKey IDs assigned to %(cn)s [%(uid)s]" % self.user_record 195 | break 196 | 197 | def select_user(self, search_list): 198 | for index in range(len(search_list)): 199 | try: 200 | uid = search_list[index][1]['uid'][0] 201 | except: 202 | error("Invalid record: %r" % search_list[index]) 203 | continue 204 | try: 205 | cn = search_list[index][1]['cn'][0] 206 | except: 207 | cn = uid 208 | print "% 3d) %s (%s)" % (index + 1, cn, uid) 209 | if len(search_list) == 1: 210 | return search_list[0] 211 | while True: 212 | try: 213 | index = int(our_input("Select user: ")) 214 | if index < 1: 215 | raise ValueError 216 | return search_list[index-1] 217 | except (ValueError, IndexError): 218 | error("Invalid selection") 219 | 220 | def user_menu(self, cmds): 221 | prompt = " / ".join(["%s %s" % (cmd == '\n' and '' or '(%s)' % cmd, self.menu[cmd]['label']) for cmd in cmds]) 222 | header(prompt) 223 | while True: 224 | # Hack - we use '\n' in self.menu but raw_input() return empty string 225 | cmd = our_input("Command: ") or '\n' 226 | if cmd in cmds: 227 | return cmd 228 | warning("Invalid command. Please try again.") 229 | 230 | def refresh_user_record(self, uid = None): 231 | if not uid: 232 | uid = self.user_record['uid'] 233 | uid_inval_chrs = re.search('([^\w\.\-])', uid) 234 | if uid_inval_chrs: 235 | error("Invalid characters in username: %s" % uid_inval_chrs.group(1)) 236 | return False 237 | filterstr = "(uid=%s)" % uid 238 | attrlist = [ 'objectClass', 'uid', 'cn', 'yubiKeyId' ] 239 | res = self.con.search_s(self.conf.base_dn, ldap.SCOPE_SUBTREE, filterstr, attrlist) 240 | if not res: 241 | error("Unknown user: %s" % uid) 242 | return False 243 | res = res[0] 244 | 245 | self.user_record = { 246 | 'dn' : res[0], 247 | 'objectClasses' : res[1]['objectClass'], 248 | 'uid' : res[1]['uid'][0], 249 | 'cn' : 'cn' in res[1] and res[1]['cn'][0] or '', 250 | 'yubiKeyIds' : 'yubiKeyId' in res[1] and res[1]['yubiKeyId'] or {}, 251 | } 252 | 253 | return True 254 | 255 | def display_user_info(self): 256 | headerstr = "%(cn)s [%(uid)s] has " % self.user_record 257 | if not self.user_record['yubiKeyIds']: 258 | headerstr += "no assigned YubiKeys" 259 | elif len(self.user_record['yubiKeyIds']) == 1: 260 | headerstr += "1 assigned YubiKey" 261 | else: 262 | headerstr += "%d assigned YubiKeys" % len(self.user_record['yubiKeyIds']) 263 | header(headerstr) 264 | for index in range(len(self.user_record['yubiKeyIds'])): 265 | print "% 3d) %s" % (index + 1, self.user_record['yubiKeyIds'][index]) 266 | print 267 | 268 | def is_modhex(self, string): 269 | return bool(re.match('^[b-lnrtuv]+\s*$', string)) 270 | 271 | def find_user_by_yubikey(self, inp): 272 | if not self.is_modhex(inp): 273 | return '' 274 | ykid = inp[:self.conf.yubi_id_len] 275 | filterstr = "(yubiKeyId=%s)" % ykid 276 | attrlist = [ 'uid', 'cn' ] 277 | res = self.con.search_s(self.conf.base_dn, ldap.SCOPE_SUBTREE, filterstr, attrlist) 278 | if not res: 279 | return '' 280 | header("YubiKey '%s' is assigned to these users:" % ykid) 281 | res = self.select_user(res) 282 | return res[1]['uid'][0] 283 | 284 | def main(self): 285 | header("\nEnter username ( to autocomplete) or YubiKey Id to manage") 286 | while True: 287 | inp = our_input("Username or YubiKey: ") 288 | if inp: 289 | break 290 | 291 | # Find user from YubiKey or use 'inp' as username 292 | user = self.find_user_by_yubikey(inp) or inp 293 | 294 | if not self.refresh_user_record(uid = user): 295 | return 296 | 297 | while True: 298 | self.display_user_info() 299 | 300 | command = self.user_menu(cmds = len(self.user_record['yubiKeyIds'])>0 and "ad\n" or "a\n") 301 | 302 | if 'callback' in self.menu[command]: 303 | self.menu[command]['callback']() 304 | elif command.strip() == "": 305 | return # self.user_recordtart main() in the caller 306 | else: 307 | error("Not yet implemented...") 308 | 309 | if __name__ == "__main__": 310 | # Temporary config-like handling. 311 | # We'll do better later. 312 | try: 313 | execfile(config_file) 314 | except: 315 | fatal("Failure reading config file: %s" % config_file) 316 | 317 | ykmgr = YubiKeyManager(conf) 318 | 319 | print(bcolours.BOLD + "yubikey-ldap manager" + bcolours.RESET + " (written by Michal Ludvig)") 320 | print(bcolours.YELLOW + "Use " + bcolours.BOLD + "Ctrl+D" + bcolours.RESET + bcolours.YELLOW + " to exit at any time") 321 | print(bcolours.YELLOW + "Use " + bcolours.BOLD + "Enter" + bcolours.RESET + bcolours.YELLOW + " to return one level up") 322 | 323 | # Enter main loop 324 | while True: 325 | try: 326 | ykmgr.main() 327 | except (KeyboardInterrupt, EOFError): 328 | print "\n" 329 | break 330 | 331 | #con.unbind_s() 332 | #print con.whoami_s() 333 | -------------------------------------------------------------------------------- /yubikey-ldap.conf.sample: -------------------------------------------------------------------------------- 1 | # 2 | # Sample yubikey-ldap.conf 3 | # 4 | # Author: Michal Ludvig - http://logix.cz/michal/devel/yubikey-ldap/ 5 | # 6 | 7 | # LDAP server URI 8 | conf.uri = "ldap://ldap.example.com" 9 | 10 | # Start TLS 11 | # (default is False, however True is recommended) 12 | conf.start_tls = True 13 | 14 | # TLS CA Certificates 15 | # By default the values from system ldap.conf are used 16 | #conf.tls_cacertpath = "/etc/pki/tls/certs" 17 | #conf.tls_cacertfile = "/etc/pki/tls/certs/ca-bundle.pem" 18 | 19 | # Only simple authentication supported, no SASL yet 20 | conf.bind_dn = "cn=Manager,dc=example,dc=com" 21 | conf.bind_pw = "Secr3t" 22 | 23 | # Where are your user objects stored? 24 | conf.base_dn = "ou=People,dc=example,dc=com" 25 | 26 | # YubiKey output is very long and only a few chars 27 | # at the beginning is the ID we need to store in LDAP. 28 | # For YubiCloud authentication it's 12 chars. 29 | conf.yubi_id_len = 12 30 | --------------------------------------------------------------------------------